summaryrefslogtreecommitdiffstats
path: root/third_party/rust/object/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/object/src/archive.rs91
-rw-r--r--third_party/rust/object/src/common.rs501
-rw-r--r--third_party/rust/object/src/elf.rs6156
-rw-r--r--third_party/rust/object/src/endian.rs831
-rw-r--r--third_party/rust/object/src/lib.rs116
-rw-r--r--third_party/rust/object/src/macho.rs3307
-rw-r--r--third_party/rust/object/src/pe.rs3054
-rw-r--r--third_party/rust/object/src/pod.rs239
-rw-r--r--third_party/rust/object/src/read/any.rs1314
-rw-r--r--third_party/rust/object/src/read/archive.rs739
-rw-r--r--third_party/rust/object/src/read/coff/comdat.rs207
-rw-r--r--third_party/rust/object/src/read/coff/file.rs364
-rw-r--r--third_party/rust/object/src/read/coff/import.rs209
-rw-r--r--third_party/rust/object/src/read/coff/mod.rs21
-rw-r--r--third_party/rust/object/src/read/coff/relocation.rs104
-rw-r--r--third_party/rust/object/src/read/coff/section.rs574
-rw-r--r--third_party/rust/object/src/read/coff/symbol.rs626
-rw-r--r--third_party/rust/object/src/read/elf/attributes.rs303
-rw-r--r--third_party/rust/object/src/read/elf/comdat.rs160
-rw-r--r--third_party/rust/object/src/read/elf/compression.rs56
-rw-r--r--third_party/rust/object/src/read/elf/dynamic.rs117
-rw-r--r--third_party/rust/object/src/read/elf/file.rs911
-rw-r--r--third_party/rust/object/src/read/elf/hash.rs220
-rw-r--r--third_party/rust/object/src/read/elf/mod.rs42
-rw-r--r--third_party/rust/object/src/read/elf/note.rs266
-rw-r--r--third_party/rust/object/src/read/elf/relocation.rs576
-rw-r--r--third_party/rust/object/src/read/elf/section.rs1146
-rw-r--r--third_party/rust/object/src/read/elf/segment.rs332
-rw-r--r--third_party/rust/object/src/read/elf/symbol.rs585
-rw-r--r--third_party/rust/object/src/read/elf/version.rs421
-rw-r--r--third_party/rust/object/src/read/macho/dyld_cache.rs343
-rw-r--r--third_party/rust/object/src/read/macho/fat.rs122
-rw-r--r--third_party/rust/object/src/read/macho/file.rs731
-rw-r--r--third_party/rust/object/src/read/macho/load_command.rs373
-rw-r--r--third_party/rust/object/src/read/macho/mod.rs30
-rw-r--r--third_party/rust/object/src/read/macho/relocation.rs127
-rw-r--r--third_party/rust/object/src/read/macho/section.rs387
-rw-r--r--third_party/rust/object/src/read/macho/segment.rs301
-rw-r--r--third_party/rust/object/src/read/macho/symbol.rs488
-rw-r--r--third_party/rust/object/src/read/mod.rs767
-rw-r--r--third_party/rust/object/src/read/pe/data_directory.rs211
-rw-r--r--third_party/rust/object/src/read/pe/export.rs331
-rw-r--r--third_party/rust/object/src/read/pe/file.rs1029
-rw-r--r--third_party/rust/object/src/read/pe/import.rs332
-rw-r--r--third_party/rust/object/src/read/pe/mod.rs34
-rw-r--r--third_party/rust/object/src/read/pe/relocation.rs90
-rw-r--r--third_party/rust/object/src/read/pe/resource.rs207
-rw-r--r--third_party/rust/object/src/read/pe/rich.rs91
-rw-r--r--third_party/rust/object/src/read/pe/section.rs434
-rw-r--r--third_party/rust/object/src/read/read_cache.rs182
-rw-r--r--third_party/rust/object/src/read/read_ref.rs137
-rw-r--r--third_party/rust/object/src/read/traits.rs469
-rw-r--r--third_party/rust/object/src/read/util.rs425
-rw-r--r--third_party/rust/object/src/read/wasm.rs951
-rw-r--r--third_party/rust/object/src/read/xcoff/comdat.rs129
-rw-r--r--third_party/rust/object/src/read/xcoff/file.rs629
-rw-r--r--third_party/rust/object/src/read/xcoff/mod.rs21
-rw-r--r--third_party/rust/object/src/read/xcoff/relocation.rs127
-rw-r--r--third_party/rust/object/src/read/xcoff/section.rs427
-rw-r--r--third_party/rust/object/src/read/xcoff/segment.rs113
-rw-r--r--third_party/rust/object/src/read/xcoff/symbol.rs695
-rw-r--r--third_party/rust/object/src/write/coff.rs725
-rw-r--r--third_party/rust/object/src/write/elf/mod.rs9
-rw-r--r--third_party/rust/object/src/write/elf/object.rs903
-rw-r--r--third_party/rust/object/src/write/elf/writer.rs2143
-rw-r--r--third_party/rust/object/src/write/macho.rs966
-rw-r--r--third_party/rust/object/src/write/mod.rs943
-rw-r--r--third_party/rust/object/src/write/pe.rs847
-rw-r--r--third_party/rust/object/src/write/string.rs159
-rw-r--r--third_party/rust/object/src/write/util.rs260
-rw-r--r--third_party/rust/object/src/write/xcoff.rs556
-rw-r--r--third_party/rust/object/src/xcoff.rs893
72 files changed, 42725 insertions, 0 deletions
diff --git a/third_party/rust/object/src/archive.rs b/third_party/rust/object/src/archive.rs
new file mode 100644
index 0000000000..6271d07360
--- /dev/null
+++ b/third_party/rust/object/src/archive.rs
@@ -0,0 +1,91 @@
+//! Archive definitions.
+//!
+//! These definitions are independent of read/write support, although we do implement
+//! some traits useful for those.
+
+use crate::pod::Pod;
+
+/// File identification bytes stored at the beginning of the file.
+pub const MAGIC: [u8; 8] = *b"!<arch>\n";
+
+/// File identification bytes at the beginning of AIX big archive.
+pub const AIX_BIG_MAGIC: [u8; 8] = *b"<bigaf>\n";
+
+/// File identification bytes stored at the beginning of a thin archive.
+///
+/// A thin archive only contains a symbol table and file names.
+pub const THIN_MAGIC: [u8; 8] = *b"!<thin>\n";
+
+/// The terminator for each archive member header.
+pub const TERMINATOR: [u8; 2] = *b"`\n";
+
+/// The header at the start of an archive member.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Header {
+ /// The file name.
+ pub name: [u8; 16],
+ /// File modification timestamp in decimal.
+ pub date: [u8; 12],
+ /// User ID in decimal.
+ pub uid: [u8; 6],
+ /// Group ID in decimal.
+ pub gid: [u8; 6],
+ /// File mode in octal.
+ pub mode: [u8; 8],
+ /// File size in decimal.
+ pub size: [u8; 10],
+ /// Must be equal to `TERMINATOR`.
+ pub terminator: [u8; 2],
+}
+
+/// The header at the start of an AIX big archive member, without name.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AixHeader {
+ /// File member size in decimal.
+ pub size: [u8; 20],
+ /// Next member offset in decimal.
+ pub nxtmem: [u8; 20],
+ /// Previous member offset in decimal.
+ pub prvmem: [u8; 20],
+ /// File member date in decimal.
+ pub date: [u8; 12],
+ /// File member user id in decimal.
+ pub uid: [u8; 12],
+ /// File member group id in decimal.
+ pub gid: [u8; 12],
+ /// File member mode in octal.
+ pub mode: [u8; 12],
+ /// File member name length in decimal.
+ pub namlen: [u8; 4],
+}
+
+/// The AIX big archive's fixed length header at file beginning.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AixFileHeader {
+ /// Archive magic string.
+ pub magic: [u8; 8],
+ /// Offset of member table.
+ pub memoff: [u8; 20],
+ /// Offset of global symbol table.
+ pub gstoff: [u8; 20],
+ /// Offset of global symbol table for 64-bit objects.
+ pub gst64off: [u8; 20],
+ /// Offset of first member.
+ pub fstmoff: [u8; 20],
+ /// Offset of last member.
+ pub lstmoff: [u8; 20],
+ /// Offset of first member on free list.
+ pub freeoff: [u8; 20],
+}
+
+/// Offset of a member in an AIX big archive.
+///
+/// This is used in the member index.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AixMemberOffset(pub [u8; 20]);
+
+unsafe_impl_pod!(Header, AixHeader, AixFileHeader, AixMemberOffset,);
diff --git a/third_party/rust/object/src/common.rs b/third_party/rust/object/src/common.rs
new file mode 100644
index 0000000000..0e6af091ce
--- /dev/null
+++ b/third_party/rust/object/src/common.rs
@@ -0,0 +1,501 @@
+/// A CPU architecture.
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum Architecture {
+ Unknown,
+ Aarch64,
+ #[allow(non_camel_case_types)]
+ Aarch64_Ilp32,
+ Arm,
+ Avr,
+ Bpf,
+ Csky,
+ I386,
+ X86_64,
+ #[allow(non_camel_case_types)]
+ X86_64_X32,
+ Hexagon,
+ LoongArch64,
+ Mips,
+ Mips64,
+ Msp430,
+ PowerPc,
+ PowerPc64,
+ Riscv32,
+ Riscv64,
+ S390x,
+ Sbf,
+ Sparc64,
+ Wasm32,
+ Wasm64,
+ Xtensa,
+}
+
+impl Architecture {
+ /// The size of an address value for this architecture.
+ ///
+ /// Returns `None` for unknown architectures.
+ pub fn address_size(self) -> Option<AddressSize> {
+ match self {
+ Architecture::Unknown => None,
+ Architecture::Aarch64 => Some(AddressSize::U64),
+ Architecture::Aarch64_Ilp32 => Some(AddressSize::U32),
+ Architecture::Arm => Some(AddressSize::U32),
+ Architecture::Avr => Some(AddressSize::U8),
+ Architecture::Bpf => Some(AddressSize::U64),
+ Architecture::Csky => Some(AddressSize::U32),
+ Architecture::I386 => Some(AddressSize::U32),
+ Architecture::X86_64 => Some(AddressSize::U64),
+ Architecture::X86_64_X32 => Some(AddressSize::U32),
+ Architecture::Hexagon => Some(AddressSize::U32),
+ Architecture::LoongArch64 => Some(AddressSize::U64),
+ Architecture::Mips => Some(AddressSize::U32),
+ Architecture::Mips64 => Some(AddressSize::U64),
+ Architecture::Msp430 => Some(AddressSize::U16),
+ Architecture::PowerPc => Some(AddressSize::U32),
+ Architecture::PowerPc64 => Some(AddressSize::U64),
+ Architecture::Riscv32 => Some(AddressSize::U32),
+ Architecture::Riscv64 => Some(AddressSize::U64),
+ Architecture::S390x => Some(AddressSize::U64),
+ Architecture::Sbf => Some(AddressSize::U64),
+ Architecture::Sparc64 => Some(AddressSize::U64),
+ Architecture::Wasm32 => Some(AddressSize::U32),
+ Architecture::Wasm64 => Some(AddressSize::U64),
+ Architecture::Xtensa => Some(AddressSize::U32),
+ }
+ }
+}
+
+/// The size of an address value for an architecture.
+///
+/// This may differ from the address size supported by the file format (such as for COFF).
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+#[repr(u8)]
+pub enum AddressSize {
+ U8 = 1,
+ U16 = 2,
+ U32 = 4,
+ U64 = 8,
+}
+
+impl AddressSize {
+ /// The size in bytes of an address value.
+ #[inline]
+ pub fn bytes(self) -> u8 {
+ self as u8
+ }
+}
+
+/// A binary file format.
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum BinaryFormat {
+ Coff,
+ Elf,
+ MachO,
+ Pe,
+ Wasm,
+ Xcoff,
+}
+
+/// The kind of a section.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SectionKind {
+ /// The section kind is unknown.
+ Unknown,
+ /// An executable code section.
+ ///
+ /// Example ELF sections: `.text`
+ ///
+ /// Example Mach-O sections: `__TEXT/__text`
+ Text,
+ /// A data section.
+ ///
+ /// Example ELF sections: `.data`
+ ///
+ /// Example Mach-O sections: `__DATA/__data`
+ Data,
+ /// A read only data section.
+ ///
+ /// Example ELF sections: `.rodata`
+ ///
+ /// Example Mach-O sections: `__TEXT/__const`, `__DATA/__const`, `__TEXT/__literal4`
+ ReadOnlyData,
+ /// A read only data section with relocations.
+ ///
+ /// This is the same as either `Data` or `ReadOnlyData`, depending on the file format.
+ /// This value is only used in the API for writing files. It is never returned when reading files.
+ ReadOnlyDataWithRel,
+ /// A loadable string section.
+ ///
+ /// Example ELF sections: `.rodata.str`
+ ///
+ /// Example Mach-O sections: `__TEXT/__cstring`
+ ReadOnlyString,
+ /// An uninitialized data section.
+ ///
+ /// Example ELF sections: `.bss`
+ ///
+ /// Example Mach-O sections: `__DATA/__bss`
+ UninitializedData,
+ /// An uninitialized common data section.
+ ///
+ /// Example Mach-O sections: `__DATA/__common`
+ Common,
+ /// A TLS data section.
+ ///
+ /// Example ELF sections: `.tdata`
+ ///
+ /// Example Mach-O sections: `__DATA/__thread_data`
+ Tls,
+ /// An uninitialized TLS data section.
+ ///
+ /// Example ELF sections: `.tbss`
+ ///
+ /// Example Mach-O sections: `__DATA/__thread_bss`
+ UninitializedTls,
+ /// A TLS variables section.
+ ///
+ /// This contains TLS variable structures, rather than the variable initializers.
+ ///
+ /// Example Mach-O sections: `__DATA/__thread_vars`
+ TlsVariables,
+ /// A non-loadable string section.
+ ///
+ /// Example ELF sections: `.comment`, `.debug_str`
+ OtherString,
+ /// Some other non-loadable section.
+ ///
+ /// Example ELF sections: `.debug_info`
+ Other,
+ /// Debug information.
+ ///
+ /// Example Mach-O sections: `__DWARF/__debug_info`
+ Debug,
+ /// Information for the linker.
+ ///
+ /// Example COFF sections: `.drectve`
+ Linker,
+ /// ELF note section.
+ Note,
+ /// Metadata such as symbols or relocations.
+ ///
+ /// Example ELF sections: `.symtab`, `.strtab`, `.group`
+ Metadata,
+ /// Some other ELF section type.
+ ///
+ /// This is the `sh_type` field in the section header.
+ /// The meaning may be dependent on the architecture.
+ Elf(u32),
+}
+
+impl SectionKind {
+ /// Return true if this section contains zerofill data.
+ pub fn is_bss(self) -> bool {
+ self == SectionKind::UninitializedData
+ || self == SectionKind::UninitializedTls
+ || self == SectionKind::Common
+ }
+}
+
+/// The selection kind for a COMDAT section group.
+///
+/// This determines the way in which the linker resolves multiple definitions of the COMDAT
+/// sections.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum ComdatKind {
+ /// The selection kind is unknown.
+ Unknown,
+ /// Multiple definitions are allowed.
+ ///
+ /// An arbitrary definition is selected, and the rest are removed.
+ ///
+ /// This is the only supported selection kind for ELF.
+ Any,
+ /// Multiple definitions are not allowed.
+ ///
+ /// This is used to group sections without allowing duplicates.
+ NoDuplicates,
+ /// Multiple definitions must have the same size.
+ ///
+ /// An arbitrary definition is selected, and the rest are removed.
+ SameSize,
+ /// Multiple definitions must match exactly.
+ ///
+ /// An arbitrary definition is selected, and the rest are removed.
+ ExactMatch,
+ /// Multiple definitions are allowed, and the largest is selected.
+ ///
+ /// An arbitrary definition with the largest size is selected, and the rest are removed.
+ Largest,
+ /// Multiple definitions are allowed, and the newest is selected.
+ Newest,
+}
+
+/// The kind of a symbol.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SymbolKind {
+ /// The symbol kind is unknown.
+ Unknown,
+ /// The symbol is a null placeholder.
+ Null,
+ /// The symbol is for executable code.
+ Text,
+ /// The symbol is for a data object.
+ Data,
+ /// The symbol is for a section.
+ Section,
+ /// The symbol is the name of a file. It precedes symbols within that file.
+ File,
+ /// The symbol is for a code label.
+ Label,
+ /// The symbol is for a thread local storage entity.
+ Tls,
+}
+
+/// A symbol scope.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum SymbolScope {
+ /// Unknown scope.
+ Unknown,
+ /// Symbol is visible to the compilation unit.
+ Compilation,
+ /// Symbol is visible to the static linkage unit.
+ Linkage,
+ /// Symbol is visible to dynamically linked objects.
+ Dynamic,
+}
+
+/// The operation used to calculate the result of the relocation.
+///
+/// The relocation descriptions use the following definitions. Note that
+/// these definitions probably don't match any ELF ABI.
+///
+/// * A - The value of the addend.
+/// * G - The address of the symbol's entry within the global offset table.
+/// * L - The address of the symbol's entry within the procedure linkage table.
+/// * P - The address of the place of the relocation.
+/// * S - The address of the symbol.
+/// * GotBase - The address of the global offset table.
+/// * Image - The base address of the image.
+/// * Section - The address of the section containing the symbol.
+///
+/// 'XxxRelative' means 'Xxx + A - P'. 'XxxOffset' means 'S + A - Xxx'.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum RelocationKind {
+ /// S + A
+ Absolute,
+ /// S + A - P
+ Relative,
+ /// G + A - GotBase
+ Got,
+ /// G + A - P
+ GotRelative,
+ /// GotBase + A - P
+ GotBaseRelative,
+ /// S + A - GotBase
+ GotBaseOffset,
+ /// L + A - P
+ PltRelative,
+ /// S + A - Image
+ ImageOffset,
+ /// S + A - Section
+ SectionOffset,
+ /// The index of the section containing the symbol.
+ SectionIndex,
+ /// Some other ELF relocation. The value is dependent on the architecture.
+ Elf(u32),
+ /// Some other Mach-O relocation. The value is dependent on the architecture.
+ MachO {
+ /// The relocation type.
+ value: u8,
+ /// Whether the relocation is relative to the place.
+ relative: bool,
+ },
+ /// Some other COFF relocation. The value is dependent on the architecture.
+ Coff(u16),
+ /// Some other XCOFF relocation.
+ Xcoff(u8),
+}
+
+/// Information about how the result of the relocation operation is encoded in the place.
+///
+/// This is usually architecture specific, such as specifying an addressing mode or
+/// a specific instruction.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum RelocationEncoding {
+ /// Generic encoding.
+ Generic,
+
+ /// x86 sign extension at runtime.
+ ///
+ /// Used with `RelocationKind::Absolute`.
+ X86Signed,
+ /// x86 rip-relative addressing.
+ ///
+ /// The `RelocationKind` must be PC relative.
+ X86RipRelative,
+ /// x86 rip-relative addressing in movq instruction.
+ ///
+ /// The `RelocationKind` must be PC relative.
+ X86RipRelativeMovq,
+ /// x86 branch instruction.
+ ///
+ /// The `RelocationKind` must be PC relative.
+ X86Branch,
+
+ /// s390x PC-relative offset shifted right by one bit.
+ ///
+ /// The `RelocationKind` must be PC relative.
+ S390xDbl,
+
+ /// AArch64 call target.
+ ///
+ /// The `RelocationKind` must be PC relative.
+ AArch64Call,
+
+ /// LoongArch branch offset with two trailing zeros.
+ ///
+ /// The `RelocationKind` must be PC relative.
+ LoongArchBranch,
+}
+
+/// File flags that are specific to each file format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum FileFlags {
+ /// No file flags.
+ None,
+ /// ELF file flags.
+ Elf {
+ /// `os_abi` field in the ELF file header.
+ os_abi: u8,
+ /// `abi_version` field in the ELF file header.
+ abi_version: u8,
+ /// `e_flags` field in the ELF file header.
+ e_flags: u32,
+ },
+ /// Mach-O file flags.
+ MachO {
+ /// `flags` field in the Mach-O file header.
+ flags: u32,
+ },
+ /// COFF file flags.
+ Coff {
+ /// `Characteristics` field in the COFF file header.
+ characteristics: u16,
+ },
+ /// XCOFF file flags.
+ Xcoff {
+ /// `f_flags` field in the XCOFF file header.
+ f_flags: u16,
+ },
+}
+
+/// Segment flags that are specific to each file format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SegmentFlags {
+ /// No segment flags.
+ None,
+ /// ELF segment flags.
+ Elf {
+ /// `p_flags` field in the segment header.
+ p_flags: u32,
+ },
+ /// Mach-O segment flags.
+ MachO {
+ /// `flags` field in the segment header.
+ flags: u32,
+ /// `maxprot` field in the segment header.
+ maxprot: u32,
+ /// `initprot` field in the segment header.
+ initprot: u32,
+ },
+ /// COFF segment flags.
+ Coff {
+ /// `Characteristics` field in the segment header.
+ characteristics: u32,
+ },
+}
+
+/// Section flags that are specific to each file format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SectionFlags {
+ /// No section flags.
+ None,
+ /// ELF section flags.
+ Elf {
+ /// `sh_flags` field in the section header.
+ sh_flags: u64,
+ },
+ /// Mach-O section flags.
+ MachO {
+ /// `flags` field in the section header.
+ flags: u32,
+ },
+ /// COFF section flags.
+ Coff {
+ /// `Characteristics` field in the section header.
+ characteristics: u32,
+ },
+ /// XCOFF section flags.
+ Xcoff {
+ /// `s_flags` field in the section header.
+ s_flags: u32,
+ },
+}
+
+/// Symbol flags that are specific to each file format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SymbolFlags<Section, Symbol> {
+ /// No symbol flags.
+ None,
+ /// ELF symbol flags.
+ Elf {
+ /// `st_info` field in the ELF symbol.
+ st_info: u8,
+ /// `st_other` field in the ELF symbol.
+ st_other: u8,
+ },
+ /// Mach-O symbol flags.
+ MachO {
+ /// `n_desc` field in the Mach-O symbol.
+ n_desc: u16,
+ },
+ /// COFF flags for a section symbol.
+ CoffSection {
+ /// `Selection` field in the auxiliary symbol for the section.
+ selection: u8,
+ /// `Number` field in the auxiliary symbol for the section.
+ associative_section: Option<Section>,
+ },
+ /// XCOFF symbol flags.
+ Xcoff {
+ /// `n_sclass` field in the XCOFF symbol.
+ n_sclass: u8,
+ /// `x_smtyp` field in the CSECT auxiliary symbol.
+ ///
+ /// Only valid if `n_sclass` is `C_EXT`, `C_WEAKEXT`, or `C_HIDEXT`.
+ x_smtyp: u8,
+ /// `x_smclas` field in the CSECT auxiliary symbol.
+ ///
+ /// Only valid if `n_sclass` is `C_EXT`, `C_WEAKEXT`, or `C_HIDEXT`.
+ x_smclas: u8,
+ /// The containing csect for the symbol.
+ ///
+ /// Only valid if `x_smtyp` is `XTY_LD`.
+ containing_csect: Option<Symbol>,
+ },
+}
diff --git a/third_party/rust/object/src/elf.rs b/third_party/rust/object/src/elf.rs
new file mode 100644
index 0000000000..da68ec2d40
--- /dev/null
+++ b/third_party/rust/object/src/elf.rs
@@ -0,0 +1,6156 @@
+//! ELF definitions.
+//!
+//! These definitions are independent of read/write support, although we do implement
+//! some traits useful for those.
+//!
+//! This module is the equivalent of /usr/include/elf.h, and is based heavily on it.
+
+#![allow(missing_docs)]
+#![allow(clippy::identity_op)]
+
+use crate::endian::{Endian, U32Bytes, U64Bytes, I32, I64, U16, U32, U64};
+use crate::pod::Pod;
+
+/// The header at the start of every 32-bit ELF file.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FileHeader32<E: Endian> {
+ /// Magic number and other information.
+ pub e_ident: Ident,
+ /// Object file type. One of the `ET_*` constants.
+ pub e_type: U16<E>,
+ /// Architecture. One of the `EM_*` constants.
+ pub e_machine: U16<E>,
+ /// Object file version. Must be `EV_CURRENT`.
+ pub e_version: U32<E>,
+ /// Entry point virtual address.
+ pub e_entry: U32<E>,
+ /// Program header table file offset.
+ pub e_phoff: U32<E>,
+ /// Section header table file offset.
+ pub e_shoff: U32<E>,
+ /// Processor-specific flags.
+ ///
+ /// A combination of the `EF_*` constants.
+ pub e_flags: U32<E>,
+ /// Size in bytes of this header.
+ pub e_ehsize: U16<E>,
+ /// Program header table entry size.
+ pub e_phentsize: U16<E>,
+ /// Program header table entry count.
+ ///
+ /// If the count is greater than or equal to `PN_XNUM` then this field is set to
+ /// `PN_XNUM` and the count is stored in the `sh_info` field of section 0.
+ pub e_phnum: U16<E>,
+ /// Section header table entry size.
+ pub e_shentsize: U16<E>,
+ /// Section header table entry count.
+ ///
+ /// If the count is greater than or equal to `SHN_LORESERVE` then this field is set to
+ /// `0` and the count is stored in the `sh_size` field of section 0.
+ /// first section header.
+ pub e_shnum: U16<E>,
+ /// Section header string table index.
+ ///
+ /// If the index is greater than or equal to `SHN_LORESERVE` then this field is set to
+ /// `SHN_XINDEX` and the index is stored in the `sh_link` field of section 0.
+ pub e_shstrndx: U16<E>,
+}
+
+/// The header at the start of every 64-bit ELF file.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FileHeader64<E: Endian> {
+ /// Magic number and other information.
+ pub e_ident: Ident,
+ /// Object file type. One of the `ET_*` constants.
+ pub e_type: U16<E>,
+ /// Architecture. One of the `EM_*` constants.
+ pub e_machine: U16<E>,
+ /// Object file version. Must be `EV_CURRENT`.
+ pub e_version: U32<E>,
+ /// Entry point virtual address.
+ pub e_entry: U64<E>,
+ /// Program header table file offset.
+ pub e_phoff: U64<E>,
+ /// Section header table file offset.
+ pub e_shoff: U64<E>,
+ /// Processor-specific flags.
+ ///
+ /// A combination of the `EF_*` constants.
+ pub e_flags: U32<E>,
+ /// Size in bytes of this header.
+ pub e_ehsize: U16<E>,
+ /// Program header table entry size.
+ pub e_phentsize: U16<E>,
+ /// Program header table entry count.
+ ///
+ /// If the count is greater than or equal to `PN_XNUM` then this field is set to
+ /// `PN_XNUM` and the count is stored in the `sh_info` field of section 0.
+ pub e_phnum: U16<E>,
+ /// Section header table entry size.
+ pub e_shentsize: U16<E>,
+ /// Section header table entry count.
+ ///
+ /// If the count is greater than or equal to `SHN_LORESERVE` then this field is set to
+ /// `0` and the count is stored in the `sh_size` field of section 0.
+ /// first section header.
+ pub e_shnum: U16<E>,
+ /// Section header string table index.
+ ///
+ /// If the index is greater than or equal to `SHN_LORESERVE` then this field is set to
+ /// `SHN_XINDEX` and the index is stored in the `sh_link` field of section 0.
+ pub e_shstrndx: U16<E>,
+}
+
+/// Magic number and other information.
+///
+/// Contained in the file header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Ident {
+ /// Magic number. Must be `ELFMAG`.
+ pub magic: [u8; 4],
+ /// File class. One of the `ELFCLASS*` constants.
+ pub class: u8,
+ /// Data encoding. One of the `ELFDATA*` constants.
+ pub data: u8,
+ /// ELF version. Must be `EV_CURRENT`.
+ pub version: u8,
+ /// OS ABI identification. One of the `ELFOSABI*` constants.
+ pub os_abi: u8,
+ /// ABI version.
+ ///
+ /// The meaning of this field depends on the `os_abi` value.
+ pub abi_version: u8,
+ /// Padding bytes.
+ pub padding: [u8; 7],
+}
+
+/// File identification bytes stored in `Ident::magic`.
+pub const ELFMAG: [u8; 4] = [0x7f, b'E', b'L', b'F'];
+
+// Values for `Ident::class`.
+/// Invalid class.
+pub const ELFCLASSNONE: u8 = 0;
+/// 32-bit object.
+pub const ELFCLASS32: u8 = 1;
+/// 64-bit object.
+pub const ELFCLASS64: u8 = 2;
+
+// Values for `Ident::data`.
+/// Invalid data encoding.
+pub const ELFDATANONE: u8 = 0;
+/// 2's complement, little endian.
+pub const ELFDATA2LSB: u8 = 1;
+/// 2's complement, big endian.
+pub const ELFDATA2MSB: u8 = 2;
+
+// Values for `Ident::os_abi`.
+/// UNIX System V ABI.
+pub const ELFOSABI_NONE: u8 = 0;
+/// UNIX System V ABI.
+///
+/// Alias.
+pub const ELFOSABI_SYSV: u8 = 0;
+/// HP-UX.
+pub const ELFOSABI_HPUX: u8 = 1;
+/// NetBSD.
+pub const ELFOSABI_NETBSD: u8 = 2;
+/// Object uses GNU ELF extensions.
+pub const ELFOSABI_GNU: u8 = 3;
+/// Object uses GNU ELF extensions.
+///
+/// Compatibility alias.
+pub const ELFOSABI_LINUX: u8 = ELFOSABI_GNU;
+/// GNU/Hurd.
+pub const ELFOSABI_HURD: u8 = 4;
+/// Sun Solaris.
+pub const ELFOSABI_SOLARIS: u8 = 6;
+/// IBM AIX.
+pub const ELFOSABI_AIX: u8 = 7;
+/// SGI Irix.
+pub const ELFOSABI_IRIX: u8 = 8;
+/// FreeBSD.
+pub const ELFOSABI_FREEBSD: u8 = 9;
+/// Compaq TRU64 UNIX.
+pub const ELFOSABI_TRU64: u8 = 10;
+/// Novell Modesto.
+pub const ELFOSABI_MODESTO: u8 = 11;
+/// OpenBSD.
+pub const ELFOSABI_OPENBSD: u8 = 12;
+/// OpenVMS.
+pub const ELFOSABI_OPENVMS: u8 = 13;
+/// Hewlett-Packard Non-Stop Kernel.
+pub const ELFOSABI_NSK: u8 = 14;
+/// AROS
+pub const ELFOSABI_AROS: u8 = 15;
+/// FenixOS
+pub const ELFOSABI_FENIXOS: u8 = 16;
+/// Nuxi CloudABI
+pub const ELFOSABI_CLOUDABI: u8 = 17;
+/// ARM EABI.
+pub const ELFOSABI_ARM_AEABI: u8 = 64;
+/// ARM.
+pub const ELFOSABI_ARM: u8 = 97;
+/// Standalone (embedded) application.
+pub const ELFOSABI_STANDALONE: u8 = 255;
+
+// Values for `FileHeader*::e_type`.
+/// No file type.
+pub const ET_NONE: u16 = 0;
+/// Relocatable file.
+pub const ET_REL: u16 = 1;
+/// Executable file.
+pub const ET_EXEC: u16 = 2;
+/// Shared object file.
+pub const ET_DYN: u16 = 3;
+/// Core file.
+pub const ET_CORE: u16 = 4;
+/// OS-specific range start.
+pub const ET_LOOS: u16 = 0xfe00;
+/// OS-specific range end.
+pub const ET_HIOS: u16 = 0xfeff;
+/// Processor-specific range start.
+pub const ET_LOPROC: u16 = 0xff00;
+/// Processor-specific range end.
+pub const ET_HIPROC: u16 = 0xffff;
+
+// Values for `FileHeader*::e_machine`.
+/// No machine
+pub const EM_NONE: u16 = 0;
+/// AT&T WE 32100
+pub const EM_M32: u16 = 1;
+/// SUN SPARC
+pub const EM_SPARC: u16 = 2;
+/// Intel 80386
+pub const EM_386: u16 = 3;
+/// Motorola m68k family
+pub const EM_68K: u16 = 4;
+/// Motorola m88k family
+pub const EM_88K: u16 = 5;
+/// Intel MCU
+pub const EM_IAMCU: u16 = 6;
+/// Intel 80860
+pub const EM_860: u16 = 7;
+/// MIPS R3000 big-endian
+pub const EM_MIPS: u16 = 8;
+/// IBM System/370
+pub const EM_S370: u16 = 9;
+/// MIPS R3000 little-endian
+pub const EM_MIPS_RS3_LE: u16 = 10;
+/// HPPA
+pub const EM_PARISC: u16 = 15;
+/// Fujitsu VPP500
+pub const EM_VPP500: u16 = 17;
+/// Sun's "v8plus"
+pub const EM_SPARC32PLUS: u16 = 18;
+/// Intel 80960
+pub const EM_960: u16 = 19;
+/// PowerPC
+pub const EM_PPC: u16 = 20;
+/// PowerPC 64-bit
+pub const EM_PPC64: u16 = 21;
+/// IBM S390
+pub const EM_S390: u16 = 22;
+/// IBM SPU/SPC
+pub const EM_SPU: u16 = 23;
+/// NEC V800 series
+pub const EM_V800: u16 = 36;
+/// Fujitsu FR20
+pub const EM_FR20: u16 = 37;
+/// TRW RH-32
+pub const EM_RH32: u16 = 38;
+/// Motorola RCE
+pub const EM_RCE: u16 = 39;
+/// ARM
+pub const EM_ARM: u16 = 40;
+/// Digital Alpha
+pub const EM_FAKE_ALPHA: u16 = 41;
+/// Hitachi SH
+pub const EM_SH: u16 = 42;
+/// SPARC v9 64-bit
+pub const EM_SPARCV9: u16 = 43;
+/// Siemens Tricore
+pub const EM_TRICORE: u16 = 44;
+/// Argonaut RISC Core
+pub const EM_ARC: u16 = 45;
+/// Hitachi H8/300
+pub const EM_H8_300: u16 = 46;
+/// Hitachi H8/300H
+pub const EM_H8_300H: u16 = 47;
+/// Hitachi H8S
+pub const EM_H8S: u16 = 48;
+/// Hitachi H8/500
+pub const EM_H8_500: u16 = 49;
+/// Intel Merced
+pub const EM_IA_64: u16 = 50;
+/// Stanford MIPS-X
+pub const EM_MIPS_X: u16 = 51;
+/// Motorola Coldfire
+pub const EM_COLDFIRE: u16 = 52;
+/// Motorola M68HC12
+pub const EM_68HC12: u16 = 53;
+/// Fujitsu MMA Multimedia Accelerator
+pub const EM_MMA: u16 = 54;
+/// Siemens PCP
+pub const EM_PCP: u16 = 55;
+/// Sony nCPU embeeded RISC
+pub const EM_NCPU: u16 = 56;
+/// Denso NDR1 microprocessor
+pub const EM_NDR1: u16 = 57;
+/// Motorola Start*Core processor
+pub const EM_STARCORE: u16 = 58;
+/// Toyota ME16 processor
+pub const EM_ME16: u16 = 59;
+/// STMicroelectronic ST100 processor
+pub const EM_ST100: u16 = 60;
+/// Advanced Logic Corp. Tinyj emb.fam
+pub const EM_TINYJ: u16 = 61;
+/// AMD x86-64 architecture
+pub const EM_X86_64: u16 = 62;
+/// Sony DSP Processor
+pub const EM_PDSP: u16 = 63;
+/// Digital PDP-10
+pub const EM_PDP10: u16 = 64;
+/// Digital PDP-11
+pub const EM_PDP11: u16 = 65;
+/// Siemens FX66 microcontroller
+pub const EM_FX66: u16 = 66;
+/// STMicroelectronics ST9+ 8/16 mc
+pub const EM_ST9PLUS: u16 = 67;
+/// STmicroelectronics ST7 8 bit mc
+pub const EM_ST7: u16 = 68;
+/// Motorola MC68HC16 microcontroller
+pub const EM_68HC16: u16 = 69;
+/// Motorola MC68HC11 microcontroller
+pub const EM_68HC11: u16 = 70;
+/// Motorola MC68HC08 microcontroller
+pub const EM_68HC08: u16 = 71;
+/// Motorola MC68HC05 microcontroller
+pub const EM_68HC05: u16 = 72;
+/// Silicon Graphics SVx
+pub const EM_SVX: u16 = 73;
+/// STMicroelectronics ST19 8 bit mc
+pub const EM_ST19: u16 = 74;
+/// Digital VAX
+pub const EM_VAX: u16 = 75;
+/// Axis Communications 32-bit emb.proc
+pub const EM_CRIS: u16 = 76;
+/// Infineon Technologies 32-bit emb.proc
+pub const EM_JAVELIN: u16 = 77;
+/// Element 14 64-bit DSP Processor
+pub const EM_FIREPATH: u16 = 78;
+/// LSI Logic 16-bit DSP Processor
+pub const EM_ZSP: u16 = 79;
+/// Donald Knuth's educational 64-bit proc
+pub const EM_MMIX: u16 = 80;
+/// Harvard University machine-independent object files
+pub const EM_HUANY: u16 = 81;
+/// SiTera Prism
+pub const EM_PRISM: u16 = 82;
+/// Atmel AVR 8-bit microcontroller
+pub const EM_AVR: u16 = 83;
+/// Fujitsu FR30
+pub const EM_FR30: u16 = 84;
+/// Mitsubishi D10V
+pub const EM_D10V: u16 = 85;
+/// Mitsubishi D30V
+pub const EM_D30V: u16 = 86;
+/// NEC v850
+pub const EM_V850: u16 = 87;
+/// Mitsubishi M32R
+pub const EM_M32R: u16 = 88;
+/// Matsushita MN10300
+pub const EM_MN10300: u16 = 89;
+/// Matsushita MN10200
+pub const EM_MN10200: u16 = 90;
+/// picoJava
+pub const EM_PJ: u16 = 91;
+/// OpenRISC 32-bit embedded processor
+pub const EM_OPENRISC: u16 = 92;
+/// ARC International ARCompact
+pub const EM_ARC_COMPACT: u16 = 93;
+/// Tensilica Xtensa Architecture
+pub const EM_XTENSA: u16 = 94;
+/// Alphamosaic VideoCore
+pub const EM_VIDEOCORE: u16 = 95;
+/// Thompson Multimedia General Purpose Proc
+pub const EM_TMM_GPP: u16 = 96;
+/// National Semi. 32000
+pub const EM_NS32K: u16 = 97;
+/// Tenor Network TPC
+pub const EM_TPC: u16 = 98;
+/// Trebia SNP 1000
+pub const EM_SNP1K: u16 = 99;
+/// STMicroelectronics ST200
+pub const EM_ST200: u16 = 100;
+/// Ubicom IP2xxx
+pub const EM_IP2K: u16 = 101;
+/// MAX processor
+pub const EM_MAX: u16 = 102;
+/// National Semi. CompactRISC
+pub const EM_CR: u16 = 103;
+/// Fujitsu F2MC16
+pub const EM_F2MC16: u16 = 104;
+/// Texas Instruments msp430
+pub const EM_MSP430: u16 = 105;
+/// Analog Devices Blackfin DSP
+pub const EM_BLACKFIN: u16 = 106;
+/// Seiko Epson S1C33 family
+pub const EM_SE_C33: u16 = 107;
+/// Sharp embedded microprocessor
+pub const EM_SEP: u16 = 108;
+/// Arca RISC
+pub const EM_ARCA: u16 = 109;
+/// PKU-Unity & MPRC Peking Uni. mc series
+pub const EM_UNICORE: u16 = 110;
+/// eXcess configurable cpu
+pub const EM_EXCESS: u16 = 111;
+/// Icera Semi. Deep Execution Processor
+pub const EM_DXP: u16 = 112;
+/// Altera Nios II
+pub const EM_ALTERA_NIOS2: u16 = 113;
+/// National Semi. CompactRISC CRX
+pub const EM_CRX: u16 = 114;
+/// Motorola XGATE
+pub const EM_XGATE: u16 = 115;
+/// Infineon C16x/XC16x
+pub const EM_C166: u16 = 116;
+/// Renesas M16C
+pub const EM_M16C: u16 = 117;
+/// Microchip Technology dsPIC30F
+pub const EM_DSPIC30F: u16 = 118;
+/// Freescale Communication Engine RISC
+pub const EM_CE: u16 = 119;
+/// Renesas M32C
+pub const EM_M32C: u16 = 120;
+/// Altium TSK3000
+pub const EM_TSK3000: u16 = 131;
+/// Freescale RS08
+pub const EM_RS08: u16 = 132;
+/// Analog Devices SHARC family
+pub const EM_SHARC: u16 = 133;
+/// Cyan Technology eCOG2
+pub const EM_ECOG2: u16 = 134;
+/// Sunplus S+core7 RISC
+pub const EM_SCORE7: u16 = 135;
+/// New Japan Radio (NJR) 24-bit DSP
+pub const EM_DSP24: u16 = 136;
+/// Broadcom VideoCore III
+pub const EM_VIDEOCORE3: u16 = 137;
+/// RISC for Lattice FPGA
+pub const EM_LATTICEMICO32: u16 = 138;
+/// Seiko Epson C17
+pub const EM_SE_C17: u16 = 139;
+/// Texas Instruments TMS320C6000 DSP
+pub const EM_TI_C6000: u16 = 140;
+/// Texas Instruments TMS320C2000 DSP
+pub const EM_TI_C2000: u16 = 141;
+/// Texas Instruments TMS320C55x DSP
+pub const EM_TI_C5500: u16 = 142;
+/// Texas Instruments App. Specific RISC
+pub const EM_TI_ARP32: u16 = 143;
+/// Texas Instruments Prog. Realtime Unit
+pub const EM_TI_PRU: u16 = 144;
+/// STMicroelectronics 64bit VLIW DSP
+pub const EM_MMDSP_PLUS: u16 = 160;
+/// Cypress M8C
+pub const EM_CYPRESS_M8C: u16 = 161;
+/// Renesas R32C
+pub const EM_R32C: u16 = 162;
+/// NXP Semi. TriMedia
+pub const EM_TRIMEDIA: u16 = 163;
+/// QUALCOMM Hexagon
+pub const EM_HEXAGON: u16 = 164;
+/// Intel 8051 and variants
+pub const EM_8051: u16 = 165;
+/// STMicroelectronics STxP7x
+pub const EM_STXP7X: u16 = 166;
+/// Andes Tech. compact code emb. RISC
+pub const EM_NDS32: u16 = 167;
+/// Cyan Technology eCOG1X
+pub const EM_ECOG1X: u16 = 168;
+/// Dallas Semi. MAXQ30 mc
+pub const EM_MAXQ30: u16 = 169;
+/// New Japan Radio (NJR) 16-bit DSP
+pub const EM_XIMO16: u16 = 170;
+/// M2000 Reconfigurable RISC
+pub const EM_MANIK: u16 = 171;
+/// Cray NV2 vector architecture
+pub const EM_CRAYNV2: u16 = 172;
+/// Renesas RX
+pub const EM_RX: u16 = 173;
+/// Imagination Tech. META
+pub const EM_METAG: u16 = 174;
+/// MCST Elbrus
+pub const EM_MCST_ELBRUS: u16 = 175;
+/// Cyan Technology eCOG16
+pub const EM_ECOG16: u16 = 176;
+/// National Semi. CompactRISC CR16
+pub const EM_CR16: u16 = 177;
+/// Freescale Extended Time Processing Unit
+pub const EM_ETPU: u16 = 178;
+/// Infineon Tech. SLE9X
+pub const EM_SLE9X: u16 = 179;
+/// Intel L10M
+pub const EM_L10M: u16 = 180;
+/// Intel K10M
+pub const EM_K10M: u16 = 181;
+/// ARM AARCH64
+pub const EM_AARCH64: u16 = 183;
+/// Amtel 32-bit microprocessor
+pub const EM_AVR32: u16 = 185;
+/// STMicroelectronics STM8
+pub const EM_STM8: u16 = 186;
+/// Tileta TILE64
+pub const EM_TILE64: u16 = 187;
+/// Tilera TILEPro
+pub const EM_TILEPRO: u16 = 188;
+/// Xilinx MicroBlaze
+pub const EM_MICROBLAZE: u16 = 189;
+/// NVIDIA CUDA
+pub const EM_CUDA: u16 = 190;
+/// Tilera TILE-Gx
+pub const EM_TILEGX: u16 = 191;
+/// CloudShield
+pub const EM_CLOUDSHIELD: u16 = 192;
+/// KIPO-KAIST Core-A 1st gen.
+pub const EM_COREA_1ST: u16 = 193;
+/// KIPO-KAIST Core-A 2nd gen.
+pub const EM_COREA_2ND: u16 = 194;
+/// Synopsys ARCompact V2
+pub const EM_ARC_COMPACT2: u16 = 195;
+/// Open8 RISC
+pub const EM_OPEN8: u16 = 196;
+/// Renesas RL78
+pub const EM_RL78: u16 = 197;
+/// Broadcom VideoCore V
+pub const EM_VIDEOCORE5: u16 = 198;
+/// Renesas 78KOR
+pub const EM_78KOR: u16 = 199;
+/// Freescale 56800EX DSC
+pub const EM_56800EX: u16 = 200;
+/// Beyond BA1
+pub const EM_BA1: u16 = 201;
+/// Beyond BA2
+pub const EM_BA2: u16 = 202;
+/// XMOS xCORE
+pub const EM_XCORE: u16 = 203;
+/// Microchip 8-bit PIC(r)
+pub const EM_MCHP_PIC: u16 = 204;
+/// KM211 KM32
+pub const EM_KM32: u16 = 210;
+/// KM211 KMX32
+pub const EM_KMX32: u16 = 211;
+/// KM211 KMX16
+pub const EM_EMX16: u16 = 212;
+/// KM211 KMX8
+pub const EM_EMX8: u16 = 213;
+/// KM211 KVARC
+pub const EM_KVARC: u16 = 214;
+/// Paneve CDP
+pub const EM_CDP: u16 = 215;
+/// Cognitive Smart Memory Processor
+pub const EM_COGE: u16 = 216;
+/// Bluechip CoolEngine
+pub const EM_COOL: u16 = 217;
+/// Nanoradio Optimized RISC
+pub const EM_NORC: u16 = 218;
+/// CSR Kalimba
+pub const EM_CSR_KALIMBA: u16 = 219;
+/// Zilog Z80
+pub const EM_Z80: u16 = 220;
+/// Controls and Data Services VISIUMcore
+pub const EM_VISIUM: u16 = 221;
+/// FTDI Chip FT32
+pub const EM_FT32: u16 = 222;
+/// Moxie processor
+pub const EM_MOXIE: u16 = 223;
+/// AMD GPU
+pub const EM_AMDGPU: u16 = 224;
+/// RISC-V
+pub const EM_RISCV: u16 = 243;
+/// Linux BPF -- in-kernel virtual machine
+pub const EM_BPF: u16 = 247;
+/// C-SKY
+pub const EM_CSKY: u16 = 252;
+/// Loongson LoongArch
+pub const EM_LOONGARCH: u16 = 258;
+/// Solana Binary Format
+pub const EM_SBF: u16 = 263;
+/// Digital Alpha
+pub const EM_ALPHA: u16 = 0x9026;
+
+// Values for `FileHeader*::e_version` and `Ident::version`.
+/// Invalid ELF version.
+pub const EV_NONE: u8 = 0;
+/// Current ELF version.
+pub const EV_CURRENT: u8 = 1;
+
+/// Section header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SectionHeader32<E: Endian> {
+ /// Section name.
+ ///
+ /// This is an offset into the section header string table.
+ pub sh_name: U32<E>,
+ /// Section type. One of the `SHT_*` constants.
+ pub sh_type: U32<E>,
+ /// Section flags. A combination of the `SHF_*` constants.
+ pub sh_flags: U32<E>,
+ /// Section virtual address at execution.
+ pub sh_addr: U32<E>,
+ /// Section file offset.
+ pub sh_offset: U32<E>,
+ /// Section size in bytes.
+ pub sh_size: U32<E>,
+ /// Link to another section.
+ ///
+ /// The section relationship depends on the `sh_type` value.
+ pub sh_link: U32<E>,
+ /// Additional section information.
+ ///
+ /// The meaning of this field depends on the `sh_type` value.
+ pub sh_info: U32<E>,
+ /// Section alignment.
+ pub sh_addralign: U32<E>,
+ /// Entry size if the section holds a table.
+ pub sh_entsize: U32<E>,
+}
+
+/// Section header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SectionHeader64<E: Endian> {
+ /// Section name.
+ ///
+ /// This is an offset into the section header string table.
+ pub sh_name: U32<E>,
+ /// Section type. One of the `SHT_*` constants.
+ pub sh_type: U32<E>,
+ /// Section flags. A combination of the `SHF_*` constants.
+ pub sh_flags: U64<E>,
+ /// Section virtual address at execution.
+ pub sh_addr: U64<E>,
+ /// Section file offset.
+ pub sh_offset: U64<E>,
+ /// Section size in bytes.
+ pub sh_size: U64<E>,
+ /// Link to another section.
+ ///
+ /// The section relationship depends on the `sh_type` value.
+ pub sh_link: U32<E>,
+ /// Additional section information.
+ ///
+ /// The meaning of this field depends on the `sh_type` value.
+ pub sh_info: U32<E>,
+ /// Section alignment.
+ pub sh_addralign: U64<E>,
+ /// Entry size if the section holds a table.
+ pub sh_entsize: U64<E>,
+}
+
+// Special values for section indices.
+/// Undefined section.
+pub const SHN_UNDEF: u16 = 0;
+/// OS-specific range start.
+/// Start of reserved section indices.
+pub const SHN_LORESERVE: u16 = 0xff00;
+/// Start of processor-specific section indices.
+pub const SHN_LOPROC: u16 = 0xff00;
+/// End of processor-specific section indices.
+pub const SHN_HIPROC: u16 = 0xff1f;
+/// Start of OS-specific section indices.
+pub const SHN_LOOS: u16 = 0xff20;
+/// End of OS-specific section indices.
+pub const SHN_HIOS: u16 = 0xff3f;
+/// Associated symbol is absolute.
+pub const SHN_ABS: u16 = 0xfff1;
+/// Associated symbol is common.
+pub const SHN_COMMON: u16 = 0xfff2;
+/// Section index is in the `SHT_SYMTAB_SHNDX` section.
+pub const SHN_XINDEX: u16 = 0xffff;
+/// End of reserved section indices.
+pub const SHN_HIRESERVE: u16 = 0xffff;
+
+// Values for `SectionHeader*::sh_type`.
+/// Section header table entry is unused.
+pub const SHT_NULL: u32 = 0;
+/// Program data.
+pub const SHT_PROGBITS: u32 = 1;
+/// Symbol table.
+pub const SHT_SYMTAB: u32 = 2;
+/// String table.
+pub const SHT_STRTAB: u32 = 3;
+/// Relocation entries with explicit addends.
+pub const SHT_RELA: u32 = 4;
+/// Symbol hash table.
+pub const SHT_HASH: u32 = 5;
+/// Dynamic linking information.
+pub const SHT_DYNAMIC: u32 = 6;
+/// Notes.
+pub const SHT_NOTE: u32 = 7;
+/// Program space with no data (bss).
+pub const SHT_NOBITS: u32 = 8;
+/// Relocation entries without explicit addends.
+pub const SHT_REL: u32 = 9;
+/// Reserved section type.
+pub const SHT_SHLIB: u32 = 10;
+/// Dynamic linker symbol table.
+pub const SHT_DYNSYM: u32 = 11;
+/// Array of constructors.
+pub const SHT_INIT_ARRAY: u32 = 14;
+/// Array of destructors.
+pub const SHT_FINI_ARRAY: u32 = 15;
+/// Array of pre-constructors.
+pub const SHT_PREINIT_ARRAY: u32 = 16;
+/// Section group.
+pub const SHT_GROUP: u32 = 17;
+/// Extended section indices for a symbol table.
+pub const SHT_SYMTAB_SHNDX: u32 = 18;
+/// Start of OS-specific section types.
+pub const SHT_LOOS: u32 = 0x6000_0000;
+/// Object attributes.
+pub const SHT_GNU_ATTRIBUTES: u32 = 0x6fff_fff5;
+/// GNU-style hash table.
+pub const SHT_GNU_HASH: u32 = 0x6fff_fff6;
+/// Prelink library list
+pub const SHT_GNU_LIBLIST: u32 = 0x6fff_fff7;
+/// Checksum for DSO content.
+pub const SHT_CHECKSUM: u32 = 0x6fff_fff8;
+/// Sun-specific low bound.
+pub const SHT_LOSUNW: u32 = 0x6fff_fffa;
+#[allow(non_upper_case_globals)]
+pub const SHT_SUNW_move: u32 = 0x6fff_fffa;
+pub const SHT_SUNW_COMDAT: u32 = 0x6fff_fffb;
+#[allow(non_upper_case_globals)]
+pub const SHT_SUNW_syminfo: u32 = 0x6fff_fffc;
+/// Version definition section.
+#[allow(non_upper_case_globals)]
+pub const SHT_GNU_VERDEF: u32 = 0x6fff_fffd;
+/// Version needs section.
+#[allow(non_upper_case_globals)]
+pub const SHT_GNU_VERNEED: u32 = 0x6fff_fffe;
+/// Version symbol table.
+#[allow(non_upper_case_globals)]
+pub const SHT_GNU_VERSYM: u32 = 0x6fff_ffff;
+/// Sun-specific high bound.
+pub const SHT_HISUNW: u32 = 0x6fff_ffff;
+/// End of OS-specific section types.
+pub const SHT_HIOS: u32 = 0x6fff_ffff;
+/// Start of processor-specific section types.
+pub const SHT_LOPROC: u32 = 0x7000_0000;
+/// End of processor-specific section types.
+pub const SHT_HIPROC: u32 = 0x7fff_ffff;
+/// Start of application-specific section types.
+pub const SHT_LOUSER: u32 = 0x8000_0000;
+/// End of application-specific section types.
+pub const SHT_HIUSER: u32 = 0x8fff_ffff;
+
+// Values for `SectionHeader*::sh_flags`.
+/// Section is writable.
+pub const SHF_WRITE: u32 = 1 << 0;
+/// Section occupies memory during execution.
+pub const SHF_ALLOC: u32 = 1 << 1;
+/// Section is executable.
+pub const SHF_EXECINSTR: u32 = 1 << 2;
+/// Section may be be merged to eliminate duplication.
+pub const SHF_MERGE: u32 = 1 << 4;
+/// Section contains nul-terminated strings.
+pub const SHF_STRINGS: u32 = 1 << 5;
+/// The `sh_info` field contains a section header table index.
+pub const SHF_INFO_LINK: u32 = 1 << 6;
+/// Section has special ordering requirements when combining sections.
+pub const SHF_LINK_ORDER: u32 = 1 << 7;
+/// Section requires special OS-specific handling.
+pub const SHF_OS_NONCONFORMING: u32 = 1 << 8;
+/// Section is a member of a group.
+pub const SHF_GROUP: u32 = 1 << 9;
+/// Section holds thread-local storage.
+pub const SHF_TLS: u32 = 1 << 10;
+/// Section is compressed.
+///
+/// Compressed sections begin with one of the `CompressionHeader*` headers.
+pub const SHF_COMPRESSED: u32 = 1 << 11;
+/// OS-specific section flags.
+pub const SHF_MASKOS: u32 = 0x0ff0_0000;
+/// Processor-specific section flags.
+pub const SHF_MASKPROC: u32 = 0xf000_0000;
+/// This section is excluded from the final executable or shared library.
+pub const SHF_EXCLUDE: u32 = 0x8000_0000;
+
+/// Section compression header.
+///
+/// Used when `SHF_COMPRESSED` is set.
+///
+/// Note: this type currently allows for misaligned headers, but that may be
+/// changed in a future version.
+#[derive(Debug, Default, Clone, Copy)]
+#[repr(C)]
+pub struct CompressionHeader32<E: Endian> {
+ /// Compression format. One of the `ELFCOMPRESS_*` values.
+ pub ch_type: U32Bytes<E>,
+ /// Uncompressed data size.
+ pub ch_size: U32Bytes<E>,
+ /// Uncompressed data alignment.
+ pub ch_addralign: U32Bytes<E>,
+}
+
+/// Section compression header.
+///
+/// Used when `SHF_COMPRESSED` is set.
+///
+/// Note: this type currently allows for misaligned headers, but that may be
+/// changed in a future version.
+#[derive(Debug, Default, Clone, Copy)]
+#[repr(C)]
+pub struct CompressionHeader64<E: Endian> {
+ /// Compression format. One of the `ELFCOMPRESS_*` values.
+ pub ch_type: U32Bytes<E>,
+ /// Reserved.
+ pub ch_reserved: U32Bytes<E>,
+ /// Uncompressed data size.
+ pub ch_size: U64Bytes<E>,
+ /// Uncompressed data alignment.
+ pub ch_addralign: U64Bytes<E>,
+}
+
+/// ZLIB/DEFLATE algorithm.
+pub const ELFCOMPRESS_ZLIB: u32 = 1;
+/// Zstandard algorithm.
+pub const ELFCOMPRESS_ZSTD: u32 = 2;
+/// Start of OS-specific compression types.
+pub const ELFCOMPRESS_LOOS: u32 = 0x6000_0000;
+/// End of OS-specific compression types.
+pub const ELFCOMPRESS_HIOS: u32 = 0x6fff_ffff;
+/// Start of processor-specific compression types.
+pub const ELFCOMPRESS_LOPROC: u32 = 0x7000_0000;
+/// End of processor-specific compression types.
+pub const ELFCOMPRESS_HIPROC: u32 = 0x7fff_ffff;
+
+// Values for the flag entry for section groups.
+/// Mark group as COMDAT.
+pub const GRP_COMDAT: u32 = 1;
+
+/// Symbol table entry.
+#[derive(Debug, Default, Clone, Copy)]
+#[repr(C)]
+pub struct Sym32<E: Endian> {
+ /// Symbol name.
+ ///
+ /// This is an offset into the symbol string table.
+ pub st_name: U32<E>,
+ /// Symbol value.
+ pub st_value: U32<E>,
+ /// Symbol size.
+ pub st_size: U32<E>,
+ /// Symbol type and binding.
+ ///
+ /// Use the `st_type` and `st_bind` methods to access this value.
+ pub st_info: u8,
+ /// Symbol visibility.
+ ///
+ /// Use the `st_visibility` method to access this value.
+ pub st_other: u8,
+ /// Section index or one of the `SHN_*` values.
+ pub st_shndx: U16<E>,
+}
+
+impl<E: Endian> Sym32<E> {
+ /// Get the `st_bind` component of the `st_info` field.
+ #[inline]
+ pub fn st_bind(&self) -> u8 {
+ self.st_info >> 4
+ }
+
+ /// Get the `st_type` component of the `st_info` field.
+ #[inline]
+ pub fn st_type(&self) -> u8 {
+ self.st_info & 0xf
+ }
+
+ /// Set the `st_info` field given the `st_bind` and `st_type` components.
+ #[inline]
+ pub fn set_st_info(&mut self, st_bind: u8, st_type: u8) {
+ self.st_info = (st_bind << 4) + (st_type & 0xf);
+ }
+
+ /// Get the `st_visibility` component of the `st_info` field.
+ #[inline]
+ pub fn st_visibility(&self) -> u8 {
+ self.st_other & 0x3
+ }
+}
+
+/// Symbol table entry.
+#[derive(Debug, Default, Clone, Copy)]
+#[repr(C)]
+pub struct Sym64<E: Endian> {
+ /// Symbol name.
+ ///
+ /// This is an offset into the symbol string table.
+ pub st_name: U32<E>,
+ /// Symbol type and binding.
+ ///
+ /// Use the `st_bind` and `st_type` methods to access this value.
+ pub st_info: u8,
+ /// Symbol visibility.
+ ///
+ /// Use the `st_visibility` method to access this value.
+ pub st_other: u8,
+ /// Section index or one of the `SHN_*` values.
+ pub st_shndx: U16<E>,
+ /// Symbol value.
+ pub st_value: U64<E>,
+ /// Symbol size.
+ pub st_size: U64<E>,
+}
+
+impl<E: Endian> Sym64<E> {
+ /// Get the `st_bind` component of the `st_info` field.
+ #[inline]
+ pub fn st_bind(&self) -> u8 {
+ self.st_info >> 4
+ }
+
+ /// Get the `st_type` component of the `st_info` field.
+ #[inline]
+ pub fn st_type(&self) -> u8 {
+ self.st_info & 0xf
+ }
+
+ /// Set the `st_info` field given the `st_bind` and `st_type` components.
+ #[inline]
+ pub fn set_st_info(&mut self, st_bind: u8, st_type: u8) {
+ self.st_info = (st_bind << 4) + (st_type & 0xf);
+ }
+
+ /// Get the `st_visibility` component of the `st_info` field.
+ #[inline]
+ pub fn st_visibility(&self) -> u8 {
+ self.st_other & 0x3
+ }
+}
+
+/// Additional information about a `Sym32`.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Syminfo32<E: Endian> {
+ /// Direct bindings, symbol bound to.
+ pub si_boundto: U16<E>,
+ /// Per symbol flags.
+ pub si_flags: U16<E>,
+}
+
+/// Additional information about a `Sym64`.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Syminfo64<E: Endian> {
+ /// Direct bindings, symbol bound to.
+ pub si_boundto: U16<E>,
+ /// Per symbol flags.
+ pub si_flags: U16<E>,
+}
+
+// Values for `Syminfo*::si_boundto`.
+/// Symbol bound to self
+pub const SYMINFO_BT_SELF: u16 = 0xffff;
+/// Symbol bound to parent
+pub const SYMINFO_BT_PARENT: u16 = 0xfffe;
+/// Beginning of reserved entries
+pub const SYMINFO_BT_LOWRESERVE: u16 = 0xff00;
+
+// Values for `Syminfo*::si_flags`.
+/// Direct bound symbol
+pub const SYMINFO_FLG_DIRECT: u16 = 0x0001;
+/// Pass-thru symbol for translator
+pub const SYMINFO_FLG_PASSTHRU: u16 = 0x0002;
+/// Symbol is a copy-reloc
+pub const SYMINFO_FLG_COPY: u16 = 0x0004;
+/// Symbol bound to object to be lazy loaded
+pub const SYMINFO_FLG_LAZYLOAD: u16 = 0x0008;
+
+// Syminfo version values.
+pub const SYMINFO_NONE: u16 = 0;
+pub const SYMINFO_CURRENT: u16 = 1;
+pub const SYMINFO_NUM: u16 = 2;
+
+// Values for bind component of `Sym*::st_info`.
+/// Local symbol.
+pub const STB_LOCAL: u8 = 0;
+/// Global symbol.
+pub const STB_GLOBAL: u8 = 1;
+/// Weak symbol.
+pub const STB_WEAK: u8 = 2;
+/// Start of OS-specific symbol binding.
+pub const STB_LOOS: u8 = 10;
+/// Unique symbol.
+pub const STB_GNU_UNIQUE: u8 = 10;
+/// End of OS-specific symbol binding.
+pub const STB_HIOS: u8 = 12;
+/// Start of processor-specific symbol binding.
+pub const STB_LOPROC: u8 = 13;
+/// End of processor-specific symbol binding.
+pub const STB_HIPROC: u8 = 15;
+
+// Values for type component of `Sym*::st_info`.
+/// Symbol type is unspecified.
+pub const STT_NOTYPE: u8 = 0;
+/// Symbol is a data object.
+pub const STT_OBJECT: u8 = 1;
+/// Symbol is a code object.
+pub const STT_FUNC: u8 = 2;
+/// Symbol is associated with a section.
+pub const STT_SECTION: u8 = 3;
+/// Symbol's name is a file name.
+pub const STT_FILE: u8 = 4;
+/// Symbol is a common data object.
+pub const STT_COMMON: u8 = 5;
+/// Symbol is a thread-local storage object.
+pub const STT_TLS: u8 = 6;
+/// Start of OS-specific symbol types.
+pub const STT_LOOS: u8 = 10;
+/// Symbol is an indirect code object.
+pub const STT_GNU_IFUNC: u8 = 10;
+/// End of OS-specific symbol types.
+pub const STT_HIOS: u8 = 12;
+/// Start of processor-specific symbol types.
+pub const STT_LOPROC: u8 = 13;
+/// End of processor-specific symbol types.
+pub const STT_HIPROC: u8 = 15;
+
+// Values for visibility component of `Symbol*::st_other`.
+/// Default symbol visibility rules.
+pub const STV_DEFAULT: u8 = 0;
+/// Processor specific hidden class.
+pub const STV_INTERNAL: u8 = 1;
+/// Symbol is not visible to other components.
+pub const STV_HIDDEN: u8 = 2;
+/// Symbol is visible to other components, but is not preemptible.
+pub const STV_PROTECTED: u8 = 3;
+
+/// Relocation table entry without explicit addend.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Rel32<E: Endian> {
+ /// Relocation address.
+ pub r_offset: U32<E>,
+ /// Relocation type and symbol index.
+ pub r_info: U32<E>,
+}
+
+impl<E: Endian> Rel32<E> {
+ /// Get the `r_sym` component of the `r_info` field.
+ #[inline]
+ pub fn r_sym(&self, endian: E) -> u32 {
+ self.r_info.get(endian) >> 8
+ }
+
+ /// Get the `r_type` component of the `r_info` field.
+ #[inline]
+ pub fn r_type(&self, endian: E) -> u32 {
+ self.r_info.get(endian) & 0xff
+ }
+
+ /// Calculate the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn r_info(endian: E, r_sym: u32, r_type: u8) -> U32<E> {
+ U32::new(endian, (r_sym << 8) | u32::from(r_type))
+ }
+
+ /// Set the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn set_r_info(&mut self, endian: E, r_sym: u32, r_type: u8) {
+ self.r_info = Self::r_info(endian, r_sym, r_type)
+ }
+}
+
+/// Relocation table entry with explicit addend.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Rela32<E: Endian> {
+ /// Relocation address.
+ pub r_offset: U32<E>,
+ /// Relocation type and symbol index.
+ pub r_info: U32<E>,
+ /// Explicit addend.
+ pub r_addend: I32<E>,
+}
+
+impl<E: Endian> Rela32<E> {
+ /// Get the `r_sym` component of the `r_info` field.
+ #[inline]
+ pub fn r_sym(&self, endian: E) -> u32 {
+ self.r_info.get(endian) >> 8
+ }
+
+ /// Get the `r_type` component of the `r_info` field.
+ #[inline]
+ pub fn r_type(&self, endian: E) -> u32 {
+ self.r_info.get(endian) & 0xff
+ }
+
+ /// Calculate the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn r_info(endian: E, r_sym: u32, r_type: u8) -> U32<E> {
+ U32::new(endian, (r_sym << 8) | u32::from(r_type))
+ }
+
+ /// Set the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn set_r_info(&mut self, endian: E, r_sym: u32, r_type: u8) {
+ self.r_info = Self::r_info(endian, r_sym, r_type)
+ }
+}
+
+impl<E: Endian> From<Rel32<E>> for Rela32<E> {
+ fn from(rel: Rel32<E>) -> Self {
+ Rela32 {
+ r_offset: rel.r_offset,
+ r_info: rel.r_info,
+ r_addend: I32::default(),
+ }
+ }
+}
+
+/// Relocation table entry without explicit addend.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Rel64<E: Endian> {
+ /// Relocation address.
+ pub r_offset: U64<E>,
+ /// Relocation type and symbol index.
+ pub r_info: U64<E>,
+}
+
+impl<E: Endian> Rel64<E> {
+ /// Get the `r_sym` component of the `r_info` field.
+ #[inline]
+ pub fn r_sym(&self, endian: E) -> u32 {
+ (self.r_info.get(endian) >> 32) as u32
+ }
+
+ /// Get the `r_type` component of the `r_info` field.
+ #[inline]
+ pub fn r_type(&self, endian: E) -> u32 {
+ (self.r_info.get(endian) & 0xffff_ffff) as u32
+ }
+
+ /// Calculate the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn r_info(endian: E, r_sym: u32, r_type: u32) -> U64<E> {
+ U64::new(endian, (u64::from(r_sym) << 32) | u64::from(r_type))
+ }
+
+ /// Set the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn set_r_info(&mut self, endian: E, r_sym: u32, r_type: u32) {
+ self.r_info = Self::r_info(endian, r_sym, r_type)
+ }
+}
+
+impl<E: Endian> From<Rel64<E>> for Rela64<E> {
+ fn from(rel: Rel64<E>) -> Self {
+ Rela64 {
+ r_offset: rel.r_offset,
+ r_info: rel.r_info,
+ r_addend: I64::default(),
+ }
+ }
+}
+
+/// Relocation table entry with explicit addend.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Rela64<E: Endian> {
+ /// Relocation address.
+ pub r_offset: U64<E>,
+ /// Relocation type and symbol index.
+ pub r_info: U64<E>,
+ /// Explicit addend.
+ pub r_addend: I64<E>,
+}
+
+impl<E: Endian> Rela64<E> {
+ pub(crate) fn get_r_info(&self, endian: E, is_mips64el: bool) -> u64 {
+ let mut t = self.r_info.get(endian);
+ if is_mips64el {
+ t = (t << 32)
+ | ((t >> 8) & 0xff000000)
+ | ((t >> 24) & 0x00ff0000)
+ | ((t >> 40) & 0x0000ff00)
+ | ((t >> 56) & 0x000000ff);
+ }
+ t
+ }
+
+ /// Get the `r_sym` component of the `r_info` field.
+ #[inline]
+ pub fn r_sym(&self, endian: E, is_mips64el: bool) -> u32 {
+ (self.get_r_info(endian, is_mips64el) >> 32) as u32
+ }
+
+ /// Get the `r_type` component of the `r_info` field.
+ #[inline]
+ pub fn r_type(&self, endian: E, is_mips64el: bool) -> u32 {
+ (self.get_r_info(endian, is_mips64el) & 0xffff_ffff) as u32
+ }
+
+ /// Calculate the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn r_info(endian: E, is_mips64el: bool, r_sym: u32, r_type: u32) -> U64<E> {
+ let mut t = (u64::from(r_sym) << 32) | u64::from(r_type);
+ if is_mips64el {
+ t = (t >> 32)
+ | ((t & 0xff000000) << 8)
+ | ((t & 0x00ff0000) << 24)
+ | ((t & 0x0000ff00) << 40)
+ | ((t & 0x000000ff) << 56);
+ }
+ U64::new(endian, t)
+ }
+
+ /// Set the `r_info` field given the `r_sym` and `r_type` components.
+ pub fn set_r_info(&mut self, endian: E, is_mips64el: bool, r_sym: u32, r_type: u32) {
+ self.r_info = Self::r_info(endian, is_mips64el, r_sym, r_type);
+ }
+}
+
+/// Program segment header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ProgramHeader32<E: Endian> {
+ /// Segment type. One of the `PT_*` constants.
+ pub p_type: U32<E>,
+ /// Segment file offset.
+ pub p_offset: U32<E>,
+ /// Segment virtual address.
+ pub p_vaddr: U32<E>,
+ /// Segment physical address.
+ pub p_paddr: U32<E>,
+ /// Segment size in the file.
+ pub p_filesz: U32<E>,
+ /// Segment size in memory.
+ pub p_memsz: U32<E>,
+ /// Segment flags. A combination of the `PF_*` constants.
+ pub p_flags: U32<E>,
+ /// Segment alignment.
+ pub p_align: U32<E>,
+}
+
+/// Program segment header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ProgramHeader64<E: Endian> {
+ /// Segment type. One of the `PT_*` constants.
+ pub p_type: U32<E>,
+ /// Segment flags. A combination of the `PF_*` constants.
+ pub p_flags: U32<E>,
+ /// Segment file offset.
+ pub p_offset: U64<E>,
+ /// Segment virtual address.
+ pub p_vaddr: U64<E>,
+ /// Segment physical address.
+ pub p_paddr: U64<E>,
+ /// Segment size in the file.
+ pub p_filesz: U64<E>,
+ /// Segment size in memory.
+ pub p_memsz: U64<E>,
+ /// Segment alignment.
+ pub p_align: U64<E>,
+}
+
+/// Special value for `FileHeader*::e_phnum`.
+///
+/// This indicates that the real number of program headers is too large to fit into e_phnum.
+/// Instead the real value is in the field `sh_info` of section 0.
+pub const PN_XNUM: u16 = 0xffff;
+
+// Values for `ProgramHeader*::p_type`.
+/// Program header table entry is unused.
+pub const PT_NULL: u32 = 0;
+/// Loadable program segment.
+pub const PT_LOAD: u32 = 1;
+/// Dynamic linking information.
+pub const PT_DYNAMIC: u32 = 2;
+/// Program interpreter.
+pub const PT_INTERP: u32 = 3;
+/// Auxiliary information.
+pub const PT_NOTE: u32 = 4;
+/// Reserved.
+pub const PT_SHLIB: u32 = 5;
+/// Segment contains the program header table.
+pub const PT_PHDR: u32 = 6;
+/// Thread-local storage segment.
+pub const PT_TLS: u32 = 7;
+/// Start of OS-specific segment types.
+pub const PT_LOOS: u32 = 0x6000_0000;
+/// GCC `.eh_frame_hdr` segment.
+pub const PT_GNU_EH_FRAME: u32 = 0x6474_e550;
+/// Indicates stack executability.
+pub const PT_GNU_STACK: u32 = 0x6474_e551;
+/// Read-only after relocation.
+pub const PT_GNU_RELRO: u32 = 0x6474_e552;
+/// Segment containing `.note.gnu.property` section.
+pub const PT_GNU_PROPERTY: u32 = 0x6474_e553;
+/// End of OS-specific segment types.
+pub const PT_HIOS: u32 = 0x6fff_ffff;
+/// Start of processor-specific segment types.
+pub const PT_LOPROC: u32 = 0x7000_0000;
+/// End of processor-specific segment types.
+pub const PT_HIPROC: u32 = 0x7fff_ffff;
+
+// Values for `ProgramHeader*::p_flags`.
+/// Segment is executable.
+pub const PF_X: u32 = 1 << 0;
+/// Segment is writable.
+pub const PF_W: u32 = 1 << 1;
+/// Segment is readable.
+pub const PF_R: u32 = 1 << 2;
+/// OS-specific segment flags.
+pub const PF_MASKOS: u32 = 0x0ff0_0000;
+/// Processor-specific segment flags.
+pub const PF_MASKPROC: u32 = 0xf000_0000;
+
+/// Note name for core files.
+pub const ELF_NOTE_CORE: &[u8] = b"CORE";
+/// Note name for linux core files.
+///
+/// Notes in linux core files may also use `ELF_NOTE_CORE`.
+pub const ELF_NOTE_LINUX: &[u8] = b"LINUX";
+
+// Values for `NoteHeader*::n_type` in core files.
+//
+/// Contains copy of prstatus struct.
+pub const NT_PRSTATUS: u32 = 1;
+/// Contains copy of fpregset struct.
+pub const NT_PRFPREG: u32 = 2;
+/// Contains copy of fpregset struct.
+pub const NT_FPREGSET: u32 = 2;
+/// Contains copy of prpsinfo struct.
+pub const NT_PRPSINFO: u32 = 3;
+/// Contains copy of prxregset struct.
+pub const NT_PRXREG: u32 = 4;
+/// Contains copy of task structure.
+pub const NT_TASKSTRUCT: u32 = 4;
+/// String from sysinfo(SI_PLATFORM).
+pub const NT_PLATFORM: u32 = 5;
+/// Contains copy of auxv array.
+pub const NT_AUXV: u32 = 6;
+/// Contains copy of gwindows struct.
+pub const NT_GWINDOWS: u32 = 7;
+/// Contains copy of asrset struct.
+pub const NT_ASRS: u32 = 8;
+/// Contains copy of pstatus struct.
+pub const NT_PSTATUS: u32 = 10;
+/// Contains copy of psinfo struct.
+pub const NT_PSINFO: u32 = 13;
+/// Contains copy of prcred struct.
+pub const NT_PRCRED: u32 = 14;
+/// Contains copy of utsname struct.
+pub const NT_UTSNAME: u32 = 15;
+/// Contains copy of lwpstatus struct.
+pub const NT_LWPSTATUS: u32 = 16;
+/// Contains copy of lwpinfo struct.
+pub const NT_LWPSINFO: u32 = 17;
+/// Contains copy of fprxregset struct.
+pub const NT_PRFPXREG: u32 = 20;
+/// Contains copy of siginfo_t, size might increase.
+pub const NT_SIGINFO: u32 = 0x5349_4749;
+/// Contains information about mapped files.
+pub const NT_FILE: u32 = 0x4649_4c45;
+/// Contains copy of user_fxsr_struct.
+pub const NT_PRXFPREG: u32 = 0x46e6_2b7f;
+/// PowerPC Altivec/VMX registers.
+pub const NT_PPC_VMX: u32 = 0x100;
+/// PowerPC SPE/EVR registers.
+pub const NT_PPC_SPE: u32 = 0x101;
+/// PowerPC VSX registers.
+pub const NT_PPC_VSX: u32 = 0x102;
+/// Target Address Register.
+pub const NT_PPC_TAR: u32 = 0x103;
+/// Program Priority Register.
+pub const NT_PPC_PPR: u32 = 0x104;
+/// Data Stream Control Register.
+pub const NT_PPC_DSCR: u32 = 0x105;
+/// Event Based Branch Registers.
+pub const NT_PPC_EBB: u32 = 0x106;
+/// Performance Monitor Registers.
+pub const NT_PPC_PMU: u32 = 0x107;
+/// TM checkpointed GPR Registers.
+pub const NT_PPC_TM_CGPR: u32 = 0x108;
+/// TM checkpointed FPR Registers.
+pub const NT_PPC_TM_CFPR: u32 = 0x109;
+/// TM checkpointed VMX Registers.
+pub const NT_PPC_TM_CVMX: u32 = 0x10a;
+/// TM checkpointed VSX Registers.
+pub const NT_PPC_TM_CVSX: u32 = 0x10b;
+/// TM Special Purpose Registers.
+pub const NT_PPC_TM_SPR: u32 = 0x10c;
+/// TM checkpointed Target Address Register.
+pub const NT_PPC_TM_CTAR: u32 = 0x10d;
+/// TM checkpointed Program Priority Register.
+pub const NT_PPC_TM_CPPR: u32 = 0x10e;
+/// TM checkpointed Data Stream Control Register.
+pub const NT_PPC_TM_CDSCR: u32 = 0x10f;
+/// Memory Protection Keys registers.
+pub const NT_PPC_PKEY: u32 = 0x110;
+/// i386 TLS slots (struct user_desc).
+pub const NT_386_TLS: u32 = 0x200;
+/// x86 io permission bitmap (1=deny).
+pub const NT_386_IOPERM: u32 = 0x201;
+/// x86 extended state using xsave.
+pub const NT_X86_XSTATE: u32 = 0x202;
+/// s390 upper register halves.
+pub const NT_S390_HIGH_GPRS: u32 = 0x300;
+/// s390 timer register.
+pub const NT_S390_TIMER: u32 = 0x301;
+/// s390 TOD clock comparator register.
+pub const NT_S390_TODCMP: u32 = 0x302;
+/// s390 TOD programmable register.
+pub const NT_S390_TODPREG: u32 = 0x303;
+/// s390 control registers.
+pub const NT_S390_CTRS: u32 = 0x304;
+/// s390 prefix register.
+pub const NT_S390_PREFIX: u32 = 0x305;
+/// s390 breaking event address.
+pub const NT_S390_LAST_BREAK: u32 = 0x306;
+/// s390 system call restart data.
+pub const NT_S390_SYSTEM_CALL: u32 = 0x307;
+/// s390 transaction diagnostic block.
+pub const NT_S390_TDB: u32 = 0x308;
+/// s390 vector registers 0-15 upper half.
+pub const NT_S390_VXRS_LOW: u32 = 0x309;
+/// s390 vector registers 16-31.
+pub const NT_S390_VXRS_HIGH: u32 = 0x30a;
+/// s390 guarded storage registers.
+pub const NT_S390_GS_CB: u32 = 0x30b;
+/// s390 guarded storage broadcast control block.
+pub const NT_S390_GS_BC: u32 = 0x30c;
+/// s390 runtime instrumentation.
+pub const NT_S390_RI_CB: u32 = 0x30d;
+/// ARM VFP/NEON registers.
+pub const NT_ARM_VFP: u32 = 0x400;
+/// ARM TLS register.
+pub const NT_ARM_TLS: u32 = 0x401;
+/// ARM hardware breakpoint registers.
+pub const NT_ARM_HW_BREAK: u32 = 0x402;
+/// ARM hardware watchpoint registers.
+pub const NT_ARM_HW_WATCH: u32 = 0x403;
+/// ARM system call number.
+pub const NT_ARM_SYSTEM_CALL: u32 = 0x404;
+/// ARM Scalable Vector Extension registers.
+pub const NT_ARM_SVE: u32 = 0x405;
+/// Vmcore Device Dump Note.
+pub const NT_VMCOREDD: u32 = 0x700;
+/// MIPS DSP ASE registers.
+pub const NT_MIPS_DSP: u32 = 0x800;
+/// MIPS floating-point mode.
+pub const NT_MIPS_FP_MODE: u32 = 0x801;
+
+/// Note type for version string.
+///
+/// This note may appear in object files.
+///
+/// It must be handled as a special case because it has no descriptor, and instead
+/// uses the note name as the version string.
+pub const NT_VERSION: u32 = 1;
+
+/// Dynamic section entry.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Dyn32<E: Endian> {
+ /// Dynamic entry type.
+ pub d_tag: U32<E>,
+ /// Value (integer or address).
+ pub d_val: U32<E>,
+}
+
+/// Dynamic section entry.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Dyn64<E: Endian> {
+ /// Dynamic entry type.
+ pub d_tag: U64<E>,
+ /// Value (integer or address).
+ pub d_val: U64<E>,
+}
+
+// Values for `Dyn*::d_tag`.
+
+/// Marks end of dynamic section
+pub const DT_NULL: u32 = 0;
+/// Name of needed library
+pub const DT_NEEDED: u32 = 1;
+/// Size in bytes of PLT relocs
+pub const DT_PLTRELSZ: u32 = 2;
+/// Processor defined value
+pub const DT_PLTGOT: u32 = 3;
+/// Address of symbol hash table
+pub const DT_HASH: u32 = 4;
+/// Address of string table
+pub const DT_STRTAB: u32 = 5;
+/// Address of symbol table
+pub const DT_SYMTAB: u32 = 6;
+/// Address of Rela relocs
+pub const DT_RELA: u32 = 7;
+/// Total size of Rela relocs
+pub const DT_RELASZ: u32 = 8;
+/// Size of one Rela reloc
+pub const DT_RELAENT: u32 = 9;
+/// Size of string table
+pub const DT_STRSZ: u32 = 10;
+/// Size of one symbol table entry
+pub const DT_SYMENT: u32 = 11;
+/// Address of init function
+pub const DT_INIT: u32 = 12;
+/// Address of termination function
+pub const DT_FINI: u32 = 13;
+/// Name of shared object
+pub const DT_SONAME: u32 = 14;
+/// Library search path (deprecated)
+pub const DT_RPATH: u32 = 15;
+/// Start symbol search here
+pub const DT_SYMBOLIC: u32 = 16;
+/// Address of Rel relocs
+pub const DT_REL: u32 = 17;
+/// Total size of Rel relocs
+pub const DT_RELSZ: u32 = 18;
+/// Size of one Rel reloc
+pub const DT_RELENT: u32 = 19;
+/// Type of reloc in PLT
+pub const DT_PLTREL: u32 = 20;
+/// For debugging; unspecified
+pub const DT_DEBUG: u32 = 21;
+/// Reloc might modify .text
+pub const DT_TEXTREL: u32 = 22;
+/// Address of PLT relocs
+pub const DT_JMPREL: u32 = 23;
+/// Process relocations of object
+pub const DT_BIND_NOW: u32 = 24;
+/// Array with addresses of init fct
+pub const DT_INIT_ARRAY: u32 = 25;
+/// Array with addresses of fini fct
+pub const DT_FINI_ARRAY: u32 = 26;
+/// Size in bytes of DT_INIT_ARRAY
+pub const DT_INIT_ARRAYSZ: u32 = 27;
+/// Size in bytes of DT_FINI_ARRAY
+pub const DT_FINI_ARRAYSZ: u32 = 28;
+/// Library search path
+pub const DT_RUNPATH: u32 = 29;
+/// Flags for the object being loaded
+pub const DT_FLAGS: u32 = 30;
+/// Start of encoded range
+pub const DT_ENCODING: u32 = 32;
+/// Array with addresses of preinit fct
+pub const DT_PREINIT_ARRAY: u32 = 32;
+/// size in bytes of DT_PREINIT_ARRAY
+pub const DT_PREINIT_ARRAYSZ: u32 = 33;
+/// Address of SYMTAB_SHNDX section
+pub const DT_SYMTAB_SHNDX: u32 = 34;
+/// Start of OS-specific
+pub const DT_LOOS: u32 = 0x6000_000d;
+/// End of OS-specific
+pub const DT_HIOS: u32 = 0x6fff_f000;
+/// Start of processor-specific
+pub const DT_LOPROC: u32 = 0x7000_0000;
+/// End of processor-specific
+pub const DT_HIPROC: u32 = 0x7fff_ffff;
+
+// `DT_*` entries between `DT_VALRNGHI` & `DT_VALRNGLO` use `d_val` as a value.
+pub const DT_VALRNGLO: u32 = 0x6fff_fd00;
+/// Prelinking timestamp
+pub const DT_GNU_PRELINKED: u32 = 0x6fff_fdf5;
+/// Size of conflict section
+pub const DT_GNU_CONFLICTSZ: u32 = 0x6fff_fdf6;
+/// Size of library list
+pub const DT_GNU_LIBLISTSZ: u32 = 0x6fff_fdf7;
+pub const DT_CHECKSUM: u32 = 0x6fff_fdf8;
+pub const DT_PLTPADSZ: u32 = 0x6fff_fdf9;
+pub const DT_MOVEENT: u32 = 0x6fff_fdfa;
+pub const DT_MOVESZ: u32 = 0x6fff_fdfb;
+/// Feature selection (DTF_*).
+pub const DT_FEATURE_1: u32 = 0x6fff_fdfc;
+/// Flags for DT_* entries, affecting the following DT_* entry.
+pub const DT_POSFLAG_1: u32 = 0x6fff_fdfd;
+/// Size of syminfo table (in bytes)
+pub const DT_SYMINSZ: u32 = 0x6fff_fdfe;
+/// Entry size of syminfo
+pub const DT_SYMINENT: u32 = 0x6fff_fdff;
+pub const DT_VALRNGHI: u32 = 0x6fff_fdff;
+
+// `DT_*` entries between `DT_ADDRRNGHI` & `DT_ADDRRNGLO` use `d_val` as an address.
+//
+// If any adjustment is made to the ELF object after it has been
+// built these entries will need to be adjusted.
+pub const DT_ADDRRNGLO: u32 = 0x6fff_fe00;
+/// GNU-style hash table.
+pub const DT_GNU_HASH: u32 = 0x6fff_fef5;
+pub const DT_TLSDESC_PLT: u32 = 0x6fff_fef6;
+pub const DT_TLSDESC_GOT: u32 = 0x6fff_fef7;
+/// Start of conflict section
+pub const DT_GNU_CONFLICT: u32 = 0x6fff_fef8;
+/// Library list
+pub const DT_GNU_LIBLIST: u32 = 0x6fff_fef9;
+/// Configuration information.
+pub const DT_CONFIG: u32 = 0x6fff_fefa;
+/// Dependency auditing.
+pub const DT_DEPAUDIT: u32 = 0x6fff_fefb;
+/// Object auditing.
+pub const DT_AUDIT: u32 = 0x6fff_fefc;
+/// PLT padding.
+pub const DT_PLTPAD: u32 = 0x6fff_fefd;
+/// Move table.
+pub const DT_MOVETAB: u32 = 0x6fff_fefe;
+/// Syminfo table.
+pub const DT_SYMINFO: u32 = 0x6fff_feff;
+pub const DT_ADDRRNGHI: u32 = 0x6fff_feff;
+
+// The versioning entry types. The next are defined as part of the
+// GNU extension.
+pub const DT_VERSYM: u32 = 0x6fff_fff0;
+pub const DT_RELACOUNT: u32 = 0x6fff_fff9;
+pub const DT_RELCOUNT: u32 = 0x6fff_fffa;
+/// State flags, see DF_1_* below.
+pub const DT_FLAGS_1: u32 = 0x6fff_fffb;
+/// Address of version definition table
+pub const DT_VERDEF: u32 = 0x6fff_fffc;
+/// Number of version definitions
+pub const DT_VERDEFNUM: u32 = 0x6fff_fffd;
+/// Address of table with needed versions
+pub const DT_VERNEED: u32 = 0x6fff_fffe;
+/// Number of needed versions
+pub const DT_VERNEEDNUM: u32 = 0x6fff_ffff;
+
+// Machine-independent extensions in the "processor-specific" range.
+/// Shared object to load before self
+pub const DT_AUXILIARY: u32 = 0x7fff_fffd;
+/// Shared object to get values from
+pub const DT_FILTER: u32 = 0x7fff_ffff;
+
+// Values of `Dyn*::d_val` in the `DT_FLAGS` entry.
+/// Object may use DF_ORIGIN
+pub const DF_ORIGIN: u32 = 0x0000_0001;
+/// Symbol resolutions starts here
+pub const DF_SYMBOLIC: u32 = 0x0000_0002;
+/// Object contains text relocations
+pub const DF_TEXTREL: u32 = 0x0000_0004;
+/// No lazy binding for this object
+pub const DF_BIND_NOW: u32 = 0x0000_0008;
+/// Module uses the static TLS model
+pub const DF_STATIC_TLS: u32 = 0x0000_0010;
+
+// Values of `Dyn*::d_val` in the `DT_FLAGS_1` entry.
+/// Set RTLD_NOW for this object.
+pub const DF_1_NOW: u32 = 0x0000_0001;
+/// Set RTLD_GLOBAL for this object.
+pub const DF_1_GLOBAL: u32 = 0x0000_0002;
+/// Set RTLD_GROUP for this object.
+pub const DF_1_GROUP: u32 = 0x0000_0004;
+/// Set RTLD_NODELETE for this object.
+pub const DF_1_NODELETE: u32 = 0x0000_0008;
+/// Trigger filtee loading at runtime.
+pub const DF_1_LOADFLTR: u32 = 0x0000_0010;
+/// Set RTLD_INITFIRST for this object.
+pub const DF_1_INITFIRST: u32 = 0x0000_0020;
+/// Set RTLD_NOOPEN for this object.
+pub const DF_1_NOOPEN: u32 = 0x0000_0040;
+/// $ORIGIN must be handled.
+pub const DF_1_ORIGIN: u32 = 0x0000_0080;
+/// Direct binding enabled.
+pub const DF_1_DIRECT: u32 = 0x0000_0100;
+pub const DF_1_TRANS: u32 = 0x0000_0200;
+/// Object is used to interpose.
+pub const DF_1_INTERPOSE: u32 = 0x0000_0400;
+/// Ignore default lib search path.
+pub const DF_1_NODEFLIB: u32 = 0x0000_0800;
+/// Object can't be dldump'ed.
+pub const DF_1_NODUMP: u32 = 0x0000_1000;
+/// Configuration alternative created.
+pub const DF_1_CONFALT: u32 = 0x0000_2000;
+/// Filtee terminates filters search.
+pub const DF_1_ENDFILTEE: u32 = 0x0000_4000;
+/// Disp reloc applied at build time.
+pub const DF_1_DISPRELDNE: u32 = 0x0000_8000;
+/// Disp reloc applied at run-time.
+pub const DF_1_DISPRELPND: u32 = 0x0001_0000;
+/// Object has no-direct binding.
+pub const DF_1_NODIRECT: u32 = 0x0002_0000;
+pub const DF_1_IGNMULDEF: u32 = 0x0004_0000;
+pub const DF_1_NOKSYMS: u32 = 0x0008_0000;
+pub const DF_1_NOHDR: u32 = 0x0010_0000;
+/// Object is modified after built.
+pub const DF_1_EDITED: u32 = 0x0020_0000;
+pub const DF_1_NORELOC: u32 = 0x0040_0000;
+/// Object has individual interposers.
+pub const DF_1_SYMINTPOSE: u32 = 0x0080_0000;
+/// Global auditing required.
+pub const DF_1_GLOBAUDIT: u32 = 0x0100_0000;
+/// Singleton symbols are used.
+pub const DF_1_SINGLETON: u32 = 0x0200_0000;
+pub const DF_1_STUB: u32 = 0x0400_0000;
+pub const DF_1_PIE: u32 = 0x0800_0000;
+
+/// Version symbol information
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Versym<E: Endian>(pub U16<E>);
+
+/// Symbol is hidden.
+pub const VERSYM_HIDDEN: u16 = 0x8000;
+/// Symbol version index.
+pub const VERSYM_VERSION: u16 = 0x7fff;
+
+/// Version definition sections
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Verdef<E: Endian> {
+ /// Version revision
+ pub vd_version: U16<E>,
+ /// Version information
+ pub vd_flags: U16<E>,
+ /// Version Index
+ pub vd_ndx: U16<E>,
+ /// Number of associated aux entries
+ pub vd_cnt: U16<E>,
+ /// Version name hash value
+ pub vd_hash: U32<E>,
+ /// Offset in bytes to verdaux array
+ pub vd_aux: U32<E>,
+ /// Offset in bytes to next verdef entry
+ pub vd_next: U32<E>,
+}
+
+// Legal values for vd_version (version revision).
+/// No version
+pub const VER_DEF_NONE: u16 = 0;
+/// Current version
+pub const VER_DEF_CURRENT: u16 = 1;
+
+// Legal values for vd_flags (version information flags).
+/// Version definition of file itself
+pub const VER_FLG_BASE: u16 = 0x1;
+// Legal values for vd_flags and vna_flags (version information flags).
+/// Weak version identifier
+pub const VER_FLG_WEAK: u16 = 0x2;
+
+// Versym symbol index values.
+/// Symbol is local.
+pub const VER_NDX_LOCAL: u16 = 0;
+/// Symbol is global.
+pub const VER_NDX_GLOBAL: u16 = 1;
+
+/// Auxiliary version information.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Verdaux<E: Endian> {
+ /// Version or dependency names
+ pub vda_name: U32<E>,
+ /// Offset in bytes to next verdaux
+ pub vda_next: U32<E>,
+}
+
+/// Version dependency.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Verneed<E: Endian> {
+ /// Version of structure
+ pub vn_version: U16<E>,
+ /// Number of associated aux entries
+ pub vn_cnt: U16<E>,
+ /// Offset of filename for this dependency
+ pub vn_file: U32<E>,
+ /// Offset in bytes to vernaux array
+ pub vn_aux: U32<E>,
+ /// Offset in bytes to next verneed entry
+ pub vn_next: U32<E>,
+}
+
+// Legal values for vn_version (version revision).
+/// No version
+pub const VER_NEED_NONE: u16 = 0;
+/// Current version
+pub const VER_NEED_CURRENT: u16 = 1;
+
+/// Auxiliary needed version information.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Vernaux<E: Endian> {
+ /// Hash value of dependency name
+ pub vna_hash: U32<E>,
+ /// Dependency specific information
+ pub vna_flags: U16<E>,
+ /// Version Index
+ pub vna_other: U16<E>,
+ /// Dependency name string offset
+ pub vna_name: U32<E>,
+ /// Offset in bytes to next vernaux entry
+ pub vna_next: U32<E>,
+}
+
+// TODO: Elf*_auxv_t, AT_*
+
+/// Note section entry header.
+///
+/// A note consists of a header followed by a variable length name and descriptor.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct NoteHeader32<E: Endian> {
+ /// Length of the note's name.
+ ///
+ /// Some known names are defined by the `ELF_NOTE_*` constants.
+ pub n_namesz: U32<E>,
+ /// Length of the note's descriptor.
+ ///
+ /// The content of the descriptor depends on the note name and type.
+ pub n_descsz: U32<E>,
+ /// Type of the note.
+ ///
+ /// One of the `NT_*` constants. The note name determines which
+ /// `NT_*` constants are valid.
+ pub n_type: U32<E>,
+}
+
+/// Note section entry header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct NoteHeader64<E: Endian> {
+ /// Length of the note's name.
+ ///
+ /// Some known names are defined by the `ELF_NOTE_*` constants.
+ pub n_namesz: U32<E>,
+ /// Length of the note's descriptor.
+ ///
+ /// The content of the descriptor depends on the note name and type.
+ pub n_descsz: U32<E>,
+ /// Type of the note.
+ ///
+ /// One of the `NT_*` constants. The note name determines which
+ /// `NT_*` constants are valid.
+ pub n_type: U32<E>,
+}
+
+/// Solaris entries in the note section have this name.
+pub const ELF_NOTE_SOLARIS: &[u8] = b"SUNW Solaris";
+
+// Values for `n_type` when the name is `ELF_NOTE_SOLARIS`.
+/// Desired pagesize for the binary.
+pub const NT_SOLARIS_PAGESIZE_HINT: u32 = 1;
+
+/// GNU entries in the note section have this name.
+pub const ELF_NOTE_GNU: &[u8] = b"GNU";
+
+/// Go entries in the note section have this name.
+// See https://go-review.googlesource.com/9520 and https://go-review.googlesource.com/10704.
+pub const ELF_NOTE_GO: &[u8] = b"Go";
+
+// Note types for `ELF_NOTE_GNU`.
+
+/// ABI information.
+///
+/// The descriptor consists of words:
+/// - word 0: OS descriptor
+/// - word 1: major version of the ABI
+/// - word 2: minor version of the ABI
+/// - word 3: subminor version of the ABI
+pub const NT_GNU_ABI_TAG: u32 = 1;
+
+/// OS descriptor for `NT_GNU_ABI_TAG`.
+pub const ELF_NOTE_OS_LINUX: u32 = 0;
+/// OS descriptor for `NT_GNU_ABI_TAG`.
+pub const ELF_NOTE_OS_GNU: u32 = 1;
+/// OS descriptor for `NT_GNU_ABI_TAG`.
+pub const ELF_NOTE_OS_SOLARIS2: u32 = 2;
+/// OS descriptor for `NT_GNU_ABI_TAG`.
+pub const ELF_NOTE_OS_FREEBSD: u32 = 3;
+
+/// Synthetic hwcap information.
+///
+/// The descriptor begins with two words:
+/// - word 0: number of entries
+/// - word 1: bitmask of enabled entries
+/// Then follow variable-length entries, one byte followed by a
+/// '\0'-terminated hwcap name string. The byte gives the bit
+/// number to test if enabled, (1U << bit) & bitmask. */
+pub const NT_GNU_HWCAP: u32 = 2;
+
+/// Build ID bits as generated by `ld --build-id`.
+///
+/// The descriptor consists of any nonzero number of bytes.
+pub const NT_GNU_BUILD_ID: u32 = 3;
+
+/// Build ID bits as generated by Go's gc compiler.
+///
+/// The descriptor consists of any nonzero number of bytes.
+// See https://go-review.googlesource.com/10707.
+pub const NT_GO_BUILD_ID: u32 = 4;
+
+/// Version note generated by GNU gold containing a version string.
+pub const NT_GNU_GOLD_VERSION: u32 = 4;
+
+/// Program property.
+pub const NT_GNU_PROPERTY_TYPE_0: u32 = 5;
+
+// Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0).
+
+/// Stack size.
+pub const GNU_PROPERTY_STACK_SIZE: u32 = 1;
+/// No copy relocation on protected data symbol.
+pub const GNU_PROPERTY_NO_COPY_ON_PROTECTED: u32 = 2;
+
+// A 4-byte unsigned integer property: A bit is set if it is set in all
+// relocatable inputs.
+pub const GNU_PROPERTY_UINT32_AND_LO: u32 = 0xb0000000;
+pub const GNU_PROPERTY_UINT32_AND_HI: u32 = 0xb0007fff;
+
+// A 4-byte unsigned integer property: A bit is set if it is set in any
+// relocatable inputs.
+pub const GNU_PROPERTY_UINT32_OR_LO: u32 = 0xb0008000;
+pub const GNU_PROPERTY_UINT32_OR_HI: u32 = 0xb000ffff;
+
+/// The needed properties by the object file. */
+pub const GNU_PROPERTY_1_NEEDED: u32 = GNU_PROPERTY_UINT32_OR_LO;
+
+/// Set if the object file requires canonical function pointers and
+/// cannot be used with copy relocation.
+pub const GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS: u32 = 1 << 0;
+
+/// Processor-specific semantics, lo
+pub const GNU_PROPERTY_LOPROC: u32 = 0xc0000000;
+/// Processor-specific semantics, hi
+pub const GNU_PROPERTY_HIPROC: u32 = 0xdfffffff;
+/// Application-specific semantics, lo
+pub const GNU_PROPERTY_LOUSER: u32 = 0xe0000000;
+/// Application-specific semantics, hi
+pub const GNU_PROPERTY_HIUSER: u32 = 0xffffffff;
+
+/// AArch64 specific GNU properties.
+pub const GNU_PROPERTY_AARCH64_FEATURE_1_AND: u32 = 0xc0000000;
+
+pub const GNU_PROPERTY_AARCH64_FEATURE_1_BTI: u32 = 1 << 0;
+pub const GNU_PROPERTY_AARCH64_FEATURE_1_PAC: u32 = 1 << 1;
+
+// A 4-byte unsigned integer property: A bit is set if it is set in all
+// relocatable inputs.
+pub const GNU_PROPERTY_X86_UINT32_AND_LO: u32 = 0xc0000002;
+pub const GNU_PROPERTY_X86_UINT32_AND_HI: u32 = 0xc0007fff;
+
+// A 4-byte unsigned integer property: A bit is set if it is set in any
+// relocatable inputs.
+pub const GNU_PROPERTY_X86_UINT32_OR_LO: u32 = 0xc0008000;
+pub const GNU_PROPERTY_X86_UINT32_OR_HI: u32 = 0xc000ffff;
+
+// A 4-byte unsigned integer property: A bit is set if it is set in any
+// relocatable inputs and the property is present in all relocatable
+// inputs.
+pub const GNU_PROPERTY_X86_UINT32_OR_AND_LO: u32 = 0xc0010000;
+pub const GNU_PROPERTY_X86_UINT32_OR_AND_HI: u32 = 0xc0017fff;
+
+/// The x86 instruction sets indicated by the corresponding bits are
+/// used in program. Their support in the hardware is optional.
+pub const GNU_PROPERTY_X86_ISA_1_USED: u32 = 0xc0010002;
+/// The x86 instruction sets indicated by the corresponding bits are
+/// used in program and they must be supported by the hardware.
+pub const GNU_PROPERTY_X86_ISA_1_NEEDED: u32 = 0xc0008002;
+/// X86 processor-specific features used in program.
+pub const GNU_PROPERTY_X86_FEATURE_1_AND: u32 = 0xc0000002;
+
+/// GNU_PROPERTY_X86_ISA_1_BASELINE: CMOV, CX8 (cmpxchg8b), FPU (fld),
+/// MMX, OSFXSR (fxsave), SCE (syscall), SSE and SSE2.
+pub const GNU_PROPERTY_X86_ISA_1_BASELINE: u32 = 1 << 0;
+/// GNU_PROPERTY_X86_ISA_1_V2: GNU_PROPERTY_X86_ISA_1_BASELINE,
+/// CMPXCHG16B (cmpxchg16b), LAHF-SAHF (lahf), POPCNT (popcnt), SSE3,
+/// SSSE3, SSE4.1 and SSE4.2.
+pub const GNU_PROPERTY_X86_ISA_1_V2: u32 = 1 << 1;
+/// GNU_PROPERTY_X86_ISA_1_V3: GNU_PROPERTY_X86_ISA_1_V2, AVX, AVX2, BMI1,
+/// BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE.
+pub const GNU_PROPERTY_X86_ISA_1_V3: u32 = 1 << 2;
+/// GNU_PROPERTY_X86_ISA_1_V4: GNU_PROPERTY_X86_ISA_1_V3, AVX512F,
+/// AVX512BW, AVX512CD, AVX512DQ and AVX512VL.
+pub const GNU_PROPERTY_X86_ISA_1_V4: u32 = 1 << 3;
+
+/// This indicates that all executable sections are compatible with IBT.
+pub const GNU_PROPERTY_X86_FEATURE_1_IBT: u32 = 1 << 0;
+/// This indicates that all executable sections are compatible with SHSTK.
+pub const GNU_PROPERTY_X86_FEATURE_1_SHSTK: u32 = 1 << 1;
+
+// TODO: Elf*_Move
+
+/// Header of `SHT_HASH` section.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct HashHeader<E: Endian> {
+ /// The number of hash buckets.
+ pub bucket_count: U32<E>,
+ /// The number of chain values.
+ pub chain_count: U32<E>,
+ // Array of hash bucket start indices.
+ // buckets: U32<E>[bucket_count]
+ // Array of hash chain links. An index of 0 terminates the chain.
+ // chains: U32<E>[chain_count]
+}
+
+/// Calculate the SysV hash for a symbol name.
+///
+/// Used for `SHT_HASH`.
+pub fn hash(name: &[u8]) -> u32 {
+ let mut hash = 0u32;
+ for byte in name {
+ hash = hash.wrapping_mul(16).wrapping_add(u32::from(*byte));
+ hash ^= (hash >> 24) & 0xf0;
+ }
+ hash & 0xfff_ffff
+}
+
+/// Header of `SHT_GNU_HASH` section.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct GnuHashHeader<E: Endian> {
+ /// The number of hash buckets.
+ pub bucket_count: U32<E>,
+ /// The symbol table index of the first symbol in the hash.
+ pub symbol_base: U32<E>,
+ /// The number of words in the bloom filter.
+ ///
+ /// Must be a non-zero power of 2.
+ pub bloom_count: U32<E>,
+ /// The bit shift count for the bloom filter.
+ pub bloom_shift: U32<E>,
+ // Array of bloom filter words.
+ // bloom_filters: U32<E>[bloom_count] or U64<E>[bloom_count]
+ // Array of hash bucket start indices.
+ // buckets: U32<E>[bucket_count]
+ // Array of hash values, one for each symbol starting at symbol_base.
+ // values: U32<E>[symbol_count]
+}
+
+/// Calculate the GNU hash for a symbol name.
+///
+/// Used for `SHT_GNU_HASH`.
+pub fn gnu_hash(name: &[u8]) -> u32 {
+ let mut hash = 5381u32;
+ for byte in name {
+ hash = hash.wrapping_mul(33).wrapping_add(u32::from(*byte));
+ }
+ hash
+}
+
+// Motorola 68k specific definitions.
+
+// m68k values for `Rel*::r_type`.
+
+/// No reloc
+pub const R_68K_NONE: u32 = 0;
+/// Direct 32 bit
+pub const R_68K_32: u32 = 1;
+/// Direct 16 bit
+pub const R_68K_16: u32 = 2;
+/// Direct 8 bit
+pub const R_68K_8: u32 = 3;
+/// PC relative 32 bit
+pub const R_68K_PC32: u32 = 4;
+/// PC relative 16 bit
+pub const R_68K_PC16: u32 = 5;
+/// PC relative 8 bit
+pub const R_68K_PC8: u32 = 6;
+/// 32 bit PC relative GOT entry
+pub const R_68K_GOT32: u32 = 7;
+/// 16 bit PC relative GOT entry
+pub const R_68K_GOT16: u32 = 8;
+/// 8 bit PC relative GOT entry
+pub const R_68K_GOT8: u32 = 9;
+/// 32 bit GOT offset
+pub const R_68K_GOT32O: u32 = 10;
+/// 16 bit GOT offset
+pub const R_68K_GOT16O: u32 = 11;
+/// 8 bit GOT offset
+pub const R_68K_GOT8O: u32 = 12;
+/// 32 bit PC relative PLT address
+pub const R_68K_PLT32: u32 = 13;
+/// 16 bit PC relative PLT address
+pub const R_68K_PLT16: u32 = 14;
+/// 8 bit PC relative PLT address
+pub const R_68K_PLT8: u32 = 15;
+/// 32 bit PLT offset
+pub const R_68K_PLT32O: u32 = 16;
+/// 16 bit PLT offset
+pub const R_68K_PLT16O: u32 = 17;
+/// 8 bit PLT offset
+pub const R_68K_PLT8O: u32 = 18;
+/// Copy symbol at runtime
+pub const R_68K_COPY: u32 = 19;
+/// Create GOT entry
+pub const R_68K_GLOB_DAT: u32 = 20;
+/// Create PLT entry
+pub const R_68K_JMP_SLOT: u32 = 21;
+/// Adjust by program base
+pub const R_68K_RELATIVE: u32 = 22;
+/// 32 bit GOT offset for GD
+pub const R_68K_TLS_GD32: u32 = 25;
+/// 16 bit GOT offset for GD
+pub const R_68K_TLS_GD16: u32 = 26;
+/// 8 bit GOT offset for GD
+pub const R_68K_TLS_GD8: u32 = 27;
+/// 32 bit GOT offset for LDM
+pub const R_68K_TLS_LDM32: u32 = 28;
+/// 16 bit GOT offset for LDM
+pub const R_68K_TLS_LDM16: u32 = 29;
+/// 8 bit GOT offset for LDM
+pub const R_68K_TLS_LDM8: u32 = 30;
+/// 32 bit module-relative offset
+pub const R_68K_TLS_LDO32: u32 = 31;
+/// 16 bit module-relative offset
+pub const R_68K_TLS_LDO16: u32 = 32;
+/// 8 bit module-relative offset
+pub const R_68K_TLS_LDO8: u32 = 33;
+/// 32 bit GOT offset for IE
+pub const R_68K_TLS_IE32: u32 = 34;
+/// 16 bit GOT offset for IE
+pub const R_68K_TLS_IE16: u32 = 35;
+/// 8 bit GOT offset for IE
+pub const R_68K_TLS_IE8: u32 = 36;
+/// 32 bit offset relative to static TLS block
+pub const R_68K_TLS_LE32: u32 = 37;
+/// 16 bit offset relative to static TLS block
+pub const R_68K_TLS_LE16: u32 = 38;
+/// 8 bit offset relative to static TLS block
+pub const R_68K_TLS_LE8: u32 = 39;
+/// 32 bit module number
+pub const R_68K_TLS_DTPMOD32: u32 = 40;
+/// 32 bit module-relative offset
+pub const R_68K_TLS_DTPREL32: u32 = 41;
+/// 32 bit TP-relative offset
+pub const R_68K_TLS_TPREL32: u32 = 42;
+
+// Intel 80386 specific definitions.
+
+// i386 values for `Rel*::r_type`.
+
+/// No reloc
+pub const R_386_NONE: u32 = 0;
+/// Direct 32 bit
+pub const R_386_32: u32 = 1;
+/// PC relative 32 bit
+pub const R_386_PC32: u32 = 2;
+/// 32 bit GOT entry
+pub const R_386_GOT32: u32 = 3;
+/// 32 bit PLT address
+pub const R_386_PLT32: u32 = 4;
+/// Copy symbol at runtime
+pub const R_386_COPY: u32 = 5;
+/// Create GOT entry
+pub const R_386_GLOB_DAT: u32 = 6;
+/// Create PLT entry
+pub const R_386_JMP_SLOT: u32 = 7;
+/// Adjust by program base
+pub const R_386_RELATIVE: u32 = 8;
+/// 32 bit offset to GOT
+pub const R_386_GOTOFF: u32 = 9;
+/// 32 bit PC relative offset to GOT
+pub const R_386_GOTPC: u32 = 10;
+/// Direct 32 bit PLT address
+pub const R_386_32PLT: u32 = 11;
+/// Offset in static TLS block
+pub const R_386_TLS_TPOFF: u32 = 14;
+/// Address of GOT entry for static TLS block offset
+pub const R_386_TLS_IE: u32 = 15;
+/// GOT entry for static TLS block offset
+pub const R_386_TLS_GOTIE: u32 = 16;
+/// Offset relative to static TLS block
+pub const R_386_TLS_LE: u32 = 17;
+/// Direct 32 bit for GNU version of general dynamic thread local data
+pub const R_386_TLS_GD: u32 = 18;
+/// Direct 32 bit for GNU version of local dynamic thread local data in LE code
+pub const R_386_TLS_LDM: u32 = 19;
+/// Direct 16 bit
+pub const R_386_16: u32 = 20;
+/// PC relative 16 bit
+pub const R_386_PC16: u32 = 21;
+/// Direct 8 bit
+pub const R_386_8: u32 = 22;
+/// PC relative 8 bit
+pub const R_386_PC8: u32 = 23;
+/// Direct 32 bit for general dynamic thread local data
+pub const R_386_TLS_GD_32: u32 = 24;
+/// Tag for pushl in GD TLS code
+pub const R_386_TLS_GD_PUSH: u32 = 25;
+/// Relocation for call to __tls_get_addr()
+pub const R_386_TLS_GD_CALL: u32 = 26;
+/// Tag for popl in GD TLS code
+pub const R_386_TLS_GD_POP: u32 = 27;
+/// Direct 32 bit for local dynamic thread local data in LE code
+pub const R_386_TLS_LDM_32: u32 = 28;
+/// Tag for pushl in LDM TLS code
+pub const R_386_TLS_LDM_PUSH: u32 = 29;
+/// Relocation for call to __tls_get_addr() in LDM code
+pub const R_386_TLS_LDM_CALL: u32 = 30;
+/// Tag for popl in LDM TLS code
+pub const R_386_TLS_LDM_POP: u32 = 31;
+/// Offset relative to TLS block
+pub const R_386_TLS_LDO_32: u32 = 32;
+/// GOT entry for negated static TLS block offset
+pub const R_386_TLS_IE_32: u32 = 33;
+/// Negated offset relative to static TLS block
+pub const R_386_TLS_LE_32: u32 = 34;
+/// ID of module containing symbol
+pub const R_386_TLS_DTPMOD32: u32 = 35;
+/// Offset in TLS block
+pub const R_386_TLS_DTPOFF32: u32 = 36;
+/// Negated offset in static TLS block
+pub const R_386_TLS_TPOFF32: u32 = 37;
+/// 32-bit symbol size
+pub const R_386_SIZE32: u32 = 38;
+/// GOT offset for TLS descriptor.
+pub const R_386_TLS_GOTDESC: u32 = 39;
+/// Marker of call through TLS descriptor for relaxation.
+pub const R_386_TLS_DESC_CALL: u32 = 40;
+/// TLS descriptor containing pointer to code and to argument, returning the TLS offset for the symbol.
+pub const R_386_TLS_DESC: u32 = 41;
+/// Adjust indirectly by program base
+pub const R_386_IRELATIVE: u32 = 42;
+/// Load from 32 bit GOT entry, relaxable.
+pub const R_386_GOT32X: u32 = 43;
+
+// SUN SPARC specific definitions.
+
+// SPARC values for `st_type` component of `Sym*::st_info`.
+
+/// Global register reserved to app.
+pub const STT_SPARC_REGISTER: u8 = 13;
+
+// SPARC values for `FileHeader64::e_flags`.
+
+pub const EF_SPARCV9_MM: u32 = 3;
+pub const EF_SPARCV9_TSO: u32 = 0;
+pub const EF_SPARCV9_PSO: u32 = 1;
+pub const EF_SPARCV9_RMO: u32 = 2;
+/// little endian data
+pub const EF_SPARC_LEDATA: u32 = 0x80_0000;
+pub const EF_SPARC_EXT_MASK: u32 = 0xFF_FF00;
+/// generic V8+ features
+pub const EF_SPARC_32PLUS: u32 = 0x00_0100;
+/// Sun UltraSPARC1 extensions
+pub const EF_SPARC_SUN_US1: u32 = 0x00_0200;
+/// HAL R1 extensions
+pub const EF_SPARC_HAL_R1: u32 = 0x00_0400;
+/// Sun UltraSPARCIII extensions
+pub const EF_SPARC_SUN_US3: u32 = 0x00_0800;
+
+// SPARC values for `Rel*::r_type`.
+
+/// No reloc
+pub const R_SPARC_NONE: u32 = 0;
+/// Direct 8 bit
+pub const R_SPARC_8: u32 = 1;
+/// Direct 16 bit
+pub const R_SPARC_16: u32 = 2;
+/// Direct 32 bit
+pub const R_SPARC_32: u32 = 3;
+/// PC relative 8 bit
+pub const R_SPARC_DISP8: u32 = 4;
+/// PC relative 16 bit
+pub const R_SPARC_DISP16: u32 = 5;
+/// PC relative 32 bit
+pub const R_SPARC_DISP32: u32 = 6;
+/// PC relative 30 bit shifted
+pub const R_SPARC_WDISP30: u32 = 7;
+/// PC relative 22 bit shifted
+pub const R_SPARC_WDISP22: u32 = 8;
+/// High 22 bit
+pub const R_SPARC_HI22: u32 = 9;
+/// Direct 22 bit
+pub const R_SPARC_22: u32 = 10;
+/// Direct 13 bit
+pub const R_SPARC_13: u32 = 11;
+/// Truncated 10 bit
+pub const R_SPARC_LO10: u32 = 12;
+/// Truncated 10 bit GOT entry
+pub const R_SPARC_GOT10: u32 = 13;
+/// 13 bit GOT entry
+pub const R_SPARC_GOT13: u32 = 14;
+/// 22 bit GOT entry shifted
+pub const R_SPARC_GOT22: u32 = 15;
+/// PC relative 10 bit truncated
+pub const R_SPARC_PC10: u32 = 16;
+/// PC relative 22 bit shifted
+pub const R_SPARC_PC22: u32 = 17;
+/// 30 bit PC relative PLT address
+pub const R_SPARC_WPLT30: u32 = 18;
+/// Copy symbol at runtime
+pub const R_SPARC_COPY: u32 = 19;
+/// Create GOT entry
+pub const R_SPARC_GLOB_DAT: u32 = 20;
+/// Create PLT entry
+pub const R_SPARC_JMP_SLOT: u32 = 21;
+/// Adjust by program base
+pub const R_SPARC_RELATIVE: u32 = 22;
+/// Direct 32 bit unaligned
+pub const R_SPARC_UA32: u32 = 23;
+
+// Sparc64 values for `Rel*::r_type`.
+
+/// Direct 32 bit ref to PLT entry
+pub const R_SPARC_PLT32: u32 = 24;
+/// High 22 bit PLT entry
+pub const R_SPARC_HIPLT22: u32 = 25;
+/// Truncated 10 bit PLT entry
+pub const R_SPARC_LOPLT10: u32 = 26;
+/// PC rel 32 bit ref to PLT entry
+pub const R_SPARC_PCPLT32: u32 = 27;
+/// PC rel high 22 bit PLT entry
+pub const R_SPARC_PCPLT22: u32 = 28;
+/// PC rel trunc 10 bit PLT entry
+pub const R_SPARC_PCPLT10: u32 = 29;
+/// Direct 10 bit
+pub const R_SPARC_10: u32 = 30;
+/// Direct 11 bit
+pub const R_SPARC_11: u32 = 31;
+/// Direct 64 bit
+pub const R_SPARC_64: u32 = 32;
+/// 10bit with secondary 13bit addend
+pub const R_SPARC_OLO10: u32 = 33;
+/// Top 22 bits of direct 64 bit
+pub const R_SPARC_HH22: u32 = 34;
+/// High middle 10 bits of ...
+pub const R_SPARC_HM10: u32 = 35;
+/// Low middle 22 bits of ...
+pub const R_SPARC_LM22: u32 = 36;
+/// Top 22 bits of pc rel 64 bit
+pub const R_SPARC_PC_HH22: u32 = 37;
+/// High middle 10 bit of ...
+pub const R_SPARC_PC_HM10: u32 = 38;
+/// Low miggle 22 bits of ...
+pub const R_SPARC_PC_LM22: u32 = 39;
+/// PC relative 16 bit shifted
+pub const R_SPARC_WDISP16: u32 = 40;
+/// PC relative 19 bit shifted
+pub const R_SPARC_WDISP19: u32 = 41;
+/// was part of v9 ABI but was removed
+pub const R_SPARC_GLOB_JMP: u32 = 42;
+/// Direct 7 bit
+pub const R_SPARC_7: u32 = 43;
+/// Direct 5 bit
+pub const R_SPARC_5: u32 = 44;
+/// Direct 6 bit
+pub const R_SPARC_6: u32 = 45;
+/// PC relative 64 bit
+pub const R_SPARC_DISP64: u32 = 46;
+/// Direct 64 bit ref to PLT entry
+pub const R_SPARC_PLT64: u32 = 47;
+/// High 22 bit complemented
+pub const R_SPARC_HIX22: u32 = 48;
+/// Truncated 11 bit complemented
+pub const R_SPARC_LOX10: u32 = 49;
+/// Direct high 12 of 44 bit
+pub const R_SPARC_H44: u32 = 50;
+/// Direct mid 22 of 44 bit
+pub const R_SPARC_M44: u32 = 51;
+/// Direct low 10 of 44 bit
+pub const R_SPARC_L44: u32 = 52;
+/// Global register usage
+pub const R_SPARC_REGISTER: u32 = 53;
+/// Direct 64 bit unaligned
+pub const R_SPARC_UA64: u32 = 54;
+/// Direct 16 bit unaligned
+pub const R_SPARC_UA16: u32 = 55;
+pub const R_SPARC_TLS_GD_HI22: u32 = 56;
+pub const R_SPARC_TLS_GD_LO10: u32 = 57;
+pub const R_SPARC_TLS_GD_ADD: u32 = 58;
+pub const R_SPARC_TLS_GD_CALL: u32 = 59;
+pub const R_SPARC_TLS_LDM_HI22: u32 = 60;
+pub const R_SPARC_TLS_LDM_LO10: u32 = 61;
+pub const R_SPARC_TLS_LDM_ADD: u32 = 62;
+pub const R_SPARC_TLS_LDM_CALL: u32 = 63;
+pub const R_SPARC_TLS_LDO_HIX22: u32 = 64;
+pub const R_SPARC_TLS_LDO_LOX10: u32 = 65;
+pub const R_SPARC_TLS_LDO_ADD: u32 = 66;
+pub const R_SPARC_TLS_IE_HI22: u32 = 67;
+pub const R_SPARC_TLS_IE_LO10: u32 = 68;
+pub const R_SPARC_TLS_IE_LD: u32 = 69;
+pub const R_SPARC_TLS_IE_LDX: u32 = 70;
+pub const R_SPARC_TLS_IE_ADD: u32 = 71;
+pub const R_SPARC_TLS_LE_HIX22: u32 = 72;
+pub const R_SPARC_TLS_LE_LOX10: u32 = 73;
+pub const R_SPARC_TLS_DTPMOD32: u32 = 74;
+pub const R_SPARC_TLS_DTPMOD64: u32 = 75;
+pub const R_SPARC_TLS_DTPOFF32: u32 = 76;
+pub const R_SPARC_TLS_DTPOFF64: u32 = 77;
+pub const R_SPARC_TLS_TPOFF32: u32 = 78;
+pub const R_SPARC_TLS_TPOFF64: u32 = 79;
+pub const R_SPARC_GOTDATA_HIX22: u32 = 80;
+pub const R_SPARC_GOTDATA_LOX10: u32 = 81;
+pub const R_SPARC_GOTDATA_OP_HIX22: u32 = 82;
+pub const R_SPARC_GOTDATA_OP_LOX10: u32 = 83;
+pub const R_SPARC_GOTDATA_OP: u32 = 84;
+pub const R_SPARC_H34: u32 = 85;
+pub const R_SPARC_SIZE32: u32 = 86;
+pub const R_SPARC_SIZE64: u32 = 87;
+pub const R_SPARC_WDISP10: u32 = 88;
+pub const R_SPARC_JMP_IREL: u32 = 248;
+pub const R_SPARC_IRELATIVE: u32 = 249;
+pub const R_SPARC_GNU_VTINHERIT: u32 = 250;
+pub const R_SPARC_GNU_VTENTRY: u32 = 251;
+pub const R_SPARC_REV32: u32 = 252;
+
+// Sparc64 values for `Dyn32::d_tag`.
+
+pub const DT_SPARC_REGISTER: u32 = 0x7000_0001;
+
+// MIPS R3000 specific definitions.
+
+// MIPS values for `FileHeader32::e_flags`.
+
+/// A .noreorder directive was used.
+pub const EF_MIPS_NOREORDER: u32 = 1;
+/// Contains PIC code.
+pub const EF_MIPS_PIC: u32 = 2;
+/// Uses PIC calling sequence.
+pub const EF_MIPS_CPIC: u32 = 4;
+pub const EF_MIPS_XGOT: u32 = 8;
+pub const EF_MIPS_64BIT_WHIRL: u32 = 16;
+pub const EF_MIPS_ABI2: u32 = 32;
+pub const EF_MIPS_ABI_ON32: u32 = 64;
+/// Uses FP64 (12 callee-saved).
+pub const EF_MIPS_FP64: u32 = 512;
+/// Uses IEEE 754-2008 NaN encoding.
+pub const EF_MIPS_NAN2008: u32 = 1024;
+/// MIPS architecture level.
+pub const EF_MIPS_ARCH: u32 = 0xf000_0000;
+
+/// The first MIPS 32 bit ABI
+pub const EF_MIPS_ABI_O32: u32 = 0x0000_1000;
+/// O32 ABI extended for 64-bit architectures
+pub const EF_MIPS_ABI_O64: u32 = 0x0000_2000;
+/// EABI in 32-bit mode
+pub const EF_MIPS_ABI_EABI32: u32 = 0x0000_3000;
+/// EABI in 64-bit mode
+pub const EF_MIPS_ABI_EABI64: u32 = 0x0000_4000;
+/// Mask for selecting EF_MIPS_ABI_ variant
+pub const EF_MIPS_ABI: u32 = 0x0000_f000;
+
+// Legal values for MIPS architecture level.
+
+/// -mips1 code.
+pub const EF_MIPS_ARCH_1: u32 = 0x0000_0000;
+/// -mips2 code.
+pub const EF_MIPS_ARCH_2: u32 = 0x1000_0000;
+/// -mips3 code.
+pub const EF_MIPS_ARCH_3: u32 = 0x2000_0000;
+/// -mips4 code.
+pub const EF_MIPS_ARCH_4: u32 = 0x3000_0000;
+/// -mips5 code.
+pub const EF_MIPS_ARCH_5: u32 = 0x4000_0000;
+/// MIPS32 code.
+pub const EF_MIPS_ARCH_32: u32 = 0x5000_0000;
+/// MIPS64 code.
+pub const EF_MIPS_ARCH_64: u32 = 0x6000_0000;
+/// MIPS32r2 code.
+pub const EF_MIPS_ARCH_32R2: u32 = 0x7000_0000;
+/// MIPS64r2 code.
+pub const EF_MIPS_ARCH_64R2: u32 = 0x8000_0000;
+/// MIPS32r6 code
+pub const EF_MIPS_ARCH_32R6: u32 = 0x9000_0000;
+/// MIPS64r6 code
+pub const EF_MIPS_ARCH_64R6: u32 = 0xa000_0000;
+
+// MIPS values for `Sym32::st_shndx`.
+
+/// Allocated common symbols.
+pub const SHN_MIPS_ACOMMON: u16 = 0xff00;
+/// Allocated test symbols.
+pub const SHN_MIPS_TEXT: u16 = 0xff01;
+/// Allocated data symbols.
+pub const SHN_MIPS_DATA: u16 = 0xff02;
+/// Small common symbols.
+pub const SHN_MIPS_SCOMMON: u16 = 0xff03;
+/// Small undefined symbols.
+pub const SHN_MIPS_SUNDEFINED: u16 = 0xff04;
+
+// MIPS values for `SectionHeader32::sh_type`.
+
+/// Shared objects used in link.
+pub const SHT_MIPS_LIBLIST: u32 = 0x7000_0000;
+pub const SHT_MIPS_MSYM: u32 = 0x7000_0001;
+/// Conflicting symbols.
+pub const SHT_MIPS_CONFLICT: u32 = 0x7000_0002;
+/// Global data area sizes.
+pub const SHT_MIPS_GPTAB: u32 = 0x7000_0003;
+/// Reserved for SGI/MIPS compilers
+pub const SHT_MIPS_UCODE: u32 = 0x7000_0004;
+/// MIPS ECOFF debugging info.
+pub const SHT_MIPS_DEBUG: u32 = 0x7000_0005;
+/// Register usage information.
+pub const SHT_MIPS_REGINFO: u32 = 0x7000_0006;
+pub const SHT_MIPS_PACKAGE: u32 = 0x7000_0007;
+pub const SHT_MIPS_PACKSYM: u32 = 0x7000_0008;
+pub const SHT_MIPS_RELD: u32 = 0x7000_0009;
+pub const SHT_MIPS_IFACE: u32 = 0x7000_000b;
+pub const SHT_MIPS_CONTENT: u32 = 0x7000_000c;
+/// Miscellaneous options.
+pub const SHT_MIPS_OPTIONS: u32 = 0x7000_000d;
+pub const SHT_MIPS_SHDR: u32 = 0x7000_0010;
+pub const SHT_MIPS_FDESC: u32 = 0x7000_0011;
+pub const SHT_MIPS_EXTSYM: u32 = 0x7000_0012;
+pub const SHT_MIPS_DENSE: u32 = 0x7000_0013;
+pub const SHT_MIPS_PDESC: u32 = 0x7000_0014;
+pub const SHT_MIPS_LOCSYM: u32 = 0x7000_0015;
+pub const SHT_MIPS_AUXSYM: u32 = 0x7000_0016;
+pub const SHT_MIPS_OPTSYM: u32 = 0x7000_0017;
+pub const SHT_MIPS_LOCSTR: u32 = 0x7000_0018;
+pub const SHT_MIPS_LINE: u32 = 0x7000_0019;
+pub const SHT_MIPS_RFDESC: u32 = 0x7000_001a;
+pub const SHT_MIPS_DELTASYM: u32 = 0x7000_001b;
+pub const SHT_MIPS_DELTAINST: u32 = 0x7000_001c;
+pub const SHT_MIPS_DELTACLASS: u32 = 0x7000_001d;
+/// DWARF debugging information.
+pub const SHT_MIPS_DWARF: u32 = 0x7000_001e;
+pub const SHT_MIPS_DELTADECL: u32 = 0x7000_001f;
+pub const SHT_MIPS_SYMBOL_LIB: u32 = 0x7000_0020;
+/// Event section.
+pub const SHT_MIPS_EVENTS: u32 = 0x7000_0021;
+pub const SHT_MIPS_TRANSLATE: u32 = 0x7000_0022;
+pub const SHT_MIPS_PIXIE: u32 = 0x7000_0023;
+pub const SHT_MIPS_XLATE: u32 = 0x7000_0024;
+pub const SHT_MIPS_XLATE_DEBUG: u32 = 0x7000_0025;
+pub const SHT_MIPS_WHIRL: u32 = 0x7000_0026;
+pub const SHT_MIPS_EH_REGION: u32 = 0x7000_0027;
+pub const SHT_MIPS_XLATE_OLD: u32 = 0x7000_0028;
+pub const SHT_MIPS_PDR_EXCEPTION: u32 = 0x7000_0029;
+
+// MIPS values for `SectionHeader32::sh_flags`.
+
+/// Must be in global data area.
+pub const SHF_MIPS_GPREL: u32 = 0x1000_0000;
+pub const SHF_MIPS_MERGE: u32 = 0x2000_0000;
+pub const SHF_MIPS_ADDR: u32 = 0x4000_0000;
+pub const SHF_MIPS_STRINGS: u32 = 0x8000_0000;
+pub const SHF_MIPS_NOSTRIP: u32 = 0x0800_0000;
+pub const SHF_MIPS_LOCAL: u32 = 0x0400_0000;
+pub const SHF_MIPS_NAMES: u32 = 0x0200_0000;
+pub const SHF_MIPS_NODUPE: u32 = 0x0100_0000;
+
+// MIPS values for `Sym32::st_other`.
+
+pub const STO_MIPS_PLT: u8 = 0x8;
+/// Only valid for `STB_MIPS_SPLIT_COMMON`.
+pub const STO_MIPS_SC_ALIGN_UNUSED: u8 = 0xff;
+
+// MIPS values for `Sym32::st_info'.
+pub const STB_MIPS_SPLIT_COMMON: u8 = 13;
+
+// Entries found in sections of type `SHT_MIPS_GPTAB`.
+
+// TODO: Elf32_gptab, Elf32_RegInfo, Elf_Options
+
+// Values for `Elf_Options::kind`.
+
+/// Undefined.
+pub const ODK_NULL: u32 = 0;
+/// Register usage information.
+pub const ODK_REGINFO: u32 = 1;
+/// Exception processing options.
+pub const ODK_EXCEPTIONS: u32 = 2;
+/// Section padding options.
+pub const ODK_PAD: u32 = 3;
+/// Hardware workarounds performed
+pub const ODK_HWPATCH: u32 = 4;
+/// record the fill value used by the linker.
+pub const ODK_FILL: u32 = 5;
+/// reserve space for desktop tools to write.
+pub const ODK_TAGS: u32 = 6;
+/// HW workarounds. 'AND' bits when merging.
+pub const ODK_HWAND: u32 = 7;
+/// HW workarounds. 'OR' bits when merging.
+pub const ODK_HWOR: u32 = 8;
+
+// Values for `Elf_Options::info` for `ODK_EXCEPTIONS` entries.
+
+/// FPE's which MUST be enabled.
+pub const OEX_FPU_MIN: u32 = 0x1f;
+/// FPE's which MAY be enabled.
+pub const OEX_FPU_MAX: u32 = 0x1f00;
+/// page zero must be mapped.
+pub const OEX_PAGE0: u32 = 0x10000;
+/// Force sequential memory mode?
+pub const OEX_SMM: u32 = 0x20000;
+/// Force floating point debug mode?
+pub const OEX_FPDBUG: u32 = 0x40000;
+pub const OEX_PRECISEFP: u32 = OEX_FPDBUG;
+/// Dismiss invalid address faults?
+pub const OEX_DISMISS: u32 = 0x80000;
+
+pub const OEX_FPU_INVAL: u32 = 0x10;
+pub const OEX_FPU_DIV0: u32 = 0x08;
+pub const OEX_FPU_OFLO: u32 = 0x04;
+pub const OEX_FPU_UFLO: u32 = 0x02;
+pub const OEX_FPU_INEX: u32 = 0x01;
+
+// Masks for `Elf_Options::info` for an `ODK_HWPATCH` entry. */
+/// R4000 end-of-page patch.
+pub const OHW_R4KEOP: u32 = 0x1;
+/// may need R8000 prefetch patch.
+pub const OHW_R8KPFETCH: u32 = 0x2;
+/// R5000 end-of-page patch.
+pub const OHW_R5KEOP: u32 = 0x4;
+/// R5000 cvt.\[ds\].l bug. clean=1.
+pub const OHW_R5KCVTL: u32 = 0x8;
+
+pub const OPAD_PREFIX: u32 = 0x1;
+pub const OPAD_POSTFIX: u32 = 0x2;
+pub const OPAD_SYMBOL: u32 = 0x4;
+
+// Entries found in sections of type `SHT_MIPS_OPTIONS`.
+
+// TODO: Elf_Options_Hw
+
+// Masks for `ElfOptions::info` for `ODK_HWAND` and `ODK_HWOR` entries.
+
+pub const OHWA0_R4KEOP_CHECKED: u32 = 0x0000_0001;
+pub const OHWA1_R4KEOP_CLEAN: u32 = 0x0000_0002;
+
+// MIPS values for `Rel*::r_type`.
+
+/// No reloc
+pub const R_MIPS_NONE: u32 = 0;
+/// Direct 16 bit
+pub const R_MIPS_16: u32 = 1;
+/// Direct 32 bit
+pub const R_MIPS_32: u32 = 2;
+/// PC relative 32 bit
+pub const R_MIPS_REL32: u32 = 3;
+/// Direct 26 bit shifted
+pub const R_MIPS_26: u32 = 4;
+/// High 16 bit
+pub const R_MIPS_HI16: u32 = 5;
+/// Low 16 bit
+pub const R_MIPS_LO16: u32 = 6;
+/// GP relative 16 bit
+pub const R_MIPS_GPREL16: u32 = 7;
+/// 16 bit literal entry
+pub const R_MIPS_LITERAL: u32 = 8;
+/// 16 bit GOT entry
+pub const R_MIPS_GOT16: u32 = 9;
+/// PC relative 16 bit
+pub const R_MIPS_PC16: u32 = 10;
+/// 16 bit GOT entry for function
+pub const R_MIPS_CALL16: u32 = 11;
+/// GP relative 32 bit
+pub const R_MIPS_GPREL32: u32 = 12;
+
+pub const R_MIPS_SHIFT5: u32 = 16;
+pub const R_MIPS_SHIFT6: u32 = 17;
+pub const R_MIPS_64: u32 = 18;
+pub const R_MIPS_GOT_DISP: u32 = 19;
+pub const R_MIPS_GOT_PAGE: u32 = 20;
+pub const R_MIPS_GOT_OFST: u32 = 21;
+pub const R_MIPS_GOT_HI16: u32 = 22;
+pub const R_MIPS_GOT_LO16: u32 = 23;
+pub const R_MIPS_SUB: u32 = 24;
+pub const R_MIPS_INSERT_A: u32 = 25;
+pub const R_MIPS_INSERT_B: u32 = 26;
+pub const R_MIPS_DELETE: u32 = 27;
+pub const R_MIPS_HIGHER: u32 = 28;
+pub const R_MIPS_HIGHEST: u32 = 29;
+pub const R_MIPS_CALL_HI16: u32 = 30;
+pub const R_MIPS_CALL_LO16: u32 = 31;
+pub const R_MIPS_SCN_DISP: u32 = 32;
+pub const R_MIPS_REL16: u32 = 33;
+pub const R_MIPS_ADD_IMMEDIATE: u32 = 34;
+pub const R_MIPS_PJUMP: u32 = 35;
+pub const R_MIPS_RELGOT: u32 = 36;
+pub const R_MIPS_JALR: u32 = 37;
+/// Module number 32 bit
+pub const R_MIPS_TLS_DTPMOD32: u32 = 38;
+/// Module-relative offset 32 bit
+pub const R_MIPS_TLS_DTPREL32: u32 = 39;
+/// Module number 64 bit
+pub const R_MIPS_TLS_DTPMOD64: u32 = 40;
+/// Module-relative offset 64 bit
+pub const R_MIPS_TLS_DTPREL64: u32 = 41;
+/// 16 bit GOT offset for GD
+pub const R_MIPS_TLS_GD: u32 = 42;
+/// 16 bit GOT offset for LDM
+pub const R_MIPS_TLS_LDM: u32 = 43;
+/// Module-relative offset, high 16 bits
+pub const R_MIPS_TLS_DTPREL_HI16: u32 = 44;
+/// Module-relative offset, low 16 bits
+pub const R_MIPS_TLS_DTPREL_LO16: u32 = 45;
+/// 16 bit GOT offset for IE
+pub const R_MIPS_TLS_GOTTPREL: u32 = 46;
+/// TP-relative offset, 32 bit
+pub const R_MIPS_TLS_TPREL32: u32 = 47;
+/// TP-relative offset, 64 bit
+pub const R_MIPS_TLS_TPREL64: u32 = 48;
+/// TP-relative offset, high 16 bits
+pub const R_MIPS_TLS_TPREL_HI16: u32 = 49;
+/// TP-relative offset, low 16 bits
+pub const R_MIPS_TLS_TPREL_LO16: u32 = 50;
+pub const R_MIPS_GLOB_DAT: u32 = 51;
+pub const R_MIPS_COPY: u32 = 126;
+pub const R_MIPS_JUMP_SLOT: u32 = 127;
+
+// MIPS values for `ProgramHeader32::p_type`.
+
+/// Register usage information.
+pub const PT_MIPS_REGINFO: u32 = 0x7000_0000;
+/// Runtime procedure table.
+pub const PT_MIPS_RTPROC: u32 = 0x7000_0001;
+pub const PT_MIPS_OPTIONS: u32 = 0x7000_0002;
+/// FP mode requirement.
+pub const PT_MIPS_ABIFLAGS: u32 = 0x7000_0003;
+
+// MIPS values for `ProgramHeader32::p_flags`.
+
+pub const PF_MIPS_LOCAL: u32 = 0x1000_0000;
+
+// MIPS values for `Dyn32::d_tag`.
+
+/// Runtime linker interface version
+pub const DT_MIPS_RLD_VERSION: u32 = 0x7000_0001;
+/// Timestamp
+pub const DT_MIPS_TIME_STAMP: u32 = 0x7000_0002;
+/// Checksum
+pub const DT_MIPS_ICHECKSUM: u32 = 0x7000_0003;
+/// Version string (string tbl index)
+pub const DT_MIPS_IVERSION: u32 = 0x7000_0004;
+/// Flags
+pub const DT_MIPS_FLAGS: u32 = 0x7000_0005;
+/// Base address
+pub const DT_MIPS_BASE_ADDRESS: u32 = 0x7000_0006;
+pub const DT_MIPS_MSYM: u32 = 0x7000_0007;
+/// Address of CONFLICT section
+pub const DT_MIPS_CONFLICT: u32 = 0x7000_0008;
+/// Address of LIBLIST section
+pub const DT_MIPS_LIBLIST: u32 = 0x7000_0009;
+/// Number of local GOT entries
+pub const DT_MIPS_LOCAL_GOTNO: u32 = 0x7000_000a;
+/// Number of CONFLICT entries
+pub const DT_MIPS_CONFLICTNO: u32 = 0x7000_000b;
+/// Number of LIBLIST entries
+pub const DT_MIPS_LIBLISTNO: u32 = 0x7000_0010;
+/// Number of DYNSYM entries
+pub const DT_MIPS_SYMTABNO: u32 = 0x7000_0011;
+/// First external DYNSYM
+pub const DT_MIPS_UNREFEXTNO: u32 = 0x7000_0012;
+/// First GOT entry in DYNSYM
+pub const DT_MIPS_GOTSYM: u32 = 0x7000_0013;
+/// Number of GOT page table entries
+pub const DT_MIPS_HIPAGENO: u32 = 0x7000_0014;
+/// Address of run time loader map.
+pub const DT_MIPS_RLD_MAP: u32 = 0x7000_0016;
+/// Delta C++ class definition.
+pub const DT_MIPS_DELTA_CLASS: u32 = 0x7000_0017;
+/// Number of entries in DT_MIPS_DELTA_CLASS.
+pub const DT_MIPS_DELTA_CLASS_NO: u32 = 0x7000_0018;
+/// Delta C++ class instances.
+pub const DT_MIPS_DELTA_INSTANCE: u32 = 0x7000_0019;
+/// Number of entries in DT_MIPS_DELTA_INSTANCE.
+pub const DT_MIPS_DELTA_INSTANCE_NO: u32 = 0x7000_001a;
+/// Delta relocations.
+pub const DT_MIPS_DELTA_RELOC: u32 = 0x7000_001b;
+/// Number of entries in DT_MIPS_DELTA_RELOC.
+pub const DT_MIPS_DELTA_RELOC_NO: u32 = 0x7000_001c;
+/// Delta symbols that Delta relocations refer to.
+pub const DT_MIPS_DELTA_SYM: u32 = 0x7000_001d;
+/// Number of entries in DT_MIPS_DELTA_SYM.
+pub const DT_MIPS_DELTA_SYM_NO: u32 = 0x7000_001e;
+/// Delta symbols that hold the class declaration.
+pub const DT_MIPS_DELTA_CLASSSYM: u32 = 0x7000_0020;
+/// Number of entries in DT_MIPS_DELTA_CLASSSYM.
+pub const DT_MIPS_DELTA_CLASSSYM_NO: u32 = 0x7000_0021;
+/// Flags indicating for C++ flavor.
+pub const DT_MIPS_CXX_FLAGS: u32 = 0x7000_0022;
+pub const DT_MIPS_PIXIE_INIT: u32 = 0x7000_0023;
+pub const DT_MIPS_SYMBOL_LIB: u32 = 0x7000_0024;
+pub const DT_MIPS_LOCALPAGE_GOTIDX: u32 = 0x7000_0025;
+pub const DT_MIPS_LOCAL_GOTIDX: u32 = 0x7000_0026;
+pub const DT_MIPS_HIDDEN_GOTIDX: u32 = 0x7000_0027;
+pub const DT_MIPS_PROTECTED_GOTIDX: u32 = 0x7000_0028;
+/// Address of .options.
+pub const DT_MIPS_OPTIONS: u32 = 0x7000_0029;
+/// Address of .interface.
+pub const DT_MIPS_INTERFACE: u32 = 0x7000_002a;
+pub const DT_MIPS_DYNSTR_ALIGN: u32 = 0x7000_002b;
+/// Size of the .interface section.
+pub const DT_MIPS_INTERFACE_SIZE: u32 = 0x7000_002c;
+/// Address of rld_text_rsolve function stored in GOT.
+pub const DT_MIPS_RLD_TEXT_RESOLVE_ADDR: u32 = 0x7000_002d;
+/// Default suffix of dso to be added by rld on dlopen() calls.
+pub const DT_MIPS_PERF_SUFFIX: u32 = 0x7000_002e;
+/// (O32)Size of compact rel section.
+pub const DT_MIPS_COMPACT_SIZE: u32 = 0x7000_002f;
+/// GP value for aux GOTs.
+pub const DT_MIPS_GP_VALUE: u32 = 0x7000_0030;
+/// Address of aux .dynamic.
+pub const DT_MIPS_AUX_DYNAMIC: u32 = 0x7000_0031;
+/// The address of .got.plt in an executable using the new non-PIC ABI.
+pub const DT_MIPS_PLTGOT: u32 = 0x7000_0032;
+/// The base of the PLT in an executable using the new non-PIC ABI if that PLT is writable. For a non-writable PLT, this is omitted or has a zero value.
+pub const DT_MIPS_RWPLT: u32 = 0x7000_0034;
+/// An alternative description of the classic MIPS RLD_MAP that is usable in a PIE as it stores a relative offset from the address of the tag rather than an absolute address.
+pub const DT_MIPS_RLD_MAP_REL: u32 = 0x7000_0035;
+
+// Values for `DT_MIPS_FLAGS` `Dyn32` entry.
+
+/// No flags
+pub const RHF_NONE: u32 = 0;
+/// Use quickstart
+pub const RHF_QUICKSTART: u32 = 1 << 0;
+/// Hash size not power of 2
+pub const RHF_NOTPOT: u32 = 1 << 1;
+/// Ignore LD_LIBRARY_PATH
+pub const RHF_NO_LIBRARY_REPLACEMENT: u32 = 1 << 2;
+pub const RHF_NO_MOVE: u32 = 1 << 3;
+pub const RHF_SGI_ONLY: u32 = 1 << 4;
+pub const RHF_GUARANTEE_INIT: u32 = 1 << 5;
+pub const RHF_DELTA_C_PLUS_PLUS: u32 = 1 << 6;
+pub const RHF_GUARANTEE_START_INIT: u32 = 1 << 7;
+pub const RHF_PIXIE: u32 = 1 << 8;
+pub const RHF_DEFAULT_DELAY_LOAD: u32 = 1 << 9;
+pub const RHF_REQUICKSTART: u32 = 1 << 10;
+pub const RHF_REQUICKSTARTED: u32 = 1 << 11;
+pub const RHF_CORD: u32 = 1 << 12;
+pub const RHF_NO_UNRES_UNDEF: u32 = 1 << 13;
+pub const RHF_RLD_ORDER_SAFE: u32 = 1 << 14;
+
+// Entries found in sections of type `SHT_MIPS_LIBLIST`.
+
+// TODO: Elf32_Lib, Elf64_Lib
+
+// Values for `Lib*::l_flags`.
+
+pub const LL_NONE: u32 = 0;
+/// Require exact match
+pub const LL_EXACT_MATCH: u32 = 1 << 0;
+/// Ignore interface version
+pub const LL_IGNORE_INT_VER: u32 = 1 << 1;
+pub const LL_REQUIRE_MINOR: u32 = 1 << 2;
+pub const LL_EXPORTS: u32 = 1 << 3;
+pub const LL_DELAY_LOAD: u32 = 1 << 4;
+pub const LL_DELTA: u32 = 1 << 5;
+
+// TODO: MIPS ABI flags
+
+// PA-RISC specific definitions.
+
+// PA-RISC values for `FileHeader32::e_flags`.
+
+/// Trap nil pointer dereference.
+pub const EF_PARISC_TRAPNIL: u32 = 0x0001_0000;
+/// Program uses arch. extensions.
+pub const EF_PARISC_EXT: u32 = 0x0002_0000;
+/// Program expects little endian.
+pub const EF_PARISC_LSB: u32 = 0x0004_0000;
+/// Program expects wide mode.
+pub const EF_PARISC_WIDE: u32 = 0x0008_0000;
+/// No kernel assisted branch prediction.
+pub const EF_PARISC_NO_KABP: u32 = 0x0010_0000;
+/// Allow lazy swapping.
+pub const EF_PARISC_LAZYSWAP: u32 = 0x0040_0000;
+/// Architecture version.
+pub const EF_PARISC_ARCH: u32 = 0x0000_ffff;
+
+// Values for `EF_PARISC_ARCH'.
+
+/// PA-RISC 1.0 big-endian.
+pub const EFA_PARISC_1_0: u32 = 0x020b;
+/// PA-RISC 1.1 big-endian.
+pub const EFA_PARISC_1_1: u32 = 0x0210;
+/// PA-RISC 2.0 big-endian.
+pub const EFA_PARISC_2_0: u32 = 0x0214;
+
+// PA-RISC values for `Sym*::st_shndx`.
+
+/// Section for tentatively declared symbols in ANSI C.
+pub const SHN_PARISC_ANSI_COMMON: u16 = 0xff00;
+/// Common blocks in huge model.
+pub const SHN_PARISC_HUGE_COMMON: u16 = 0xff01;
+
+// PA-RISC values for `SectionHeader32::sh_type`.
+
+/// Contains product specific ext.
+pub const SHT_PARISC_EXT: u32 = 0x7000_0000;
+/// Unwind information.
+pub const SHT_PARISC_UNWIND: u32 = 0x7000_0001;
+/// Debug info for optimized code.
+pub const SHT_PARISC_DOC: u32 = 0x7000_0002;
+
+// PA-RISC values for `SectionHeader32::sh_flags`.
+
+/// Section with short addressing.
+pub const SHF_PARISC_SHORT: u32 = 0x2000_0000;
+/// Section far from gp.
+pub const SHF_PARISC_HUGE: u32 = 0x4000_0000;
+/// Static branch prediction code.
+pub const SHF_PARISC_SBP: u32 = 0x8000_0000;
+
+// PA-RISC values for `st_type` component of `Sym32::st_info`.
+
+/// Millicode function entry point.
+pub const STT_PARISC_MILLICODE: u8 = 13;
+
+pub const STT_HP_OPAQUE: u8 = STT_LOOS + 0x1;
+pub const STT_HP_STUB: u8 = STT_LOOS + 0x2;
+
+// PA-RISC values for `Rel*::r_type`.
+
+/// No reloc.
+pub const R_PARISC_NONE: u32 = 0;
+/// Direct 32-bit reference.
+pub const R_PARISC_DIR32: u32 = 1;
+/// Left 21 bits of eff. address.
+pub const R_PARISC_DIR21L: u32 = 2;
+/// Right 17 bits of eff. address.
+pub const R_PARISC_DIR17R: u32 = 3;
+/// 17 bits of eff. address.
+pub const R_PARISC_DIR17F: u32 = 4;
+/// Right 14 bits of eff. address.
+pub const R_PARISC_DIR14R: u32 = 6;
+/// 32-bit rel. address.
+pub const R_PARISC_PCREL32: u32 = 9;
+/// Left 21 bits of rel. address.
+pub const R_PARISC_PCREL21L: u32 = 10;
+/// Right 17 bits of rel. address.
+pub const R_PARISC_PCREL17R: u32 = 11;
+/// 17 bits of rel. address.
+pub const R_PARISC_PCREL17F: u32 = 12;
+/// Right 14 bits of rel. address.
+pub const R_PARISC_PCREL14R: u32 = 14;
+/// Left 21 bits of rel. address.
+pub const R_PARISC_DPREL21L: u32 = 18;
+/// Right 14 bits of rel. address.
+pub const R_PARISC_DPREL14R: u32 = 22;
+/// GP-relative, left 21 bits.
+pub const R_PARISC_GPREL21L: u32 = 26;
+/// GP-relative, right 14 bits.
+pub const R_PARISC_GPREL14R: u32 = 30;
+/// LT-relative, left 21 bits.
+pub const R_PARISC_LTOFF21L: u32 = 34;
+/// LT-relative, right 14 bits.
+pub const R_PARISC_LTOFF14R: u32 = 38;
+/// 32 bits section rel. address.
+pub const R_PARISC_SECREL32: u32 = 41;
+/// No relocation, set segment base.
+pub const R_PARISC_SEGBASE: u32 = 48;
+/// 32 bits segment rel. address.
+pub const R_PARISC_SEGREL32: u32 = 49;
+/// PLT rel. address, left 21 bits.
+pub const R_PARISC_PLTOFF21L: u32 = 50;
+/// PLT rel. address, right 14 bits.
+pub const R_PARISC_PLTOFF14R: u32 = 54;
+/// 32 bits LT-rel. function pointer.
+pub const R_PARISC_LTOFF_FPTR32: u32 = 57;
+/// LT-rel. fct ptr, left 21 bits.
+pub const R_PARISC_LTOFF_FPTR21L: u32 = 58;
+/// LT-rel. fct ptr, right 14 bits.
+pub const R_PARISC_LTOFF_FPTR14R: u32 = 62;
+/// 64 bits function address.
+pub const R_PARISC_FPTR64: u32 = 64;
+/// 32 bits function address.
+pub const R_PARISC_PLABEL32: u32 = 65;
+/// Left 21 bits of fdesc address.
+pub const R_PARISC_PLABEL21L: u32 = 66;
+/// Right 14 bits of fdesc address.
+pub const R_PARISC_PLABEL14R: u32 = 70;
+/// 64 bits PC-rel. address.
+pub const R_PARISC_PCREL64: u32 = 72;
+/// 22 bits PC-rel. address.
+pub const R_PARISC_PCREL22F: u32 = 74;
+/// PC-rel. address, right 14 bits.
+pub const R_PARISC_PCREL14WR: u32 = 75;
+/// PC rel. address, right 14 bits.
+pub const R_PARISC_PCREL14DR: u32 = 76;
+/// 16 bits PC-rel. address.
+pub const R_PARISC_PCREL16F: u32 = 77;
+/// 16 bits PC-rel. address.
+pub const R_PARISC_PCREL16WF: u32 = 78;
+/// 16 bits PC-rel. address.
+pub const R_PARISC_PCREL16DF: u32 = 79;
+/// 64 bits of eff. address.
+pub const R_PARISC_DIR64: u32 = 80;
+/// 14 bits of eff. address.
+pub const R_PARISC_DIR14WR: u32 = 83;
+/// 14 bits of eff. address.
+pub const R_PARISC_DIR14DR: u32 = 84;
+/// 16 bits of eff. address.
+pub const R_PARISC_DIR16F: u32 = 85;
+/// 16 bits of eff. address.
+pub const R_PARISC_DIR16WF: u32 = 86;
+/// 16 bits of eff. address.
+pub const R_PARISC_DIR16DF: u32 = 87;
+/// 64 bits of GP-rel. address.
+pub const R_PARISC_GPREL64: u32 = 88;
+/// GP-rel. address, right 14 bits.
+pub const R_PARISC_GPREL14WR: u32 = 91;
+/// GP-rel. address, right 14 bits.
+pub const R_PARISC_GPREL14DR: u32 = 92;
+/// 16 bits GP-rel. address.
+pub const R_PARISC_GPREL16F: u32 = 93;
+/// 16 bits GP-rel. address.
+pub const R_PARISC_GPREL16WF: u32 = 94;
+/// 16 bits GP-rel. address.
+pub const R_PARISC_GPREL16DF: u32 = 95;
+/// 64 bits LT-rel. address.
+pub const R_PARISC_LTOFF64: u32 = 96;
+/// LT-rel. address, right 14 bits.
+pub const R_PARISC_LTOFF14WR: u32 = 99;
+/// LT-rel. address, right 14 bits.
+pub const R_PARISC_LTOFF14DR: u32 = 100;
+/// 16 bits LT-rel. address.
+pub const R_PARISC_LTOFF16F: u32 = 101;
+/// 16 bits LT-rel. address.
+pub const R_PARISC_LTOFF16WF: u32 = 102;
+/// 16 bits LT-rel. address.
+pub const R_PARISC_LTOFF16DF: u32 = 103;
+/// 64 bits section rel. address.
+pub const R_PARISC_SECREL64: u32 = 104;
+/// 64 bits segment rel. address.
+pub const R_PARISC_SEGREL64: u32 = 112;
+/// PLT-rel. address, right 14 bits.
+pub const R_PARISC_PLTOFF14WR: u32 = 115;
+/// PLT-rel. address, right 14 bits.
+pub const R_PARISC_PLTOFF14DR: u32 = 116;
+/// 16 bits LT-rel. address.
+pub const R_PARISC_PLTOFF16F: u32 = 117;
+/// 16 bits PLT-rel. address.
+pub const R_PARISC_PLTOFF16WF: u32 = 118;
+/// 16 bits PLT-rel. address.
+pub const R_PARISC_PLTOFF16DF: u32 = 119;
+/// 64 bits LT-rel. function ptr.
+pub const R_PARISC_LTOFF_FPTR64: u32 = 120;
+/// LT-rel. fct. ptr., right 14 bits.
+pub const R_PARISC_LTOFF_FPTR14WR: u32 = 123;
+/// LT-rel. fct. ptr., right 14 bits.
+pub const R_PARISC_LTOFF_FPTR14DR: u32 = 124;
+/// 16 bits LT-rel. function ptr.
+pub const R_PARISC_LTOFF_FPTR16F: u32 = 125;
+/// 16 bits LT-rel. function ptr.
+pub const R_PARISC_LTOFF_FPTR16WF: u32 = 126;
+/// 16 bits LT-rel. function ptr.
+pub const R_PARISC_LTOFF_FPTR16DF: u32 = 127;
+pub const R_PARISC_LORESERVE: u32 = 128;
+/// Copy relocation.
+pub const R_PARISC_COPY: u32 = 128;
+/// Dynamic reloc, imported PLT
+pub const R_PARISC_IPLT: u32 = 129;
+/// Dynamic reloc, exported PLT
+pub const R_PARISC_EPLT: u32 = 130;
+/// 32 bits TP-rel. address.
+pub const R_PARISC_TPREL32: u32 = 153;
+/// TP-rel. address, left 21 bits.
+pub const R_PARISC_TPREL21L: u32 = 154;
+/// TP-rel. address, right 14 bits.
+pub const R_PARISC_TPREL14R: u32 = 158;
+/// LT-TP-rel. address, left 21 bits.
+pub const R_PARISC_LTOFF_TP21L: u32 = 162;
+/// LT-TP-rel. address, right 14 bits.
+pub const R_PARISC_LTOFF_TP14R: u32 = 166;
+/// 14 bits LT-TP-rel. address.
+pub const R_PARISC_LTOFF_TP14F: u32 = 167;
+/// 64 bits TP-rel. address.
+pub const R_PARISC_TPREL64: u32 = 216;
+/// TP-rel. address, right 14 bits.
+pub const R_PARISC_TPREL14WR: u32 = 219;
+/// TP-rel. address, right 14 bits.
+pub const R_PARISC_TPREL14DR: u32 = 220;
+/// 16 bits TP-rel. address.
+pub const R_PARISC_TPREL16F: u32 = 221;
+/// 16 bits TP-rel. address.
+pub const R_PARISC_TPREL16WF: u32 = 222;
+/// 16 bits TP-rel. address.
+pub const R_PARISC_TPREL16DF: u32 = 223;
+/// 64 bits LT-TP-rel. address.
+pub const R_PARISC_LTOFF_TP64: u32 = 224;
+/// LT-TP-rel. address, right 14 bits.
+pub const R_PARISC_LTOFF_TP14WR: u32 = 227;
+/// LT-TP-rel. address, right 14 bits.
+pub const R_PARISC_LTOFF_TP14DR: u32 = 228;
+/// 16 bits LT-TP-rel. address.
+pub const R_PARISC_LTOFF_TP16F: u32 = 229;
+/// 16 bits LT-TP-rel. address.
+pub const R_PARISC_LTOFF_TP16WF: u32 = 230;
+/// 16 bits LT-TP-rel. address.
+pub const R_PARISC_LTOFF_TP16DF: u32 = 231;
+pub const R_PARISC_GNU_VTENTRY: u32 = 232;
+pub const R_PARISC_GNU_VTINHERIT: u32 = 233;
+/// GD 21-bit left.
+pub const R_PARISC_TLS_GD21L: u32 = 234;
+/// GD 14-bit right.
+pub const R_PARISC_TLS_GD14R: u32 = 235;
+/// GD call to __t_g_a.
+pub const R_PARISC_TLS_GDCALL: u32 = 236;
+/// LD module 21-bit left.
+pub const R_PARISC_TLS_LDM21L: u32 = 237;
+/// LD module 14-bit right.
+pub const R_PARISC_TLS_LDM14R: u32 = 238;
+/// LD module call to __t_g_a.
+pub const R_PARISC_TLS_LDMCALL: u32 = 239;
+/// LD offset 21-bit left.
+pub const R_PARISC_TLS_LDO21L: u32 = 240;
+/// LD offset 14-bit right.
+pub const R_PARISC_TLS_LDO14R: u32 = 241;
+/// DTP module 32-bit.
+pub const R_PARISC_TLS_DTPMOD32: u32 = 242;
+/// DTP module 64-bit.
+pub const R_PARISC_TLS_DTPMOD64: u32 = 243;
+/// DTP offset 32-bit.
+pub const R_PARISC_TLS_DTPOFF32: u32 = 244;
+/// DTP offset 32-bit.
+pub const R_PARISC_TLS_DTPOFF64: u32 = 245;
+pub const R_PARISC_TLS_LE21L: u32 = R_PARISC_TPREL21L;
+pub const R_PARISC_TLS_LE14R: u32 = R_PARISC_TPREL14R;
+pub const R_PARISC_TLS_IE21L: u32 = R_PARISC_LTOFF_TP21L;
+pub const R_PARISC_TLS_IE14R: u32 = R_PARISC_LTOFF_TP14R;
+pub const R_PARISC_TLS_TPREL32: u32 = R_PARISC_TPREL32;
+pub const R_PARISC_TLS_TPREL64: u32 = R_PARISC_TPREL64;
+pub const R_PARISC_HIRESERVE: u32 = 255;
+
+// PA-RISC values for `ProgramHeader*::p_type`.
+
+pub const PT_HP_TLS: u32 = PT_LOOS + 0x0;
+pub const PT_HP_CORE_NONE: u32 = PT_LOOS + 0x1;
+pub const PT_HP_CORE_VERSION: u32 = PT_LOOS + 0x2;
+pub const PT_HP_CORE_KERNEL: u32 = PT_LOOS + 0x3;
+pub const PT_HP_CORE_COMM: u32 = PT_LOOS + 0x4;
+pub const PT_HP_CORE_PROC: u32 = PT_LOOS + 0x5;
+pub const PT_HP_CORE_LOADABLE: u32 = PT_LOOS + 0x6;
+pub const PT_HP_CORE_STACK: u32 = PT_LOOS + 0x7;
+pub const PT_HP_CORE_SHM: u32 = PT_LOOS + 0x8;
+pub const PT_HP_CORE_MMF: u32 = PT_LOOS + 0x9;
+pub const PT_HP_PARALLEL: u32 = PT_LOOS + 0x10;
+pub const PT_HP_FASTBIND: u32 = PT_LOOS + 0x11;
+pub const PT_HP_OPT_ANNOT: u32 = PT_LOOS + 0x12;
+pub const PT_HP_HSL_ANNOT: u32 = PT_LOOS + 0x13;
+pub const PT_HP_STACK: u32 = PT_LOOS + 0x14;
+
+pub const PT_PARISC_ARCHEXT: u32 = 0x7000_0000;
+pub const PT_PARISC_UNWIND: u32 = 0x7000_0001;
+
+// PA-RISC values for `ProgramHeader*::p_flags`.
+
+pub const PF_PARISC_SBP: u32 = 0x0800_0000;
+
+pub const PF_HP_PAGE_SIZE: u32 = 0x0010_0000;
+pub const PF_HP_FAR_SHARED: u32 = 0x0020_0000;
+pub const PF_HP_NEAR_SHARED: u32 = 0x0040_0000;
+pub const PF_HP_CODE: u32 = 0x0100_0000;
+pub const PF_HP_MODIFY: u32 = 0x0200_0000;
+pub const PF_HP_LAZYSWAP: u32 = 0x0400_0000;
+pub const PF_HP_SBP: u32 = 0x0800_0000;
+
+// Alpha specific definitions.
+
+// Alpha values for `FileHeader64::e_flags`.
+
+/// All addresses must be < 2GB.
+pub const EF_ALPHA_32BIT: u32 = 1;
+/// Relocations for relaxing exist.
+pub const EF_ALPHA_CANRELAX: u32 = 2;
+
+// Alpha values for `SectionHeader64::sh_type`.
+
+// These two are primerily concerned with ECOFF debugging info.
+pub const SHT_ALPHA_DEBUG: u32 = 0x7000_0001;
+pub const SHT_ALPHA_REGINFO: u32 = 0x7000_0002;
+
+// Alpha values for `SectionHeader64::sh_flags`.
+
+pub const SHF_ALPHA_GPREL: u32 = 0x1000_0000;
+
+// Alpha values for `Sym64::st_other`.
+/// No PV required.
+pub const STO_ALPHA_NOPV: u8 = 0x80;
+/// PV only used for initial ldgp.
+pub const STO_ALPHA_STD_GPLOAD: u8 = 0x88;
+
+// Alpha values for `Rel64::r_type`.
+
+/// No reloc
+pub const R_ALPHA_NONE: u32 = 0;
+/// Direct 32 bit
+pub const R_ALPHA_REFLONG: u32 = 1;
+/// Direct 64 bit
+pub const R_ALPHA_REFQUAD: u32 = 2;
+/// GP relative 32 bit
+pub const R_ALPHA_GPREL32: u32 = 3;
+/// GP relative 16 bit w/optimization
+pub const R_ALPHA_LITERAL: u32 = 4;
+/// Optimization hint for LITERAL
+pub const R_ALPHA_LITUSE: u32 = 5;
+/// Add displacement to GP
+pub const R_ALPHA_GPDISP: u32 = 6;
+/// PC+4 relative 23 bit shifted
+pub const R_ALPHA_BRADDR: u32 = 7;
+/// PC+4 relative 16 bit shifted
+pub const R_ALPHA_HINT: u32 = 8;
+/// PC relative 16 bit
+pub const R_ALPHA_SREL16: u32 = 9;
+/// PC relative 32 bit
+pub const R_ALPHA_SREL32: u32 = 10;
+/// PC relative 64 bit
+pub const R_ALPHA_SREL64: u32 = 11;
+/// GP relative 32 bit, high 16 bits
+pub const R_ALPHA_GPRELHIGH: u32 = 17;
+/// GP relative 32 bit, low 16 bits
+pub const R_ALPHA_GPRELLOW: u32 = 18;
+/// GP relative 16 bit
+pub const R_ALPHA_GPREL16: u32 = 19;
+/// Copy symbol at runtime
+pub const R_ALPHA_COPY: u32 = 24;
+/// Create GOT entry
+pub const R_ALPHA_GLOB_DAT: u32 = 25;
+/// Create PLT entry
+pub const R_ALPHA_JMP_SLOT: u32 = 26;
+/// Adjust by program base
+pub const R_ALPHA_RELATIVE: u32 = 27;
+pub const R_ALPHA_TLS_GD_HI: u32 = 28;
+pub const R_ALPHA_TLSGD: u32 = 29;
+pub const R_ALPHA_TLS_LDM: u32 = 30;
+pub const R_ALPHA_DTPMOD64: u32 = 31;
+pub const R_ALPHA_GOTDTPREL: u32 = 32;
+pub const R_ALPHA_DTPREL64: u32 = 33;
+pub const R_ALPHA_DTPRELHI: u32 = 34;
+pub const R_ALPHA_DTPRELLO: u32 = 35;
+pub const R_ALPHA_DTPREL16: u32 = 36;
+pub const R_ALPHA_GOTTPREL: u32 = 37;
+pub const R_ALPHA_TPREL64: u32 = 38;
+pub const R_ALPHA_TPRELHI: u32 = 39;
+pub const R_ALPHA_TPRELLO: u32 = 40;
+pub const R_ALPHA_TPREL16: u32 = 41;
+
+// Magic values of the `R_ALPHA_LITUSE` relocation addend.
+pub const LITUSE_ALPHA_ADDR: u32 = 0;
+pub const LITUSE_ALPHA_BASE: u32 = 1;
+pub const LITUSE_ALPHA_BYTOFF: u32 = 2;
+pub const LITUSE_ALPHA_JSR: u32 = 3;
+pub const LITUSE_ALPHA_TLS_GD: u32 = 4;
+pub const LITUSE_ALPHA_TLS_LDM: u32 = 5;
+
+// Alpha values for `Dyn64::d_tag`.
+pub const DT_ALPHA_PLTRO: u32 = DT_LOPROC + 0;
+
+// PowerPC specific declarations.
+
+// PowerPC values for `FileHeader*::e_flags`.
+/// PowerPC embedded flag
+pub const EF_PPC_EMB: u32 = 0x8000_0000;
+
+// Cygnus local bits below .
+/// PowerPC -mrelocatable flag
+pub const EF_PPC_RELOCATABLE: u32 = 0x0001_0000;
+/// PowerPC -mrelocatable-lib flag
+pub const EF_PPC_RELOCATABLE_LIB: u32 = 0x0000_8000;
+
+// PowerPC values for `Rel*::r_type` defined by the ABIs.
+pub const R_PPC_NONE: u32 = 0;
+/// 32bit absolute address
+pub const R_PPC_ADDR32: u32 = 1;
+/// 26bit address, 2 bits ignored.
+pub const R_PPC_ADDR24: u32 = 2;
+/// 16bit absolute address
+pub const R_PPC_ADDR16: u32 = 3;
+/// lower 16bit of absolute address
+pub const R_PPC_ADDR16_LO: u32 = 4;
+/// high 16bit of absolute address
+pub const R_PPC_ADDR16_HI: u32 = 5;
+/// adjusted high 16bit
+pub const R_PPC_ADDR16_HA: u32 = 6;
+/// 16bit address, 2 bits ignored
+pub const R_PPC_ADDR14: u32 = 7;
+pub const R_PPC_ADDR14_BRTAKEN: u32 = 8;
+pub const R_PPC_ADDR14_BRNTAKEN: u32 = 9;
+/// PC relative 26 bit
+pub const R_PPC_REL24: u32 = 10;
+/// PC relative 16 bit
+pub const R_PPC_REL14: u32 = 11;
+pub const R_PPC_REL14_BRTAKEN: u32 = 12;
+pub const R_PPC_REL14_BRNTAKEN: u32 = 13;
+pub const R_PPC_GOT16: u32 = 14;
+pub const R_PPC_GOT16_LO: u32 = 15;
+pub const R_PPC_GOT16_HI: u32 = 16;
+pub const R_PPC_GOT16_HA: u32 = 17;
+pub const R_PPC_PLTREL24: u32 = 18;
+pub const R_PPC_COPY: u32 = 19;
+pub const R_PPC_GLOB_DAT: u32 = 20;
+pub const R_PPC_JMP_SLOT: u32 = 21;
+pub const R_PPC_RELATIVE: u32 = 22;
+pub const R_PPC_LOCAL24PC: u32 = 23;
+pub const R_PPC_UADDR32: u32 = 24;
+pub const R_PPC_UADDR16: u32 = 25;
+pub const R_PPC_REL32: u32 = 26;
+pub const R_PPC_PLT32: u32 = 27;
+pub const R_PPC_PLTREL32: u32 = 28;
+pub const R_PPC_PLT16_LO: u32 = 29;
+pub const R_PPC_PLT16_HI: u32 = 30;
+pub const R_PPC_PLT16_HA: u32 = 31;
+pub const R_PPC_SDAREL16: u32 = 32;
+pub const R_PPC_SECTOFF: u32 = 33;
+pub const R_PPC_SECTOFF_LO: u32 = 34;
+pub const R_PPC_SECTOFF_HI: u32 = 35;
+pub const R_PPC_SECTOFF_HA: u32 = 36;
+
+// PowerPC values for `Rel*::r_type` defined for the TLS access ABI.
+/// none (sym+add)@tls
+pub const R_PPC_TLS: u32 = 67;
+/// word32 (sym+add)@dtpmod
+pub const R_PPC_DTPMOD32: u32 = 68;
+/// half16* (sym+add)@tprel
+pub const R_PPC_TPREL16: u32 = 69;
+/// half16 (sym+add)@tprel@l
+pub const R_PPC_TPREL16_LO: u32 = 70;
+/// half16 (sym+add)@tprel@h
+pub const R_PPC_TPREL16_HI: u32 = 71;
+/// half16 (sym+add)@tprel@ha
+pub const R_PPC_TPREL16_HA: u32 = 72;
+/// word32 (sym+add)@tprel
+pub const R_PPC_TPREL32: u32 = 73;
+/// half16*(sym+add)@dtprel
+pub const R_PPC_DTPREL16: u32 = 74;
+/// half16 (sym+add)@dtprel@l
+pub const R_PPC_DTPREL16_LO: u32 = 75;
+/// half16 (sym+add)@dtprel@h
+pub const R_PPC_DTPREL16_HI: u32 = 76;
+/// half16 (sym+add)@dtprel@ha
+pub const R_PPC_DTPREL16_HA: u32 = 77;
+/// word32 (sym+add)@dtprel
+pub const R_PPC_DTPREL32: u32 = 78;
+/// half16* (sym+add)@got@tlsgd
+pub const R_PPC_GOT_TLSGD16: u32 = 79;
+/// half16 (sym+add)@got@tlsgd@l
+pub const R_PPC_GOT_TLSGD16_LO: u32 = 80;
+/// half16 (sym+add)@got@tlsgd@h
+pub const R_PPC_GOT_TLSGD16_HI: u32 = 81;
+/// half16 (sym+add)@got@tlsgd@ha
+pub const R_PPC_GOT_TLSGD16_HA: u32 = 82;
+/// half16* (sym+add)@got@tlsld
+pub const R_PPC_GOT_TLSLD16: u32 = 83;
+/// half16 (sym+add)@got@tlsld@l
+pub const R_PPC_GOT_TLSLD16_LO: u32 = 84;
+/// half16 (sym+add)@got@tlsld@h
+pub const R_PPC_GOT_TLSLD16_HI: u32 = 85;
+/// half16 (sym+add)@got@tlsld@ha
+pub const R_PPC_GOT_TLSLD16_HA: u32 = 86;
+/// half16* (sym+add)@got@tprel
+pub const R_PPC_GOT_TPREL16: u32 = 87;
+/// half16 (sym+add)@got@tprel@l
+pub const R_PPC_GOT_TPREL16_LO: u32 = 88;
+/// half16 (sym+add)@got@tprel@h
+pub const R_PPC_GOT_TPREL16_HI: u32 = 89;
+/// half16 (sym+add)@got@tprel@ha
+pub const R_PPC_GOT_TPREL16_HA: u32 = 90;
+/// half16* (sym+add)@got@dtprel
+pub const R_PPC_GOT_DTPREL16: u32 = 91;
+/// half16* (sym+add)@got@dtprel@l
+pub const R_PPC_GOT_DTPREL16_LO: u32 = 92;
+/// half16* (sym+add)@got@dtprel@h
+pub const R_PPC_GOT_DTPREL16_HI: u32 = 93;
+/// half16* (sym+add)@got@dtprel@ha
+pub const R_PPC_GOT_DTPREL16_HA: u32 = 94;
+/// none (sym+add)@tlsgd
+pub const R_PPC_TLSGD: u32 = 95;
+/// none (sym+add)@tlsld
+pub const R_PPC_TLSLD: u32 = 96;
+
+// PowerPC values for `Rel*::r_type` from the Embedded ELF ABI.
+pub const R_PPC_EMB_NADDR32: u32 = 101;
+pub const R_PPC_EMB_NADDR16: u32 = 102;
+pub const R_PPC_EMB_NADDR16_LO: u32 = 103;
+pub const R_PPC_EMB_NADDR16_HI: u32 = 104;
+pub const R_PPC_EMB_NADDR16_HA: u32 = 105;
+pub const R_PPC_EMB_SDAI16: u32 = 106;
+pub const R_PPC_EMB_SDA2I16: u32 = 107;
+pub const R_PPC_EMB_SDA2REL: u32 = 108;
+/// 16 bit offset in SDA
+pub const R_PPC_EMB_SDA21: u32 = 109;
+pub const R_PPC_EMB_MRKREF: u32 = 110;
+pub const R_PPC_EMB_RELSEC16: u32 = 111;
+pub const R_PPC_EMB_RELST_LO: u32 = 112;
+pub const R_PPC_EMB_RELST_HI: u32 = 113;
+pub const R_PPC_EMB_RELST_HA: u32 = 114;
+pub const R_PPC_EMB_BIT_FLD: u32 = 115;
+/// 16 bit relative offset in SDA
+pub const R_PPC_EMB_RELSDA: u32 = 116;
+
+// Diab tool values for `Rel*::r_type`.
+/// like EMB_SDA21, but lower 16 bit
+pub const R_PPC_DIAB_SDA21_LO: u32 = 180;
+/// like EMB_SDA21, but high 16 bit
+pub const R_PPC_DIAB_SDA21_HI: u32 = 181;
+/// like EMB_SDA21, adjusted high 16
+pub const R_PPC_DIAB_SDA21_HA: u32 = 182;
+/// like EMB_RELSDA, but lower 16 bit
+pub const R_PPC_DIAB_RELSDA_LO: u32 = 183;
+/// like EMB_RELSDA, but high 16 bit
+pub const R_PPC_DIAB_RELSDA_HI: u32 = 184;
+/// like EMB_RELSDA, adjusted high 16
+pub const R_PPC_DIAB_RELSDA_HA: u32 = 185;
+
+/// GNU extension to support local ifunc.
+pub const R_PPC_IRELATIVE: u32 = 248;
+
+// GNU relocs used in PIC code sequences.
+/// half16 (sym+add-.)
+pub const R_PPC_REL16: u32 = 249;
+/// half16 (sym+add-.)@l
+pub const R_PPC_REL16_LO: u32 = 250;
+/// half16 (sym+add-.)@h
+pub const R_PPC_REL16_HI: u32 = 251;
+/// half16 (sym+add-.)@ha
+pub const R_PPC_REL16_HA: u32 = 252;
+
+/// This is a phony reloc to handle any old fashioned TOC16 references that may
+/// still be in object files.
+pub const R_PPC_TOC16: u32 = 255;
+
+// PowerPC specific values for `Dyn*::d_tag`.
+pub const DT_PPC_GOT: u32 = DT_LOPROC + 0;
+pub const DT_PPC_OPT: u32 = DT_LOPROC + 1;
+
+// PowerPC specific values for the `DT_PPC_OPT` entry.
+pub const PPC_OPT_TLS: u32 = 1;
+
+// PowerPC64 values for `Rel*::r_type` defined by the ABIs.
+pub const R_PPC64_NONE: u32 = R_PPC_NONE;
+/// 32bit absolute address
+pub const R_PPC64_ADDR32: u32 = R_PPC_ADDR32;
+/// 26bit address, word aligned
+pub const R_PPC64_ADDR24: u32 = R_PPC_ADDR24;
+/// 16bit absolute address
+pub const R_PPC64_ADDR16: u32 = R_PPC_ADDR16;
+/// lower 16bits of address
+pub const R_PPC64_ADDR16_LO: u32 = R_PPC_ADDR16_LO;
+/// high 16bits of address.
+pub const R_PPC64_ADDR16_HI: u32 = R_PPC_ADDR16_HI;
+/// adjusted high 16bits.
+pub const R_PPC64_ADDR16_HA: u32 = R_PPC_ADDR16_HA;
+/// 16bit address, word aligned
+pub const R_PPC64_ADDR14: u32 = R_PPC_ADDR14;
+pub const R_PPC64_ADDR14_BRTAKEN: u32 = R_PPC_ADDR14_BRTAKEN;
+pub const R_PPC64_ADDR14_BRNTAKEN: u32 = R_PPC_ADDR14_BRNTAKEN;
+/// PC-rel. 26 bit, word aligned
+pub const R_PPC64_REL24: u32 = R_PPC_REL24;
+/// PC relative 16 bit
+pub const R_PPC64_REL14: u32 = R_PPC_REL14;
+pub const R_PPC64_REL14_BRTAKEN: u32 = R_PPC_REL14_BRTAKEN;
+pub const R_PPC64_REL14_BRNTAKEN: u32 = R_PPC_REL14_BRNTAKEN;
+pub const R_PPC64_GOT16: u32 = R_PPC_GOT16;
+pub const R_PPC64_GOT16_LO: u32 = R_PPC_GOT16_LO;
+pub const R_PPC64_GOT16_HI: u32 = R_PPC_GOT16_HI;
+pub const R_PPC64_GOT16_HA: u32 = R_PPC_GOT16_HA;
+
+pub const R_PPC64_COPY: u32 = R_PPC_COPY;
+pub const R_PPC64_GLOB_DAT: u32 = R_PPC_GLOB_DAT;
+pub const R_PPC64_JMP_SLOT: u32 = R_PPC_JMP_SLOT;
+pub const R_PPC64_RELATIVE: u32 = R_PPC_RELATIVE;
+
+pub const R_PPC64_UADDR32: u32 = R_PPC_UADDR32;
+pub const R_PPC64_UADDR16: u32 = R_PPC_UADDR16;
+pub const R_PPC64_REL32: u32 = R_PPC_REL32;
+pub const R_PPC64_PLT32: u32 = R_PPC_PLT32;
+pub const R_PPC64_PLTREL32: u32 = R_PPC_PLTREL32;
+pub const R_PPC64_PLT16_LO: u32 = R_PPC_PLT16_LO;
+pub const R_PPC64_PLT16_HI: u32 = R_PPC_PLT16_HI;
+pub const R_PPC64_PLT16_HA: u32 = R_PPC_PLT16_HA;
+
+pub const R_PPC64_SECTOFF: u32 = R_PPC_SECTOFF;
+pub const R_PPC64_SECTOFF_LO: u32 = R_PPC_SECTOFF_LO;
+pub const R_PPC64_SECTOFF_HI: u32 = R_PPC_SECTOFF_HI;
+pub const R_PPC64_SECTOFF_HA: u32 = R_PPC_SECTOFF_HA;
+/// word30 (S + A - P) >> 2
+pub const R_PPC64_ADDR30: u32 = 37;
+/// doubleword64 S + A
+pub const R_PPC64_ADDR64: u32 = 38;
+/// half16 #higher(S + A)
+pub const R_PPC64_ADDR16_HIGHER: u32 = 39;
+/// half16 #highera(S + A)
+pub const R_PPC64_ADDR16_HIGHERA: u32 = 40;
+/// half16 #highest(S + A)
+pub const R_PPC64_ADDR16_HIGHEST: u32 = 41;
+/// half16 #highesta(S + A)
+pub const R_PPC64_ADDR16_HIGHESTA: u32 = 42;
+/// doubleword64 S + A
+pub const R_PPC64_UADDR64: u32 = 43;
+/// doubleword64 S + A - P
+pub const R_PPC64_REL64: u32 = 44;
+/// doubleword64 L + A
+pub const R_PPC64_PLT64: u32 = 45;
+/// doubleword64 L + A - P
+pub const R_PPC64_PLTREL64: u32 = 46;
+/// half16* S + A - .TOC
+pub const R_PPC64_TOC16: u32 = 47;
+/// half16 #lo(S + A - .TOC.)
+pub const R_PPC64_TOC16_LO: u32 = 48;
+/// half16 #hi(S + A - .TOC.)
+pub const R_PPC64_TOC16_HI: u32 = 49;
+/// half16 #ha(S + A - .TOC.)
+pub const R_PPC64_TOC16_HA: u32 = 50;
+/// doubleword64 .TOC
+pub const R_PPC64_TOC: u32 = 51;
+/// half16* M + A
+pub const R_PPC64_PLTGOT16: u32 = 52;
+/// half16 #lo(M + A)
+pub const R_PPC64_PLTGOT16_LO: u32 = 53;
+/// half16 #hi(M + A)
+pub const R_PPC64_PLTGOT16_HI: u32 = 54;
+/// half16 #ha(M + A)
+pub const R_PPC64_PLTGOT16_HA: u32 = 55;
+
+/// half16ds* (S + A) >> 2
+pub const R_PPC64_ADDR16_DS: u32 = 56;
+/// half16ds #lo(S + A) >> 2
+pub const R_PPC64_ADDR16_LO_DS: u32 = 57;
+/// half16ds* (G + A) >> 2
+pub const R_PPC64_GOT16_DS: u32 = 58;
+/// half16ds #lo(G + A) >> 2
+pub const R_PPC64_GOT16_LO_DS: u32 = 59;
+/// half16ds #lo(L + A) >> 2
+pub const R_PPC64_PLT16_LO_DS: u32 = 60;
+/// half16ds* (R + A) >> 2
+pub const R_PPC64_SECTOFF_DS: u32 = 61;
+/// half16ds #lo(R + A) >> 2
+pub const R_PPC64_SECTOFF_LO_DS: u32 = 62;
+/// half16ds* (S + A - .TOC.) >> 2
+pub const R_PPC64_TOC16_DS: u32 = 63;
+/// half16ds #lo(S + A - .TOC.) >> 2
+pub const R_PPC64_TOC16_LO_DS: u32 = 64;
+/// half16ds* (M + A) >> 2
+pub const R_PPC64_PLTGOT16_DS: u32 = 65;
+/// half16ds #lo(M + A) >> 2
+pub const R_PPC64_PLTGOT16_LO_DS: u32 = 66;
+
+// PowerPC64 values for `Rel*::r_type` defined for the TLS access ABI.
+/// none (sym+add)@tls
+pub const R_PPC64_TLS: u32 = 67;
+/// doubleword64 (sym+add)@dtpmod
+pub const R_PPC64_DTPMOD64: u32 = 68;
+/// half16* (sym+add)@tprel
+pub const R_PPC64_TPREL16: u32 = 69;
+/// half16 (sym+add)@tprel@l
+pub const R_PPC64_TPREL16_LO: u32 = 70;
+/// half16 (sym+add)@tprel@h
+pub const R_PPC64_TPREL16_HI: u32 = 71;
+/// half16 (sym+add)@tprel@ha
+pub const R_PPC64_TPREL16_HA: u32 = 72;
+/// doubleword64 (sym+add)@tprel
+pub const R_PPC64_TPREL64: u32 = 73;
+/// half16* (sym+add)@dtprel
+pub const R_PPC64_DTPREL16: u32 = 74;
+/// half16 (sym+add)@dtprel@l
+pub const R_PPC64_DTPREL16_LO: u32 = 75;
+/// half16 (sym+add)@dtprel@h
+pub const R_PPC64_DTPREL16_HI: u32 = 76;
+/// half16 (sym+add)@dtprel@ha
+pub const R_PPC64_DTPREL16_HA: u32 = 77;
+/// doubleword64 (sym+add)@dtprel
+pub const R_PPC64_DTPREL64: u32 = 78;
+/// half16* (sym+add)@got@tlsgd
+pub const R_PPC64_GOT_TLSGD16: u32 = 79;
+/// half16 (sym+add)@got@tlsgd@l
+pub const R_PPC64_GOT_TLSGD16_LO: u32 = 80;
+/// half16 (sym+add)@got@tlsgd@h
+pub const R_PPC64_GOT_TLSGD16_HI: u32 = 81;
+/// half16 (sym+add)@got@tlsgd@ha
+pub const R_PPC64_GOT_TLSGD16_HA: u32 = 82;
+/// half16* (sym+add)@got@tlsld
+pub const R_PPC64_GOT_TLSLD16: u32 = 83;
+/// half16 (sym+add)@got@tlsld@l
+pub const R_PPC64_GOT_TLSLD16_LO: u32 = 84;
+/// half16 (sym+add)@got@tlsld@h
+pub const R_PPC64_GOT_TLSLD16_HI: u32 = 85;
+/// half16 (sym+add)@got@tlsld@ha
+pub const R_PPC64_GOT_TLSLD16_HA: u32 = 86;
+/// half16ds* (sym+add)@got@tprel
+pub const R_PPC64_GOT_TPREL16_DS: u32 = 87;
+/// half16ds (sym+add)@got@tprel@l
+pub const R_PPC64_GOT_TPREL16_LO_DS: u32 = 88;
+/// half16 (sym+add)@got@tprel@h
+pub const R_PPC64_GOT_TPREL16_HI: u32 = 89;
+/// half16 (sym+add)@got@tprel@ha
+pub const R_PPC64_GOT_TPREL16_HA: u32 = 90;
+/// half16ds* (sym+add)@got@dtprel
+pub const R_PPC64_GOT_DTPREL16_DS: u32 = 91;
+/// half16ds (sym+add)@got@dtprel@l
+pub const R_PPC64_GOT_DTPREL16_LO_DS: u32 = 92;
+/// half16 (sym+add)@got@dtprel@h
+pub const R_PPC64_GOT_DTPREL16_HI: u32 = 93;
+/// half16 (sym+add)@got@dtprel@ha
+pub const R_PPC64_GOT_DTPREL16_HA: u32 = 94;
+/// half16ds* (sym+add)@tprel
+pub const R_PPC64_TPREL16_DS: u32 = 95;
+/// half16ds (sym+add)@tprel@l
+pub const R_PPC64_TPREL16_LO_DS: u32 = 96;
+/// half16 (sym+add)@tprel@higher
+pub const R_PPC64_TPREL16_HIGHER: u32 = 97;
+/// half16 (sym+add)@tprel@highera
+pub const R_PPC64_TPREL16_HIGHERA: u32 = 98;
+/// half16 (sym+add)@tprel@highest
+pub const R_PPC64_TPREL16_HIGHEST: u32 = 99;
+/// half16 (sym+add)@tprel@highesta
+pub const R_PPC64_TPREL16_HIGHESTA: u32 = 100;
+/// half16ds* (sym+add)@dtprel
+pub const R_PPC64_DTPREL16_DS: u32 = 101;
+/// half16ds (sym+add)@dtprel@l
+pub const R_PPC64_DTPREL16_LO_DS: u32 = 102;
+/// half16 (sym+add)@dtprel@higher
+pub const R_PPC64_DTPREL16_HIGHER: u32 = 103;
+/// half16 (sym+add)@dtprel@highera
+pub const R_PPC64_DTPREL16_HIGHERA: u32 = 104;
+/// half16 (sym+add)@dtprel@highest
+pub const R_PPC64_DTPREL16_HIGHEST: u32 = 105;
+/// half16 (sym+add)@dtprel@highesta
+pub const R_PPC64_DTPREL16_HIGHESTA: u32 = 106;
+/// none (sym+add)@tlsgd
+pub const R_PPC64_TLSGD: u32 = 107;
+/// none (sym+add)@tlsld
+pub const R_PPC64_TLSLD: u32 = 108;
+/// none
+pub const R_PPC64_TOCSAVE: u32 = 109;
+
+// Added when HA and HI relocs were changed to report overflows.
+pub const R_PPC64_ADDR16_HIGH: u32 = 110;
+pub const R_PPC64_ADDR16_HIGHA: u32 = 111;
+pub const R_PPC64_TPREL16_HIGH: u32 = 112;
+pub const R_PPC64_TPREL16_HIGHA: u32 = 113;
+pub const R_PPC64_DTPREL16_HIGH: u32 = 114;
+pub const R_PPC64_DTPREL16_HIGHA: u32 = 115;
+
+/// GNU extension to support local ifunc.
+pub const R_PPC64_JMP_IREL: u32 = 247;
+/// GNU extension to support local ifunc.
+pub const R_PPC64_IRELATIVE: u32 = 248;
+/// half16 (sym+add-.)
+pub const R_PPC64_REL16: u32 = 249;
+/// half16 (sym+add-.)@l
+pub const R_PPC64_REL16_LO: u32 = 250;
+/// half16 (sym+add-.)@h
+pub const R_PPC64_REL16_HI: u32 = 251;
+/// half16 (sym+add-.)@ha
+pub const R_PPC64_REL16_HA: u32 = 252;
+
+// PowerPC64 values for `FileHeader64::e_flags.
+/// PowerPC64 bits specifying ABI.
+///
+/// 1 for original function descriptor using ABI,
+/// 2 for revised ABI without function descriptors,
+/// 0 for unspecified or not using any features affected by the differences.
+pub const EF_PPC64_ABI: u32 = 3;
+
+// PowerPC64 values for `Dyn64::d_tag.
+pub const DT_PPC64_GLINK: u32 = DT_LOPROC + 0;
+pub const DT_PPC64_OPD: u32 = DT_LOPROC + 1;
+pub const DT_PPC64_OPDSZ: u32 = DT_LOPROC + 2;
+pub const DT_PPC64_OPT: u32 = DT_LOPROC + 3;
+
+// PowerPC64 bits for `DT_PPC64_OPT` entry.
+pub const PPC64_OPT_TLS: u32 = 1;
+pub const PPC64_OPT_MULTI_TOC: u32 = 2;
+pub const PPC64_OPT_LOCALENTRY: u32 = 4;
+
+// PowerPC64 values for `Sym64::st_other.
+pub const STO_PPC64_LOCAL_BIT: u8 = 5;
+pub const STO_PPC64_LOCAL_MASK: u8 = 7 << STO_PPC64_LOCAL_BIT;
+
+// ARM specific declarations.
+
+// ARM values for `FileHeader*::e_flags`.
+pub const EF_ARM_RELEXEC: u32 = 0x01;
+pub const EF_ARM_HASENTRY: u32 = 0x02;
+pub const EF_ARM_INTERWORK: u32 = 0x04;
+pub const EF_ARM_APCS_26: u32 = 0x08;
+pub const EF_ARM_APCS_FLOAT: u32 = 0x10;
+pub const EF_ARM_PIC: u32 = 0x20;
+/// 8-bit structure alignment is in use
+pub const EF_ARM_ALIGN8: u32 = 0x40;
+pub const EF_ARM_NEW_ABI: u32 = 0x80;
+pub const EF_ARM_OLD_ABI: u32 = 0x100;
+pub const EF_ARM_SOFT_FLOAT: u32 = 0x200;
+pub const EF_ARM_VFP_FLOAT: u32 = 0x400;
+pub const EF_ARM_MAVERICK_FLOAT: u32 = 0x800;
+
+/// NB conflicts with EF_ARM_SOFT_FLOAT
+pub const EF_ARM_ABI_FLOAT_SOFT: u32 = 0x200;
+/// NB conflicts with EF_ARM_VFP_FLOAT
+pub const EF_ARM_ABI_FLOAT_HARD: u32 = 0x400;
+
+// Other constants defined in the ARM ELF spec. version B-01.
+// NB. These conflict with values defined above.
+pub const EF_ARM_SYMSARESORTED: u32 = 0x04;
+pub const EF_ARM_DYNSYMSUSESEGIDX: u32 = 0x08;
+pub const EF_ARM_MAPSYMSFIRST: u32 = 0x10;
+
+// Constants defined in AAELF.
+pub const EF_ARM_BE8: u32 = 0x0080_0000;
+pub const EF_ARM_LE8: u32 = 0x0040_0000;
+
+pub const EF_ARM_EABIMASK: u32 = 0xff00_0000;
+pub const EF_ARM_EABI_UNKNOWN: u32 = 0x0000_0000;
+pub const EF_ARM_EABI_VER1: u32 = 0x0100_0000;
+pub const EF_ARM_EABI_VER2: u32 = 0x0200_0000;
+pub const EF_ARM_EABI_VER3: u32 = 0x0300_0000;
+pub const EF_ARM_EABI_VER4: u32 = 0x0400_0000;
+pub const EF_ARM_EABI_VER5: u32 = 0x0500_0000;
+
+// ARM Thumb values for `st_type` component of `Sym*::st_info`.
+/// A Thumb function.
+pub const STT_ARM_TFUNC: u8 = STT_LOPROC;
+/// A Thumb label.
+pub const STT_ARM_16BIT: u8 = STT_HIPROC;
+
+// ARM values for `SectionHeader*::sh_flags`.
+/// Section contains an entry point
+pub const SHF_ARM_ENTRYSECT: u32 = 0x1000_0000;
+/// Section may be multiply defined in the input to a link step.
+pub const SHF_ARM_COMDEF: u32 = 0x8000_0000;
+
+// ARM values for `ProgramHeader*::p_flags`.
+/// Segment contains the location addressed by the static base.
+pub const PF_ARM_SB: u32 = 0x1000_0000;
+/// Position-independent segment.
+pub const PF_ARM_PI: u32 = 0x2000_0000;
+/// Absolute segment.
+pub const PF_ARM_ABS: u32 = 0x4000_0000;
+
+// ARM values for `ProgramHeader*::p_type`.
+/// ARM unwind segment.
+pub const PT_ARM_EXIDX: u32 = PT_LOPROC + 1;
+
+// ARM values for `SectionHeader*::sh_type`.
+/// ARM unwind section.
+pub const SHT_ARM_EXIDX: u32 = SHT_LOPROC + 1;
+/// Preemption details.
+pub const SHT_ARM_PREEMPTMAP: u32 = SHT_LOPROC + 2;
+/// ARM attributes section.
+pub const SHT_ARM_ATTRIBUTES: u32 = SHT_LOPROC + 3;
+
+// AArch64 values for `Rel*::r_type`.
+
+/// No relocation.
+pub const R_AARCH64_NONE: u32 = 0;
+
+// ILP32 AArch64 relocs.
+/// Direct 32 bit.
+pub const R_AARCH64_P32_ABS32: u32 = 1;
+/// Copy symbol at runtime.
+pub const R_AARCH64_P32_COPY: u32 = 180;
+/// Create GOT entry.
+pub const R_AARCH64_P32_GLOB_DAT: u32 = 181;
+/// Create PLT entry.
+pub const R_AARCH64_P32_JUMP_SLOT: u32 = 182;
+/// Adjust by program base.
+pub const R_AARCH64_P32_RELATIVE: u32 = 183;
+/// Module number, 32 bit.
+pub const R_AARCH64_P32_TLS_DTPMOD: u32 = 184;
+/// Module-relative offset, 32 bit.
+pub const R_AARCH64_P32_TLS_DTPREL: u32 = 185;
+/// TP-relative offset, 32 bit.
+pub const R_AARCH64_P32_TLS_TPREL: u32 = 186;
+/// TLS Descriptor.
+pub const R_AARCH64_P32_TLSDESC: u32 = 187;
+/// STT_GNU_IFUNC relocation.
+pub const R_AARCH64_P32_IRELATIVE: u32 = 188;
+
+// LP64 AArch64 relocs.
+/// Direct 64 bit.
+pub const R_AARCH64_ABS64: u32 = 257;
+/// Direct 32 bit.
+pub const R_AARCH64_ABS32: u32 = 258;
+/// Direct 16-bit.
+pub const R_AARCH64_ABS16: u32 = 259;
+/// PC-relative 64-bit.
+pub const R_AARCH64_PREL64: u32 = 260;
+/// PC-relative 32-bit.
+pub const R_AARCH64_PREL32: u32 = 261;
+/// PC-relative 16-bit.
+pub const R_AARCH64_PREL16: u32 = 262;
+/// Dir. MOVZ imm. from bits 15:0.
+pub const R_AARCH64_MOVW_UABS_G0: u32 = 263;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_UABS_G0_NC: u32 = 264;
+/// Dir. MOVZ imm. from bits 31:16.
+pub const R_AARCH64_MOVW_UABS_G1: u32 = 265;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_UABS_G1_NC: u32 = 266;
+/// Dir. MOVZ imm. from bits 47:32.
+pub const R_AARCH64_MOVW_UABS_G2: u32 = 267;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_UABS_G2_NC: u32 = 268;
+/// Dir. MOV{K,Z} imm. from 63:48.
+pub const R_AARCH64_MOVW_UABS_G3: u32 = 269;
+/// Dir. MOV{N,Z} imm. from 15:0.
+pub const R_AARCH64_MOVW_SABS_G0: u32 = 270;
+/// Dir. MOV{N,Z} imm. from 31:16.
+pub const R_AARCH64_MOVW_SABS_G1: u32 = 271;
+/// Dir. MOV{N,Z} imm. from 47:32.
+pub const R_AARCH64_MOVW_SABS_G2: u32 = 272;
+/// PC-rel. LD imm. from bits 20:2.
+pub const R_AARCH64_LD_PREL_LO19: u32 = 273;
+/// PC-rel. ADR imm. from bits 20:0.
+pub const R_AARCH64_ADR_PREL_LO21: u32 = 274;
+/// Page-rel. ADRP imm. from 32:12.
+pub const R_AARCH64_ADR_PREL_PG_HI21: u32 = 275;
+/// Likewise; no overflow check.
+pub const R_AARCH64_ADR_PREL_PG_HI21_NC: u32 = 276;
+/// Dir. ADD imm. from bits 11:0.
+pub const R_AARCH64_ADD_ABS_LO12_NC: u32 = 277;
+/// Likewise for LD/ST; no check.
+pub const R_AARCH64_LDST8_ABS_LO12_NC: u32 = 278;
+/// PC-rel. TBZ/TBNZ imm. from 15:2.
+pub const R_AARCH64_TSTBR14: u32 = 279;
+/// PC-rel. cond. br. imm. from 20:2.
+pub const R_AARCH64_CONDBR19: u32 = 280;
+/// PC-rel. B imm. from bits 27:2.
+pub const R_AARCH64_JUMP26: u32 = 282;
+/// Likewise for CALL.
+pub const R_AARCH64_CALL26: u32 = 283;
+/// Dir. ADD imm. from bits 11:1.
+pub const R_AARCH64_LDST16_ABS_LO12_NC: u32 = 284;
+/// Likewise for bits 11:2.
+pub const R_AARCH64_LDST32_ABS_LO12_NC: u32 = 285;
+/// Likewise for bits 11:3.
+pub const R_AARCH64_LDST64_ABS_LO12_NC: u32 = 286;
+/// PC-rel. MOV{N,Z} imm. from 15:0.
+pub const R_AARCH64_MOVW_PREL_G0: u32 = 287;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_PREL_G0_NC: u32 = 288;
+/// PC-rel. MOV{N,Z} imm. from 31:16.
+pub const R_AARCH64_MOVW_PREL_G1: u32 = 289;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_PREL_G1_NC: u32 = 290;
+/// PC-rel. MOV{N,Z} imm. from 47:32.
+pub const R_AARCH64_MOVW_PREL_G2: u32 = 291;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_PREL_G2_NC: u32 = 292;
+/// PC-rel. MOV{N,Z} imm. from 63:48.
+pub const R_AARCH64_MOVW_PREL_G3: u32 = 293;
+/// Dir. ADD imm. from bits 11:4.
+pub const R_AARCH64_LDST128_ABS_LO12_NC: u32 = 299;
+/// GOT-rel. off. MOV{N,Z} imm. 15:0.
+pub const R_AARCH64_MOVW_GOTOFF_G0: u32 = 300;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_GOTOFF_G0_NC: u32 = 301;
+/// GOT-rel. o. MOV{N,Z} imm. 31:16.
+pub const R_AARCH64_MOVW_GOTOFF_G1: u32 = 302;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_GOTOFF_G1_NC: u32 = 303;
+/// GOT-rel. o. MOV{N,Z} imm. 47:32.
+pub const R_AARCH64_MOVW_GOTOFF_G2: u32 = 304;
+/// Likewise for MOVK; no check.
+pub const R_AARCH64_MOVW_GOTOFF_G2_NC: u32 = 305;
+/// GOT-rel. o. MOV{N,Z} imm. 63:48.
+pub const R_AARCH64_MOVW_GOTOFF_G3: u32 = 306;
+/// GOT-relative 64-bit.
+pub const R_AARCH64_GOTREL64: u32 = 307;
+/// GOT-relative 32-bit.
+pub const R_AARCH64_GOTREL32: u32 = 308;
+/// PC-rel. GOT off. load imm. 20:2.
+pub const R_AARCH64_GOT_LD_PREL19: u32 = 309;
+/// GOT-rel. off. LD/ST imm. 14:3.
+pub const R_AARCH64_LD64_GOTOFF_LO15: u32 = 310;
+/// P-page-rel. GOT off. ADRP 32:12.
+pub const R_AARCH64_ADR_GOT_PAGE: u32 = 311;
+/// Dir. GOT off. LD/ST imm. 11:3.
+pub const R_AARCH64_LD64_GOT_LO12_NC: u32 = 312;
+/// GOT-page-rel. GOT off. LD/ST 14:3
+pub const R_AARCH64_LD64_GOTPAGE_LO15: u32 = 313;
+/// PC-relative ADR imm. 20:0.
+pub const R_AARCH64_TLSGD_ADR_PREL21: u32 = 512;
+/// page-rel. ADRP imm. 32:12.
+pub const R_AARCH64_TLSGD_ADR_PAGE21: u32 = 513;
+/// direct ADD imm. from 11:0.
+pub const R_AARCH64_TLSGD_ADD_LO12_NC: u32 = 514;
+/// GOT-rel. MOV{N,Z} 31:16.
+pub const R_AARCH64_TLSGD_MOVW_G1: u32 = 515;
+/// GOT-rel. MOVK imm. 15:0.
+pub const R_AARCH64_TLSGD_MOVW_G0_NC: u32 = 516;
+/// Like 512; local dynamic model.
+pub const R_AARCH64_TLSLD_ADR_PREL21: u32 = 517;
+/// Like 513; local dynamic model.
+pub const R_AARCH64_TLSLD_ADR_PAGE21: u32 = 518;
+/// Like 514; local dynamic model.
+pub const R_AARCH64_TLSLD_ADD_LO12_NC: u32 = 519;
+/// Like 515; local dynamic model.
+pub const R_AARCH64_TLSLD_MOVW_G1: u32 = 520;
+/// Like 516; local dynamic model.
+pub const R_AARCH64_TLSLD_MOVW_G0_NC: u32 = 521;
+/// TLS PC-rel. load imm. 20:2.
+pub const R_AARCH64_TLSLD_LD_PREL19: u32 = 522;
+/// TLS DTP-rel. MOV{N,Z} 47:32.
+pub const R_AARCH64_TLSLD_MOVW_DTPREL_G2: u32 = 523;
+/// TLS DTP-rel. MOV{N,Z} 31:16.
+pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1: u32 = 524;
+/// Likewise; MOVK; no check.
+pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: u32 = 525;
+/// TLS DTP-rel. MOV{N,Z} 15:0.
+pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0: u32 = 526;
+/// Likewise; MOVK; no check.
+pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: u32 = 527;
+/// DTP-rel. ADD imm. from 23:12.
+pub const R_AARCH64_TLSLD_ADD_DTPREL_HI12: u32 = 528;
+/// DTP-rel. ADD imm. from 11:0.
+pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12: u32 = 529;
+/// Likewise; no ovfl. check.
+pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: u32 = 530;
+/// DTP-rel. LD/ST imm. 11:0.
+pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12: u32 = 531;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: u32 = 532;
+/// DTP-rel. LD/ST imm. 11:1.
+pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12: u32 = 533;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: u32 = 534;
+/// DTP-rel. LD/ST imm. 11:2.
+pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12: u32 = 535;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: u32 = 536;
+/// DTP-rel. LD/ST imm. 11:3.
+pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12: u32 = 537;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: u32 = 538;
+/// GOT-rel. MOV{N,Z} 31:16.
+pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G1: u32 = 539;
+/// GOT-rel. MOVK 15:0.
+pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: u32 = 540;
+/// Page-rel. ADRP 32:12.
+pub const R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: u32 = 541;
+/// Direct LD off. 11:3.
+pub const R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: u32 = 542;
+/// PC-rel. load imm. 20:2.
+pub const R_AARCH64_TLSIE_LD_GOTTPREL_PREL19: u32 = 543;
+/// TLS TP-rel. MOV{N,Z} 47:32.
+pub const R_AARCH64_TLSLE_MOVW_TPREL_G2: u32 = 544;
+/// TLS TP-rel. MOV{N,Z} 31:16.
+pub const R_AARCH64_TLSLE_MOVW_TPREL_G1: u32 = 545;
+/// Likewise; MOVK; no check.
+pub const R_AARCH64_TLSLE_MOVW_TPREL_G1_NC: u32 = 546;
+/// TLS TP-rel. MOV{N,Z} 15:0.
+pub const R_AARCH64_TLSLE_MOVW_TPREL_G0: u32 = 547;
+/// Likewise; MOVK; no check.
+pub const R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: u32 = 548;
+/// TP-rel. ADD imm. 23:12.
+pub const R_AARCH64_TLSLE_ADD_TPREL_HI12: u32 = 549;
+/// TP-rel. ADD imm. 11:0.
+pub const R_AARCH64_TLSLE_ADD_TPREL_LO12: u32 = 550;
+/// Likewise; no ovfl. check.
+pub const R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: u32 = 551;
+/// TP-rel. LD/ST off. 11:0.
+pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12: u32 = 552;
+/// Likewise; no ovfl. check.
+pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: u32 = 553;
+/// TP-rel. LD/ST off. 11:1.
+pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12: u32 = 554;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: u32 = 555;
+/// TP-rel. LD/ST off. 11:2.
+pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12: u32 = 556;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: u32 = 557;
+/// TP-rel. LD/ST off. 11:3.
+pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12: u32 = 558;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: u32 = 559;
+/// PC-rel. load immediate 20:2.
+pub const R_AARCH64_TLSDESC_LD_PREL19: u32 = 560;
+/// PC-rel. ADR immediate 20:0.
+pub const R_AARCH64_TLSDESC_ADR_PREL21: u32 = 561;
+/// Page-rel. ADRP imm. 32:12.
+pub const R_AARCH64_TLSDESC_ADR_PAGE21: u32 = 562;
+/// Direct LD off. from 11:3.
+pub const R_AARCH64_TLSDESC_LD64_LO12: u32 = 563;
+/// Direct ADD imm. from 11:0.
+pub const R_AARCH64_TLSDESC_ADD_LO12: u32 = 564;
+/// GOT-rel. MOV{N,Z} imm. 31:16.
+pub const R_AARCH64_TLSDESC_OFF_G1: u32 = 565;
+/// GOT-rel. MOVK imm. 15:0; no ck.
+pub const R_AARCH64_TLSDESC_OFF_G0_NC: u32 = 566;
+/// Relax LDR.
+pub const R_AARCH64_TLSDESC_LDR: u32 = 567;
+/// Relax ADD.
+pub const R_AARCH64_TLSDESC_ADD: u32 = 568;
+/// Relax BLR.
+pub const R_AARCH64_TLSDESC_CALL: u32 = 569;
+/// TP-rel. LD/ST off. 11:4.
+pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: u32 = 570;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: u32 = 571;
+/// DTP-rel. LD/ST imm. 11:4.
+pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: u32 = 572;
+/// Likewise; no check.
+pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: u32 = 573;
+/// Copy symbol at runtime.
+pub const R_AARCH64_COPY: u32 = 1024;
+/// Create GOT entry.
+pub const R_AARCH64_GLOB_DAT: u32 = 1025;
+/// Create PLT entry.
+pub const R_AARCH64_JUMP_SLOT: u32 = 1026;
+/// Adjust by program base.
+pub const R_AARCH64_RELATIVE: u32 = 1027;
+/// Module number, 64 bit.
+pub const R_AARCH64_TLS_DTPMOD: u32 = 1028;
+/// Module-relative offset, 64 bit.
+pub const R_AARCH64_TLS_DTPREL: u32 = 1029;
+/// TP-relative offset, 64 bit.
+pub const R_AARCH64_TLS_TPREL: u32 = 1030;
+/// TLS Descriptor.
+pub const R_AARCH64_TLSDESC: u32 = 1031;
+/// STT_GNU_IFUNC relocation.
+pub const R_AARCH64_IRELATIVE: u32 = 1032;
+
+// AVR values for `FileHeader*::e_flags`.
+
+/// Bitmask for `EF_AVR_ARCH_*`.
+pub const EF_AVR_ARCH: u32 = 0x7F;
+
+/// If set, it is assumed that the elf file uses local symbols as reference
+/// for the relocations so that linker relaxation is possible.
+pub const EF_AVR_LINKRELAX_PREPARED: u32 = 0x80;
+
+pub const EF_AVR_ARCH_AVR1: u32 = 1;
+pub const EF_AVR_ARCH_AVR2: u32 = 2;
+pub const EF_AVR_ARCH_AVR25: u32 = 25;
+pub const EF_AVR_ARCH_AVR3: u32 = 3;
+pub const EF_AVR_ARCH_AVR31: u32 = 31;
+pub const EF_AVR_ARCH_AVR35: u32 = 35;
+pub const EF_AVR_ARCH_AVR4: u32 = 4;
+pub const EF_AVR_ARCH_AVR5: u32 = 5;
+pub const EF_AVR_ARCH_AVR51: u32 = 51;
+pub const EF_AVR_ARCH_AVR6: u32 = 6;
+pub const EF_AVR_ARCH_AVRTINY: u32 = 100;
+pub const EF_AVR_ARCH_XMEGA1: u32 = 101;
+pub const EF_AVR_ARCH_XMEGA2: u32 = 102;
+pub const EF_AVR_ARCH_XMEGA3: u32 = 103;
+pub const EF_AVR_ARCH_XMEGA4: u32 = 104;
+pub const EF_AVR_ARCH_XMEGA5: u32 = 105;
+pub const EF_AVR_ARCH_XMEGA6: u32 = 106;
+pub const EF_AVR_ARCH_XMEGA7: u32 = 107;
+
+// AVR values for `Rel*::r_type`.
+
+pub const R_AVR_NONE: u32 = 0;
+/// Direct 32 bit
+pub const R_AVR_32: u32 = 1;
+pub const R_AVR_7_PCREL: u32 = 2;
+pub const R_AVR_13_PCREL: u32 = 3;
+/// Direct 16 bit
+pub const R_AVR_16: u32 = 4;
+pub const R_AVR_16_PM: u32 = 5;
+pub const R_AVR_LO8_LDI: u32 = 6;
+pub const R_AVR_HI8_LDI: u32 = 7;
+pub const R_AVR_HH8_LDI: u32 = 8;
+pub const R_AVR_LO8_LDI_NEG: u32 = 9;
+pub const R_AVR_HI8_LDI_NEG: u32 = 10;
+pub const R_AVR_HH8_LDI_NEG: u32 = 11;
+pub const R_AVR_LO8_LDI_PM: u32 = 12;
+pub const R_AVR_HI8_LDI_PM: u32 = 13;
+pub const R_AVR_HH8_LDI_PM: u32 = 14;
+pub const R_AVR_LO8_LDI_PM_NEG: u32 = 15;
+pub const R_AVR_HI8_LDI_PM_NEG: u32 = 16;
+pub const R_AVR_HH8_LDI_PM_NEG: u32 = 17;
+pub const R_AVR_CALL: u32 = 18;
+pub const R_AVR_LDI: u32 = 19;
+pub const R_AVR_6: u32 = 20;
+pub const R_AVR_6_ADIW: u32 = 21;
+pub const R_AVR_MS8_LDI: u32 = 22;
+pub const R_AVR_MS8_LDI_NEG: u32 = 23;
+pub const R_AVR_LO8_LDI_GS: u32 = 24;
+pub const R_AVR_HI8_LDI_GS: u32 = 25;
+pub const R_AVR_8: u32 = 26;
+pub const R_AVR_8_LO8: u32 = 27;
+pub const R_AVR_8_HI8: u32 = 28;
+pub const R_AVR_8_HLO8: u32 = 29;
+pub const R_AVR_DIFF8: u32 = 30;
+pub const R_AVR_DIFF16: u32 = 31;
+pub const R_AVR_DIFF32: u32 = 32;
+pub const R_AVR_LDS_STS_16: u32 = 33;
+pub const R_AVR_PORT6: u32 = 34;
+pub const R_AVR_PORT5: u32 = 35;
+pub const R_AVR_32_PCREL: u32 = 36;
+
+// MSP430 values for `Rel*::r_type`.
+
+/// Direct 32 bit
+pub const R_MSP430_32: u32 = 1;
+/// Direct 16 bit
+pub const R_MSP430_16_BYTE: u32 = 5;
+
+// Hexagon values for `Rel*::r_type`.
+
+/// Direct 32 bit
+pub const R_HEX_32: u32 = 6;
+
+// ARM values for `Rel*::r_type`.
+
+/// No reloc
+pub const R_ARM_NONE: u32 = 0;
+/// Deprecated PC relative 26 bit branch.
+pub const R_ARM_PC24: u32 = 1;
+/// Direct 32 bit
+pub const R_ARM_ABS32: u32 = 2;
+/// PC relative 32 bit
+pub const R_ARM_REL32: u32 = 3;
+pub const R_ARM_PC13: u32 = 4;
+/// Direct 16 bit
+pub const R_ARM_ABS16: u32 = 5;
+/// Direct 12 bit
+pub const R_ARM_ABS12: u32 = 6;
+/// Direct & 0x7C (LDR, STR).
+pub const R_ARM_THM_ABS5: u32 = 7;
+/// Direct 8 bit
+pub const R_ARM_ABS8: u32 = 8;
+pub const R_ARM_SBREL32: u32 = 9;
+/// PC relative 24 bit (Thumb32 BL).
+pub const R_ARM_THM_PC22: u32 = 10;
+/// PC relative & 0x3FC (Thumb16 LDR, ADD, ADR).
+pub const R_ARM_THM_PC8: u32 = 11;
+pub const R_ARM_AMP_VCALL9: u32 = 12;
+/// Obsolete static relocation.
+pub const R_ARM_SWI24: u32 = 13;
+/// Dynamic relocation.
+pub const R_ARM_TLS_DESC: u32 = 13;
+/// Reserved.
+pub const R_ARM_THM_SWI8: u32 = 14;
+/// Reserved.
+pub const R_ARM_XPC25: u32 = 15;
+/// Reserved.
+pub const R_ARM_THM_XPC22: u32 = 16;
+/// ID of module containing symbol
+pub const R_ARM_TLS_DTPMOD32: u32 = 17;
+/// Offset in TLS block
+pub const R_ARM_TLS_DTPOFF32: u32 = 18;
+/// Offset in static TLS block
+pub const R_ARM_TLS_TPOFF32: u32 = 19;
+/// Copy symbol at runtime
+pub const R_ARM_COPY: u32 = 20;
+/// Create GOT entry
+pub const R_ARM_GLOB_DAT: u32 = 21;
+/// Create PLT entry
+pub const R_ARM_JUMP_SLOT: u32 = 22;
+/// Adjust by program base
+pub const R_ARM_RELATIVE: u32 = 23;
+/// 32 bit offset to GOT
+pub const R_ARM_GOTOFF: u32 = 24;
+/// 32 bit PC relative offset to GOT
+pub const R_ARM_GOTPC: u32 = 25;
+/// 32 bit GOT entry
+pub const R_ARM_GOT32: u32 = 26;
+/// Deprecated, 32 bit PLT address.
+pub const R_ARM_PLT32: u32 = 27;
+/// PC relative 24 bit (BL, BLX).
+pub const R_ARM_CALL: u32 = 28;
+/// PC relative 24 bit (B, BL<cond>).
+pub const R_ARM_JUMP24: u32 = 29;
+/// PC relative 24 bit (Thumb32 B.W).
+pub const R_ARM_THM_JUMP24: u32 = 30;
+/// Adjust by program base.
+pub const R_ARM_BASE_ABS: u32 = 31;
+/// Obsolete.
+pub const R_ARM_ALU_PCREL_7_0: u32 = 32;
+/// Obsolete.
+pub const R_ARM_ALU_PCREL_15_8: u32 = 33;
+/// Obsolete.
+pub const R_ARM_ALU_PCREL_23_15: u32 = 34;
+/// Deprecated, prog. base relative.
+pub const R_ARM_LDR_SBREL_11_0: u32 = 35;
+/// Deprecated, prog. base relative.
+pub const R_ARM_ALU_SBREL_19_12: u32 = 36;
+/// Deprecated, prog. base relative.
+pub const R_ARM_ALU_SBREL_27_20: u32 = 37;
+pub const R_ARM_TARGET1: u32 = 38;
+/// Program base relative.
+pub const R_ARM_SBREL31: u32 = 39;
+pub const R_ARM_V4BX: u32 = 40;
+pub const R_ARM_TARGET2: u32 = 41;
+/// 32 bit PC relative.
+pub const R_ARM_PREL31: u32 = 42;
+/// Direct 16-bit (MOVW).
+pub const R_ARM_MOVW_ABS_NC: u32 = 43;
+/// Direct high 16-bit (MOVT).
+pub const R_ARM_MOVT_ABS: u32 = 44;
+/// PC relative 16-bit (MOVW).
+pub const R_ARM_MOVW_PREL_NC: u32 = 45;
+/// PC relative (MOVT).
+pub const R_ARM_MOVT_PREL: u32 = 46;
+/// Direct 16 bit (Thumb32 MOVW).
+pub const R_ARM_THM_MOVW_ABS_NC: u32 = 47;
+/// Direct high 16 bit (Thumb32 MOVT).
+pub const R_ARM_THM_MOVT_ABS: u32 = 48;
+/// PC relative 16 bit (Thumb32 MOVW).
+pub const R_ARM_THM_MOVW_PREL_NC: u32 = 49;
+/// PC relative high 16 bit (Thumb32 MOVT).
+pub const R_ARM_THM_MOVT_PREL: u32 = 50;
+/// PC relative 20 bit (Thumb32 B<cond>.W).
+pub const R_ARM_THM_JUMP19: u32 = 51;
+/// PC relative X & 0x7E (Thumb16 CBZ, CBNZ).
+pub const R_ARM_THM_JUMP6: u32 = 52;
+/// PC relative 12 bit (Thumb32 ADR.W).
+pub const R_ARM_THM_ALU_PREL_11_0: u32 = 53;
+/// PC relative 12 bit (Thumb32 LDR{D,SB,H,SH}).
+pub const R_ARM_THM_PC12: u32 = 54;
+/// Direct 32-bit.
+pub const R_ARM_ABS32_NOI: u32 = 55;
+/// PC relative 32-bit.
+pub const R_ARM_REL32_NOI: u32 = 56;
+/// PC relative (ADD, SUB).
+pub const R_ARM_ALU_PC_G0_NC: u32 = 57;
+/// PC relative (ADD, SUB).
+pub const R_ARM_ALU_PC_G0: u32 = 58;
+/// PC relative (ADD, SUB).
+pub const R_ARM_ALU_PC_G1_NC: u32 = 59;
+/// PC relative (ADD, SUB).
+pub const R_ARM_ALU_PC_G1: u32 = 60;
+/// PC relative (ADD, SUB).
+pub const R_ARM_ALU_PC_G2: u32 = 61;
+/// PC relative (LDR,STR,LDRB,STRB).
+pub const R_ARM_LDR_PC_G1: u32 = 62;
+/// PC relative (LDR,STR,LDRB,STRB).
+pub const R_ARM_LDR_PC_G2: u32 = 63;
+/// PC relative (STR{D,H}, LDR{D,SB,H,SH}).
+pub const R_ARM_LDRS_PC_G0: u32 = 64;
+/// PC relative (STR{D,H}, LDR{D,SB,H,SH}).
+pub const R_ARM_LDRS_PC_G1: u32 = 65;
+/// PC relative (STR{D,H}, LDR{D,SB,H,SH}).
+pub const R_ARM_LDRS_PC_G2: u32 = 66;
+/// PC relative (LDC, STC).
+pub const R_ARM_LDC_PC_G0: u32 = 67;
+/// PC relative (LDC, STC).
+pub const R_ARM_LDC_PC_G1: u32 = 68;
+/// PC relative (LDC, STC).
+pub const R_ARM_LDC_PC_G2: u32 = 69;
+/// Program base relative (ADD,SUB).
+pub const R_ARM_ALU_SB_G0_NC: u32 = 70;
+/// Program base relative (ADD,SUB).
+pub const R_ARM_ALU_SB_G0: u32 = 71;
+/// Program base relative (ADD,SUB).
+pub const R_ARM_ALU_SB_G1_NC: u32 = 72;
+/// Program base relative (ADD,SUB).
+pub const R_ARM_ALU_SB_G1: u32 = 73;
+/// Program base relative (ADD,SUB).
+pub const R_ARM_ALU_SB_G2: u32 = 74;
+/// Program base relative (LDR, STR, LDRB, STRB).
+pub const R_ARM_LDR_SB_G0: u32 = 75;
+/// Program base relative (LDR, STR, LDRB, STRB).
+pub const R_ARM_LDR_SB_G1: u32 = 76;
+/// Program base relative (LDR, STR, LDRB, STRB).
+pub const R_ARM_LDR_SB_G2: u32 = 77;
+/// Program base relative (LDR, STR, LDRB, STRB).
+pub const R_ARM_LDRS_SB_G0: u32 = 78;
+/// Program base relative (LDR, STR, LDRB, STRB).
+pub const R_ARM_LDRS_SB_G1: u32 = 79;
+/// Program base relative (LDR, STR, LDRB, STRB).
+pub const R_ARM_LDRS_SB_G2: u32 = 80;
+/// Program base relative (LDC,STC).
+pub const R_ARM_LDC_SB_G0: u32 = 81;
+/// Program base relative (LDC,STC).
+pub const R_ARM_LDC_SB_G1: u32 = 82;
+/// Program base relative (LDC,STC).
+pub const R_ARM_LDC_SB_G2: u32 = 83;
+/// Program base relative 16 bit (MOVW).
+pub const R_ARM_MOVW_BREL_NC: u32 = 84;
+/// Program base relative high 16 bit (MOVT).
+pub const R_ARM_MOVT_BREL: u32 = 85;
+/// Program base relative 16 bit (MOVW).
+pub const R_ARM_MOVW_BREL: u32 = 86;
+/// Program base relative 16 bit (Thumb32 MOVW).
+pub const R_ARM_THM_MOVW_BREL_NC: u32 = 87;
+/// Program base relative high 16 bit (Thumb32 MOVT).
+pub const R_ARM_THM_MOVT_BREL: u32 = 88;
+/// Program base relative 16 bit (Thumb32 MOVW).
+pub const R_ARM_THM_MOVW_BREL: u32 = 89;
+pub const R_ARM_TLS_GOTDESC: u32 = 90;
+pub const R_ARM_TLS_CALL: u32 = 91;
+/// TLS relaxation.
+pub const R_ARM_TLS_DESCSEQ: u32 = 92;
+pub const R_ARM_THM_TLS_CALL: u32 = 93;
+pub const R_ARM_PLT32_ABS: u32 = 94;
+/// GOT entry.
+pub const R_ARM_GOT_ABS: u32 = 95;
+/// PC relative GOT entry.
+pub const R_ARM_GOT_PREL: u32 = 96;
+/// GOT entry relative to GOT origin (LDR).
+pub const R_ARM_GOT_BREL12: u32 = 97;
+/// 12 bit, GOT entry relative to GOT origin (LDR, STR).
+pub const R_ARM_GOTOFF12: u32 = 98;
+pub const R_ARM_GOTRELAX: u32 = 99;
+pub const R_ARM_GNU_VTENTRY: u32 = 100;
+pub const R_ARM_GNU_VTINHERIT: u32 = 101;
+/// PC relative & 0xFFE (Thumb16 B).
+pub const R_ARM_THM_PC11: u32 = 102;
+/// PC relative & 0x1FE (Thumb16 B/B<cond>).
+pub const R_ARM_THM_PC9: u32 = 103;
+/// PC-rel 32 bit for global dynamic thread local data
+pub const R_ARM_TLS_GD32: u32 = 104;
+/// PC-rel 32 bit for local dynamic thread local data
+pub const R_ARM_TLS_LDM32: u32 = 105;
+/// 32 bit offset relative to TLS block
+pub const R_ARM_TLS_LDO32: u32 = 106;
+/// PC-rel 32 bit for GOT entry of static TLS block offset
+pub const R_ARM_TLS_IE32: u32 = 107;
+/// 32 bit offset relative to static TLS block
+pub const R_ARM_TLS_LE32: u32 = 108;
+/// 12 bit relative to TLS block (LDR, STR).
+pub const R_ARM_TLS_LDO12: u32 = 109;
+/// 12 bit relative to static TLS block (LDR, STR).
+pub const R_ARM_TLS_LE12: u32 = 110;
+/// 12 bit GOT entry relative to GOT origin (LDR).
+pub const R_ARM_TLS_IE12GP: u32 = 111;
+/// Obsolete.
+pub const R_ARM_ME_TOO: u32 = 128;
+pub const R_ARM_THM_TLS_DESCSEQ: u32 = 129;
+pub const R_ARM_THM_TLS_DESCSEQ16: u32 = 129;
+pub const R_ARM_THM_TLS_DESCSEQ32: u32 = 130;
+/// GOT entry relative to GOT origin, 12 bit (Thumb32 LDR).
+pub const R_ARM_THM_GOT_BREL12: u32 = 131;
+pub const R_ARM_IRELATIVE: u32 = 160;
+pub const R_ARM_RXPC25: u32 = 249;
+pub const R_ARM_RSBREL32: u32 = 250;
+pub const R_ARM_THM_RPC22: u32 = 251;
+pub const R_ARM_RREL32: u32 = 252;
+pub const R_ARM_RABS22: u32 = 253;
+pub const R_ARM_RPC24: u32 = 254;
+pub const R_ARM_RBASE: u32 = 255;
+
+// C-SKY values for `Rel*::r_type`.
+/// no reloc
+pub const R_CKCORE_NONE: u32 = 0;
+/// direct 32 bit (S + A)
+pub const R_CKCORE_ADDR32: u32 = 1;
+/// disp ((S + A - P) >> 2) & 0xff
+pub const R_CKCORE_PCRELIMM8BY4: u32 = 2;
+/// disp ((S + A - P) >> 1) & 0x7ff
+pub const R_CKCORE_PCRELIMM11BY2: u32 = 3;
+/// 32-bit rel (S + A - P)
+pub const R_CKCORE_PCREL32: u32 = 5;
+/// disp ((S + A - P) >>1) & 0x7ff
+pub const R_CKCORE_PCRELJSR_IMM11BY2: u32 = 6;
+/// 32 bit adjust program base(B + A)
+pub const R_CKCORE_RELATIVE: u32 = 9;
+/// 32 bit adjust by program base
+pub const R_CKCORE_COPY: u32 = 10;
+/// off between got and sym (S)
+pub const R_CKCORE_GLOB_DAT: u32 = 11;
+/// PLT entry (S)
+pub const R_CKCORE_JUMP_SLOT: u32 = 12;
+/// offset to GOT (S + A - GOT)
+pub const R_CKCORE_GOTOFF: u32 = 13;
+/// PC offset to GOT (GOT + A - P)
+pub const R_CKCORE_GOTPC: u32 = 14;
+/// 32 bit GOT entry (G)
+pub const R_CKCORE_GOT32: u32 = 15;
+/// 32 bit PLT entry (G)
+pub const R_CKCORE_PLT32: u32 = 16;
+/// GOT entry in GLOB_DAT (GOT + G)
+pub const R_CKCORE_ADDRGOT: u32 = 17;
+/// PLT entry in GLOB_DAT (GOT + G)
+pub const R_CKCORE_ADDRPLT: u32 = 18;
+/// ((S + A - P) >> 1) & 0x3ff_ffff
+pub const R_CKCORE_PCREL_IMM26BY2: u32 = 19;
+/// disp ((S + A - P) >> 1) & 0xffff
+pub const R_CKCORE_PCREL_IMM16BY2: u32 = 20;
+/// disp ((S + A - P) >> 2) & 0xffff
+pub const R_CKCORE_PCREL_IMM16BY4: u32 = 21;
+/// disp ((S + A - P) >> 1) & 0x3ff
+pub const R_CKCORE_PCREL_IMM10BY2: u32 = 22;
+/// disp ((S + A - P) >> 2) & 0x3ff
+pub const R_CKCORE_PCREL_IMM10BY4: u32 = 23;
+/// high & low 16 bit ADDR, ((S + A) >> 16) & 0xffff
+pub const R_CKCORE_ADDR_HI16: u32 = 24;
+/// (S + A) & 0xffff
+pub const R_CKCORE_ADDR_LO16: u32 = 25;
+/// high & low 16 bit GOTPC, ((GOT + A - P) >> 16) & 0xffff
+pub const R_CKCORE_GOTPC_HI16: u32 = 26;
+/// (GOT + A - P) & 0xffff
+pub const R_CKCORE_GOTPC_LO16: u32 = 27;
+/// high & low 16 bit GOTOFF, ((S + A - GOT) >> 16) & 0xffff
+pub const R_CKCORE_GOTOFF_HI16: u32 = 28;
+/// (S + A - GOT) & 0xffff
+pub const R_CKCORE_GOTOFF_LO16: u32 = 29;
+/// 12 bit disp GOT entry (G)
+pub const R_CKCORE_GOT12: u32 = 30;
+/// high & low 16 bit GOT, (G >> 16) & 0xffff
+pub const R_CKCORE_GOT_HI16: u32 = 31;
+/// (G & 0xffff)
+pub const R_CKCORE_GOT_LO16: u32 = 32;
+/// 12 bit disp PLT entry (G)
+pub const R_CKCORE_PLT12: u32 = 33;
+/// high & low 16 bit PLT, (G >> 16) & 0xffff
+pub const R_CKCORE_PLT_HI16: u32 = 34;
+/// G & 0xffff
+pub const R_CKCORE_PLT_LO16: u32 = 35;
+/// high & low 16 bit ADDRGOT, (GOT + G * 4) & 0xffff
+pub const R_CKCORE_ADDRGOT_HI16: u32 = 36;
+/// (GOT + G * 4) & 0xffff
+pub const R_CKCORE_ADDRGOT_LO16: u32 = 37;
+/// high & low 16 bit ADDRPLT, ((GOT + G * 4) >> 16) & 0xFFFF
+pub const R_CKCORE_ADDRPLT_HI16: u32 = 38;
+/// (GOT+G*4) & 0xffff
+pub const R_CKCORE_ADDRPLT_LO16: u32 = 39;
+/// disp ((S+A-P) >>1) & x3ff_ffff
+pub const R_CKCORE_PCREL_JSR_IMM26BY2: u32 = 40;
+/// (S+A-BTEXT) & 0xffff
+pub const R_CKCORE_TOFFSET_LO16: u32 = 41;
+/// (S+A-BTEXT) & 0xffff
+pub const R_CKCORE_DOFFSET_LO16: u32 = 42;
+/// disp ((S+A-P) >>1) & 0x3ffff
+pub const R_CKCORE_PCREL_IMM18BY2: u32 = 43;
+/// disp (S+A-BDATA) & 0x3ffff
+pub const R_CKCORE_DOFFSET_IMM18: u32 = 44;
+/// disp ((S+A-BDATA)>>1) & 0x3ffff
+pub const R_CKCORE_DOFFSET_IMM18BY2: u32 = 45;
+/// disp ((S+A-BDATA)>>2) & 0x3ffff
+pub const R_CKCORE_DOFFSET_IMM18BY4: u32 = 46;
+/// disp (G >> 2)
+pub const R_CKCORE_GOT_IMM18BY4: u32 = 48;
+/// disp (G >> 2)
+pub const R_CKCORE_PLT_IMM18BY4: u32 = 49;
+/// disp ((S+A-P) >>2) & 0x7f
+pub const R_CKCORE_PCREL_IMM7BY4: u32 = 50;
+/// 32 bit offset to TLS block
+pub const R_CKCORE_TLS_LE32: u32 = 51;
+pub const R_CKCORE_TLS_IE32: u32 = 52;
+pub const R_CKCORE_TLS_GD32: u32 = 53;
+pub const R_CKCORE_TLS_LDM32: u32 = 54;
+pub const R_CKCORE_TLS_LDO32: u32 = 55;
+pub const R_CKCORE_TLS_DTPMOD32: u32 = 56;
+pub const R_CKCORE_TLS_DTPOFF32: u32 = 57;
+pub const R_CKCORE_TLS_TPOFF32: u32 = 58;
+
+// C-SKY values for `FileHeader*::e_flags`.
+pub const EF_CSKY_ABIMASK: u32 = 0xF000_0000;
+pub const EF_CSKY_OTHER: u32 = 0x0FFF_0000;
+pub const EF_CSKY_PROCESSOR: u32 = 0x0000_FFFF;
+
+pub const EF_CSKY_ABIV1: u32 = 0x1000_0000;
+pub const EF_CSKY_ABIV2: u32 = 0x2000_0000;
+
+// C-SKY values for `SectionHeader*::sh_type`.
+/// C-SKY attributes section.
+pub const SHT_CSKY_ATTRIBUTES: u32 = SHT_LOPROC + 1;
+
+// IA-64 specific declarations.
+
+// IA-64 values for `FileHeader64::e_flags`.
+/// os-specific flags
+pub const EF_IA_64_MASKOS: u32 = 0x0000_000f;
+/// 64-bit ABI
+pub const EF_IA_64_ABI64: u32 = 0x0000_0010;
+/// arch. version mask
+pub const EF_IA_64_ARCH: u32 = 0xff00_0000;
+
+// IA-64 values for `ProgramHeader64::p_type`.
+/// arch extension bits
+pub const PT_IA_64_ARCHEXT: u32 = PT_LOPROC + 0;
+/// ia64 unwind bits
+pub const PT_IA_64_UNWIND: u32 = PT_LOPROC + 1;
+pub const PT_IA_64_HP_OPT_ANOT: u32 = PT_LOOS + 0x12;
+pub const PT_IA_64_HP_HSL_ANOT: u32 = PT_LOOS + 0x13;
+pub const PT_IA_64_HP_STACK: u32 = PT_LOOS + 0x14;
+
+// IA-64 values for `ProgramHeader64::p_flags`.
+/// spec insns w/o recovery
+pub const PF_IA_64_NORECOV: u32 = 0x8000_0000;
+
+// IA-64 values for `SectionHeader64::sh_type`.
+/// extension bits
+pub const SHT_IA_64_EXT: u32 = SHT_LOPROC + 0;
+/// unwind bits
+pub const SHT_IA_64_UNWIND: u32 = SHT_LOPROC + 1;
+
+// IA-64 values for `SectionHeader64::sh_flags`.
+/// section near gp
+pub const SHF_IA_64_SHORT: u32 = 0x1000_0000;
+/// spec insns w/o recovery
+pub const SHF_IA_64_NORECOV: u32 = 0x2000_0000;
+
+// IA-64 values for `Dyn64::d_tag`.
+pub const DT_IA_64_PLT_RESERVE: u32 = DT_LOPROC + 0;
+
+// IA-64 values for `Rel*::r_type`.
+/// none
+pub const R_IA64_NONE: u32 = 0x00;
+/// symbol + addend, add imm14
+pub const R_IA64_IMM14: u32 = 0x21;
+/// symbol + addend, add imm22
+pub const R_IA64_IMM22: u32 = 0x22;
+/// symbol + addend, mov imm64
+pub const R_IA64_IMM64: u32 = 0x23;
+/// symbol + addend, data4 MSB
+pub const R_IA64_DIR32MSB: u32 = 0x24;
+/// symbol + addend, data4 LSB
+pub const R_IA64_DIR32LSB: u32 = 0x25;
+/// symbol + addend, data8 MSB
+pub const R_IA64_DIR64MSB: u32 = 0x26;
+/// symbol + addend, data8 LSB
+pub const R_IA64_DIR64LSB: u32 = 0x27;
+/// @gprel(sym + add), add imm22
+pub const R_IA64_GPREL22: u32 = 0x2a;
+/// @gprel(sym + add), mov imm64
+pub const R_IA64_GPREL64I: u32 = 0x2b;
+/// @gprel(sym + add), data4 MSB
+pub const R_IA64_GPREL32MSB: u32 = 0x2c;
+/// @gprel(sym + add), data4 LSB
+pub const R_IA64_GPREL32LSB: u32 = 0x2d;
+/// @gprel(sym + add), data8 MSB
+pub const R_IA64_GPREL64MSB: u32 = 0x2e;
+/// @gprel(sym + add), data8 LSB
+pub const R_IA64_GPREL64LSB: u32 = 0x2f;
+/// @ltoff(sym + add), add imm22
+pub const R_IA64_LTOFF22: u32 = 0x32;
+/// @ltoff(sym + add), mov imm64
+pub const R_IA64_LTOFF64I: u32 = 0x33;
+/// @pltoff(sym + add), add imm22
+pub const R_IA64_PLTOFF22: u32 = 0x3a;
+/// @pltoff(sym + add), mov imm64
+pub const R_IA64_PLTOFF64I: u32 = 0x3b;
+/// @pltoff(sym + add), data8 MSB
+pub const R_IA64_PLTOFF64MSB: u32 = 0x3e;
+/// @pltoff(sym + add), data8 LSB
+pub const R_IA64_PLTOFF64LSB: u32 = 0x3f;
+/// @fptr(sym + add), mov imm64
+pub const R_IA64_FPTR64I: u32 = 0x43;
+/// @fptr(sym + add), data4 MSB
+pub const R_IA64_FPTR32MSB: u32 = 0x44;
+/// @fptr(sym + add), data4 LSB
+pub const R_IA64_FPTR32LSB: u32 = 0x45;
+/// @fptr(sym + add), data8 MSB
+pub const R_IA64_FPTR64MSB: u32 = 0x46;
+/// @fptr(sym + add), data8 LSB
+pub const R_IA64_FPTR64LSB: u32 = 0x47;
+/// @pcrel(sym + add), brl
+pub const R_IA64_PCREL60B: u32 = 0x48;
+/// @pcrel(sym + add), ptb, call
+pub const R_IA64_PCREL21B: u32 = 0x49;
+/// @pcrel(sym + add), chk.s
+pub const R_IA64_PCREL21M: u32 = 0x4a;
+/// @pcrel(sym + add), fchkf
+pub const R_IA64_PCREL21F: u32 = 0x4b;
+/// @pcrel(sym + add), data4 MSB
+pub const R_IA64_PCREL32MSB: u32 = 0x4c;
+/// @pcrel(sym + add), data4 LSB
+pub const R_IA64_PCREL32LSB: u32 = 0x4d;
+/// @pcrel(sym + add), data8 MSB
+pub const R_IA64_PCREL64MSB: u32 = 0x4e;
+/// @pcrel(sym + add), data8 LSB
+pub const R_IA64_PCREL64LSB: u32 = 0x4f;
+/// @ltoff(@fptr(s+a)), imm22
+pub const R_IA64_LTOFF_FPTR22: u32 = 0x52;
+/// @ltoff(@fptr(s+a)), imm64
+pub const R_IA64_LTOFF_FPTR64I: u32 = 0x53;
+/// @ltoff(@fptr(s+a)), data4 MSB
+pub const R_IA64_LTOFF_FPTR32MSB: u32 = 0x54;
+/// @ltoff(@fptr(s+a)), data4 LSB
+pub const R_IA64_LTOFF_FPTR32LSB: u32 = 0x55;
+/// @ltoff(@fptr(s+a)), data8 MSB
+pub const R_IA64_LTOFF_FPTR64MSB: u32 = 0x56;
+/// @ltoff(@fptr(s+a)), data8 LSB
+pub const R_IA64_LTOFF_FPTR64LSB: u32 = 0x57;
+/// @segrel(sym + add), data4 MSB
+pub const R_IA64_SEGREL32MSB: u32 = 0x5c;
+/// @segrel(sym + add), data4 LSB
+pub const R_IA64_SEGREL32LSB: u32 = 0x5d;
+/// @segrel(sym + add), data8 MSB
+pub const R_IA64_SEGREL64MSB: u32 = 0x5e;
+/// @segrel(sym + add), data8 LSB
+pub const R_IA64_SEGREL64LSB: u32 = 0x5f;
+/// @secrel(sym + add), data4 MSB
+pub const R_IA64_SECREL32MSB: u32 = 0x64;
+/// @secrel(sym + add), data4 LSB
+pub const R_IA64_SECREL32LSB: u32 = 0x65;
+/// @secrel(sym + add), data8 MSB
+pub const R_IA64_SECREL64MSB: u32 = 0x66;
+/// @secrel(sym + add), data8 LSB
+pub const R_IA64_SECREL64LSB: u32 = 0x67;
+/// data 4 + REL
+pub const R_IA64_REL32MSB: u32 = 0x6c;
+/// data 4 + REL
+pub const R_IA64_REL32LSB: u32 = 0x6d;
+/// data 8 + REL
+pub const R_IA64_REL64MSB: u32 = 0x6e;
+/// data 8 + REL
+pub const R_IA64_REL64LSB: u32 = 0x6f;
+/// symbol + addend, data4 MSB
+pub const R_IA64_LTV32MSB: u32 = 0x74;
+/// symbol + addend, data4 LSB
+pub const R_IA64_LTV32LSB: u32 = 0x75;
+/// symbol + addend, data8 MSB
+pub const R_IA64_LTV64MSB: u32 = 0x76;
+/// symbol + addend, data8 LSB
+pub const R_IA64_LTV64LSB: u32 = 0x77;
+/// @pcrel(sym + add), 21bit inst
+pub const R_IA64_PCREL21BI: u32 = 0x79;
+/// @pcrel(sym + add), 22bit inst
+pub const R_IA64_PCREL22: u32 = 0x7a;
+/// @pcrel(sym + add), 64bit inst
+pub const R_IA64_PCREL64I: u32 = 0x7b;
+/// dynamic reloc, imported PLT, MSB
+pub const R_IA64_IPLTMSB: u32 = 0x80;
+/// dynamic reloc, imported PLT, LSB
+pub const R_IA64_IPLTLSB: u32 = 0x81;
+/// copy relocation
+pub const R_IA64_COPY: u32 = 0x84;
+/// Addend and symbol difference
+pub const R_IA64_SUB: u32 = 0x85;
+/// LTOFF22, relaxable.
+pub const R_IA64_LTOFF22X: u32 = 0x86;
+/// Use of LTOFF22X.
+pub const R_IA64_LDXMOV: u32 = 0x87;
+/// @tprel(sym + add), imm14
+pub const R_IA64_TPREL14: u32 = 0x91;
+/// @tprel(sym + add), imm22
+pub const R_IA64_TPREL22: u32 = 0x92;
+/// @tprel(sym + add), imm64
+pub const R_IA64_TPREL64I: u32 = 0x93;
+/// @tprel(sym + add), data8 MSB
+pub const R_IA64_TPREL64MSB: u32 = 0x96;
+/// @tprel(sym + add), data8 LSB
+pub const R_IA64_TPREL64LSB: u32 = 0x97;
+/// @ltoff(@tprel(s+a)), imm2
+pub const R_IA64_LTOFF_TPREL22: u32 = 0x9a;
+/// @dtpmod(sym + add), data8 MSB
+pub const R_IA64_DTPMOD64MSB: u32 = 0xa6;
+/// @dtpmod(sym + add), data8 LSB
+pub const R_IA64_DTPMOD64LSB: u32 = 0xa7;
+/// @ltoff(@dtpmod(sym + add)), imm22
+pub const R_IA64_LTOFF_DTPMOD22: u32 = 0xaa;
+/// @dtprel(sym + add), imm14
+pub const R_IA64_DTPREL14: u32 = 0xb1;
+/// @dtprel(sym + add), imm22
+pub const R_IA64_DTPREL22: u32 = 0xb2;
+/// @dtprel(sym + add), imm64
+pub const R_IA64_DTPREL64I: u32 = 0xb3;
+/// @dtprel(sym + add), data4 MSB
+pub const R_IA64_DTPREL32MSB: u32 = 0xb4;
+/// @dtprel(sym + add), data4 LSB
+pub const R_IA64_DTPREL32LSB: u32 = 0xb5;
+/// @dtprel(sym + add), data8 MSB
+pub const R_IA64_DTPREL64MSB: u32 = 0xb6;
+/// @dtprel(sym + add), data8 LSB
+pub const R_IA64_DTPREL64LSB: u32 = 0xb7;
+/// @ltoff(@dtprel(s+a)), imm22
+pub const R_IA64_LTOFF_DTPREL22: u32 = 0xba;
+
+// SH specific declarations.
+
+// SH values `FileHeader*::e_flags`.
+pub const EF_SH_MACH_MASK: u32 = 0x1f;
+pub const EF_SH_UNKNOWN: u32 = 0x0;
+pub const EF_SH1: u32 = 0x1;
+pub const EF_SH2: u32 = 0x2;
+pub const EF_SH3: u32 = 0x3;
+pub const EF_SH_DSP: u32 = 0x4;
+pub const EF_SH3_DSP: u32 = 0x5;
+pub const EF_SH4AL_DSP: u32 = 0x6;
+pub const EF_SH3E: u32 = 0x8;
+pub const EF_SH4: u32 = 0x9;
+pub const EF_SH2E: u32 = 0xb;
+pub const EF_SH4A: u32 = 0xc;
+pub const EF_SH2A: u32 = 0xd;
+pub const EF_SH4_NOFPU: u32 = 0x10;
+pub const EF_SH4A_NOFPU: u32 = 0x11;
+pub const EF_SH4_NOMMU_NOFPU: u32 = 0x12;
+pub const EF_SH2A_NOFPU: u32 = 0x13;
+pub const EF_SH3_NOMMU: u32 = 0x14;
+pub const EF_SH2A_SH4_NOFPU: u32 = 0x15;
+pub const EF_SH2A_SH3_NOFPU: u32 = 0x16;
+pub const EF_SH2A_SH4: u32 = 0x17;
+pub const EF_SH2A_SH3E: u32 = 0x18;
+
+// SH values `Rel*::r_type`.
+pub const R_SH_NONE: u32 = 0;
+pub const R_SH_DIR32: u32 = 1;
+pub const R_SH_REL32: u32 = 2;
+pub const R_SH_DIR8WPN: u32 = 3;
+pub const R_SH_IND12W: u32 = 4;
+pub const R_SH_DIR8WPL: u32 = 5;
+pub const R_SH_DIR8WPZ: u32 = 6;
+pub const R_SH_DIR8BP: u32 = 7;
+pub const R_SH_DIR8W: u32 = 8;
+pub const R_SH_DIR8L: u32 = 9;
+pub const R_SH_SWITCH16: u32 = 25;
+pub const R_SH_SWITCH32: u32 = 26;
+pub const R_SH_USES: u32 = 27;
+pub const R_SH_COUNT: u32 = 28;
+pub const R_SH_ALIGN: u32 = 29;
+pub const R_SH_CODE: u32 = 30;
+pub const R_SH_DATA: u32 = 31;
+pub const R_SH_LABEL: u32 = 32;
+pub const R_SH_SWITCH8: u32 = 33;
+pub const R_SH_GNU_VTINHERIT: u32 = 34;
+pub const R_SH_GNU_VTENTRY: u32 = 35;
+pub const R_SH_TLS_GD_32: u32 = 144;
+pub const R_SH_TLS_LD_32: u32 = 145;
+pub const R_SH_TLS_LDO_32: u32 = 146;
+pub const R_SH_TLS_IE_32: u32 = 147;
+pub const R_SH_TLS_LE_32: u32 = 148;
+pub const R_SH_TLS_DTPMOD32: u32 = 149;
+pub const R_SH_TLS_DTPOFF32: u32 = 150;
+pub const R_SH_TLS_TPOFF32: u32 = 151;
+pub const R_SH_GOT32: u32 = 160;
+pub const R_SH_PLT32: u32 = 161;
+pub const R_SH_COPY: u32 = 162;
+pub const R_SH_GLOB_DAT: u32 = 163;
+pub const R_SH_JMP_SLOT: u32 = 164;
+pub const R_SH_RELATIVE: u32 = 165;
+pub const R_SH_GOTOFF: u32 = 166;
+pub const R_SH_GOTPC: u32 = 167;
+
+// S/390 specific definitions.
+
+// S/390 values `FileHeader*::e_flags`.
+
+/// High GPRs kernel facility needed.
+pub const EF_S390_HIGH_GPRS: u32 = 0x0000_0001;
+
+// S/390 values `Rel*::r_type`.
+
+/// No reloc.
+pub const R_390_NONE: u32 = 0;
+/// Direct 8 bit.
+pub const R_390_8: u32 = 1;
+/// Direct 12 bit.
+pub const R_390_12: u32 = 2;
+/// Direct 16 bit.
+pub const R_390_16: u32 = 3;
+/// Direct 32 bit.
+pub const R_390_32: u32 = 4;
+/// PC relative 32 bit.
+pub const R_390_PC32: u32 = 5;
+/// 12 bit GOT offset.
+pub const R_390_GOT12: u32 = 6;
+/// 32 bit GOT offset.
+pub const R_390_GOT32: u32 = 7;
+/// 32 bit PC relative PLT address.
+pub const R_390_PLT32: u32 = 8;
+/// Copy symbol at runtime.
+pub const R_390_COPY: u32 = 9;
+/// Create GOT entry.
+pub const R_390_GLOB_DAT: u32 = 10;
+/// Create PLT entry.
+pub const R_390_JMP_SLOT: u32 = 11;
+/// Adjust by program base.
+pub const R_390_RELATIVE: u32 = 12;
+/// 32 bit offset to GOT.
+pub const R_390_GOTOFF32: u32 = 13;
+/// 32 bit PC relative offset to GOT.
+pub const R_390_GOTPC: u32 = 14;
+/// 16 bit GOT offset.
+pub const R_390_GOT16: u32 = 15;
+/// PC relative 16 bit.
+pub const R_390_PC16: u32 = 16;
+/// PC relative 16 bit shifted by 1.
+pub const R_390_PC16DBL: u32 = 17;
+/// 16 bit PC rel. PLT shifted by 1.
+pub const R_390_PLT16DBL: u32 = 18;
+/// PC relative 32 bit shifted by 1.
+pub const R_390_PC32DBL: u32 = 19;
+/// 32 bit PC rel. PLT shifted by 1.
+pub const R_390_PLT32DBL: u32 = 20;
+/// 32 bit PC rel. GOT shifted by 1.
+pub const R_390_GOTPCDBL: u32 = 21;
+/// Direct 64 bit.
+pub const R_390_64: u32 = 22;
+/// PC relative 64 bit.
+pub const R_390_PC64: u32 = 23;
+/// 64 bit GOT offset.
+pub const R_390_GOT64: u32 = 24;
+/// 64 bit PC relative PLT address.
+pub const R_390_PLT64: u32 = 25;
+/// 32 bit PC rel. to GOT entry >> 1.
+pub const R_390_GOTENT: u32 = 26;
+/// 16 bit offset to GOT.
+pub const R_390_GOTOFF16: u32 = 27;
+/// 64 bit offset to GOT.
+pub const R_390_GOTOFF64: u32 = 28;
+/// 12 bit offset to jump slot.
+pub const R_390_GOTPLT12: u32 = 29;
+/// 16 bit offset to jump slot.
+pub const R_390_GOTPLT16: u32 = 30;
+/// 32 bit offset to jump slot.
+pub const R_390_GOTPLT32: u32 = 31;
+/// 64 bit offset to jump slot.
+pub const R_390_GOTPLT64: u32 = 32;
+/// 32 bit rel. offset to jump slot.
+pub const R_390_GOTPLTENT: u32 = 33;
+/// 16 bit offset from GOT to PLT.
+pub const R_390_PLTOFF16: u32 = 34;
+/// 32 bit offset from GOT to PLT.
+pub const R_390_PLTOFF32: u32 = 35;
+/// 16 bit offset from GOT to PLT.
+pub const R_390_PLTOFF64: u32 = 36;
+/// Tag for load insn in TLS code.
+pub const R_390_TLS_LOAD: u32 = 37;
+/// Tag for function call in general dynamic TLS code.
+pub const R_390_TLS_GDCALL: u32 = 38;
+/// Tag for function call in local dynamic TLS code.
+pub const R_390_TLS_LDCALL: u32 = 39;
+/// Direct 32 bit for general dynamic thread local data.
+pub const R_390_TLS_GD32: u32 = 40;
+/// Direct 64 bit for general dynamic thread local data.
+pub const R_390_TLS_GD64: u32 = 41;
+/// 12 bit GOT offset for static TLS block offset.
+pub const R_390_TLS_GOTIE12: u32 = 42;
+/// 32 bit GOT offset for static TLS block offset.
+pub const R_390_TLS_GOTIE32: u32 = 43;
+/// 64 bit GOT offset for static TLS block offset.
+pub const R_390_TLS_GOTIE64: u32 = 44;
+/// Direct 32 bit for local dynamic thread local data in LE code.
+pub const R_390_TLS_LDM32: u32 = 45;
+/// Direct 64 bit for local dynamic thread local data in LE code.
+pub const R_390_TLS_LDM64: u32 = 46;
+/// 32 bit address of GOT entry for negated static TLS block offset.
+pub const R_390_TLS_IE32: u32 = 47;
+/// 64 bit address of GOT entry for negated static TLS block offset.
+pub const R_390_TLS_IE64: u32 = 48;
+/// 32 bit rel. offset to GOT entry for negated static TLS block offset.
+pub const R_390_TLS_IEENT: u32 = 49;
+/// 32 bit negated offset relative to static TLS block.
+pub const R_390_TLS_LE32: u32 = 50;
+/// 64 bit negated offset relative to static TLS block.
+pub const R_390_TLS_LE64: u32 = 51;
+/// 32 bit offset relative to TLS block.
+pub const R_390_TLS_LDO32: u32 = 52;
+/// 64 bit offset relative to TLS block.
+pub const R_390_TLS_LDO64: u32 = 53;
+/// ID of module containing symbol.
+pub const R_390_TLS_DTPMOD: u32 = 54;
+/// Offset in TLS block.
+pub const R_390_TLS_DTPOFF: u32 = 55;
+/// Negated offset in static TLS block.
+pub const R_390_TLS_TPOFF: u32 = 56;
+/// Direct 20 bit.
+pub const R_390_20: u32 = 57;
+/// 20 bit GOT offset.
+pub const R_390_GOT20: u32 = 58;
+/// 20 bit offset to jump slot.
+pub const R_390_GOTPLT20: u32 = 59;
+/// 20 bit GOT offset for static TLS block offset.
+pub const R_390_TLS_GOTIE20: u32 = 60;
+/// STT_GNU_IFUNC relocation.
+pub const R_390_IRELATIVE: u32 = 61;
+
+// CRIS values `Rel*::r_type`.
+pub const R_CRIS_NONE: u32 = 0;
+pub const R_CRIS_8: u32 = 1;
+pub const R_CRIS_16: u32 = 2;
+pub const R_CRIS_32: u32 = 3;
+pub const R_CRIS_8_PCREL: u32 = 4;
+pub const R_CRIS_16_PCREL: u32 = 5;
+pub const R_CRIS_32_PCREL: u32 = 6;
+pub const R_CRIS_GNU_VTINHERIT: u32 = 7;
+pub const R_CRIS_GNU_VTENTRY: u32 = 8;
+pub const R_CRIS_COPY: u32 = 9;
+pub const R_CRIS_GLOB_DAT: u32 = 10;
+pub const R_CRIS_JUMP_SLOT: u32 = 11;
+pub const R_CRIS_RELATIVE: u32 = 12;
+pub const R_CRIS_16_GOT: u32 = 13;
+pub const R_CRIS_32_GOT: u32 = 14;
+pub const R_CRIS_16_GOTPLT: u32 = 15;
+pub const R_CRIS_32_GOTPLT: u32 = 16;
+pub const R_CRIS_32_GOTREL: u32 = 17;
+pub const R_CRIS_32_PLT_GOTREL: u32 = 18;
+pub const R_CRIS_32_PLT_PCREL: u32 = 19;
+
+// AMD x86-64 values `Rel*::r_type`.
+/// No reloc
+pub const R_X86_64_NONE: u32 = 0;
+/// Direct 64 bit
+pub const R_X86_64_64: u32 = 1;
+/// PC relative 32 bit signed
+pub const R_X86_64_PC32: u32 = 2;
+/// 32 bit GOT entry
+pub const R_X86_64_GOT32: u32 = 3;
+/// 32 bit PLT address
+pub const R_X86_64_PLT32: u32 = 4;
+/// Copy symbol at runtime
+pub const R_X86_64_COPY: u32 = 5;
+/// Create GOT entry
+pub const R_X86_64_GLOB_DAT: u32 = 6;
+/// Create PLT entry
+pub const R_X86_64_JUMP_SLOT: u32 = 7;
+/// Adjust by program base
+pub const R_X86_64_RELATIVE: u32 = 8;
+/// 32 bit signed PC relative offset to GOT
+pub const R_X86_64_GOTPCREL: u32 = 9;
+/// Direct 32 bit zero extended
+pub const R_X86_64_32: u32 = 10;
+/// Direct 32 bit sign extended
+pub const R_X86_64_32S: u32 = 11;
+/// Direct 16 bit zero extended
+pub const R_X86_64_16: u32 = 12;
+/// 16 bit sign extended pc relative
+pub const R_X86_64_PC16: u32 = 13;
+/// Direct 8 bit sign extended
+pub const R_X86_64_8: u32 = 14;
+/// 8 bit sign extended pc relative
+pub const R_X86_64_PC8: u32 = 15;
+/// ID of module containing symbol
+pub const R_X86_64_DTPMOD64: u32 = 16;
+/// Offset in module's TLS block
+pub const R_X86_64_DTPOFF64: u32 = 17;
+/// Offset in initial TLS block
+pub const R_X86_64_TPOFF64: u32 = 18;
+/// 32 bit signed PC relative offset to two GOT entries for GD symbol
+pub const R_X86_64_TLSGD: u32 = 19;
+/// 32 bit signed PC relative offset to two GOT entries for LD symbol
+pub const R_X86_64_TLSLD: u32 = 20;
+/// Offset in TLS block
+pub const R_X86_64_DTPOFF32: u32 = 21;
+/// 32 bit signed PC relative offset to GOT entry for IE symbol
+pub const R_X86_64_GOTTPOFF: u32 = 22;
+/// Offset in initial TLS block
+pub const R_X86_64_TPOFF32: u32 = 23;
+/// PC relative 64 bit
+pub const R_X86_64_PC64: u32 = 24;
+/// 64 bit offset to GOT
+pub const R_X86_64_GOTOFF64: u32 = 25;
+/// 32 bit signed pc relative offset to GOT
+pub const R_X86_64_GOTPC32: u32 = 26;
+/// 64-bit GOT entry offset
+pub const R_X86_64_GOT64: u32 = 27;
+/// 64-bit PC relative offset to GOT entry
+pub const R_X86_64_GOTPCREL64: u32 = 28;
+/// 64-bit PC relative offset to GOT
+pub const R_X86_64_GOTPC64: u32 = 29;
+/// like GOT64, says PLT entry needed
+pub const R_X86_64_GOTPLT64: u32 = 30;
+/// 64-bit GOT relative offset to PLT entry
+pub const R_X86_64_PLTOFF64: u32 = 31;
+/// Size of symbol plus 32-bit addend
+pub const R_X86_64_SIZE32: u32 = 32;
+/// Size of symbol plus 64-bit addend
+pub const R_X86_64_SIZE64: u32 = 33;
+/// GOT offset for TLS descriptor.
+pub const R_X86_64_GOTPC32_TLSDESC: u32 = 34;
+/// Marker for call through TLS descriptor.
+pub const R_X86_64_TLSDESC_CALL: u32 = 35;
+/// TLS descriptor.
+pub const R_X86_64_TLSDESC: u32 = 36;
+/// Adjust indirectly by program base
+pub const R_X86_64_IRELATIVE: u32 = 37;
+/// 64-bit adjust by program base
+pub const R_X86_64_RELATIVE64: u32 = 38;
+// 39 Reserved was R_X86_64_PC32_BND
+// 40 Reserved was R_X86_64_PLT32_BND
+/// Load from 32 bit signed pc relative offset to GOT entry without REX prefix, relaxable.
+pub const R_X86_64_GOTPCRELX: u32 = 41;
+/// Load from 32 bit signed pc relative offset to GOT entry with REX prefix, relaxable.
+pub const R_X86_64_REX_GOTPCRELX: u32 = 42;
+
+// AMD x86-64 values `SectionHeader*::sh_type`.
+/// Unwind information.
+pub const SHT_X86_64_UNWIND: u32 = 0x7000_0001;
+
+// AM33 values `Rel*::r_type`.
+/// No reloc.
+pub const R_MN10300_NONE: u32 = 0;
+/// Direct 32 bit.
+pub const R_MN10300_32: u32 = 1;
+/// Direct 16 bit.
+pub const R_MN10300_16: u32 = 2;
+/// Direct 8 bit.
+pub const R_MN10300_8: u32 = 3;
+/// PC-relative 32-bit.
+pub const R_MN10300_PCREL32: u32 = 4;
+/// PC-relative 16-bit signed.
+pub const R_MN10300_PCREL16: u32 = 5;
+/// PC-relative 8-bit signed.
+pub const R_MN10300_PCREL8: u32 = 6;
+/// Ancient C++ vtable garbage...
+pub const R_MN10300_GNU_VTINHERIT: u32 = 7;
+/// ... collection annotation.
+pub const R_MN10300_GNU_VTENTRY: u32 = 8;
+/// Direct 24 bit.
+pub const R_MN10300_24: u32 = 9;
+/// 32-bit PCrel offset to GOT.
+pub const R_MN10300_GOTPC32: u32 = 10;
+/// 16-bit PCrel offset to GOT.
+pub const R_MN10300_GOTPC16: u32 = 11;
+/// 32-bit offset from GOT.
+pub const R_MN10300_GOTOFF32: u32 = 12;
+/// 24-bit offset from GOT.
+pub const R_MN10300_GOTOFF24: u32 = 13;
+/// 16-bit offset from GOT.
+pub const R_MN10300_GOTOFF16: u32 = 14;
+/// 32-bit PCrel to PLT entry.
+pub const R_MN10300_PLT32: u32 = 15;
+/// 16-bit PCrel to PLT entry.
+pub const R_MN10300_PLT16: u32 = 16;
+/// 32-bit offset to GOT entry.
+pub const R_MN10300_GOT32: u32 = 17;
+/// 24-bit offset to GOT entry.
+pub const R_MN10300_GOT24: u32 = 18;
+/// 16-bit offset to GOT entry.
+pub const R_MN10300_GOT16: u32 = 19;
+/// Copy symbol at runtime.
+pub const R_MN10300_COPY: u32 = 20;
+/// Create GOT entry.
+pub const R_MN10300_GLOB_DAT: u32 = 21;
+/// Create PLT entry.
+pub const R_MN10300_JMP_SLOT: u32 = 22;
+/// Adjust by program base.
+pub const R_MN10300_RELATIVE: u32 = 23;
+/// 32-bit offset for global dynamic.
+pub const R_MN10300_TLS_GD: u32 = 24;
+/// 32-bit offset for local dynamic.
+pub const R_MN10300_TLS_LD: u32 = 25;
+/// Module-relative offset.
+pub const R_MN10300_TLS_LDO: u32 = 26;
+/// GOT offset for static TLS block offset.
+pub const R_MN10300_TLS_GOTIE: u32 = 27;
+/// GOT address for static TLS block offset.
+pub const R_MN10300_TLS_IE: u32 = 28;
+/// Offset relative to static TLS block.
+pub const R_MN10300_TLS_LE: u32 = 29;
+/// ID of module containing symbol.
+pub const R_MN10300_TLS_DTPMOD: u32 = 30;
+/// Offset in module TLS block.
+pub const R_MN10300_TLS_DTPOFF: u32 = 31;
+/// Offset in static TLS block.
+pub const R_MN10300_TLS_TPOFF: u32 = 32;
+/// Adjustment for next reloc as needed by linker relaxation.
+pub const R_MN10300_SYM_DIFF: u32 = 33;
+/// Alignment requirement for linker relaxation.
+pub const R_MN10300_ALIGN: u32 = 34;
+
+// M32R values `Rel32::r_type`.
+/// No reloc.
+pub const R_M32R_NONE: u32 = 0;
+/// Direct 16 bit.
+pub const R_M32R_16: u32 = 1;
+/// Direct 32 bit.
+pub const R_M32R_32: u32 = 2;
+/// Direct 24 bit.
+pub const R_M32R_24: u32 = 3;
+/// PC relative 10 bit shifted.
+pub const R_M32R_10_PCREL: u32 = 4;
+/// PC relative 18 bit shifted.
+pub const R_M32R_18_PCREL: u32 = 5;
+/// PC relative 26 bit shifted.
+pub const R_M32R_26_PCREL: u32 = 6;
+/// High 16 bit with unsigned low.
+pub const R_M32R_HI16_ULO: u32 = 7;
+/// High 16 bit with signed low.
+pub const R_M32R_HI16_SLO: u32 = 8;
+/// Low 16 bit.
+pub const R_M32R_LO16: u32 = 9;
+/// 16 bit offset in SDA.
+pub const R_M32R_SDA16: u32 = 10;
+pub const R_M32R_GNU_VTINHERIT: u32 = 11;
+pub const R_M32R_GNU_VTENTRY: u32 = 12;
+// M32R values `Rela32::r_type`.
+/// Direct 16 bit.
+pub const R_M32R_16_RELA: u32 = 33;
+/// Direct 32 bit.
+pub const R_M32R_32_RELA: u32 = 34;
+/// Direct 24 bit.
+pub const R_M32R_24_RELA: u32 = 35;
+/// PC relative 10 bit shifted.
+pub const R_M32R_10_PCREL_RELA: u32 = 36;
+/// PC relative 18 bit shifted.
+pub const R_M32R_18_PCREL_RELA: u32 = 37;
+/// PC relative 26 bit shifted.
+pub const R_M32R_26_PCREL_RELA: u32 = 38;
+/// High 16 bit with unsigned low
+pub const R_M32R_HI16_ULO_RELA: u32 = 39;
+/// High 16 bit with signed low
+pub const R_M32R_HI16_SLO_RELA: u32 = 40;
+/// Low 16 bit
+pub const R_M32R_LO16_RELA: u32 = 41;
+/// 16 bit offset in SDA
+pub const R_M32R_SDA16_RELA: u32 = 42;
+pub const R_M32R_RELA_GNU_VTINHERIT: u32 = 43;
+pub const R_M32R_RELA_GNU_VTENTRY: u32 = 44;
+/// PC relative 32 bit.
+pub const R_M32R_REL32: u32 = 45;
+
+/// 24 bit GOT entry
+pub const R_M32R_GOT24: u32 = 48;
+/// 26 bit PC relative to PLT shifted
+pub const R_M32R_26_PLTREL: u32 = 49;
+/// Copy symbol at runtime
+pub const R_M32R_COPY: u32 = 50;
+/// Create GOT entry
+pub const R_M32R_GLOB_DAT: u32 = 51;
+/// Create PLT entry
+pub const R_M32R_JMP_SLOT: u32 = 52;
+/// Adjust by program base
+pub const R_M32R_RELATIVE: u32 = 53;
+/// 24 bit offset to GOT
+pub const R_M32R_GOTOFF: u32 = 54;
+/// 24 bit PC relative offset to GOT
+pub const R_M32R_GOTPC24: u32 = 55;
+/// High 16 bit GOT entry with unsigned low
+pub const R_M32R_GOT16_HI_ULO: u32 = 56;
+/// High 16 bit GOT entry with signed low
+pub const R_M32R_GOT16_HI_SLO: u32 = 57;
+/// Low 16 bit GOT entry
+pub const R_M32R_GOT16_LO: u32 = 58;
+/// High 16 bit PC relative offset to GOT with unsigned low
+pub const R_M32R_GOTPC_HI_ULO: u32 = 59;
+/// High 16 bit PC relative offset to GOT with signed low
+pub const R_M32R_GOTPC_HI_SLO: u32 = 60;
+/// Low 16 bit PC relative offset to GOT
+pub const R_M32R_GOTPC_LO: u32 = 61;
+/// High 16 bit offset to GOT with unsigned low
+pub const R_M32R_GOTOFF_HI_ULO: u32 = 62;
+/// High 16 bit offset to GOT with signed low
+pub const R_M32R_GOTOFF_HI_SLO: u32 = 63;
+/// Low 16 bit offset to GOT
+pub const R_M32R_GOTOFF_LO: u32 = 64;
+/// Keep this the last entry.
+pub const R_M32R_NUM: u32 = 256;
+
+// MicroBlaze values `Rel*::r_type`.
+/// No reloc.
+pub const R_MICROBLAZE_NONE: u32 = 0;
+/// Direct 32 bit.
+pub const R_MICROBLAZE_32: u32 = 1;
+/// PC relative 32 bit.
+pub const R_MICROBLAZE_32_PCREL: u32 = 2;
+/// PC relative 64 bit.
+pub const R_MICROBLAZE_64_PCREL: u32 = 3;
+/// Low 16 bits of PCREL32.
+pub const R_MICROBLAZE_32_PCREL_LO: u32 = 4;
+/// Direct 64 bit.
+pub const R_MICROBLAZE_64: u32 = 5;
+/// Low 16 bit.
+pub const R_MICROBLAZE_32_LO: u32 = 6;
+/// Read-only small data area.
+pub const R_MICROBLAZE_SRO32: u32 = 7;
+/// Read-write small data area.
+pub const R_MICROBLAZE_SRW32: u32 = 8;
+/// No reloc.
+pub const R_MICROBLAZE_64_NONE: u32 = 9;
+/// Symbol Op Symbol relocation.
+pub const R_MICROBLAZE_32_SYM_OP_SYM: u32 = 10;
+/// GNU C++ vtable hierarchy.
+pub const R_MICROBLAZE_GNU_VTINHERIT: u32 = 11;
+/// GNU C++ vtable member usage.
+pub const R_MICROBLAZE_GNU_VTENTRY: u32 = 12;
+/// PC-relative GOT offset.
+pub const R_MICROBLAZE_GOTPC_64: u32 = 13;
+/// GOT entry offset.
+pub const R_MICROBLAZE_GOT_64: u32 = 14;
+/// PLT offset (PC-relative).
+pub const R_MICROBLAZE_PLT_64: u32 = 15;
+/// Adjust by program base.
+pub const R_MICROBLAZE_REL: u32 = 16;
+/// Create PLT entry.
+pub const R_MICROBLAZE_JUMP_SLOT: u32 = 17;
+/// Create GOT entry.
+pub const R_MICROBLAZE_GLOB_DAT: u32 = 18;
+/// 64 bit offset to GOT.
+pub const R_MICROBLAZE_GOTOFF_64: u32 = 19;
+/// 32 bit offset to GOT.
+pub const R_MICROBLAZE_GOTOFF_32: u32 = 20;
+/// Runtime copy.
+pub const R_MICROBLAZE_COPY: u32 = 21;
+/// TLS Reloc.
+pub const R_MICROBLAZE_TLS: u32 = 22;
+/// TLS General Dynamic.
+pub const R_MICROBLAZE_TLSGD: u32 = 23;
+/// TLS Local Dynamic.
+pub const R_MICROBLAZE_TLSLD: u32 = 24;
+/// TLS Module ID.
+pub const R_MICROBLAZE_TLSDTPMOD32: u32 = 25;
+/// TLS Offset Within TLS Block.
+pub const R_MICROBLAZE_TLSDTPREL32: u32 = 26;
+/// TLS Offset Within TLS Block.
+pub const R_MICROBLAZE_TLSDTPREL64: u32 = 27;
+/// TLS Offset From Thread Pointer.
+pub const R_MICROBLAZE_TLSGOTTPREL32: u32 = 28;
+/// TLS Offset From Thread Pointer.
+pub const R_MICROBLAZE_TLSTPREL32: u32 = 29;
+
+// Nios II values `Dyn::d_tag`.
+/// Address of _gp.
+pub const DT_NIOS2_GP: u32 = 0x7000_0002;
+
+// Nios II values `Rel*::r_type`.
+/// No reloc.
+pub const R_NIOS2_NONE: u32 = 0;
+/// Direct signed 16 bit.
+pub const R_NIOS2_S16: u32 = 1;
+/// Direct unsigned 16 bit.
+pub const R_NIOS2_U16: u32 = 2;
+/// PC relative 16 bit.
+pub const R_NIOS2_PCREL16: u32 = 3;
+/// Direct call.
+pub const R_NIOS2_CALL26: u32 = 4;
+/// 5 bit constant expression.
+pub const R_NIOS2_IMM5: u32 = 5;
+/// 5 bit expression, shift 22.
+pub const R_NIOS2_CACHE_OPX: u32 = 6;
+/// 6 bit constant expression.
+pub const R_NIOS2_IMM6: u32 = 7;
+/// 8 bit constant expression.
+pub const R_NIOS2_IMM8: u32 = 8;
+/// High 16 bit.
+pub const R_NIOS2_HI16: u32 = 9;
+/// Low 16 bit.
+pub const R_NIOS2_LO16: u32 = 10;
+/// High 16 bit, adjusted.
+pub const R_NIOS2_HIADJ16: u32 = 11;
+/// 32 bit symbol value + addend.
+pub const R_NIOS2_BFD_RELOC_32: u32 = 12;
+/// 16 bit symbol value + addend.
+pub const R_NIOS2_BFD_RELOC_16: u32 = 13;
+/// 8 bit symbol value + addend.
+pub const R_NIOS2_BFD_RELOC_8: u32 = 14;
+/// 16 bit GP pointer offset.
+pub const R_NIOS2_GPREL: u32 = 15;
+/// GNU C++ vtable hierarchy.
+pub const R_NIOS2_GNU_VTINHERIT: u32 = 16;
+/// GNU C++ vtable member usage.
+pub const R_NIOS2_GNU_VTENTRY: u32 = 17;
+/// Unconditional branch.
+pub const R_NIOS2_UJMP: u32 = 18;
+/// Conditional branch.
+pub const R_NIOS2_CJMP: u32 = 19;
+/// Indirect call through register.
+pub const R_NIOS2_CALLR: u32 = 20;
+/// Alignment requirement for linker relaxation.
+pub const R_NIOS2_ALIGN: u32 = 21;
+/// 16 bit GOT entry.
+pub const R_NIOS2_GOT16: u32 = 22;
+/// 16 bit GOT entry for function.
+pub const R_NIOS2_CALL16: u32 = 23;
+/// %lo of offset to GOT pointer.
+pub const R_NIOS2_GOTOFF_LO: u32 = 24;
+/// %hiadj of offset to GOT pointer.
+pub const R_NIOS2_GOTOFF_HA: u32 = 25;
+/// %lo of PC relative offset.
+pub const R_NIOS2_PCREL_LO: u32 = 26;
+/// %hiadj of PC relative offset.
+pub const R_NIOS2_PCREL_HA: u32 = 27;
+/// 16 bit GOT offset for TLS GD.
+pub const R_NIOS2_TLS_GD16: u32 = 28;
+/// 16 bit GOT offset for TLS LDM.
+pub const R_NIOS2_TLS_LDM16: u32 = 29;
+/// 16 bit module relative offset.
+pub const R_NIOS2_TLS_LDO16: u32 = 30;
+/// 16 bit GOT offset for TLS IE.
+pub const R_NIOS2_TLS_IE16: u32 = 31;
+/// 16 bit LE TP-relative offset.
+pub const R_NIOS2_TLS_LE16: u32 = 32;
+/// Module number.
+pub const R_NIOS2_TLS_DTPMOD: u32 = 33;
+/// Module-relative offset.
+pub const R_NIOS2_TLS_DTPREL: u32 = 34;
+/// TP-relative offset.
+pub const R_NIOS2_TLS_TPREL: u32 = 35;
+/// Copy symbol at runtime.
+pub const R_NIOS2_COPY: u32 = 36;
+/// Create GOT entry.
+pub const R_NIOS2_GLOB_DAT: u32 = 37;
+/// Create PLT entry.
+pub const R_NIOS2_JUMP_SLOT: u32 = 38;
+/// Adjust by program base.
+pub const R_NIOS2_RELATIVE: u32 = 39;
+/// 16 bit offset to GOT pointer.
+pub const R_NIOS2_GOTOFF: u32 = 40;
+/// Direct call in .noat section.
+pub const R_NIOS2_CALL26_NOAT: u32 = 41;
+/// %lo() of GOT entry.
+pub const R_NIOS2_GOT_LO: u32 = 42;
+/// %hiadj() of GOT entry.
+pub const R_NIOS2_GOT_HA: u32 = 43;
+/// %lo() of function GOT entry.
+pub const R_NIOS2_CALL_LO: u32 = 44;
+/// %hiadj() of function GOT entry.
+pub const R_NIOS2_CALL_HA: u32 = 45;
+
+// TILEPro values `Rel*::r_type`.
+/// No reloc
+pub const R_TILEPRO_NONE: u32 = 0;
+/// Direct 32 bit
+pub const R_TILEPRO_32: u32 = 1;
+/// Direct 16 bit
+pub const R_TILEPRO_16: u32 = 2;
+/// Direct 8 bit
+pub const R_TILEPRO_8: u32 = 3;
+/// PC relative 32 bit
+pub const R_TILEPRO_32_PCREL: u32 = 4;
+/// PC relative 16 bit
+pub const R_TILEPRO_16_PCREL: u32 = 5;
+/// PC relative 8 bit
+pub const R_TILEPRO_8_PCREL: u32 = 6;
+/// Low 16 bit
+pub const R_TILEPRO_LO16: u32 = 7;
+/// High 16 bit
+pub const R_TILEPRO_HI16: u32 = 8;
+/// High 16 bit, adjusted
+pub const R_TILEPRO_HA16: u32 = 9;
+/// Copy relocation
+pub const R_TILEPRO_COPY: u32 = 10;
+/// Create GOT entry
+pub const R_TILEPRO_GLOB_DAT: u32 = 11;
+/// Create PLT entry
+pub const R_TILEPRO_JMP_SLOT: u32 = 12;
+/// Adjust by program base
+pub const R_TILEPRO_RELATIVE: u32 = 13;
+/// X1 pipe branch offset
+pub const R_TILEPRO_BROFF_X1: u32 = 14;
+/// X1 pipe jump offset
+pub const R_TILEPRO_JOFFLONG_X1: u32 = 15;
+/// X1 pipe jump offset to PLT
+pub const R_TILEPRO_JOFFLONG_X1_PLT: u32 = 16;
+/// X0 pipe 8-bit
+pub const R_TILEPRO_IMM8_X0: u32 = 17;
+/// Y0 pipe 8-bit
+pub const R_TILEPRO_IMM8_Y0: u32 = 18;
+/// X1 pipe 8-bit
+pub const R_TILEPRO_IMM8_X1: u32 = 19;
+/// Y1 pipe 8-bit
+pub const R_TILEPRO_IMM8_Y1: u32 = 20;
+/// X1 pipe mtspr
+pub const R_TILEPRO_MT_IMM15_X1: u32 = 21;
+/// X1 pipe mfspr
+pub const R_TILEPRO_MF_IMM15_X1: u32 = 22;
+/// X0 pipe 16-bit
+pub const R_TILEPRO_IMM16_X0: u32 = 23;
+/// X1 pipe 16-bit
+pub const R_TILEPRO_IMM16_X1: u32 = 24;
+/// X0 pipe low 16-bit
+pub const R_TILEPRO_IMM16_X0_LO: u32 = 25;
+/// X1 pipe low 16-bit
+pub const R_TILEPRO_IMM16_X1_LO: u32 = 26;
+/// X0 pipe high 16-bit
+pub const R_TILEPRO_IMM16_X0_HI: u32 = 27;
+/// X1 pipe high 16-bit
+pub const R_TILEPRO_IMM16_X1_HI: u32 = 28;
+/// X0 pipe high 16-bit, adjusted
+pub const R_TILEPRO_IMM16_X0_HA: u32 = 29;
+/// X1 pipe high 16-bit, adjusted
+pub const R_TILEPRO_IMM16_X1_HA: u32 = 30;
+/// X0 pipe PC relative 16 bit
+pub const R_TILEPRO_IMM16_X0_PCREL: u32 = 31;
+/// X1 pipe PC relative 16 bit
+pub const R_TILEPRO_IMM16_X1_PCREL: u32 = 32;
+/// X0 pipe PC relative low 16 bit
+pub const R_TILEPRO_IMM16_X0_LO_PCREL: u32 = 33;
+/// X1 pipe PC relative low 16 bit
+pub const R_TILEPRO_IMM16_X1_LO_PCREL: u32 = 34;
+/// X0 pipe PC relative high 16 bit
+pub const R_TILEPRO_IMM16_X0_HI_PCREL: u32 = 35;
+/// X1 pipe PC relative high 16 bit
+pub const R_TILEPRO_IMM16_X1_HI_PCREL: u32 = 36;
+/// X0 pipe PC relative ha() 16 bit
+pub const R_TILEPRO_IMM16_X0_HA_PCREL: u32 = 37;
+/// X1 pipe PC relative ha() 16 bit
+pub const R_TILEPRO_IMM16_X1_HA_PCREL: u32 = 38;
+/// X0 pipe 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X0_GOT: u32 = 39;
+/// X1 pipe 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X1_GOT: u32 = 40;
+/// X0 pipe low 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X0_GOT_LO: u32 = 41;
+/// X1 pipe low 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X1_GOT_LO: u32 = 42;
+/// X0 pipe high 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X0_GOT_HI: u32 = 43;
+/// X1 pipe high 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X1_GOT_HI: u32 = 44;
+/// X0 pipe ha() 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X0_GOT_HA: u32 = 45;
+/// X1 pipe ha() 16-bit GOT offset
+pub const R_TILEPRO_IMM16_X1_GOT_HA: u32 = 46;
+/// X0 pipe mm "start"
+pub const R_TILEPRO_MMSTART_X0: u32 = 47;
+/// X0 pipe mm "end"
+pub const R_TILEPRO_MMEND_X0: u32 = 48;
+/// X1 pipe mm "start"
+pub const R_TILEPRO_MMSTART_X1: u32 = 49;
+/// X1 pipe mm "end"
+pub const R_TILEPRO_MMEND_X1: u32 = 50;
+/// X0 pipe shift amount
+pub const R_TILEPRO_SHAMT_X0: u32 = 51;
+/// X1 pipe shift amount
+pub const R_TILEPRO_SHAMT_X1: u32 = 52;
+/// Y0 pipe shift amount
+pub const R_TILEPRO_SHAMT_Y0: u32 = 53;
+/// Y1 pipe shift amount
+pub const R_TILEPRO_SHAMT_Y1: u32 = 54;
+/// X1 pipe destination 8-bit
+pub const R_TILEPRO_DEST_IMM8_X1: u32 = 55;
+// Relocs 56-59 are currently not defined.
+/// "jal" for TLS GD
+pub const R_TILEPRO_TLS_GD_CALL: u32 = 60;
+/// X0 pipe "addi" for TLS GD
+pub const R_TILEPRO_IMM8_X0_TLS_GD_ADD: u32 = 61;
+/// X1 pipe "addi" for TLS GD
+pub const R_TILEPRO_IMM8_X1_TLS_GD_ADD: u32 = 62;
+/// Y0 pipe "addi" for TLS GD
+pub const R_TILEPRO_IMM8_Y0_TLS_GD_ADD: u32 = 63;
+/// Y1 pipe "addi" for TLS GD
+pub const R_TILEPRO_IMM8_Y1_TLS_GD_ADD: u32 = 64;
+/// "lw_tls" for TLS IE
+pub const R_TILEPRO_TLS_IE_LOAD: u32 = 65;
+/// X0 pipe 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X0_TLS_GD: u32 = 66;
+/// X1 pipe 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X1_TLS_GD: u32 = 67;
+/// X0 pipe low 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X0_TLS_GD_LO: u32 = 68;
+/// X1 pipe low 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X1_TLS_GD_LO: u32 = 69;
+/// X0 pipe high 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X0_TLS_GD_HI: u32 = 70;
+/// X1 pipe high 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X1_TLS_GD_HI: u32 = 71;
+/// X0 pipe ha() 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X0_TLS_GD_HA: u32 = 72;
+/// X1 pipe ha() 16-bit TLS GD offset
+pub const R_TILEPRO_IMM16_X1_TLS_GD_HA: u32 = 73;
+/// X0 pipe 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X0_TLS_IE: u32 = 74;
+/// X1 pipe 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X1_TLS_IE: u32 = 75;
+/// X0 pipe low 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X0_TLS_IE_LO: u32 = 76;
+/// X1 pipe low 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X1_TLS_IE_LO: u32 = 77;
+/// X0 pipe high 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X0_TLS_IE_HI: u32 = 78;
+/// X1 pipe high 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X1_TLS_IE_HI: u32 = 79;
+/// X0 pipe ha() 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X0_TLS_IE_HA: u32 = 80;
+/// X1 pipe ha() 16-bit TLS IE offset
+pub const R_TILEPRO_IMM16_X1_TLS_IE_HA: u32 = 81;
+/// ID of module containing symbol
+pub const R_TILEPRO_TLS_DTPMOD32: u32 = 82;
+/// Offset in TLS block
+pub const R_TILEPRO_TLS_DTPOFF32: u32 = 83;
+/// Offset in static TLS block
+pub const R_TILEPRO_TLS_TPOFF32: u32 = 84;
+/// X0 pipe 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X0_TLS_LE: u32 = 85;
+/// X1 pipe 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X1_TLS_LE: u32 = 86;
+/// X0 pipe low 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X0_TLS_LE_LO: u32 = 87;
+/// X1 pipe low 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X1_TLS_LE_LO: u32 = 88;
+/// X0 pipe high 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X0_TLS_LE_HI: u32 = 89;
+/// X1 pipe high 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X1_TLS_LE_HI: u32 = 90;
+/// X0 pipe ha() 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X0_TLS_LE_HA: u32 = 91;
+/// X1 pipe ha() 16-bit TLS LE offset
+pub const R_TILEPRO_IMM16_X1_TLS_LE_HA: u32 = 92;
+
+/// GNU C++ vtable hierarchy
+pub const R_TILEPRO_GNU_VTINHERIT: u32 = 128;
+/// GNU C++ vtable member usage
+pub const R_TILEPRO_GNU_VTENTRY: u32 = 129;
+
+// TILE-Gx values `Rel*::r_type`.
+/// No reloc
+pub const R_TILEGX_NONE: u32 = 0;
+/// Direct 64 bit
+pub const R_TILEGX_64: u32 = 1;
+/// Direct 32 bit
+pub const R_TILEGX_32: u32 = 2;
+/// Direct 16 bit
+pub const R_TILEGX_16: u32 = 3;
+/// Direct 8 bit
+pub const R_TILEGX_8: u32 = 4;
+/// PC relative 64 bit
+pub const R_TILEGX_64_PCREL: u32 = 5;
+/// PC relative 32 bit
+pub const R_TILEGX_32_PCREL: u32 = 6;
+/// PC relative 16 bit
+pub const R_TILEGX_16_PCREL: u32 = 7;
+/// PC relative 8 bit
+pub const R_TILEGX_8_PCREL: u32 = 8;
+/// hword 0 16-bit
+pub const R_TILEGX_HW0: u32 = 9;
+/// hword 1 16-bit
+pub const R_TILEGX_HW1: u32 = 10;
+/// hword 2 16-bit
+pub const R_TILEGX_HW2: u32 = 11;
+/// hword 3 16-bit
+pub const R_TILEGX_HW3: u32 = 12;
+/// last hword 0 16-bit
+pub const R_TILEGX_HW0_LAST: u32 = 13;
+/// last hword 1 16-bit
+pub const R_TILEGX_HW1_LAST: u32 = 14;
+/// last hword 2 16-bit
+pub const R_TILEGX_HW2_LAST: u32 = 15;
+/// Copy relocation
+pub const R_TILEGX_COPY: u32 = 16;
+/// Create GOT entry
+pub const R_TILEGX_GLOB_DAT: u32 = 17;
+/// Create PLT entry
+pub const R_TILEGX_JMP_SLOT: u32 = 18;
+/// Adjust by program base
+pub const R_TILEGX_RELATIVE: u32 = 19;
+/// X1 pipe branch offset
+pub const R_TILEGX_BROFF_X1: u32 = 20;
+/// X1 pipe jump offset
+pub const R_TILEGX_JUMPOFF_X1: u32 = 21;
+/// X1 pipe jump offset to PLT
+pub const R_TILEGX_JUMPOFF_X1_PLT: u32 = 22;
+/// X0 pipe 8-bit
+pub const R_TILEGX_IMM8_X0: u32 = 23;
+/// Y0 pipe 8-bit
+pub const R_TILEGX_IMM8_Y0: u32 = 24;
+/// X1 pipe 8-bit
+pub const R_TILEGX_IMM8_X1: u32 = 25;
+/// Y1 pipe 8-bit
+pub const R_TILEGX_IMM8_Y1: u32 = 26;
+/// X1 pipe destination 8-bit
+pub const R_TILEGX_DEST_IMM8_X1: u32 = 27;
+/// X1 pipe mtspr
+pub const R_TILEGX_MT_IMM14_X1: u32 = 28;
+/// X1 pipe mfspr
+pub const R_TILEGX_MF_IMM14_X1: u32 = 29;
+/// X0 pipe mm "start"
+pub const R_TILEGX_MMSTART_X0: u32 = 30;
+/// X0 pipe mm "end"
+pub const R_TILEGX_MMEND_X0: u32 = 31;
+/// X0 pipe shift amount
+pub const R_TILEGX_SHAMT_X0: u32 = 32;
+/// X1 pipe shift amount
+pub const R_TILEGX_SHAMT_X1: u32 = 33;
+/// Y0 pipe shift amount
+pub const R_TILEGX_SHAMT_Y0: u32 = 34;
+/// Y1 pipe shift amount
+pub const R_TILEGX_SHAMT_Y1: u32 = 35;
+/// X0 pipe hword 0
+pub const R_TILEGX_IMM16_X0_HW0: u32 = 36;
+/// X1 pipe hword 0
+pub const R_TILEGX_IMM16_X1_HW0: u32 = 37;
+/// X0 pipe hword 1
+pub const R_TILEGX_IMM16_X0_HW1: u32 = 38;
+/// X1 pipe hword 1
+pub const R_TILEGX_IMM16_X1_HW1: u32 = 39;
+/// X0 pipe hword 2
+pub const R_TILEGX_IMM16_X0_HW2: u32 = 40;
+/// X1 pipe hword 2
+pub const R_TILEGX_IMM16_X1_HW2: u32 = 41;
+/// X0 pipe hword 3
+pub const R_TILEGX_IMM16_X0_HW3: u32 = 42;
+/// X1 pipe hword 3
+pub const R_TILEGX_IMM16_X1_HW3: u32 = 43;
+/// X0 pipe last hword 0
+pub const R_TILEGX_IMM16_X0_HW0_LAST: u32 = 44;
+/// X1 pipe last hword 0
+pub const R_TILEGX_IMM16_X1_HW0_LAST: u32 = 45;
+/// X0 pipe last hword 1
+pub const R_TILEGX_IMM16_X0_HW1_LAST: u32 = 46;
+/// X1 pipe last hword 1
+pub const R_TILEGX_IMM16_X1_HW1_LAST: u32 = 47;
+/// X0 pipe last hword 2
+pub const R_TILEGX_IMM16_X0_HW2_LAST: u32 = 48;
+/// X1 pipe last hword 2
+pub const R_TILEGX_IMM16_X1_HW2_LAST: u32 = 49;
+/// X0 pipe PC relative hword 0
+pub const R_TILEGX_IMM16_X0_HW0_PCREL: u32 = 50;
+/// X1 pipe PC relative hword 0
+pub const R_TILEGX_IMM16_X1_HW0_PCREL: u32 = 51;
+/// X0 pipe PC relative hword 1
+pub const R_TILEGX_IMM16_X0_HW1_PCREL: u32 = 52;
+/// X1 pipe PC relative hword 1
+pub const R_TILEGX_IMM16_X1_HW1_PCREL: u32 = 53;
+/// X0 pipe PC relative hword 2
+pub const R_TILEGX_IMM16_X0_HW2_PCREL: u32 = 54;
+/// X1 pipe PC relative hword 2
+pub const R_TILEGX_IMM16_X1_HW2_PCREL: u32 = 55;
+/// X0 pipe PC relative hword 3
+pub const R_TILEGX_IMM16_X0_HW3_PCREL: u32 = 56;
+/// X1 pipe PC relative hword 3
+pub const R_TILEGX_IMM16_X1_HW3_PCREL: u32 = 57;
+/// X0 pipe PC-rel last hword 0
+pub const R_TILEGX_IMM16_X0_HW0_LAST_PCREL: u32 = 58;
+/// X1 pipe PC-rel last hword 0
+pub const R_TILEGX_IMM16_X1_HW0_LAST_PCREL: u32 = 59;
+/// X0 pipe PC-rel last hword 1
+pub const R_TILEGX_IMM16_X0_HW1_LAST_PCREL: u32 = 60;
+/// X1 pipe PC-rel last hword 1
+pub const R_TILEGX_IMM16_X1_HW1_LAST_PCREL: u32 = 61;
+/// X0 pipe PC-rel last hword 2
+pub const R_TILEGX_IMM16_X0_HW2_LAST_PCREL: u32 = 62;
+/// X1 pipe PC-rel last hword 2
+pub const R_TILEGX_IMM16_X1_HW2_LAST_PCREL: u32 = 63;
+/// X0 pipe hword 0 GOT offset
+pub const R_TILEGX_IMM16_X0_HW0_GOT: u32 = 64;
+/// X1 pipe hword 0 GOT offset
+pub const R_TILEGX_IMM16_X1_HW0_GOT: u32 = 65;
+/// X0 pipe PC-rel PLT hword 0
+pub const R_TILEGX_IMM16_X0_HW0_PLT_PCREL: u32 = 66;
+/// X1 pipe PC-rel PLT hword 0
+pub const R_TILEGX_IMM16_X1_HW0_PLT_PCREL: u32 = 67;
+/// X0 pipe PC-rel PLT hword 1
+pub const R_TILEGX_IMM16_X0_HW1_PLT_PCREL: u32 = 68;
+/// X1 pipe PC-rel PLT hword 1
+pub const R_TILEGX_IMM16_X1_HW1_PLT_PCREL: u32 = 69;
+/// X0 pipe PC-rel PLT hword 2
+pub const R_TILEGX_IMM16_X0_HW2_PLT_PCREL: u32 = 70;
+/// X1 pipe PC-rel PLT hword 2
+pub const R_TILEGX_IMM16_X1_HW2_PLT_PCREL: u32 = 71;
+/// X0 pipe last hword 0 GOT offset
+pub const R_TILEGX_IMM16_X0_HW0_LAST_GOT: u32 = 72;
+/// X1 pipe last hword 0 GOT offset
+pub const R_TILEGX_IMM16_X1_HW0_LAST_GOT: u32 = 73;
+/// X0 pipe last hword 1 GOT offset
+pub const R_TILEGX_IMM16_X0_HW1_LAST_GOT: u32 = 74;
+/// X1 pipe last hword 1 GOT offset
+pub const R_TILEGX_IMM16_X1_HW1_LAST_GOT: u32 = 75;
+/// X0 pipe PC-rel PLT hword 3
+pub const R_TILEGX_IMM16_X0_HW3_PLT_PCREL: u32 = 76;
+/// X1 pipe PC-rel PLT hword 3
+pub const R_TILEGX_IMM16_X1_HW3_PLT_PCREL: u32 = 77;
+/// X0 pipe hword 0 TLS GD offset
+pub const R_TILEGX_IMM16_X0_HW0_TLS_GD: u32 = 78;
+/// X1 pipe hword 0 TLS GD offset
+pub const R_TILEGX_IMM16_X1_HW0_TLS_GD: u32 = 79;
+/// X0 pipe hword 0 TLS LE offset
+pub const R_TILEGX_IMM16_X0_HW0_TLS_LE: u32 = 80;
+/// X1 pipe hword 0 TLS LE offset
+pub const R_TILEGX_IMM16_X1_HW0_TLS_LE: u32 = 81;
+/// X0 pipe last hword 0 LE off
+pub const R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE: u32 = 82;
+/// X1 pipe last hword 0 LE off
+pub const R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE: u32 = 83;
+/// X0 pipe last hword 1 LE off
+pub const R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE: u32 = 84;
+/// X1 pipe last hword 1 LE off
+pub const R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE: u32 = 85;
+/// X0 pipe last hword 0 GD off
+pub const R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: u32 = 86;
+/// X1 pipe last hword 0 GD off
+pub const R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: u32 = 87;
+/// X0 pipe last hword 1 GD off
+pub const R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: u32 = 88;
+/// X1 pipe last hword 1 GD off
+pub const R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: u32 = 89;
+// Relocs 90-91 are currently not defined.
+/// X0 pipe hword 0 TLS IE offset
+pub const R_TILEGX_IMM16_X0_HW0_TLS_IE: u32 = 92;
+/// X1 pipe hword 0 TLS IE offset
+pub const R_TILEGX_IMM16_X1_HW0_TLS_IE: u32 = 93;
+/// X0 pipe PC-rel PLT last hword 0
+pub const R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL: u32 = 94;
+/// X1 pipe PC-rel PLT last hword 0
+pub const R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL: u32 = 95;
+/// X0 pipe PC-rel PLT last hword 1
+pub const R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL: u32 = 96;
+/// X1 pipe PC-rel PLT last hword 1
+pub const R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL: u32 = 97;
+/// X0 pipe PC-rel PLT last hword 2
+pub const R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL: u32 = 98;
+/// X1 pipe PC-rel PLT last hword 2
+pub const R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL: u32 = 99;
+/// X0 pipe last hword 0 IE off
+pub const R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: u32 = 100;
+/// X1 pipe last hword 0 IE off
+pub const R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: u32 = 101;
+/// X0 pipe last hword 1 IE off
+pub const R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: u32 = 102;
+/// X1 pipe last hword 1 IE off
+pub const R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: u32 = 103;
+// Relocs 104-105 are currently not defined.
+/// 64-bit ID of symbol's module
+pub const R_TILEGX_TLS_DTPMOD64: u32 = 106;
+/// 64-bit offset in TLS block
+pub const R_TILEGX_TLS_DTPOFF64: u32 = 107;
+/// 64-bit offset in static TLS block
+pub const R_TILEGX_TLS_TPOFF64: u32 = 108;
+/// 32-bit ID of symbol's module
+pub const R_TILEGX_TLS_DTPMOD32: u32 = 109;
+/// 32-bit offset in TLS block
+pub const R_TILEGX_TLS_DTPOFF32: u32 = 110;
+/// 32-bit offset in static TLS block
+pub const R_TILEGX_TLS_TPOFF32: u32 = 111;
+/// "jal" for TLS GD
+pub const R_TILEGX_TLS_GD_CALL: u32 = 112;
+/// X0 pipe "addi" for TLS GD
+pub const R_TILEGX_IMM8_X0_TLS_GD_ADD: u32 = 113;
+/// X1 pipe "addi" for TLS GD
+pub const R_TILEGX_IMM8_X1_TLS_GD_ADD: u32 = 114;
+/// Y0 pipe "addi" for TLS GD
+pub const R_TILEGX_IMM8_Y0_TLS_GD_ADD: u32 = 115;
+/// Y1 pipe "addi" for TLS GD
+pub const R_TILEGX_IMM8_Y1_TLS_GD_ADD: u32 = 116;
+/// "ld_tls" for TLS IE
+pub const R_TILEGX_TLS_IE_LOAD: u32 = 117;
+/// X0 pipe "addi" for TLS GD/IE
+pub const R_TILEGX_IMM8_X0_TLS_ADD: u32 = 118;
+/// X1 pipe "addi" for TLS GD/IE
+pub const R_TILEGX_IMM8_X1_TLS_ADD: u32 = 119;
+/// Y0 pipe "addi" for TLS GD/IE
+pub const R_TILEGX_IMM8_Y0_TLS_ADD: u32 = 120;
+/// Y1 pipe "addi" for TLS GD/IE
+pub const R_TILEGX_IMM8_Y1_TLS_ADD: u32 = 121;
+
+/// GNU C++ vtable hierarchy
+pub const R_TILEGX_GNU_VTINHERIT: u32 = 128;
+/// GNU C++ vtable member usage
+pub const R_TILEGX_GNU_VTENTRY: u32 = 129;
+
+// RISC-V values `FileHeader*::e_flags`.
+pub const EF_RISCV_RVC: u32 = 0x0001;
+pub const EF_RISCV_FLOAT_ABI: u32 = 0x0006;
+pub const EF_RISCV_FLOAT_ABI_SOFT: u32 = 0x0000;
+pub const EF_RISCV_FLOAT_ABI_SINGLE: u32 = 0x0002;
+pub const EF_RISCV_FLOAT_ABI_DOUBLE: u32 = 0x0004;
+pub const EF_RISCV_FLOAT_ABI_QUAD: u32 = 0x0006;
+pub const EF_RISCV_RVE: u32 = 0x0008;
+pub const EF_RISCV_TSO: u32 = 0x0010;
+
+// RISC-V values `Rel*::r_type`.
+pub const R_RISCV_NONE: u32 = 0;
+pub const R_RISCV_32: u32 = 1;
+pub const R_RISCV_64: u32 = 2;
+pub const R_RISCV_RELATIVE: u32 = 3;
+pub const R_RISCV_COPY: u32 = 4;
+pub const R_RISCV_JUMP_SLOT: u32 = 5;
+pub const R_RISCV_TLS_DTPMOD32: u32 = 6;
+pub const R_RISCV_TLS_DTPMOD64: u32 = 7;
+pub const R_RISCV_TLS_DTPREL32: u32 = 8;
+pub const R_RISCV_TLS_DTPREL64: u32 = 9;
+pub const R_RISCV_TLS_TPREL32: u32 = 10;
+pub const R_RISCV_TLS_TPREL64: u32 = 11;
+pub const R_RISCV_BRANCH: u32 = 16;
+pub const R_RISCV_JAL: u32 = 17;
+pub const R_RISCV_CALL: u32 = 18;
+pub const R_RISCV_CALL_PLT: u32 = 19;
+pub const R_RISCV_GOT_HI20: u32 = 20;
+pub const R_RISCV_TLS_GOT_HI20: u32 = 21;
+pub const R_RISCV_TLS_GD_HI20: u32 = 22;
+pub const R_RISCV_PCREL_HI20: u32 = 23;
+pub const R_RISCV_PCREL_LO12_I: u32 = 24;
+pub const R_RISCV_PCREL_LO12_S: u32 = 25;
+pub const R_RISCV_HI20: u32 = 26;
+pub const R_RISCV_LO12_I: u32 = 27;
+pub const R_RISCV_LO12_S: u32 = 28;
+pub const R_RISCV_TPREL_HI20: u32 = 29;
+pub const R_RISCV_TPREL_LO12_I: u32 = 30;
+pub const R_RISCV_TPREL_LO12_S: u32 = 31;
+pub const R_RISCV_TPREL_ADD: u32 = 32;
+pub const R_RISCV_ADD8: u32 = 33;
+pub const R_RISCV_ADD16: u32 = 34;
+pub const R_RISCV_ADD32: u32 = 35;
+pub const R_RISCV_ADD64: u32 = 36;
+pub const R_RISCV_SUB8: u32 = 37;
+pub const R_RISCV_SUB16: u32 = 38;
+pub const R_RISCV_SUB32: u32 = 39;
+pub const R_RISCV_SUB64: u32 = 40;
+pub const R_RISCV_GNU_VTINHERIT: u32 = 41;
+pub const R_RISCV_GNU_VTENTRY: u32 = 42;
+pub const R_RISCV_ALIGN: u32 = 43;
+pub const R_RISCV_RVC_BRANCH: u32 = 44;
+pub const R_RISCV_RVC_JUMP: u32 = 45;
+pub const R_RISCV_RVC_LUI: u32 = 46;
+pub const R_RISCV_GPREL_I: u32 = 47;
+pub const R_RISCV_GPREL_S: u32 = 48;
+pub const R_RISCV_TPREL_I: u32 = 49;
+pub const R_RISCV_TPREL_S: u32 = 50;
+pub const R_RISCV_RELAX: u32 = 51;
+pub const R_RISCV_SUB6: u32 = 52;
+pub const R_RISCV_SET6: u32 = 53;
+pub const R_RISCV_SET8: u32 = 54;
+pub const R_RISCV_SET16: u32 = 55;
+pub const R_RISCV_SET32: u32 = 56;
+pub const R_RISCV_32_PCREL: u32 = 57;
+
+// BPF values `Rel*::r_type`.
+/// No reloc
+pub const R_BPF_NONE: u32 = 0;
+pub const R_BPF_64_64: u32 = 1;
+pub const R_BPF_64_32: u32 = 10;
+
+// SBF values `Rel*::r_type`.
+/// No reloc
+pub const R_SBF_NONE: u32 = 0;
+pub const R_SBF_64_64: u32 = 1;
+pub const R_SBF_64_32: u32 = 10;
+
+// Imagination Meta values `Rel*::r_type`.
+
+pub const R_METAG_HIADDR16: u32 = 0;
+pub const R_METAG_LOADDR16: u32 = 1;
+/// 32bit absolute address
+pub const R_METAG_ADDR32: u32 = 2;
+/// No reloc
+pub const R_METAG_NONE: u32 = 3;
+pub const R_METAG_RELBRANCH: u32 = 4;
+pub const R_METAG_GETSETOFF: u32 = 5;
+
+// Backward compatibility
+pub const R_METAG_REG32OP1: u32 = 6;
+pub const R_METAG_REG32OP2: u32 = 7;
+pub const R_METAG_REG32OP3: u32 = 8;
+pub const R_METAG_REG16OP1: u32 = 9;
+pub const R_METAG_REG16OP2: u32 = 10;
+pub const R_METAG_REG16OP3: u32 = 11;
+pub const R_METAG_REG32OP4: u32 = 12;
+
+pub const R_METAG_HIOG: u32 = 13;
+pub const R_METAG_LOOG: u32 = 14;
+
+pub const R_METAG_REL8: u32 = 15;
+pub const R_METAG_REL16: u32 = 16;
+
+pub const R_METAG_GNU_VTINHERIT: u32 = 30;
+pub const R_METAG_GNU_VTENTRY: u32 = 31;
+
+// PIC relocations
+pub const R_METAG_HI16_GOTOFF: u32 = 32;
+pub const R_METAG_LO16_GOTOFF: u32 = 33;
+pub const R_METAG_GETSET_GOTOFF: u32 = 34;
+pub const R_METAG_GETSET_GOT: u32 = 35;
+pub const R_METAG_HI16_GOTPC: u32 = 36;
+pub const R_METAG_LO16_GOTPC: u32 = 37;
+pub const R_METAG_HI16_PLT: u32 = 38;
+pub const R_METAG_LO16_PLT: u32 = 39;
+pub const R_METAG_RELBRANCH_PLT: u32 = 40;
+pub const R_METAG_GOTOFF: u32 = 41;
+pub const R_METAG_PLT: u32 = 42;
+pub const R_METAG_COPY: u32 = 43;
+pub const R_METAG_JMP_SLOT: u32 = 44;
+pub const R_METAG_RELATIVE: u32 = 45;
+pub const R_METAG_GLOB_DAT: u32 = 46;
+
+// TLS relocations
+pub const R_METAG_TLS_GD: u32 = 47;
+pub const R_METAG_TLS_LDM: u32 = 48;
+pub const R_METAG_TLS_LDO_HI16: u32 = 49;
+pub const R_METAG_TLS_LDO_LO16: u32 = 50;
+pub const R_METAG_TLS_LDO: u32 = 51;
+pub const R_METAG_TLS_IE: u32 = 52;
+pub const R_METAG_TLS_IENONPIC: u32 = 53;
+pub const R_METAG_TLS_IENONPIC_HI16: u32 = 54;
+pub const R_METAG_TLS_IENONPIC_LO16: u32 = 55;
+pub const R_METAG_TLS_TPOFF: u32 = 56;
+pub const R_METAG_TLS_DTPMOD: u32 = 57;
+pub const R_METAG_TLS_DTPOFF: u32 = 58;
+pub const R_METAG_TLS_LE: u32 = 59;
+pub const R_METAG_TLS_LE_HI16: u32 = 60;
+pub const R_METAG_TLS_LE_LO16: u32 = 61;
+
+// NDS32 values `Rel*::r_type`.
+pub const R_NDS32_NONE: u32 = 0;
+pub const R_NDS32_32_RELA: u32 = 20;
+pub const R_NDS32_COPY: u32 = 39;
+pub const R_NDS32_GLOB_DAT: u32 = 40;
+pub const R_NDS32_JMP_SLOT: u32 = 41;
+pub const R_NDS32_RELATIVE: u32 = 42;
+pub const R_NDS32_TLS_TPOFF: u32 = 102;
+pub const R_NDS32_TLS_DESC: u32 = 119;
+
+// LoongArch values `FileHeader*::e_flags`.
+/// Additional properties of the base ABI type, including the FP calling
+/// convention.
+pub const EF_LARCH_ABI_MODIFIER_MASK: u32 = 0x7;
+/// Uses GPRs and the stack for parameter passing
+pub const EF_LARCH_ABI_SOFT_FLOAT: u32 = 0x1;
+/// Uses GPRs, 32-bit FPRs and the stack for parameter passing
+pub const EF_LARCH_ABI_SINGLE_FLOAT: u32 = 0x2;
+/// Uses GPRs, 64-bit FPRs and the stack for parameter passing
+pub const EF_LARCH_ABI_DOUBLE_FLOAT: u32 = 0x3;
+/// Uses relocation types directly writing to immediate slots
+pub const EF_LARCH_OBJABI_V1: u32 = 0x40;
+
+// LoongArch values `Rel*::r_type`.
+/// No reloc
+pub const R_LARCH_NONE: u32 = 0;
+/// Runtime address resolving
+pub const R_LARCH_32: u32 = 1;
+/// Runtime address resolving
+pub const R_LARCH_64: u32 = 2;
+/// Runtime fixup for load-address
+pub const R_LARCH_RELATIVE: u32 = 3;
+/// Runtime memory copy in executable
+pub const R_LARCH_COPY: u32 = 4;
+/// Runtime PLT supporting
+pub const R_LARCH_JUMP_SLOT: u32 = 5;
+/// Runtime relocation for TLS-GD
+pub const R_LARCH_TLS_DTPMOD32: u32 = 6;
+/// Runtime relocation for TLS-GD
+pub const R_LARCH_TLS_DTPMOD64: u32 = 7;
+/// Runtime relocation for TLS-GD
+pub const R_LARCH_TLS_DTPREL32: u32 = 8;
+/// Runtime relocation for TLS-GD
+pub const R_LARCH_TLS_DTPREL64: u32 = 9;
+/// Runtime relocation for TLE-IE
+pub const R_LARCH_TLS_TPREL32: u32 = 10;
+/// Runtime relocation for TLE-IE
+pub const R_LARCH_TLS_TPREL64: u32 = 11;
+/// Runtime local indirect function resolving
+pub const R_LARCH_IRELATIVE: u32 = 12;
+/// Mark la.abs: load absolute address for static link.
+pub const R_LARCH_MARK_LA: u32 = 20;
+/// Mark external label branch: access PC relative address for static link.
+pub const R_LARCH_MARK_PCREL: u32 = 21;
+/// Push PC-relative offset
+pub const R_LARCH_SOP_PUSH_PCREL: u32 = 22;
+/// Push constant or absolute address
+pub const R_LARCH_SOP_PUSH_ABSOLUTE: u32 = 23;
+/// Duplicate stack top
+pub const R_LARCH_SOP_PUSH_DUP: u32 = 24;
+/// Push for access GOT entry
+pub const R_LARCH_SOP_PUSH_GPREL: u32 = 25;
+/// Push for TLS-LE
+pub const R_LARCH_SOP_PUSH_TLS_TPREL: u32 = 26;
+/// Push for TLS-IE
+pub const R_LARCH_SOP_PUSH_TLS_GOT: u32 = 27;
+/// Push for TLS-GD
+pub const R_LARCH_SOP_PUSH_TLS_GD: u32 = 28;
+/// Push for external function calling
+pub const R_LARCH_SOP_PUSH_PLT_PCREL: u32 = 29;
+/// Assert stack top
+pub const R_LARCH_SOP_ASSERT: u32 = 30;
+/// Stack top logical not (unary)
+pub const R_LARCH_SOP_NOT: u32 = 31;
+/// Stack top subtraction (binary)
+pub const R_LARCH_SOP_SUB: u32 = 32;
+/// Stack top left shift (binary)
+pub const R_LARCH_SOP_SL: u32 = 33;
+/// Stack top right shift (binary)
+pub const R_LARCH_SOP_SR: u32 = 34;
+/// Stack top addition (binary)
+pub const R_LARCH_SOP_ADD: u32 = 35;
+/// Stack top bitwise and (binary)
+pub const R_LARCH_SOP_AND: u32 = 36;
+/// Stack top selection (tertiary)
+pub const R_LARCH_SOP_IF_ELSE: u32 = 37;
+/// Pop stack top to fill 5-bit signed immediate operand
+pub const R_LARCH_SOP_POP_32_S_10_5: u32 = 38;
+/// Pop stack top to fill 12-bit unsigned immediate operand
+pub const R_LARCH_SOP_POP_32_U_10_12: u32 = 39;
+/// Pop stack top to fill 12-bit signed immediate operand
+pub const R_LARCH_SOP_POP_32_S_10_12: u32 = 40;
+/// Pop stack top to fill 16-bit signed immediate operand
+pub const R_LARCH_SOP_POP_32_S_10_16: u32 = 41;
+/// Pop stack top to fill 18-bit signed immediate operand with two trailing
+/// zeros implied
+pub const R_LARCH_SOP_POP_32_S_10_16_S2: u32 = 42;
+/// Pop stack top to fill 20-bit signed immediate operand
+pub const R_LARCH_SOP_POP_32_S_5_20: u32 = 43;
+/// Pop stack top to fill 23-bit signed immediate operand with two trailing
+/// zeros implied
+pub const R_LARCH_SOP_POP_32_S_0_5_10_16_S2: u32 = 44;
+/// Pop stack top to fill 28-bit signed immediate operand with two trailing
+/// zeros implied
+pub const R_LARCH_SOP_POP_32_S_0_10_10_16_S2: u32 = 45;
+/// Pop stack top to fill an instruction
+pub const R_LARCH_SOP_POP_32_U: u32 = 46;
+/// 8-bit in-place addition
+pub const R_LARCH_ADD8: u32 = 47;
+/// 16-bit in-place addition
+pub const R_LARCH_ADD16: u32 = 48;
+/// 24-bit in-place addition
+pub const R_LARCH_ADD24: u32 = 49;
+/// 32-bit in-place addition
+pub const R_LARCH_ADD32: u32 = 50;
+/// 64-bit in-place addition
+pub const R_LARCH_ADD64: u32 = 51;
+/// 8-bit in-place subtraction
+pub const R_LARCH_SUB8: u32 = 52;
+/// 16-bit in-place subtraction
+pub const R_LARCH_SUB16: u32 = 53;
+/// 24-bit in-place subtraction
+pub const R_LARCH_SUB24: u32 = 54;
+/// 32-bit in-place subtraction
+pub const R_LARCH_SUB32: u32 = 55;
+/// 64-bit in-place subtraction
+pub const R_LARCH_SUB64: u32 = 56;
+/// GNU C++ vtable hierarchy
+pub const R_LARCH_GNU_VTINHERIT: u32 = 57;
+/// GNU C++ vtable member usage
+pub const R_LARCH_GNU_VTENTRY: u32 = 58;
+/// 18-bit PC-relative jump offset with two trailing zeros
+pub const R_LARCH_B16: u32 = 64;
+/// 23-bit PC-relative jump offset with two trailing zeros
+pub const R_LARCH_B21: u32 = 65;
+/// 28-bit PC-relative jump offset with two trailing zeros
+pub const R_LARCH_B26: u32 = 66;
+/// 12..=31 bits of 32/64-bit absolute address
+pub const R_LARCH_ABS_HI20: u32 = 67;
+/// 0..=11 bits of 32/64-bit absolute address
+pub const R_LARCH_ABS_LO12: u32 = 68;
+/// 32..=51 bits of 64-bit absolute address
+pub const R_LARCH_ABS64_LO20: u32 = 69;
+/// 52..=63 bits of 64-bit absolute address
+pub const R_LARCH_ABS64_HI12: u32 = 70;
+/// The signed 32-bit offset `offs` from `PC & 0xfffff000` to
+/// `(S + A + 0x800) & 0xfffff000`, with 12 trailing zeros removed.
+///
+/// We define the *PC relative anchor* for `S + A` as `PC + offs` (`offs`
+/// is sign-extended to VA bits).
+pub const R_LARCH_PCALA_HI20: u32 = 71;
+/// Same as R_LARCH_ABS_LO12. 0..=11 bits of the 32/64-bit offset from the
+/// [PC relative anchor][R_LARCH_PCALA_HI20].
+pub const R_LARCH_PCALA_LO12: u32 = 72;
+/// 32..=51 bits of the 64-bit offset from the
+/// [PC relative anchor][R_LARCH_PCALA_HI20].
+pub const R_LARCH_PCALA64_LO20: u32 = 73;
+/// 52..=63 bits of the 64-bit offset from the
+/// [PC relative anchor][R_LARCH_PCALA_HI20].
+pub const R_LARCH_PCALA64_HI12: u32 = 74;
+/// The signed 32-bit offset `offs` from `PC & 0xfffff000` to
+/// `(GP + G + 0x800) & 0xfffff000`, with 12 trailing zeros removed.
+///
+/// We define the *PC relative anchor* for the GOT entry at `GP + G` as
+/// `PC + offs` (`offs` is sign-extended to VA bits).
+pub const R_LARCH_GOT_PC_HI20: u32 = 75;
+/// 0..=11 bits of the 32/64-bit offset from the
+/// [PC relative anchor][R_LARCH_GOT_PC_HI20] to the GOT entry.
+pub const R_LARCH_GOT_PC_LO12: u32 = 76;
+/// 32..=51 bits of the 64-bit offset from the
+/// [PC relative anchor][R_LARCH_GOT_PC_HI20] to the GOT entry.
+pub const R_LARCH_GOT64_PC_LO20: u32 = 77;
+/// 52..=63 bits of the 64-bit offset from the
+/// [PC relative anchor][R_LARCH_GOT_PC_HI20] to the GOT entry.
+pub const R_LARCH_GOT64_PC_HI12: u32 = 78;
+/// 12..=31 bits of 32/64-bit GOT entry absolute address
+pub const R_LARCH_GOT_HI20: u32 = 79;
+/// 0..=11 bits of 32/64-bit GOT entry absolute address
+pub const R_LARCH_GOT_LO12: u32 = 80;
+/// 32..=51 bits of 64-bit GOT entry absolute address
+pub const R_LARCH_GOT64_LO20: u32 = 81;
+/// 52..=63 bits of 64-bit GOT entry absolute address
+pub const R_LARCH_GOT64_HI12: u32 = 82;
+/// 12..=31 bits of TLS LE 32/64-bit offset from thread pointer
+pub const R_LARCH_TLS_LE_HI20: u32 = 83;
+/// 0..=11 bits of TLS LE 32/64-bit offset from thread pointer
+pub const R_LARCH_TLS_LE_LO12: u32 = 84;
+/// 32..=51 bits of TLS LE 64-bit offset from thread pointer
+pub const R_LARCH_TLS_LE64_LO20: u32 = 85;
+/// 52..=63 bits of TLS LE 64-bit offset from thread pointer
+pub const R_LARCH_TLS_LE64_HI12: u32 = 86;
+/// The signed 32-bit offset `offs` from `PC & 0xfffff000` to
+/// `(GP + IE + 0x800) & 0xfffff000`, with 12 trailing zeros removed.
+///
+/// We define the *PC relative anchor* for the TLS IE GOT entry at
+/// `GP + IE` as `PC + offs` (`offs` is sign-extended to VA bits).
+pub const R_LARCH_TLS_IE_PC_HI20: u32 = 87;
+/// 0..=12 bits of the 32/64-bit offset from the
+/// [PC-relative anchor][R_LARCH_TLS_IE_PC_HI20] to the TLS IE GOT entry.
+pub const R_LARCH_TLS_IE_PC_LO12: u32 = 88;
+/// 32..=51 bits of the 64-bit offset from the
+/// [PC-relative anchor][R_LARCH_TLS_IE_PC_HI20] to the TLS IE GOT entry.
+pub const R_LARCH_TLS_IE64_PC_LO20: u32 = 89;
+/// 52..=63 bits of the 64-bit offset from the
+/// [PC-relative anchor][R_LARCH_TLS_IE_PC_HI20] to the TLS IE GOT entry.
+pub const R_LARCH_TLS_IE64_PC_HI12: u32 = 90;
+/// 12..=31 bits of TLS IE GOT entry 32/64-bit absolute address
+pub const R_LARCH_TLS_IE_HI20: u32 = 91;
+/// 0..=11 bits of TLS IE GOT entry 32/64-bit absolute address
+pub const R_LARCH_TLS_IE_LO12: u32 = 92;
+/// 32..=51 bits of TLS IE GOT entry 64-bit absolute address
+pub const R_LARCH_TLS_IE64_LO20: u32 = 93;
+/// 51..=63 bits of TLS IE GOT entry 64-bit absolute address
+pub const R_LARCH_TLS_IE64_HI12: u32 = 94;
+/// 12..=31 bits of the offset from `PC` to `GP + GD + 0x800`, where
+/// `GP + GD` is a TLS LD GOT entry
+pub const R_LARCH_TLS_LD_PC_HI20: u32 = 95;
+/// 12..=31 bits of TLS LD GOT entry 32/64-bit absolute address
+pub const R_LARCH_TLS_LD_HI20: u32 = 96;
+/// 12..=31 bits of the 32/64-bit PC-relative offset to the PC-relative
+/// anchor for the TLE GD GOT entry.
+pub const R_LARCH_TLS_GD_PC_HI20: u32 = 97;
+/// 12..=31 bits of TLS GD GOT entry 32/64-bit absolute address
+pub const R_LARCH_TLS_GD_HI20: u32 = 98;
+/// 32-bit PC relative
+pub const R_LARCH_32_PCREL: u32 = 99;
+/// Paired with a normal relocation at the same address to indicate the
+/// insturction can be relaxed
+pub const R_LARCH_RELAX: u32 = 100;
+
+// Xtensa values Rel*::r_type`.
+pub const R_XTENSA_NONE: u32 = 0;
+pub const R_XTENSA_32: u32 = 1;
+pub const R_XTENSA_RTLD: u32 = 2;
+pub const R_XTENSA_GLOB_DAT: u32 = 3;
+pub const R_XTENSA_JMP_SLOT: u32 = 4;
+pub const R_XTENSA_RELATIVE: u32 = 5;
+pub const R_XTENSA_PLT: u32 = 6;
+pub const R_XTENSA_OP0: u32 = 8;
+pub const R_XTENSA_OP1: u32 = 9;
+pub const R_XTENSA_OP2: u32 = 10;
+pub const R_XTENSA_ASM_EXPAND: u32 = 11;
+pub const R_XTENSA_ASM_SIMPLIFY: u32 = 12;
+pub const R_XTENSA_32_PCREL: u32 = 14;
+pub const R_XTENSA_GNU_VTINHERIT: u32 = 15;
+pub const R_XTENSA_GNU_VTENTRY: u32 = 16;
+pub const R_XTENSA_DIFF8: u32 = 17;
+pub const R_XTENSA_DIFF16: u32 = 18;
+pub const R_XTENSA_DIFF32: u32 = 19;
+pub const R_XTENSA_SLOT0_OP: u32 = 20;
+pub const R_XTENSA_SLOT1_OP: u32 = 21;
+pub const R_XTENSA_SLOT2_OP: u32 = 22;
+pub const R_XTENSA_SLOT3_OP: u32 = 23;
+pub const R_XTENSA_SLOT4_OP: u32 = 24;
+pub const R_XTENSA_SLOT5_OP: u32 = 25;
+pub const R_XTENSA_SLOT6_OP: u32 = 26;
+pub const R_XTENSA_SLOT7_OP: u32 = 27;
+pub const R_XTENSA_SLOT8_OP: u32 = 28;
+pub const R_XTENSA_SLOT9_OP: u32 = 29;
+pub const R_XTENSA_SLOT10_OP: u32 = 30;
+pub const R_XTENSA_SLOT11_OP: u32 = 31;
+pub const R_XTENSA_SLOT12_OP: u32 = 32;
+pub const R_XTENSA_SLOT13_OP: u32 = 33;
+pub const R_XTENSA_SLOT14_OP: u32 = 34;
+pub const R_XTENSA_SLOT0_ALT: u32 = 35;
+pub const R_XTENSA_SLOT1_ALT: u32 = 36;
+pub const R_XTENSA_SLOT2_ALT: u32 = 37;
+pub const R_XTENSA_SLOT3_ALT: u32 = 38;
+pub const R_XTENSA_SLOT4_ALT: u32 = 39;
+pub const R_XTENSA_SLOT5_ALT: u32 = 40;
+pub const R_XTENSA_SLOT6_ALT: u32 = 41;
+pub const R_XTENSA_SLOT7_ALT: u32 = 42;
+pub const R_XTENSA_SLOT8_ALT: u32 = 43;
+pub const R_XTENSA_SLOT9_ALT: u32 = 44;
+pub const R_XTENSA_SLOT10_ALT: u32 = 45;
+pub const R_XTENSA_SLOT11_ALT: u32 = 46;
+pub const R_XTENSA_SLOT12_ALT: u32 = 47;
+pub const R_XTENSA_SLOT13_ALT: u32 = 48;
+pub const R_XTENSA_SLOT14_ALT: u32 = 49;
+pub const R_XTENSA_TLSDESC_FN: u32 = 50;
+pub const R_XTENSA_TLSDESC_ARG: u32 = 51;
+pub const R_XTENSA_TLS_DTPOFF: u32 = 52;
+pub const R_XTENSA_TLS_TPOFF: u32 = 53;
+pub const R_XTENSA_TLS_FUNC: u32 = 54;
+pub const R_XTENSA_TLS_ARG: u32 = 55;
+pub const R_XTENSA_TLS_CALL: u32 = 56;
+pub const R_XTENSA_PDIFF8: u32 = 57;
+pub const R_XTENSA_PDIFF16: u32 = 58;
+pub const R_XTENSA_PDIFF32: u32 = 59;
+pub const R_XTENSA_NDIFF8: u32 = 60;
+pub const R_XTENSA_NDIFF16: u32 = 61;
+pub const R_XTENSA_NDIFF32: u32 = 62;
+
+#[allow(non_upper_case_globals)]
+pub const Tag_File: u8 = 1;
+#[allow(non_upper_case_globals)]
+pub const Tag_Section: u8 = 2;
+#[allow(non_upper_case_globals)]
+pub const Tag_Symbol: u8 = 3;
+
+unsafe_impl_endian_pod!(
+ FileHeader32,
+ FileHeader64,
+ SectionHeader32,
+ SectionHeader64,
+ CompressionHeader32,
+ CompressionHeader64,
+ Sym32,
+ Sym64,
+ Syminfo32,
+ Syminfo64,
+ Rel32,
+ Rel64,
+ Rela32,
+ Rela64,
+ ProgramHeader32,
+ ProgramHeader64,
+ Dyn32,
+ Dyn64,
+ Versym,
+ Verdef,
+ Verdaux,
+ Verneed,
+ Vernaux,
+ NoteHeader32,
+ NoteHeader64,
+ HashHeader,
+ GnuHashHeader,
+);
diff --git a/third_party/rust/object/src/endian.rs b/third_party/rust/object/src/endian.rs
new file mode 100644
index 0000000000..e4a36ba13f
--- /dev/null
+++ b/third_party/rust/object/src/endian.rs
@@ -0,0 +1,831 @@
+//! Types for compile-time and run-time endianness.
+
+use crate::pod::Pod;
+use core::fmt::{self, Debug};
+use core::marker::PhantomData;
+
+/// A trait for using an endianness specification.
+///
+/// Provides methods for converting between the specified endianness and
+/// the native endianness of the target machine.
+///
+/// This trait does not require that the endianness is known at compile time.
+pub trait Endian: Debug + Default + Clone + Copy + PartialEq + Eq + 'static {
+ /// Construct a specification for the endianness of some values.
+ ///
+ /// Returns `None` if the type does not support specifying the given endianness.
+ fn from_big_endian(big_endian: bool) -> Option<Self>;
+
+ /// Construct a specification for the endianness of some values.
+ ///
+ /// Returns `None` if the type does not support specifying the given endianness.
+ fn from_little_endian(little_endian: bool) -> Option<Self> {
+ Self::from_big_endian(!little_endian)
+ }
+
+ /// Return true for big endian byte order.
+ fn is_big_endian(self) -> bool;
+
+ /// Return true for little endian byte order.
+ #[inline]
+ fn is_little_endian(self) -> bool {
+ !self.is_big_endian()
+ }
+
+ /// Converts an unsigned 16 bit integer to native endian.
+ #[inline]
+ fn read_u16(self, n: u16) -> u16 {
+ if self.is_big_endian() {
+ u16::from_be(n)
+ } else {
+ u16::from_le(n)
+ }
+ }
+
+ /// Converts an unsigned 32 bit integer to native endian.
+ #[inline]
+ fn read_u32(self, n: u32) -> u32 {
+ if self.is_big_endian() {
+ u32::from_be(n)
+ } else {
+ u32::from_le(n)
+ }
+ }
+
+ /// Converts an unsigned 64 bit integer to native endian.
+ #[inline]
+ fn read_u64(self, n: u64) -> u64 {
+ if self.is_big_endian() {
+ u64::from_be(n)
+ } else {
+ u64::from_le(n)
+ }
+ }
+
+ /// Converts a signed 16 bit integer to native endian.
+ #[inline]
+ fn read_i16(self, n: i16) -> i16 {
+ if self.is_big_endian() {
+ i16::from_be(n)
+ } else {
+ i16::from_le(n)
+ }
+ }
+
+ /// Converts a signed 32 bit integer to native endian.
+ #[inline]
+ fn read_i32(self, n: i32) -> i32 {
+ if self.is_big_endian() {
+ i32::from_be(n)
+ } else {
+ i32::from_le(n)
+ }
+ }
+
+ /// Converts a signed 64 bit integer to native endian.
+ #[inline]
+ fn read_i64(self, n: i64) -> i64 {
+ if self.is_big_endian() {
+ i64::from_be(n)
+ } else {
+ i64::from_le(n)
+ }
+ }
+
+ /// Converts an unaligned unsigned 16 bit integer to native endian.
+ #[inline]
+ fn read_u16_bytes(self, n: [u8; 2]) -> u16 {
+ if self.is_big_endian() {
+ u16::from_be_bytes(n)
+ } else {
+ u16::from_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned unsigned 32 bit integer to native endian.
+ #[inline]
+ fn read_u32_bytes(self, n: [u8; 4]) -> u32 {
+ if self.is_big_endian() {
+ u32::from_be_bytes(n)
+ } else {
+ u32::from_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned unsigned 64 bit integer to native endian.
+ #[inline]
+ fn read_u64_bytes(self, n: [u8; 8]) -> u64 {
+ if self.is_big_endian() {
+ u64::from_be_bytes(n)
+ } else {
+ u64::from_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned signed 16 bit integer to native endian.
+ #[inline]
+ fn read_i16_bytes(self, n: [u8; 2]) -> i16 {
+ if self.is_big_endian() {
+ i16::from_be_bytes(n)
+ } else {
+ i16::from_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned signed 32 bit integer to native endian.
+ #[inline]
+ fn read_i32_bytes(self, n: [u8; 4]) -> i32 {
+ if self.is_big_endian() {
+ i32::from_be_bytes(n)
+ } else {
+ i32::from_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned signed 64 bit integer to native endian.
+ #[inline]
+ fn read_i64_bytes(self, n: [u8; 8]) -> i64 {
+ if self.is_big_endian() {
+ i64::from_be_bytes(n)
+ } else {
+ i64::from_le_bytes(n)
+ }
+ }
+
+ /// Converts an unsigned 16 bit integer from native endian.
+ #[inline]
+ fn write_u16(self, n: u16) -> u16 {
+ if self.is_big_endian() {
+ u16::to_be(n)
+ } else {
+ u16::to_le(n)
+ }
+ }
+
+ /// Converts an unsigned 32 bit integer from native endian.
+ #[inline]
+ fn write_u32(self, n: u32) -> u32 {
+ if self.is_big_endian() {
+ u32::to_be(n)
+ } else {
+ u32::to_le(n)
+ }
+ }
+
+ /// Converts an unsigned 64 bit integer from native endian.
+ #[inline]
+ fn write_u64(self, n: u64) -> u64 {
+ if self.is_big_endian() {
+ u64::to_be(n)
+ } else {
+ u64::to_le(n)
+ }
+ }
+
+ /// Converts a signed 16 bit integer from native endian.
+ #[inline]
+ fn write_i16(self, n: i16) -> i16 {
+ if self.is_big_endian() {
+ i16::to_be(n)
+ } else {
+ i16::to_le(n)
+ }
+ }
+
+ /// Converts a signed 32 bit integer from native endian.
+ #[inline]
+ fn write_i32(self, n: i32) -> i32 {
+ if self.is_big_endian() {
+ i32::to_be(n)
+ } else {
+ i32::to_le(n)
+ }
+ }
+
+ /// Converts a signed 64 bit integer from native endian.
+ #[inline]
+ fn write_i64(self, n: i64) -> i64 {
+ if self.is_big_endian() {
+ i64::to_be(n)
+ } else {
+ i64::to_le(n)
+ }
+ }
+
+ /// Converts an unaligned unsigned 16 bit integer from native endian.
+ #[inline]
+ fn write_u16_bytes(self, n: u16) -> [u8; 2] {
+ if self.is_big_endian() {
+ u16::to_be_bytes(n)
+ } else {
+ u16::to_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned unsigned 32 bit integer from native endian.
+ #[inline]
+ fn write_u32_bytes(self, n: u32) -> [u8; 4] {
+ if self.is_big_endian() {
+ u32::to_be_bytes(n)
+ } else {
+ u32::to_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned unsigned 64 bit integer from native endian.
+ #[inline]
+ fn write_u64_bytes(self, n: u64) -> [u8; 8] {
+ if self.is_big_endian() {
+ u64::to_be_bytes(n)
+ } else {
+ u64::to_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned signed 16 bit integer from native endian.
+ #[inline]
+ fn write_i16_bytes(self, n: i16) -> [u8; 2] {
+ if self.is_big_endian() {
+ i16::to_be_bytes(n)
+ } else {
+ i16::to_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned signed 32 bit integer from native endian.
+ #[inline]
+ fn write_i32_bytes(self, n: i32) -> [u8; 4] {
+ if self.is_big_endian() {
+ i32::to_be_bytes(n)
+ } else {
+ i32::to_le_bytes(n)
+ }
+ }
+
+ /// Converts an unaligned signed 64 bit integer from native endian.
+ #[inline]
+ fn write_i64_bytes(self, n: i64) -> [u8; 8] {
+ if self.is_big_endian() {
+ i64::to_be_bytes(n)
+ } else {
+ i64::to_le_bytes(n)
+ }
+ }
+}
+
+/// An endianness that is selectable at run-time.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Endianness {
+ /// Little endian byte order.
+ Little,
+ /// Big endian byte order.
+ Big,
+}
+
+impl Default for Endianness {
+ #[cfg(target_endian = "little")]
+ #[inline]
+ fn default() -> Endianness {
+ Endianness::Little
+ }
+
+ #[cfg(target_endian = "big")]
+ #[inline]
+ fn default() -> Endianness {
+ Endianness::Big
+ }
+}
+
+impl Endian for Endianness {
+ #[inline]
+ fn from_big_endian(big_endian: bool) -> Option<Self> {
+ Some(if big_endian {
+ Endianness::Big
+ } else {
+ Endianness::Little
+ })
+ }
+
+ #[inline]
+ fn is_big_endian(self) -> bool {
+ self != Endianness::Little
+ }
+}
+
+/// Compile-time little endian byte order.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct LittleEndian;
+
+impl Default for LittleEndian {
+ #[inline]
+ fn default() -> LittleEndian {
+ LittleEndian
+ }
+}
+
+impl Endian for LittleEndian {
+ #[inline]
+ fn from_big_endian(big_endian: bool) -> Option<Self> {
+ if big_endian {
+ None
+ } else {
+ Some(LittleEndian)
+ }
+ }
+
+ #[inline]
+ fn is_big_endian(self) -> bool {
+ false
+ }
+}
+
+/// Compile-time big endian byte order.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct BigEndian;
+
+impl Default for BigEndian {
+ #[inline]
+ fn default() -> BigEndian {
+ BigEndian
+ }
+}
+
+impl Endian for BigEndian {
+ #[inline]
+ fn from_big_endian(big_endian: bool) -> Option<Self> {
+ if big_endian {
+ Some(BigEndian)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn is_big_endian(self) -> bool {
+ true
+ }
+}
+
+/// The native endianness for the target platform.
+#[cfg(target_endian = "little")]
+pub type NativeEndian = LittleEndian;
+
+#[cfg(target_endian = "little")]
+#[allow(non_upper_case_globals)]
+#[doc(hidden)]
+pub const NativeEndian: LittleEndian = LittleEndian;
+
+/// The native endianness for the target platform.
+#[cfg(target_endian = "big")]
+pub type NativeEndian = BigEndian;
+
+#[cfg(target_endian = "big")]
+#[allow(non_upper_case_globals)]
+#[doc(hidden)]
+pub const NativeEndian: BigEndian = BigEndian;
+
+macro_rules! unsafe_impl_endian_pod {
+ ($($struct_name:ident),+ $(,)?) => {
+ $(
+ unsafe impl<E: Endian> Pod for $struct_name<E> { }
+ )+
+ }
+}
+
+#[cfg(not(feature = "unaligned"))]
+mod aligned {
+ use super::{fmt, Endian, PhantomData, Pod};
+
+ /// A `u16` value with an externally specified endianness of type `E`.
+ #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[repr(transparent)]
+ pub struct U16<E: Endian>(u16, PhantomData<E>);
+
+ impl<E: Endian> U16<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 2]) -> Self {
+ Self(u16::from_ne_bytes(n), PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: u16) -> Self {
+ Self(e.write_u16(n), PhantomData)
+ }
+
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> u16 {
+ e.read_u16(self.0)
+ }
+
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: u16) {
+ self.0 = e.write_u16(n);
+ }
+ }
+
+ /// A `u32` value with an externally specified endianness of type `E`.
+ #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[repr(transparent)]
+ pub struct U32<E: Endian>(u32, PhantomData<E>);
+
+ impl<E: Endian> U32<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 4]) -> Self {
+ Self(u32::from_ne_bytes(n), PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: u32) -> Self {
+ Self(e.write_u32(n), PhantomData)
+ }
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> u32 {
+ e.read_u32(self.0)
+ }
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: u32) {
+ self.0 = e.write_u32(n);
+ }
+ }
+
+ /// A `u64` value with an externally specified endianness of type `E`.
+ #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[repr(transparent)]
+ pub struct U64<E: Endian>(u64, PhantomData<E>);
+
+ impl<E: Endian> U64<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 8]) -> Self {
+ Self(u64::from_ne_bytes(n), PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: u64) -> Self {
+ Self(e.write_u64(n), PhantomData)
+ }
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> u64 {
+ e.read_u64(self.0)
+ }
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: u64) {
+ self.0 = e.write_u64(n);
+ }
+ }
+
+ /// An `i16` value with an externally specified endianness of type `E`.
+ #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[repr(transparent)]
+ pub struct I16<E: Endian>(i16, PhantomData<E>);
+
+ impl<E: Endian> I16<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 2]) -> Self {
+ Self(i16::from_ne_bytes(n), PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: i16) -> Self {
+ Self(e.write_i16(n), PhantomData)
+ }
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> i16 {
+ e.read_i16(self.0)
+ }
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: i16) {
+ self.0 = e.write_i16(n);
+ }
+ }
+
+ /// An `i32` value with an externally specified endianness of type `E`.
+ #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[repr(transparent)]
+ pub struct I32<E: Endian>(i32, PhantomData<E>);
+
+ impl<E: Endian> I32<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 4]) -> Self {
+ Self(i32::from_ne_bytes(n), PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: i32) -> Self {
+ Self(e.write_i32(n), PhantomData)
+ }
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> i32 {
+ e.read_i32(self.0)
+ }
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: i32) {
+ self.0 = e.write_i32(n);
+ }
+ }
+
+ /// An `i64` value with an externally specified endianness of type `E`.
+ #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[repr(transparent)]
+ pub struct I64<E: Endian>(i64, PhantomData<E>);
+
+ impl<E: Endian> I64<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 8]) -> Self {
+ Self(i64::from_ne_bytes(n), PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: i64) -> Self {
+ Self(e.write_i64(n), PhantomData)
+ }
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> i64 {
+ e.read_i64(self.0)
+ }
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: i64) {
+ self.0 = e.write_i64(n);
+ }
+ }
+
+ impl<E: Endian> fmt::Debug for U16<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "U16({:x})", self.0)
+ }
+ }
+
+ impl<E: Endian> fmt::Debug for U32<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "U32({:x})", self.0)
+ }
+ }
+
+ impl<E: Endian> fmt::Debug for U64<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "U64({:x})", self.0)
+ }
+ }
+
+ impl<E: Endian> fmt::Debug for I16<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "I16({:x})", self.0)
+ }
+ }
+
+ impl<E: Endian> fmt::Debug for I32<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "I32({:x})", self.0)
+ }
+ }
+
+ impl<E: Endian> fmt::Debug for I64<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "I64({:x})", self.0)
+ }
+ }
+
+ unsafe_impl_endian_pod!(U16, U32, U64, I16, I32, I64);
+}
+
+#[cfg(not(feature = "unaligned"))]
+pub use aligned::*;
+
+/// A `u16` value with an externally specified endianness of type `E`.
+#[cfg(feature = "unaligned")]
+pub type U16<E> = U16Bytes<E>;
+
+/// A `u32` value with an externally specified endianness of type `E`.
+#[cfg(feature = "unaligned")]
+pub type U32<E> = U32Bytes<E>;
+
+/// A `u64` value with an externally specified endianness of type `E`.
+#[cfg(feature = "unaligned")]
+pub type U64<E> = U64Bytes<E>;
+
+/// An `i16` value with an externally specified endianness of type `E`.
+#[cfg(feature = "unaligned")]
+pub type I16<E> = I16Bytes<E>;
+
+/// An `i32` value with an externally specified endianness of type `E`.
+#[cfg(feature = "unaligned")]
+pub type I32<E> = I32Bytes<E>;
+
+/// An `i64` value with an externally specified endianness of type `E`.
+#[cfg(feature = "unaligned")]
+pub type I64<E> = I64Bytes<E>;
+
+/// An unaligned `u16` value with an externally specified endianness of type `E`.
+#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct U16Bytes<E: Endian>([u8; 2], PhantomData<E>);
+
+impl<E: Endian> U16Bytes<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 2]) -> Self {
+ Self(n, PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: u16) -> Self {
+ Self(e.write_u16_bytes(n), PhantomData)
+ }
+
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> u16 {
+ e.read_u16_bytes(self.0)
+ }
+
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: u16) {
+ self.0 = e.write_u16_bytes(n);
+ }
+}
+
+/// An unaligned `u32` value with an externally specified endianness of type `E`.
+#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct U32Bytes<E: Endian>([u8; 4], PhantomData<E>);
+
+impl<E: Endian> U32Bytes<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 4]) -> Self {
+ Self(n, PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: u32) -> Self {
+ Self(e.write_u32_bytes(n), PhantomData)
+ }
+
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> u32 {
+ e.read_u32_bytes(self.0)
+ }
+
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: u32) {
+ self.0 = e.write_u32_bytes(n);
+ }
+}
+
+/// An unaligned `u64` value with an externally specified endianness of type `E`.
+#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct U64Bytes<E: Endian>([u8; 8], PhantomData<E>);
+
+impl<E: Endian> U64Bytes<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 8]) -> Self {
+ Self(n, PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: u64) -> Self {
+ Self(e.write_u64_bytes(n), PhantomData)
+ }
+
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> u64 {
+ e.read_u64_bytes(self.0)
+ }
+
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: u64) {
+ self.0 = e.write_u64_bytes(n);
+ }
+}
+
+/// An unaligned `i16` value with an externally specified endianness of type `E`.
+#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct I16Bytes<E: Endian>([u8; 2], PhantomData<E>);
+
+impl<E: Endian> I16Bytes<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 2]) -> Self {
+ Self(n, PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: i16) -> Self {
+ Self(e.write_i16_bytes(n), PhantomData)
+ }
+
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> i16 {
+ e.read_i16_bytes(self.0)
+ }
+
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: i16) {
+ self.0 = e.write_i16_bytes(n);
+ }
+}
+
+/// An unaligned `i32` value with an externally specified endianness of type `E`.
+#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct I32Bytes<E: Endian>([u8; 4], PhantomData<E>);
+
+impl<E: Endian> I32Bytes<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 4]) -> Self {
+ Self(n, PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: i32) -> Self {
+ Self(e.write_i32_bytes(n), PhantomData)
+ }
+
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> i32 {
+ e.read_i32_bytes(self.0)
+ }
+
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: i32) {
+ self.0 = e.write_i32_bytes(n);
+ }
+}
+
+/// An unaligned `i64` value with an externally specified endianness of type `E`.
+#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct I64Bytes<E: Endian>([u8; 8], PhantomData<E>);
+
+impl<E: Endian> I64Bytes<E> {
+ /// Construct a new value given bytes that already have the required endianness.
+ pub fn from_bytes(n: [u8; 8]) -> Self {
+ Self(n, PhantomData)
+ }
+
+ /// Construct a new value given a native endian value.
+ pub fn new(e: E, n: i64) -> Self {
+ Self(e.write_i64_bytes(n), PhantomData)
+ }
+
+ /// Return the value as a native endian value.
+ pub fn get(self, e: E) -> i64 {
+ e.read_i64_bytes(self.0)
+ }
+
+ /// Set the value given a native endian value.
+ pub fn set(&mut self, e: E, n: i64) {
+ self.0 = e.write_i64_bytes(n);
+ }
+}
+
+impl<E: Endian> fmt::Debug for U16Bytes<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "U16({:x}, {:x})", self.0[0], self.0[1],)
+ }
+}
+
+impl<E: Endian> fmt::Debug for U32Bytes<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "U32({:x}, {:x}, {:x}, {:x})",
+ self.0[0], self.0[1], self.0[2], self.0[3],
+ )
+ }
+}
+
+impl<E: Endian> fmt::Debug for U64Bytes<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "U64({:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x})",
+ self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
+ )
+ }
+}
+
+impl<E: Endian> fmt::Debug for I16Bytes<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "I16({:x}, {:x})", self.0[0], self.0[1],)
+ }
+}
+
+impl<E: Endian> fmt::Debug for I32Bytes<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "I32({:x}, {:x}, {:x}, {:x})",
+ self.0[0], self.0[1], self.0[2], self.0[3],
+ )
+ }
+}
+
+impl<E: Endian> fmt::Debug for I64Bytes<E> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "I64({:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x})",
+ self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
+ )
+ }
+}
+
+unsafe_impl_endian_pod!(U16Bytes, U32Bytes, U64Bytes, I16Bytes, I32Bytes, I64Bytes);
diff --git a/third_party/rust/object/src/lib.rs b/third_party/rust/object/src/lib.rs
new file mode 100644
index 0000000000..e17802c4fa
--- /dev/null
+++ b/third_party/rust/object/src/lib.rs
@@ -0,0 +1,116 @@
+//! # `object`
+//!
+//! The `object` crate provides a unified interface to working with object files
+//! across platforms. It supports reading relocatable object files and executable files,
+//! and writing relocatable object files and some executable files.
+//!
+//! ## Raw struct definitions
+//!
+//! Raw structs are defined for: [ELF](elf), [Mach-O](macho), [PE/COFF](pe),
+//! [XCOFF](xcoff), [archive].
+//! Types and traits for zerocopy support are defined in [pod] and [endian].
+//!
+//! ## Unified read API
+//!
+//! The [read::Object] trait defines the unified interface. This trait is implemented
+//! by [read::File], which allows reading any file format, as well as implementations
+//! for each file format: [ELF](read::elf::ElfFile), [Mach-O](read::macho::MachOFile),
+//! [COFF](read::coff::CoffFile), [PE](read::pe::PeFile), [Wasm](read::wasm::WasmFile),
+//! [XCOFF](read::xcoff::XcoffFile).
+//!
+//! ## Low level read API
+//!
+//! In addition to the unified read API, the various `read` modules define helpers that
+//! operate on the raw structs. These also provide traits that abstract over the differences
+//! between 32-bit and 64-bit versions of the file format.
+//!
+//! ## Unified write API
+//!
+//! [write::Object] allows building a COFF/ELF/Mach-O/XCOFF relocatable object file and
+//! then writing it out.
+//!
+//! ## Low level executable writers
+//!
+//! [write::elf::Writer] and [write::pe::Writer] allow writing executable files.
+//!
+//! ## Example for unified read API
+//! ```no_run
+//! # #[cfg(feature = "read")]
+//! use object::{Object, ObjectSection};
+//! use std::error::Error;
+//! use std::fs;
+//!
+//! /// Reads a file and displays the content of the ".boot" section.
+//! fn main() -> Result<(), Box<dyn Error>> {
+//! # #[cfg(all(feature = "read", feature = "std"))] {
+//! let bin_data = fs::read("./multiboot2-binary.elf")?;
+//! let obj_file = object::File::parse(&*bin_data)?;
+//! if let Some(section) = obj_file.section_by_name(".boot") {
+//! println!("{:#x?}", section.data()?);
+//! } else {
+//! eprintln!("section not available");
+//! }
+//! # }
+//! Ok(())
+//! }
+//! ```
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![no_std]
+#![warn(rust_2018_idioms)]
+// Style.
+#![allow(clippy::collapsible_if)]
+#![allow(clippy::comparison_chain)]
+#![allow(clippy::match_like_matches_macro)]
+#![allow(clippy::single_match)]
+#![allow(clippy::type_complexity)]
+// Occurs due to fallible iteration.
+#![allow(clippy::should_implement_trait)]
+// Unit errors are converted to other types by callers.
+#![allow(clippy::result_unit_err)]
+// Worse readability sometimes.
+#![allow(clippy::collapsible_else_if)]
+
+#[cfg(feature = "cargo-all")]
+compile_error!("'--all-features' is not supported; use '--features all' instead");
+
+#[cfg(any(feature = "read_core", feature = "write_core"))]
+#[allow(unused_imports)]
+#[macro_use]
+extern crate alloc;
+
+#[cfg(feature = "std")]
+#[allow(unused_imports)]
+#[macro_use]
+extern crate std;
+
+mod common;
+pub use common::*;
+
+#[macro_use]
+pub mod endian;
+pub use endian::*;
+
+#[macro_use]
+pub mod pod;
+pub use pod::*;
+
+#[cfg(feature = "read_core")]
+pub mod read;
+#[cfg(feature = "read_core")]
+pub use read::*;
+
+#[cfg(feature = "write_core")]
+pub mod write;
+
+#[cfg(feature = "archive")]
+pub mod archive;
+#[cfg(feature = "elf")]
+pub mod elf;
+#[cfg(feature = "macho")]
+pub mod macho;
+#[cfg(any(feature = "coff", feature = "pe"))]
+pub mod pe;
+#[cfg(feature = "xcoff")]
+pub mod xcoff;
diff --git a/third_party/rust/object/src/macho.rs b/third_party/rust/object/src/macho.rs
new file mode 100644
index 0000000000..3cd38e0eef
--- /dev/null
+++ b/third_party/rust/object/src/macho.rs
@@ -0,0 +1,3307 @@
+//! Mach-O definitions.
+//!
+//! These definitions are independent of read/write support, although we do implement
+//! some traits useful for those.
+//!
+//! This module is based heavily on header files from MacOSX11.1.sdk.
+
+#![allow(missing_docs)]
+
+use crate::endian::{BigEndian, Endian, U64Bytes, U16, U32, U64};
+use crate::pod::Pod;
+
+// Definitions from "/usr/include/mach/machine.h".
+
+/*
+ * Capability bits used in the definition of cpu_type.
+ */
+
+/// mask for architecture bits
+pub const CPU_ARCH_MASK: u32 = 0xff00_0000;
+/// 64 bit ABI
+pub const CPU_ARCH_ABI64: u32 = 0x0100_0000;
+/// ABI for 64-bit hardware with 32-bit types; LP32
+pub const CPU_ARCH_ABI64_32: u32 = 0x0200_0000;
+
+/*
+ * Machine types known by all.
+ */
+
+pub const CPU_TYPE_ANY: u32 = !0;
+
+pub const CPU_TYPE_VAX: u32 = 1;
+pub const CPU_TYPE_MC680X0: u32 = 6;
+pub const CPU_TYPE_X86: u32 = 7;
+pub const CPU_TYPE_X86_64: u32 = CPU_TYPE_X86 | CPU_ARCH_ABI64;
+pub const CPU_TYPE_MIPS: u32 = 8;
+pub const CPU_TYPE_MC98000: u32 = 10;
+pub const CPU_TYPE_HPPA: u32 = 11;
+pub const CPU_TYPE_ARM: u32 = 12;
+pub const CPU_TYPE_ARM64: u32 = CPU_TYPE_ARM | CPU_ARCH_ABI64;
+pub const CPU_TYPE_ARM64_32: u32 = CPU_TYPE_ARM | CPU_ARCH_ABI64_32;
+pub const CPU_TYPE_MC88000: u32 = 13;
+pub const CPU_TYPE_SPARC: u32 = 14;
+pub const CPU_TYPE_I860: u32 = 15;
+pub const CPU_TYPE_ALPHA: u32 = 16;
+pub const CPU_TYPE_POWERPC: u32 = 18;
+pub const CPU_TYPE_POWERPC64: u32 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64;
+
+/*
+ * Capability bits used in the definition of cpu_subtype.
+ */
+/// mask for feature flags
+pub const CPU_SUBTYPE_MASK: u32 = 0xff00_0000;
+/// 64 bit libraries
+pub const CPU_SUBTYPE_LIB64: u32 = 0x8000_0000;
+/// pointer authentication with versioned ABI
+pub const CPU_SUBTYPE_PTRAUTH_ABI: u32 = 0x8000_0000;
+
+/// When selecting a slice, ANY will pick the slice with the best
+/// grading for the selected cpu_type_t, unlike the "ALL" subtypes,
+/// which are the slices that can run on any hardware for that cpu type.
+pub const CPU_SUBTYPE_ANY: u32 = !0;
+
+/*
+ * Object files that are hand-crafted to run on any
+ * implementation of an architecture are tagged with
+ * CPU_SUBTYPE_MULTIPLE. This functions essentially the same as
+ * the "ALL" subtype of an architecture except that it allows us
+ * to easily find object files that may need to be modified
+ * whenever a new implementation of an architecture comes out.
+ *
+ * It is the responsibility of the implementor to make sure the
+ * software handles unsupported implementations elegantly.
+ */
+pub const CPU_SUBTYPE_MULTIPLE: u32 = !0;
+pub const CPU_SUBTYPE_LITTLE_ENDIAN: u32 = 0;
+pub const CPU_SUBTYPE_BIG_ENDIAN: u32 = 1;
+
+/*
+ * VAX subtypes (these do *not* necessary conform to the actual cpu
+ * ID assigned by DEC available via the SID register).
+ */
+
+pub const CPU_SUBTYPE_VAX_ALL: u32 = 0;
+pub const CPU_SUBTYPE_VAX780: u32 = 1;
+pub const CPU_SUBTYPE_VAX785: u32 = 2;
+pub const CPU_SUBTYPE_VAX750: u32 = 3;
+pub const CPU_SUBTYPE_VAX730: u32 = 4;
+pub const CPU_SUBTYPE_UVAXI: u32 = 5;
+pub const CPU_SUBTYPE_UVAXII: u32 = 6;
+pub const CPU_SUBTYPE_VAX8200: u32 = 7;
+pub const CPU_SUBTYPE_VAX8500: u32 = 8;
+pub const CPU_SUBTYPE_VAX8600: u32 = 9;
+pub const CPU_SUBTYPE_VAX8650: u32 = 10;
+pub const CPU_SUBTYPE_VAX8800: u32 = 11;
+pub const CPU_SUBTYPE_UVAXIII: u32 = 12;
+
+/*
+ * 680x0 subtypes
+ *
+ * The subtype definitions here are unusual for historical reasons.
+ * NeXT used to consider 68030 code as generic 68000 code. For
+ * backwards compatibility:
+ *
+ * CPU_SUBTYPE_MC68030 symbol has been preserved for source code
+ * compatibility.
+ *
+ * CPU_SUBTYPE_MC680x0_ALL has been defined to be the same
+ * subtype as CPU_SUBTYPE_MC68030 for binary comatability.
+ *
+ * CPU_SUBTYPE_MC68030_ONLY has been added to allow new object
+ * files to be tagged as containing 68030-specific instructions.
+ */
+
+pub const CPU_SUBTYPE_MC680X0_ALL: u32 = 1;
+// compat
+pub const CPU_SUBTYPE_MC68030: u32 = 1;
+pub const CPU_SUBTYPE_MC68040: u32 = 2;
+pub const CPU_SUBTYPE_MC68030_ONLY: u32 = 3;
+
+/*
+ * I386 subtypes
+ */
+
+#[inline]
+pub const fn cpu_subtype_intel(f: u32, m: u32) -> u32 {
+ f + (m << 4)
+}
+
+pub const CPU_SUBTYPE_I386_ALL: u32 = cpu_subtype_intel(3, 0);
+pub const CPU_SUBTYPE_386: u32 = cpu_subtype_intel(3, 0);
+pub const CPU_SUBTYPE_486: u32 = cpu_subtype_intel(4, 0);
+pub const CPU_SUBTYPE_486SX: u32 = cpu_subtype_intel(4, 8);
+pub const CPU_SUBTYPE_586: u32 = cpu_subtype_intel(5, 0);
+pub const CPU_SUBTYPE_PENT: u32 = cpu_subtype_intel(5, 0);
+pub const CPU_SUBTYPE_PENTPRO: u32 = cpu_subtype_intel(6, 1);
+pub const CPU_SUBTYPE_PENTII_M3: u32 = cpu_subtype_intel(6, 3);
+pub const CPU_SUBTYPE_PENTII_M5: u32 = cpu_subtype_intel(6, 5);
+pub const CPU_SUBTYPE_CELERON: u32 = cpu_subtype_intel(7, 6);
+pub const CPU_SUBTYPE_CELERON_MOBILE: u32 = cpu_subtype_intel(7, 7);
+pub const CPU_SUBTYPE_PENTIUM_3: u32 = cpu_subtype_intel(8, 0);
+pub const CPU_SUBTYPE_PENTIUM_3_M: u32 = cpu_subtype_intel(8, 1);
+pub const CPU_SUBTYPE_PENTIUM_3_XEON: u32 = cpu_subtype_intel(8, 2);
+pub const CPU_SUBTYPE_PENTIUM_M: u32 = cpu_subtype_intel(9, 0);
+pub const CPU_SUBTYPE_PENTIUM_4: u32 = cpu_subtype_intel(10, 0);
+pub const CPU_SUBTYPE_PENTIUM_4_M: u32 = cpu_subtype_intel(10, 1);
+pub const CPU_SUBTYPE_ITANIUM: u32 = cpu_subtype_intel(11, 0);
+pub const CPU_SUBTYPE_ITANIUM_2: u32 = cpu_subtype_intel(11, 1);
+pub const CPU_SUBTYPE_XEON: u32 = cpu_subtype_intel(12, 0);
+pub const CPU_SUBTYPE_XEON_MP: u32 = cpu_subtype_intel(12, 1);
+
+#[inline]
+pub const fn cpu_subtype_intel_family(x: u32) -> u32 {
+ x & 15
+}
+pub const CPU_SUBTYPE_INTEL_FAMILY_MAX: u32 = 15;
+
+#[inline]
+pub const fn cpu_subtype_intel_model(x: u32) -> u32 {
+ x >> 4
+}
+pub const CPU_SUBTYPE_INTEL_MODEL_ALL: u32 = 0;
+
+/*
+ * X86 subtypes.
+ */
+
+pub const CPU_SUBTYPE_X86_ALL: u32 = 3;
+pub const CPU_SUBTYPE_X86_64_ALL: u32 = 3;
+pub const CPU_SUBTYPE_X86_ARCH1: u32 = 4;
+/// Haswell feature subset
+pub const CPU_SUBTYPE_X86_64_H: u32 = 8;
+
+/*
+ * Mips subtypes.
+ */
+
+pub const CPU_SUBTYPE_MIPS_ALL: u32 = 0;
+pub const CPU_SUBTYPE_MIPS_R2300: u32 = 1;
+pub const CPU_SUBTYPE_MIPS_R2600: u32 = 2;
+pub const CPU_SUBTYPE_MIPS_R2800: u32 = 3;
+/// pmax
+pub const CPU_SUBTYPE_MIPS_R2000A: u32 = 4;
+pub const CPU_SUBTYPE_MIPS_R2000: u32 = 5;
+/// 3max
+pub const CPU_SUBTYPE_MIPS_R3000A: u32 = 6;
+pub const CPU_SUBTYPE_MIPS_R3000: u32 = 7;
+
+/*
+ * MC98000 (PowerPC) subtypes
+ */
+pub const CPU_SUBTYPE_MC98000_ALL: u32 = 0;
+pub const CPU_SUBTYPE_MC98601: u32 = 1;
+
+/*
+ * HPPA subtypes for Hewlett-Packard HP-PA family of
+ * risc processors. Port by NeXT to 700 series.
+ */
+
+pub const CPU_SUBTYPE_HPPA_ALL: u32 = 0;
+pub const CPU_SUBTYPE_HPPA_7100LC: u32 = 1;
+
+/*
+ * MC88000 subtypes.
+ */
+pub const CPU_SUBTYPE_MC88000_ALL: u32 = 0;
+pub const CPU_SUBTYPE_MC88100: u32 = 1;
+pub const CPU_SUBTYPE_MC88110: u32 = 2;
+
+/*
+ * SPARC subtypes
+ */
+pub const CPU_SUBTYPE_SPARC_ALL: u32 = 0;
+
+/*
+ * I860 subtypes
+ */
+pub const CPU_SUBTYPE_I860_ALL: u32 = 0;
+pub const CPU_SUBTYPE_I860_860: u32 = 1;
+
+/*
+ * PowerPC subtypes
+ */
+pub const CPU_SUBTYPE_POWERPC_ALL: u32 = 0;
+pub const CPU_SUBTYPE_POWERPC_601: u32 = 1;
+pub const CPU_SUBTYPE_POWERPC_602: u32 = 2;
+pub const CPU_SUBTYPE_POWERPC_603: u32 = 3;
+pub const CPU_SUBTYPE_POWERPC_603E: u32 = 4;
+pub const CPU_SUBTYPE_POWERPC_603EV: u32 = 5;
+pub const CPU_SUBTYPE_POWERPC_604: u32 = 6;
+pub const CPU_SUBTYPE_POWERPC_604E: u32 = 7;
+pub const CPU_SUBTYPE_POWERPC_620: u32 = 8;
+pub const CPU_SUBTYPE_POWERPC_750: u32 = 9;
+pub const CPU_SUBTYPE_POWERPC_7400: u32 = 10;
+pub const CPU_SUBTYPE_POWERPC_7450: u32 = 11;
+pub const CPU_SUBTYPE_POWERPC_970: u32 = 100;
+
+/*
+ * ARM subtypes
+ */
+pub const CPU_SUBTYPE_ARM_ALL: u32 = 0;
+pub const CPU_SUBTYPE_ARM_V4T: u32 = 5;
+pub const CPU_SUBTYPE_ARM_V6: u32 = 6;
+pub const CPU_SUBTYPE_ARM_V5TEJ: u32 = 7;
+pub const CPU_SUBTYPE_ARM_XSCALE: u32 = 8;
+/// ARMv7-A and ARMv7-R
+pub const CPU_SUBTYPE_ARM_V7: u32 = 9;
+/// Cortex A9
+pub const CPU_SUBTYPE_ARM_V7F: u32 = 10;
+/// Swift
+pub const CPU_SUBTYPE_ARM_V7S: u32 = 11;
+pub const CPU_SUBTYPE_ARM_V7K: u32 = 12;
+pub const CPU_SUBTYPE_ARM_V8: u32 = 13;
+/// Not meant to be run under xnu
+pub const CPU_SUBTYPE_ARM_V6M: u32 = 14;
+/// Not meant to be run under xnu
+pub const CPU_SUBTYPE_ARM_V7M: u32 = 15;
+/// Not meant to be run under xnu
+pub const CPU_SUBTYPE_ARM_V7EM: u32 = 16;
+/// Not meant to be run under xnu
+pub const CPU_SUBTYPE_ARM_V8M: u32 = 17;
+
+/*
+ * ARM64 subtypes
+ */
+pub const CPU_SUBTYPE_ARM64_ALL: u32 = 0;
+pub const CPU_SUBTYPE_ARM64_V8: u32 = 1;
+pub const CPU_SUBTYPE_ARM64E: u32 = 2;
+
+/*
+ * ARM64_32 subtypes
+ */
+pub const CPU_SUBTYPE_ARM64_32_ALL: u32 = 0;
+pub const CPU_SUBTYPE_ARM64_32_V8: u32 = 1;
+
+// Definitions from "/usr/include/mach/vm_prot.h".
+
+/// read permission
+pub const VM_PROT_READ: u32 = 0x01;
+/// write permission
+pub const VM_PROT_WRITE: u32 = 0x02;
+/// execute permission
+pub const VM_PROT_EXECUTE: u32 = 0x04;
+
+// Definitions from https://opensource.apple.com/source/dyld/dyld-210.2.3/launch-cache/dyld_cache_format.h.auto.html
+
+/// The dyld cache header.
+/// Corresponds to struct dyld_cache_header from dyld_cache_format.h.
+/// This header has grown over time. Only the fields up to and including dyld_base_address
+/// are guaranteed to be present. For all other fields, check the header size before
+/// accessing the field. The header size is stored in mapping_offset; the mappings start
+/// right after the theader.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DyldCacheHeader<E: Endian> {
+ /// e.g. "dyld_v0 i386"
+ pub magic: [u8; 16],
+ /// file offset to first dyld_cache_mapping_info
+ pub mapping_offset: U32<E>, // offset: 0x10
+ /// number of dyld_cache_mapping_info entries
+ pub mapping_count: U32<E>, // offset: 0x14
+ /// file offset to first dyld_cache_image_info
+ pub images_offset: U32<E>, // offset: 0x18
+ /// number of dyld_cache_image_info entries
+ pub images_count: U32<E>, // offset: 0x1c
+ /// base address of dyld when cache was built
+ pub dyld_base_address: U64<E>, // offset: 0x20
+ ///
+ reserved1: [u8; 32], // offset: 0x28
+ /// file offset of where local symbols are stored
+ pub local_symbols_offset: U64<E>, // offset: 0x48
+ /// size of local symbols information
+ pub local_symbols_size: U64<E>, // offset: 0x50
+ /// unique value for each shared cache file
+ pub uuid: [u8; 16], // offset: 0x58
+ ///
+ reserved2: [u8; 32], // offset: 0x68
+ ///
+ reserved3: [u8; 32], // offset: 0x88
+ ///
+ reserved4: [u8; 32], // offset: 0xa8
+ ///
+ reserved5: [u8; 32], // offset: 0xc8
+ ///
+ reserved6: [u8; 32], // offset: 0xe8
+ ///
+ reserved7: [u8; 32], // offset: 0x108
+ ///
+ reserved8: [u8; 32], // offset: 0x128
+ ///
+ reserved9: [u8; 32], // offset: 0x148
+ ///
+ reserved10: [u8; 32], // offset: 0x168
+ /// file offset to first dyld_subcache_info
+ pub subcaches_offset: U32<E>, // offset: 0x188
+ /// number of dyld_subcache_info entries
+ pub subcaches_count: U32<E>, // offset: 0x18c
+ /// the UUID of the .symbols subcache
+ pub symbols_subcache_uuid: [u8; 16], // offset: 0x190
+ ///
+ reserved11: [u8; 32], // offset: 0x1a0
+ /// file offset to first dyld_cache_image_info
+ /// Use this instead of images_offset if mapping_offset is at least 0x1c4.
+ pub images_across_all_subcaches_offset: U32<E>, // offset: 0x1c0
+ /// number of dyld_cache_image_info entries
+ /// Use this instead of images_count if mapping_offset is at least 0x1c4.
+ pub images_across_all_subcaches_count: U32<E>, // offset: 0x1c4
+}
+
+/// Corresponds to struct dyld_cache_mapping_info from dyld_cache_format.h.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DyldCacheMappingInfo<E: Endian> {
+ ///
+ pub address: U64<E>,
+ ///
+ pub size: U64<E>,
+ ///
+ pub file_offset: U64<E>,
+ ///
+ pub max_prot: U32<E>,
+ ///
+ pub init_prot: U32<E>,
+}
+
+/// Corresponds to struct dyld_cache_image_info from dyld_cache_format.h.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DyldCacheImageInfo<E: Endian> {
+ ///
+ pub address: U64<E>,
+ ///
+ pub mod_time: U64<E>,
+ ///
+ pub inode: U64<E>,
+ ///
+ pub path_file_offset: U32<E>,
+ ///
+ pub pad: U32<E>,
+}
+
+/// Corresponds to a struct whose source code has not been published as of Nov 2021.
+/// Added in the dyld cache version which shipped with macOS 12 / iOS 15.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DyldSubCacheInfo<E: Endian> {
+ /// The UUID of this subcache.
+ pub uuid: [u8; 16],
+ /// The size of this subcache plus all previous subcaches.
+ pub cumulative_size: U64<E>,
+}
+
+// Definitions from "/usr/include/mach-o/loader.h".
+
+/*
+ * This header file describes the structures of the file format for "fat"
+ * architecture specific file (wrapper design). At the beginning of the file
+ * there is one `FatHeader` structure followed by a number of `FatArch*`
+ * structures. For each architecture in the file, specified by a pair of
+ * cputype and cpusubtype, the `FatHeader` describes the file offset, file
+ * size and alignment in the file of the architecture specific member.
+ * The padded bytes in the file to place each member on it's specific alignment
+ * are defined to be read as zeros and can be left as "holes" if the file system
+ * can support them as long as they read as zeros.
+ *
+ * All structures defined here are always written and read to/from disk
+ * in big-endian order.
+ */
+
+pub const FAT_MAGIC: u32 = 0xcafe_babe;
+/// NXSwapLong(FAT_MAGIC)
+pub const FAT_CIGAM: u32 = 0xbeba_feca;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FatHeader {
+ /// FAT_MAGIC or FAT_MAGIC_64
+ pub magic: U32<BigEndian>,
+ /// number of structs that follow
+ pub nfat_arch: U32<BigEndian>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FatArch32 {
+ /// cpu specifier (int)
+ pub cputype: U32<BigEndian>,
+ /// machine specifier (int)
+ pub cpusubtype: U32<BigEndian>,
+ /// file offset to this object file
+ pub offset: U32<BigEndian>,
+ /// size of this object file
+ pub size: U32<BigEndian>,
+ /// alignment as a power of 2
+ pub align: U32<BigEndian>,
+}
+
+/*
+ * The support for the 64-bit fat file format described here is a work in
+ * progress and not yet fully supported in all the Apple Developer Tools.
+ *
+ * When a slice is greater than 4mb or an offset to a slice is greater than 4mb
+ * then the 64-bit fat file format is used.
+ */
+pub const FAT_MAGIC_64: u32 = 0xcafe_babf;
+/// NXSwapLong(FAT_MAGIC_64)
+pub const FAT_CIGAM_64: u32 = 0xbfba_feca;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FatArch64 {
+ /// cpu specifier (int)
+ pub cputype: U32<BigEndian>,
+ /// machine specifier (int)
+ pub cpusubtype: U32<BigEndian>,
+ /// file offset to this object file
+ pub offset: U64<BigEndian>,
+ /// size of this object file
+ pub size: U64<BigEndian>,
+ /// alignment as a power of 2
+ pub align: U32<BigEndian>,
+ /// reserved
+ pub reserved: U32<BigEndian>,
+}
+
+// Definitions from "/usr/include/mach-o/loader.h".
+
+/// The 32-bit mach header.
+///
+/// Appears at the very beginning of the object file for 32-bit architectures.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct MachHeader32<E: Endian> {
+ /// mach magic number identifier
+ pub magic: U32<BigEndian>,
+ /// cpu specifier
+ pub cputype: U32<E>,
+ /// machine specifier
+ pub cpusubtype: U32<E>,
+ /// type of file
+ pub filetype: U32<E>,
+ /// number of load commands
+ pub ncmds: U32<E>,
+ /// the size of all the load commands
+ pub sizeofcmds: U32<E>,
+ /// flags
+ pub flags: U32<E>,
+}
+
+// Values for `MachHeader32::magic`.
+/// the mach magic number
+pub const MH_MAGIC: u32 = 0xfeed_face;
+/// NXSwapInt(MH_MAGIC)
+pub const MH_CIGAM: u32 = 0xcefa_edfe;
+
+/// The 64-bit mach header.
+///
+/// Appears at the very beginning of object files for 64-bit architectures.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct MachHeader64<E: Endian> {
+ /// mach magic number identifier
+ pub magic: U32<BigEndian>,
+ /// cpu specifier
+ pub cputype: U32<E>,
+ /// machine specifier
+ pub cpusubtype: U32<E>,
+ /// type of file
+ pub filetype: U32<E>,
+ /// number of load commands
+ pub ncmds: U32<E>,
+ /// the size of all the load commands
+ pub sizeofcmds: U32<E>,
+ /// flags
+ pub flags: U32<E>,
+ /// reserved
+ pub reserved: U32<E>,
+}
+
+// Values for `MachHeader64::magic`.
+/// the 64-bit mach magic number
+pub const MH_MAGIC_64: u32 = 0xfeed_facf;
+/// NXSwapInt(MH_MAGIC_64)
+pub const MH_CIGAM_64: u32 = 0xcffa_edfe;
+
+/*
+ * The layout of the file depends on the filetype. For all but the MH_OBJECT
+ * file type the segments are padded out and aligned on a segment alignment
+ * boundary for efficient demand pageing. The MH_EXECUTE, MH_FVMLIB, MH_DYLIB,
+ * MH_DYLINKER and MH_BUNDLE file types also have the headers included as part
+ * of their first segment.
+ *
+ * The file type MH_OBJECT is a compact format intended as output of the
+ * assembler and input (and possibly output) of the link editor (the .o
+ * format). All sections are in one unnamed segment with no segment padding.
+ * This format is used as an executable format when the file is so small the
+ * segment padding greatly increases its size.
+ *
+ * The file type MH_PRELOAD is an executable format intended for things that
+ * are not executed under the kernel (proms, stand alones, kernels, etc). The
+ * format can be executed under the kernel but may demand paged it and not
+ * preload it before execution.
+ *
+ * A core file is in MH_CORE format and can be any in an arbritray legal
+ * Mach-O file.
+ */
+
+// Values for `MachHeader*::filetype`.
+/// relocatable object file
+pub const MH_OBJECT: u32 = 0x1;
+/// demand paged executable file
+pub const MH_EXECUTE: u32 = 0x2;
+/// fixed VM shared library file
+pub const MH_FVMLIB: u32 = 0x3;
+/// core file
+pub const MH_CORE: u32 = 0x4;
+/// preloaded executable file
+pub const MH_PRELOAD: u32 = 0x5;
+/// dynamically bound shared library
+pub const MH_DYLIB: u32 = 0x6;
+/// dynamic link editor
+pub const MH_DYLINKER: u32 = 0x7;
+/// dynamically bound bundle file
+pub const MH_BUNDLE: u32 = 0x8;
+/// shared library stub for static linking only, no section contents
+pub const MH_DYLIB_STUB: u32 = 0x9;
+/// companion file with only debug sections
+pub const MH_DSYM: u32 = 0xa;
+/// x86_64 kexts
+pub const MH_KEXT_BUNDLE: u32 = 0xb;
+/// set of mach-o's
+pub const MH_FILESET: u32 = 0xc;
+
+// Values for `MachHeader*::flags`.
+/// the object file has no undefined references
+pub const MH_NOUNDEFS: u32 = 0x1;
+/// the object file is the output of an incremental link against a base file and can't be link edited again
+pub const MH_INCRLINK: u32 = 0x2;
+/// the object file is input for the dynamic linker and can't be statically link edited again
+pub const MH_DYLDLINK: u32 = 0x4;
+/// the object file's undefined references are bound by the dynamic linker when loaded.
+pub const MH_BINDATLOAD: u32 = 0x8;
+/// the file has its dynamic undefined references prebound.
+pub const MH_PREBOUND: u32 = 0x10;
+/// the file has its read-only and read-write segments split
+pub const MH_SPLIT_SEGS: u32 = 0x20;
+/// the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)
+pub const MH_LAZY_INIT: u32 = 0x40;
+/// the image is using two-level name space bindings
+pub const MH_TWOLEVEL: u32 = 0x80;
+/// the executable is forcing all images to use flat name space bindings
+pub const MH_FORCE_FLAT: u32 = 0x100;
+/// this umbrella guarantees no multiple definitions of symbols in its sub-images so the two-level namespace hints can always be used.
+pub const MH_NOMULTIDEFS: u32 = 0x200;
+/// do not have dyld notify the prebinding agent about this executable
+pub const MH_NOFIXPREBINDING: u32 = 0x400;
+/// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.
+pub const MH_PREBINDABLE: u32 = 0x800;
+/// indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set.
+pub const MH_ALLMODSBOUND: u32 = 0x1000;
+/// safe to divide up the sections into sub-sections via symbols for dead code stripping
+pub const MH_SUBSECTIONS_VIA_SYMBOLS: u32 = 0x2000;
+/// the binary has been canonicalized via the unprebind operation
+pub const MH_CANONICAL: u32 = 0x4000;
+/// the final linked image contains external weak symbols
+pub const MH_WEAK_DEFINES: u32 = 0x8000;
+/// the final linked image uses weak symbols
+pub const MH_BINDS_TO_WEAK: u32 = 0x10000;
+/// When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes.
+pub const MH_ALLOW_STACK_EXECUTION: u32 = 0x20000;
+/// When this bit is set, the binary declares it is safe for use in processes with uid zero
+pub const MH_ROOT_SAFE: u32 = 0x40000;
+/// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true
+pub const MH_SETUID_SAFE: u32 = 0x80000;
+/// When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported
+pub const MH_NO_REEXPORTED_DYLIBS: u32 = 0x10_0000;
+/// When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes.
+pub const MH_PIE: u32 = 0x20_0000;
+/// Only for use on dylibs. When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being referenced from the dylib.
+pub const MH_DEAD_STRIPPABLE_DYLIB: u32 = 0x40_0000;
+/// Contains a section of type S_THREAD_LOCAL_VARIABLES
+pub const MH_HAS_TLV_DESCRIPTORS: u32 = 0x80_0000;
+/// When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes.
+pub const MH_NO_HEAP_EXECUTION: u32 = 0x100_0000;
+/// The code was linked for use in an application extension.
+pub const MH_APP_EXTENSION_SAFE: u32 = 0x0200_0000;
+/// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info.
+pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO: u32 = 0x0400_0000;
+/// Allow LC_MIN_VERSION_MACOS and LC_BUILD_VERSION load commands with
+/// the platforms macOS, iOSMac, iOSSimulator, tvOSSimulator and watchOSSimulator.
+pub const MH_SIM_SUPPORT: u32 = 0x0800_0000;
+/// Only for use on dylibs. When this bit is set, the dylib is part of the dyld
+/// shared cache, rather than loose in the filesystem.
+pub const MH_DYLIB_IN_CACHE: u32 = 0x8000_0000;
+
+/// Common fields at the start of every load command.
+///
+/// The load commands directly follow the mach_header. The total size of all
+/// of the commands is given by the sizeofcmds field in the mach_header. All
+/// load commands must have as their first two fields `cmd` and `cmdsize`. The `cmd`
+/// field is filled in with a constant for that command type. Each command type
+/// has a structure specifically for it. The `cmdsize` field is the size in bytes
+/// of the particular load command structure plus anything that follows it that
+/// is a part of the load command (i.e. section structures, strings, etc.). To
+/// advance to the next load command the `cmdsize` can be added to the offset or
+/// pointer of the current load command. The `cmdsize` for 32-bit architectures
+/// MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple
+/// of 8 bytes (these are forever the maximum alignment of any load commands).
+/// The padded bytes must be zero. All tables in the object file must also
+/// follow these rules so the file can be memory mapped. Otherwise the pointers
+/// to these tables will not work well or at all on some machines. With all
+/// padding zeroed like objects will compare byte for byte.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct LoadCommand<E: Endian> {
+ /// Type of load command.
+ ///
+ /// One of the `LC_*` constants.
+ pub cmd: U32<E>,
+ /// Total size of command in bytes.
+ pub cmdsize: U32<E>,
+}
+
+/*
+ * After MacOS X 10.1 when a new load command is added that is required to be
+ * understood by the dynamic linker for the image to execute properly the
+ * LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic
+ * linker sees such a load command it it does not understand will issue a
+ * "unknown load command required for execution" error and refuse to use the
+ * image. Other load commands without this bit that are not understood will
+ * simply be ignored.
+ */
+pub const LC_REQ_DYLD: u32 = 0x8000_0000;
+
+/* Constants for the cmd field of all load commands, the type */
+/// segment of this file to be mapped
+pub const LC_SEGMENT: u32 = 0x1;
+/// link-edit stab symbol table info
+pub const LC_SYMTAB: u32 = 0x2;
+/// link-edit gdb symbol table info (obsolete)
+pub const LC_SYMSEG: u32 = 0x3;
+/// thread
+pub const LC_THREAD: u32 = 0x4;
+/// unix thread (includes a stack)
+pub const LC_UNIXTHREAD: u32 = 0x5;
+/// load a specified fixed VM shared library
+pub const LC_LOADFVMLIB: u32 = 0x6;
+/// fixed VM shared library identification
+pub const LC_IDFVMLIB: u32 = 0x7;
+/// object identification info (obsolete)
+pub const LC_IDENT: u32 = 0x8;
+/// fixed VM file inclusion (internal use)
+pub const LC_FVMFILE: u32 = 0x9;
+/// prepage command (internal use)
+pub const LC_PREPAGE: u32 = 0xa;
+/// dynamic link-edit symbol table info
+pub const LC_DYSYMTAB: u32 = 0xb;
+/// load a dynamically linked shared library
+pub const LC_LOAD_DYLIB: u32 = 0xc;
+/// dynamically linked shared lib ident
+pub const LC_ID_DYLIB: u32 = 0xd;
+/// load a dynamic linker
+pub const LC_LOAD_DYLINKER: u32 = 0xe;
+/// dynamic linker identification
+pub const LC_ID_DYLINKER: u32 = 0xf;
+/// modules prebound for a dynamically linked shared library
+pub const LC_PREBOUND_DYLIB: u32 = 0x10;
+/// image routines
+pub const LC_ROUTINES: u32 = 0x11;
+/// sub framework
+pub const LC_SUB_FRAMEWORK: u32 = 0x12;
+/// sub umbrella
+pub const LC_SUB_UMBRELLA: u32 = 0x13;
+/// sub client
+pub const LC_SUB_CLIENT: u32 = 0x14;
+/// sub library
+pub const LC_SUB_LIBRARY: u32 = 0x15;
+/// two-level namespace lookup hints
+pub const LC_TWOLEVEL_HINTS: u32 = 0x16;
+/// prebind checksum
+pub const LC_PREBIND_CKSUM: u32 = 0x17;
+/// load a dynamically linked shared library that is allowed to be missing
+/// (all symbols are weak imported).
+pub const LC_LOAD_WEAK_DYLIB: u32 = 0x18 | LC_REQ_DYLD;
+/// 64-bit segment of this file to be mapped
+pub const LC_SEGMENT_64: u32 = 0x19;
+/// 64-bit image routines
+pub const LC_ROUTINES_64: u32 = 0x1a;
+/// the uuid
+pub const LC_UUID: u32 = 0x1b;
+/// runpath additions
+pub const LC_RPATH: u32 = 0x1c | LC_REQ_DYLD;
+/// local of code signature
+pub const LC_CODE_SIGNATURE: u32 = 0x1d;
+/// local of info to split segments
+pub const LC_SEGMENT_SPLIT_INFO: u32 = 0x1e;
+/// load and re-export dylib
+pub const LC_REEXPORT_DYLIB: u32 = 0x1f | LC_REQ_DYLD;
+/// delay load of dylib until first use
+pub const LC_LAZY_LOAD_DYLIB: u32 = 0x20;
+/// encrypted segment information
+pub const LC_ENCRYPTION_INFO: u32 = 0x21;
+/// compressed dyld information
+pub const LC_DYLD_INFO: u32 = 0x22;
+/// compressed dyld information only
+pub const LC_DYLD_INFO_ONLY: u32 = 0x22 | LC_REQ_DYLD;
+/// load upward dylib
+pub const LC_LOAD_UPWARD_DYLIB: u32 = 0x23 | LC_REQ_DYLD;
+/// build for MacOSX min OS version
+pub const LC_VERSION_MIN_MACOSX: u32 = 0x24;
+/// build for iPhoneOS min OS version
+pub const LC_VERSION_MIN_IPHONEOS: u32 = 0x25;
+/// compressed table of function start addresses
+pub const LC_FUNCTION_STARTS: u32 = 0x26;
+/// string for dyld to treat like environment variable
+pub const LC_DYLD_ENVIRONMENT: u32 = 0x27;
+/// replacement for LC_UNIXTHREAD
+pub const LC_MAIN: u32 = 0x28 | LC_REQ_DYLD;
+/// table of non-instructions in __text
+pub const LC_DATA_IN_CODE: u32 = 0x29;
+/// source version used to build binary
+pub const LC_SOURCE_VERSION: u32 = 0x2A;
+/// Code signing DRs copied from linked dylibs
+pub const LC_DYLIB_CODE_SIGN_DRS: u32 = 0x2B;
+/// 64-bit encrypted segment information
+pub const LC_ENCRYPTION_INFO_64: u32 = 0x2C;
+/// linker options in MH_OBJECT files
+pub const LC_LINKER_OPTION: u32 = 0x2D;
+/// optimization hints in MH_OBJECT files
+pub const LC_LINKER_OPTIMIZATION_HINT: u32 = 0x2E;
+/// build for AppleTV min OS version
+pub const LC_VERSION_MIN_TVOS: u32 = 0x2F;
+/// build for Watch min OS version
+pub const LC_VERSION_MIN_WATCHOS: u32 = 0x30;
+/// arbitrary data included within a Mach-O file
+pub const LC_NOTE: u32 = 0x31;
+/// build for platform min OS version
+pub const LC_BUILD_VERSION: u32 = 0x32;
+/// used with `LinkeditDataCommand`, payload is trie
+pub const LC_DYLD_EXPORTS_TRIE: u32 = 0x33 | LC_REQ_DYLD;
+/// used with `LinkeditDataCommand`
+pub const LC_DYLD_CHAINED_FIXUPS: u32 = 0x34 | LC_REQ_DYLD;
+/// used with `FilesetEntryCommand`
+pub const LC_FILESET_ENTRY: u32 = 0x35 | LC_REQ_DYLD;
+
+/// A variable length string in a load command.
+///
+/// The strings are stored just after the load command structure and
+/// the offset is from the start of the load command structure. The size
+/// of the string is reflected in the `cmdsize` field of the load command.
+/// Once again any padded bytes to bring the `cmdsize` field to a multiple
+/// of 4 bytes must be zero.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct LcStr<E: Endian> {
+ /// offset to the string
+ pub offset: U32<E>,
+}
+
+/// 32-bit segment load command.
+///
+/// The segment load command indicates that a part of this file is to be
+/// mapped into the task's address space. The size of this segment in memory,
+/// vmsize, maybe equal to or larger than the amount to map from this file,
+/// filesize. The file is mapped starting at fileoff to the beginning of
+/// the segment in memory, vmaddr. The rest of the memory of the segment,
+/// if any, is allocated zero fill on demand. The segment's maximum virtual
+/// memory protection and initial virtual memory protection are specified
+/// by the maxprot and initprot fields. If the segment has sections then the
+/// `Section32` structures directly follow the segment command and their size is
+/// reflected in `cmdsize`.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SegmentCommand32<E: Endian> {
+ /// LC_SEGMENT
+ pub cmd: U32<E>,
+ /// includes sizeof section structs
+ pub cmdsize: U32<E>,
+ /// segment name
+ pub segname: [u8; 16],
+ /// memory address of this segment
+ pub vmaddr: U32<E>,
+ /// memory size of this segment
+ pub vmsize: U32<E>,
+ /// file offset of this segment
+ pub fileoff: U32<E>,
+ /// amount to map from the file
+ pub filesize: U32<E>,
+ /// maximum VM protection
+ pub maxprot: U32<E>,
+ /// initial VM protection
+ pub initprot: U32<E>,
+ /// number of sections in segment
+ pub nsects: U32<E>,
+ /// flags
+ pub flags: U32<E>,
+}
+
+/// 64-bit segment load command.
+///
+/// The 64-bit segment load command indicates that a part of this file is to be
+/// mapped into a 64-bit task's address space. If the 64-bit segment has
+/// sections then `Section64` structures directly follow the 64-bit segment
+/// command and their size is reflected in `cmdsize`.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SegmentCommand64<E: Endian> {
+ /// LC_SEGMENT_64
+ pub cmd: U32<E>,
+ /// includes sizeof section_64 structs
+ pub cmdsize: U32<E>,
+ /// segment name
+ pub segname: [u8; 16],
+ /// memory address of this segment
+ pub vmaddr: U64<E>,
+ /// memory size of this segment
+ pub vmsize: U64<E>,
+ /// file offset of this segment
+ pub fileoff: U64<E>,
+ /// amount to map from the file
+ pub filesize: U64<E>,
+ /// maximum VM protection
+ pub maxprot: U32<E>,
+ /// initial VM protection
+ pub initprot: U32<E>,
+ /// number of sections in segment
+ pub nsects: U32<E>,
+ /// flags
+ pub flags: U32<E>,
+}
+
+// Values for `SegmentCommand*::flags`.
+/// the file contents for this segment is for the high part of the VM space, the low part is zero filled (for stacks in core files)
+pub const SG_HIGHVM: u32 = 0x1;
+/// this segment is the VM that is allocated by a fixed VM library, for overlap checking in the link editor
+pub const SG_FVMLIB: u32 = 0x2;
+/// this segment has nothing that was relocated in it and nothing relocated to it, that is it maybe safely replaced without relocation
+pub const SG_NORELOC: u32 = 0x4;
+/// This segment is protected. If the segment starts at file offset 0, the first page of the segment is not protected. All other pages of the segment are protected.
+pub const SG_PROTECTED_VERSION_1: u32 = 0x8;
+/// This segment is made read-only after fixups
+pub const SG_READ_ONLY: u32 = 0x10;
+
+/*
+ * A segment is made up of zero or more sections. Non-MH_OBJECT files have
+ * all of their segments with the proper sections in each, and padded to the
+ * specified segment alignment when produced by the link editor. The first
+ * segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header
+ * and load commands of the object file before its first section. The zero
+ * fill sections are always last in their segment (in all formats). This
+ * allows the zeroed segment padding to be mapped into memory where zero fill
+ * sections might be. The gigabyte zero fill sections, those with the section
+ * type S_GB_ZEROFILL, can only be in a segment with sections of this type.
+ * These segments are then placed after all other segments.
+ *
+ * The MH_OBJECT format has all of its sections in one segment for
+ * compactness. There is no padding to a specified segment boundary and the
+ * mach_header and load commands are not part of the segment.
+ *
+ * Sections with the same section name, sectname, going into the same segment,
+ * segname, are combined by the link editor. The resulting section is aligned
+ * to the maximum alignment of the combined sections and is the new section's
+ * alignment. The combined sections are aligned to their original alignment in
+ * the combined section. Any padded bytes to get the specified alignment are
+ * zeroed.
+ *
+ * The format of the relocation entries referenced by the reloff and nreloc
+ * fields of the section structure for mach object files is described in the
+ * header file <reloc.h>.
+ */
+/// 32-bit section.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Section32<E: Endian> {
+ /// name of this section
+ pub sectname: [u8; 16],
+ /// segment this section goes in
+ pub segname: [u8; 16],
+ /// memory address of this section
+ pub addr: U32<E>,
+ /// size in bytes of this section
+ pub size: U32<E>,
+ /// file offset of this section
+ pub offset: U32<E>,
+ /// section alignment (power of 2)
+ pub align: U32<E>,
+ /// file offset of relocation entries
+ pub reloff: U32<E>,
+ /// number of relocation entries
+ pub nreloc: U32<E>,
+ /// flags (section type and attributes)
+ pub flags: U32<E>,
+ /// reserved (for offset or index)
+ pub reserved1: U32<E>,
+ /// reserved (for count or sizeof)
+ pub reserved2: U32<E>,
+}
+
+/// 64-bit section.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Section64<E: Endian> {
+ /// name of this section
+ pub sectname: [u8; 16],
+ /// segment this section goes in
+ pub segname: [u8; 16],
+ /// memory address of this section
+ pub addr: U64<E>,
+ /// size in bytes of this section
+ pub size: U64<E>,
+ /// file offset of this section
+ pub offset: U32<E>,
+ /// section alignment (power of 2)
+ pub align: U32<E>,
+ /// file offset of relocation entries
+ pub reloff: U32<E>,
+ /// number of relocation entries
+ pub nreloc: U32<E>,
+ /// flags (section type and attributes)
+ pub flags: U32<E>,
+ /// reserved (for offset or index)
+ pub reserved1: U32<E>,
+ /// reserved (for count or sizeof)
+ pub reserved2: U32<E>,
+ /// reserved
+ pub reserved3: U32<E>,
+}
+
+/*
+ * The flags field of a section structure is separated into two parts a section
+ * type and section attributes. The section types are mutually exclusive (it
+ * can only have one type) but the section attributes are not (it may have more
+ * than one attribute).
+ */
+/// 256 section types
+pub const SECTION_TYPE: u32 = 0x0000_00ff;
+/// 24 section attributes
+pub const SECTION_ATTRIBUTES: u32 = 0xffff_ff00;
+
+/* Constants for the type of a section */
+/// regular section
+pub const S_REGULAR: u32 = 0x0;
+/// zero fill on demand section
+pub const S_ZEROFILL: u32 = 0x1;
+/// section with only literal C strings
+pub const S_CSTRING_LITERALS: u32 = 0x2;
+/// section with only 4 byte literals
+pub const S_4BYTE_LITERALS: u32 = 0x3;
+/// section with only 8 byte literals
+pub const S_8BYTE_LITERALS: u32 = 0x4;
+/// section with only pointers to literals
+pub const S_LITERAL_POINTERS: u32 = 0x5;
+/*
+ * For the two types of symbol pointers sections and the symbol stubs section
+ * they have indirect symbol table entries. For each of the entries in the
+ * section the indirect symbol table entries, in corresponding order in the
+ * indirect symbol table, start at the index stored in the reserved1 field
+ * of the section structure. Since the indirect symbol table entries
+ * correspond to the entries in the section the number of indirect symbol table
+ * entries is inferred from the size of the section divided by the size of the
+ * entries in the section. For symbol pointers sections the size of the entries
+ * in the section is 4 bytes and for symbol stubs sections the byte size of the
+ * stubs is stored in the reserved2 field of the section structure.
+ */
+/// section with only non-lazy symbol pointers
+pub const S_NON_LAZY_SYMBOL_POINTERS: u32 = 0x6;
+/// section with only lazy symbol pointers
+pub const S_LAZY_SYMBOL_POINTERS: u32 = 0x7;
+/// section with only symbol stubs, byte size of stub in the reserved2 field
+pub const S_SYMBOL_STUBS: u32 = 0x8;
+/// section with only function pointers for initialization
+pub const S_MOD_INIT_FUNC_POINTERS: u32 = 0x9;
+/// section with only function pointers for termination
+pub const S_MOD_TERM_FUNC_POINTERS: u32 = 0xa;
+/// section contains symbols that are to be coalesced
+pub const S_COALESCED: u32 = 0xb;
+/// zero fill on demand section (that can be larger than 4 gigabytes)
+pub const S_GB_ZEROFILL: u32 = 0xc;
+/// section with only pairs of function pointers for interposing
+pub const S_INTERPOSING: u32 = 0xd;
+/// section with only 16 byte literals
+pub const S_16BYTE_LITERALS: u32 = 0xe;
+/// section contains DTrace Object Format
+pub const S_DTRACE_DOF: u32 = 0xf;
+/// section with only lazy symbol pointers to lazy loaded dylibs
+pub const S_LAZY_DYLIB_SYMBOL_POINTERS: u32 = 0x10;
+/*
+ * Section types to support thread local variables
+ */
+/// template of initial values for TLVs
+pub const S_THREAD_LOCAL_REGULAR: u32 = 0x11;
+/// template of initial values for TLVs
+pub const S_THREAD_LOCAL_ZEROFILL: u32 = 0x12;
+/// TLV descriptors
+pub const S_THREAD_LOCAL_VARIABLES: u32 = 0x13;
+/// pointers to TLV descriptors
+pub const S_THREAD_LOCAL_VARIABLE_POINTERS: u32 = 0x14;
+/// functions to call to initialize TLV values
+pub const S_THREAD_LOCAL_INIT_FUNCTION_POINTERS: u32 = 0x15;
+/// 32-bit offsets to initializers
+pub const S_INIT_FUNC_OFFSETS: u32 = 0x16;
+
+/*
+ * Constants for the section attributes part of the flags field of a section
+ * structure.
+ */
+/// User setable attributes
+pub const SECTION_ATTRIBUTES_USR: u32 = 0xff00_0000;
+/// section contains only true machine instructions
+pub const S_ATTR_PURE_INSTRUCTIONS: u32 = 0x8000_0000;
+/// section contains coalesced symbols that are not to be in a ranlib table of contents
+pub const S_ATTR_NO_TOC: u32 = 0x4000_0000;
+/// ok to strip static symbols in this section in files with the MH_DYLDLINK flag
+pub const S_ATTR_STRIP_STATIC_SYMS: u32 = 0x2000_0000;
+/// no dead stripping
+pub const S_ATTR_NO_DEAD_STRIP: u32 = 0x1000_0000;
+/// blocks are live if they reference live blocks
+pub const S_ATTR_LIVE_SUPPORT: u32 = 0x0800_0000;
+/// Used with i386 code stubs written on by dyld
+pub const S_ATTR_SELF_MODIFYING_CODE: u32 = 0x0400_0000;
+/*
+ * If a segment contains any sections marked with S_ATTR_DEBUG then all
+ * sections in that segment must have this attribute. No section other than
+ * a section marked with this attribute may reference the contents of this
+ * section. A section with this attribute may contain no symbols and must have
+ * a section type S_REGULAR. The static linker will not copy section contents
+ * from sections with this attribute into its output file. These sections
+ * generally contain DWARF debugging info.
+ */
+/// a debug section
+pub const S_ATTR_DEBUG: u32 = 0x0200_0000;
+/// system setable attributes
+pub const SECTION_ATTRIBUTES_SYS: u32 = 0x00ff_ff00;
+/// section contains some machine instructions
+pub const S_ATTR_SOME_INSTRUCTIONS: u32 = 0x0000_0400;
+/// section has external relocation entries
+pub const S_ATTR_EXT_RELOC: u32 = 0x0000_0200;
+/// section has local relocation entries
+pub const S_ATTR_LOC_RELOC: u32 = 0x0000_0100;
+
+/*
+ * The names of segments and sections in them are mostly meaningless to the
+ * link-editor. But there are few things to support traditional UNIX
+ * executables that require the link-editor and assembler to use some names
+ * agreed upon by convention.
+ *
+ * The initial protection of the "__TEXT" segment has write protection turned
+ * off (not writeable).
+ *
+ * The link-editor will allocate common symbols at the end of the "__common"
+ * section in the "__DATA" segment. It will create the section and segment
+ * if needed.
+ */
+
+/* The currently known segment names and the section names in those segments */
+
+/// the pagezero segment which has no protections and catches NULL references for MH_EXECUTE files
+pub const SEG_PAGEZERO: &str = "__PAGEZERO";
+
+/// the tradition UNIX text segment
+pub const SEG_TEXT: &str = "__TEXT";
+/// the real text part of the text section no headers, and no padding
+pub const SECT_TEXT: &str = "__text";
+/// the fvmlib initialization section
+pub const SECT_FVMLIB_INIT0: &str = "__fvmlib_init0";
+/// the section following the fvmlib initialization section
+pub const SECT_FVMLIB_INIT1: &str = "__fvmlib_init1";
+
+/// the tradition UNIX data segment
+pub const SEG_DATA: &str = "__DATA";
+/// the real initialized data section no padding, no bss overlap
+pub const SECT_DATA: &str = "__data";
+/// the real uninitialized data section no padding
+pub const SECT_BSS: &str = "__bss";
+/// the section common symbols are allocated in by the link editor
+pub const SECT_COMMON: &str = "__common";
+
+/// objective-C runtime segment
+pub const SEG_OBJC: &str = "__OBJC";
+/// symbol table
+pub const SECT_OBJC_SYMBOLS: &str = "__symbol_table";
+/// module information
+pub const SECT_OBJC_MODULES: &str = "__module_info";
+/// string table
+pub const SECT_OBJC_STRINGS: &str = "__selector_strs";
+/// string table
+pub const SECT_OBJC_REFS: &str = "__selector_refs";
+
+/// the icon segment
+pub const SEG_ICON: &str = "__ICON";
+/// the icon headers
+pub const SECT_ICON_HEADER: &str = "__header";
+/// the icons in tiff format
+pub const SECT_ICON_TIFF: &str = "__tiff";
+
+/// the segment containing all structs created and maintained by the link editor. Created with -seglinkedit option to ld(1) for MH_EXECUTE and FVMLIB file types only
+pub const SEG_LINKEDIT: &str = "__LINKEDIT";
+
+/// the segment overlapping with linkedit containing linking information
+pub const SEG_LINKINFO: &str = "__LINKINFO";
+
+/// the unix stack segment
+pub const SEG_UNIXSTACK: &str = "__UNIXSTACK";
+
+/// the segment for the self (dyld) modifying code stubs that has read, write and execute permissions
+pub const SEG_IMPORT: &str = "__IMPORT";
+
+/*
+ * Fixed virtual memory shared libraries are identified by two things. The
+ * target pathname (the name of the library as found for execution), and the
+ * minor version number. The address of where the headers are loaded is in
+ * header_addr. (THIS IS OBSOLETE and no longer supported).
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Fvmlib<E: Endian> {
+ /// library's target pathname
+ pub name: LcStr<E>,
+ /// library's minor version number
+ pub minor_version: U32<E>,
+ /// library's header address
+ pub header_addr: U32<E>,
+}
+
+/*
+ * A fixed virtual shared library (filetype == MH_FVMLIB in the mach header)
+ * contains a `FvmlibCommand` (cmd == LC_IDFVMLIB) to identify the library.
+ * An object that uses a fixed virtual shared library also contains a
+ * `FvmlibCommand` (cmd == LC_LOADFVMLIB) for each library it uses.
+ * (THIS IS OBSOLETE and no longer supported).
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FvmlibCommand<E: Endian> {
+ /// LC_IDFVMLIB or LC_LOADFVMLIB
+ pub cmd: U32<E>,
+ /// includes pathname string
+ pub cmdsize: U32<E>,
+ /// the library identification
+ pub fvmlib: Fvmlib<E>,
+}
+
+/*
+ * Dynamically linked shared libraries are identified by two things. The
+ * pathname (the name of the library as found for execution), and the
+ * compatibility version number. The pathname must match and the compatibility
+ * number in the user of the library must be greater than or equal to the
+ * library being used. The time stamp is used to record the time a library was
+ * built and copied into user so it can be use to determined if the library used
+ * at runtime is exactly the same as used to built the program.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Dylib<E: Endian> {
+ /// library's path name
+ pub name: LcStr<E>,
+ /// library's build time stamp
+ pub timestamp: U32<E>,
+ /// library's current version number
+ pub current_version: U32<E>,
+ /// library's compatibility vers number
+ pub compatibility_version: U32<E>,
+}
+
+/*
+ * A dynamically linked shared library (filetype == MH_DYLIB in the mach header)
+ * contains a `DylibCommand` (cmd == LC_ID_DYLIB) to identify the library.
+ * An object that uses a dynamically linked shared library also contains a
+ * `DylibCommand` (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
+ * LC_REEXPORT_DYLIB) for each library it uses.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DylibCommand<E: Endian> {
+ /// LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, LC_REEXPORT_DYLIB
+ pub cmd: U32<E>,
+ /// includes pathname string
+ pub cmdsize: U32<E>,
+ /// the library identification
+ pub dylib: Dylib<E>,
+}
+
+/*
+ * A dynamically linked shared library may be a subframework of an umbrella
+ * framework. If so it will be linked with "-umbrella umbrella_name" where
+ * Where "umbrella_name" is the name of the umbrella framework. A subframework
+ * can only be linked against by its umbrella framework or other subframeworks
+ * that are part of the same umbrella framework. Otherwise the static link
+ * editor produces an error and states to link against the umbrella framework.
+ * The name of the umbrella framework for subframeworks is recorded in the
+ * following structure.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SubFrameworkCommand<E: Endian> {
+ /// LC_SUB_FRAMEWORK
+ pub cmd: U32<E>,
+ /// includes umbrella string
+ pub cmdsize: U32<E>,
+ /// the umbrella framework name
+ pub umbrella: LcStr<E>,
+}
+
+/*
+ * For dynamically linked shared libraries that are subframework of an umbrella
+ * framework they can allow clients other than the umbrella framework or other
+ * subframeworks in the same umbrella framework. To do this the subframework
+ * is built with "-allowable_client client_name" and an LC_SUB_CLIENT load
+ * command is created for each -allowable_client flag. The client_name is
+ * usually a framework name. It can also be a name used for bundles clients
+ * where the bundle is built with "-client_name client_name".
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SubClientCommand<E: Endian> {
+ /// LC_SUB_CLIENT
+ pub cmd: U32<E>,
+ /// includes client string
+ pub cmdsize: U32<E>,
+ /// the client name
+ pub client: LcStr<E>,
+}
+
+/*
+ * A dynamically linked shared library may be a sub_umbrella of an umbrella
+ * framework. If so it will be linked with "-sub_umbrella umbrella_name" where
+ * Where "umbrella_name" is the name of the sub_umbrella framework. When
+ * statically linking when -twolevel_namespace is in effect a twolevel namespace
+ * umbrella framework will only cause its subframeworks and those frameworks
+ * listed as sub_umbrella frameworks to be implicited linked in. Any other
+ * dependent dynamic libraries will not be linked it when -twolevel_namespace
+ * is in effect. The primary library recorded by the static linker when
+ * resolving a symbol in these libraries will be the umbrella framework.
+ * Zero or more sub_umbrella frameworks may be use by an umbrella framework.
+ * The name of a sub_umbrella framework is recorded in the following structure.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SubUmbrellaCommand<E: Endian> {
+ /// LC_SUB_UMBRELLA
+ pub cmd: U32<E>,
+ /// includes sub_umbrella string
+ pub cmdsize: U32<E>,
+ /// the sub_umbrella framework name
+ pub sub_umbrella: LcStr<E>,
+}
+
+/*
+ * A dynamically linked shared library may be a sub_library of another shared
+ * library. If so it will be linked with "-sub_library library_name" where
+ * Where "library_name" is the name of the sub_library shared library. When
+ * statically linking when -twolevel_namespace is in effect a twolevel namespace
+ * shared library will only cause its subframeworks and those frameworks
+ * listed as sub_umbrella frameworks and libraries listed as sub_libraries to
+ * be implicited linked in. Any other dependent dynamic libraries will not be
+ * linked it when -twolevel_namespace is in effect. The primary library
+ * recorded by the static linker when resolving a symbol in these libraries
+ * will be the umbrella framework (or dynamic library). Zero or more sub_library
+ * shared libraries may be use by an umbrella framework or (or dynamic library).
+ * The name of a sub_library framework is recorded in the following structure.
+ * For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc".
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SubLibraryCommand<E: Endian> {
+ /// LC_SUB_LIBRARY
+ pub cmd: U32<E>,
+ /// includes sub_library string
+ pub cmdsize: U32<E>,
+ /// the sub_library name
+ pub sub_library: LcStr<E>,
+}
+
+/*
+ * A program (filetype == MH_EXECUTE) that is
+ * prebound to its dynamic libraries has one of these for each library that
+ * the static linker used in prebinding. It contains a bit vector for the
+ * modules in the library. The bits indicate which modules are bound (1) and
+ * which are not (0) from the library. The bit for module 0 is the low bit
+ * of the first byte. So the bit for the Nth module is:
+ * (linked_modules[N/8] >> N%8) & 1
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct PreboundDylibCommand<E: Endian> {
+ /// LC_PREBOUND_DYLIB
+ pub cmd: U32<E>,
+ /// includes strings
+ pub cmdsize: U32<E>,
+ /// library's path name
+ pub name: LcStr<E>,
+ /// number of modules in library
+ pub nmodules: U32<E>,
+ /// bit vector of linked modules
+ pub linked_modules: LcStr<E>,
+}
+
+/*
+ * A program that uses a dynamic linker contains a `DylinkerCommand` to identify
+ * the name of the dynamic linker (LC_LOAD_DYLINKER). And a dynamic linker
+ * contains a `DylinkerCommand` to identify the dynamic linker (LC_ID_DYLINKER).
+ * A file can have at most one of these.
+ * This struct is also used for the LC_DYLD_ENVIRONMENT load command and
+ * contains string for dyld to treat like environment variable.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DylinkerCommand<E: Endian> {
+ /// LC_ID_DYLINKER, LC_LOAD_DYLINKER or LC_DYLD_ENVIRONMENT
+ pub cmd: U32<E>,
+ /// includes pathname string
+ pub cmdsize: U32<E>,
+ /// dynamic linker's path name
+ pub name: LcStr<E>,
+}
+
+/*
+ * Thread commands contain machine-specific data structures suitable for
+ * use in the thread state primitives. The machine specific data structures
+ * follow the struct `ThreadCommand` as follows.
+ * Each flavor of machine specific data structure is preceded by an uint32_t
+ * constant for the flavor of that data structure, an uint32_t that is the
+ * count of uint32_t's of the size of the state data structure and then
+ * the state data structure follows. This triple may be repeated for many
+ * flavors. The constants for the flavors, counts and state data structure
+ * definitions are expected to be in the header file <machine/thread_status.h>.
+ * These machine specific data structures sizes must be multiples of
+ * 4 bytes. The `cmdsize` reflects the total size of the `ThreadCommand`
+ * and all of the sizes of the constants for the flavors, counts and state
+ * data structures.
+ *
+ * For executable objects that are unix processes there will be one
+ * `ThreadCommand` (cmd == LC_UNIXTHREAD) created for it by the link-editor.
+ * This is the same as a LC_THREAD, except that a stack is automatically
+ * created (based on the shell's limit for the stack size). Command arguments
+ * and environment variables are copied onto that stack.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ThreadCommand<E: Endian> {
+ /// LC_THREAD or LC_UNIXTHREAD
+ pub cmd: U32<E>,
+ /// total size of this command
+ pub cmdsize: U32<E>,
+ /* uint32_t flavor flavor of thread state */
+ /* uint32_t count count of uint32_t's in thread state */
+ /* struct XXX_thread_state state thread state for this flavor */
+ /* ... */
+}
+
+/*
+ * The routines command contains the address of the dynamic shared library
+ * initialization routine and an index into the module table for the module
+ * that defines the routine. Before any modules are used from the library the
+ * dynamic linker fully binds the module that defines the initialization routine
+ * and then calls it. This gets called before any module initialization
+ * routines (used for C++ static constructors) in the library.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct RoutinesCommand32<E: Endian> {
+ /* for 32-bit architectures */
+ /// LC_ROUTINES
+ pub cmd: U32<E>,
+ /// total size of this command
+ pub cmdsize: U32<E>,
+ /// address of initialization routine
+ pub init_address: U32<E>,
+ /// index into the module table that the init routine is defined in
+ pub init_module: U32<E>,
+ pub reserved1: U32<E>,
+ pub reserved2: U32<E>,
+ pub reserved3: U32<E>,
+ pub reserved4: U32<E>,
+ pub reserved5: U32<E>,
+ pub reserved6: U32<E>,
+}
+
+/*
+ * The 64-bit routines command. Same use as above.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct RoutinesCommand64<E: Endian> {
+ /* for 64-bit architectures */
+ /// LC_ROUTINES_64
+ pub cmd: U32<E>,
+ /// total size of this command
+ pub cmdsize: U32<E>,
+ /// address of initialization routine
+ pub init_address: U64<E>,
+ /// index into the module table that the init routine is defined in
+ pub init_module: U64<E>,
+ pub reserved1: U64<E>,
+ pub reserved2: U64<E>,
+ pub reserved3: U64<E>,
+ pub reserved4: U64<E>,
+ pub reserved5: U64<E>,
+ pub reserved6: U64<E>,
+}
+
+/*
+ * The `SymtabCommand` contains the offsets and sizes of the link-edit 4.3BSD
+ * "stab" style symbol table information as described in the header files
+ * <nlist.h> and <stab.h>.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SymtabCommand<E: Endian> {
+ /// LC_SYMTAB
+ pub cmd: U32<E>,
+ /// sizeof(struct SymtabCommand)
+ pub cmdsize: U32<E>,
+ /// symbol table offset
+ pub symoff: U32<E>,
+ /// number of symbol table entries
+ pub nsyms: U32<E>,
+ /// string table offset
+ pub stroff: U32<E>,
+ /// string table size in bytes
+ pub strsize: U32<E>,
+}
+
+/*
+ * This is the second set of the symbolic information which is used to support
+ * the data structures for the dynamically link editor.
+ *
+ * The original set of symbolic information in the `SymtabCommand` which contains
+ * the symbol and string tables must also be present when this load command is
+ * present. When this load command is present the symbol table is organized
+ * into three groups of symbols:
+ * local symbols (static and debugging symbols) - grouped by module
+ * defined external symbols - grouped by module (sorted by name if not lib)
+ * undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
+ * and in order the were seen by the static
+ * linker if MH_BINDATLOAD is set)
+ * In this load command there are offsets and counts to each of the three groups
+ * of symbols.
+ *
+ * This load command contains a the offsets and sizes of the following new
+ * symbolic information tables:
+ * table of contents
+ * module table
+ * reference symbol table
+ * indirect symbol table
+ * The first three tables above (the table of contents, module table and
+ * reference symbol table) are only present if the file is a dynamically linked
+ * shared library. For executable and object modules, which are files
+ * containing only one module, the information that would be in these three
+ * tables is determined as follows:
+ * table of contents - the defined external symbols are sorted by name
+ * module table - the file contains only one module so everything in the
+ * file is part of the module.
+ * reference symbol table - is the defined and undefined external symbols
+ *
+ * For dynamically linked shared library files this load command also contains
+ * offsets and sizes to the pool of relocation entries for all sections
+ * separated into two groups:
+ * external relocation entries
+ * local relocation entries
+ * For executable and object modules the relocation entries continue to hang
+ * off the section structures.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DysymtabCommand<E: Endian> {
+ /// LC_DYSYMTAB
+ pub cmd: U32<E>,
+ /// sizeof(struct DysymtabCommand)
+ pub cmdsize: U32<E>,
+
+ /*
+ * The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
+ * are grouped into the following three groups:
+ * local symbols (further grouped by the module they are from)
+ * defined external symbols (further grouped by the module they are from)
+ * undefined symbols
+ *
+ * The local symbols are used only for debugging. The dynamic binding
+ * process may have to use them to indicate to the debugger the local
+ * symbols for a module that is being bound.
+ *
+ * The last two groups are used by the dynamic binding process to do the
+ * binding (indirectly through the module table and the reference symbol
+ * table when this is a dynamically linked shared library file).
+ */
+ /// index to local symbols
+ pub ilocalsym: U32<E>,
+ /// number of local symbols
+ pub nlocalsym: U32<E>,
+
+ /// index to externally defined symbols
+ pub iextdefsym: U32<E>,
+ /// number of externally defined symbols
+ pub nextdefsym: U32<E>,
+
+ /// index to undefined symbols
+ pub iundefsym: U32<E>,
+ /// number of undefined symbols
+ pub nundefsym: U32<E>,
+
+ /*
+ * For the for the dynamic binding process to find which module a symbol
+ * is defined in the table of contents is used (analogous to the ranlib
+ * structure in an archive) which maps defined external symbols to modules
+ * they are defined in. This exists only in a dynamically linked shared
+ * library file. For executable and object modules the defined external
+ * symbols are sorted by name and is use as the table of contents.
+ */
+ /// file offset to table of contents
+ pub tocoff: U32<E>,
+ /// number of entries in table of contents
+ pub ntoc: U32<E>,
+
+ /*
+ * To support dynamic binding of "modules" (whole object files) the symbol
+ * table must reflect the modules that the file was created from. This is
+ * done by having a module table that has indexes and counts into the merged
+ * tables for each module. The module structure that these two entries
+ * refer to is described below. This exists only in a dynamically linked
+ * shared library file. For executable and object modules the file only
+ * contains one module so everything in the file belongs to the module.
+ */
+ /// file offset to module table
+ pub modtaboff: U32<E>,
+ /// number of module table entries
+ pub nmodtab: U32<E>,
+
+ /*
+ * To support dynamic module binding the module structure for each module
+ * indicates the external references (defined and undefined) each module
+ * makes. For each module there is an offset and a count into the
+ * reference symbol table for the symbols that the module references.
+ * This exists only in a dynamically linked shared library file. For
+ * executable and object modules the defined external symbols and the
+ * undefined external symbols indicates the external references.
+ */
+ /// offset to referenced symbol table
+ pub extrefsymoff: U32<E>,
+ /// number of referenced symbol table entries
+ pub nextrefsyms: U32<E>,
+
+ /*
+ * The sections that contain "symbol pointers" and "routine stubs" have
+ * indexes and (implied counts based on the size of the section and fixed
+ * size of the entry) into the "indirect symbol" table for each pointer
+ * and stub. For every section of these two types the index into the
+ * indirect symbol table is stored in the section header in the field
+ * reserved1. An indirect symbol table entry is simply a 32bit index into
+ * the symbol table to the symbol that the pointer or stub is referring to.
+ * The indirect symbol table is ordered to match the entries in the section.
+ */
+ /// file offset to the indirect symbol table
+ pub indirectsymoff: U32<E>,
+ /// number of indirect symbol table entries
+ pub nindirectsyms: U32<E>,
+
+ /*
+ * To support relocating an individual module in a library file quickly the
+ * external relocation entries for each module in the library need to be
+ * accessed efficiently. Since the relocation entries can't be accessed
+ * through the section headers for a library file they are separated into
+ * groups of local and external entries further grouped by module. In this
+ * case the presents of this load command who's extreloff, nextrel,
+ * locreloff and nlocrel fields are non-zero indicates that the relocation
+ * entries of non-merged sections are not referenced through the section
+ * structures (and the reloff and nreloc fields in the section headers are
+ * set to zero).
+ *
+ * Since the relocation entries are not accessed through the section headers
+ * this requires the r_address field to be something other than a section
+ * offset to identify the item to be relocated. In this case r_address is
+ * set to the offset from the vmaddr of the first LC_SEGMENT command.
+ * For MH_SPLIT_SEGS images r_address is set to the the offset from the
+ * vmaddr of the first read-write LC_SEGMENT command.
+ *
+ * The relocation entries are grouped by module and the module table
+ * entries have indexes and counts into them for the group of external
+ * relocation entries for that the module.
+ *
+ * For sections that are merged across modules there must not be any
+ * remaining external relocation entries for them (for merged sections
+ * remaining relocation entries must be local).
+ */
+ /// offset to external relocation entries
+ pub extreloff: U32<E>,
+ /// number of external relocation entries
+ pub nextrel: U32<E>,
+
+ /*
+ * All the local relocation entries are grouped together (they are not
+ * grouped by their module since they are only used if the object is moved
+ * from it statically link edited address).
+ */
+ /// offset to local relocation entries
+ pub locreloff: U32<E>,
+ /// number of local relocation entries
+ pub nlocrel: U32<E>,
+}
+
+/*
+ * An indirect symbol table entry is simply a 32bit index into the symbol table
+ * to the symbol that the pointer or stub is referring to. Unless it is for a
+ * non-lazy symbol pointer section for a defined symbol which strip(1) as
+ * removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the
+ * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that.
+ */
+pub const INDIRECT_SYMBOL_LOCAL: u32 = 0x8000_0000;
+pub const INDIRECT_SYMBOL_ABS: u32 = 0x4000_0000;
+
+/* a table of contents entry */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DylibTableOfContents<E: Endian> {
+ /// the defined external symbol (index into the symbol table)
+ pub symbol_index: U32<E>,
+ /// index into the module table this symbol is defined in
+ pub module_index: U32<E>,
+}
+
+/* a module table entry */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DylibModule32<E: Endian> {
+ /// the module name (index into string table)
+ pub module_name: U32<E>,
+
+ /// index into externally defined symbols
+ pub iextdefsym: U32<E>,
+ /// number of externally defined symbols
+ pub nextdefsym: U32<E>,
+ /// index into reference symbol table
+ pub irefsym: U32<E>,
+ /// number of reference symbol table entries
+ pub nrefsym: U32<E>,
+ /// index into symbols for local symbols
+ pub ilocalsym: U32<E>,
+ /// number of local symbols
+ pub nlocalsym: U32<E>,
+
+ /// index into external relocation entries
+ pub iextrel: U32<E>,
+ /// number of external relocation entries
+ pub nextrel: U32<E>,
+
+ /// low 16 bits are the index into the init section, high 16 bits are the index into the term section
+ pub iinit_iterm: U32<E>,
+ /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries
+ pub ninit_nterm: U32<E>,
+
+ /// for this module address of the start of the (__OBJC,__module_info) section
+ pub objc_module_info_addr: U32<E>,
+ /// for this module size of the (__OBJC,__module_info) section
+ pub objc_module_info_size: U32<E>,
+}
+
+/* a 64-bit module table entry */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DylibModule64<E: Endian> {
+ /// the module name (index into string table)
+ pub module_name: U32<E>,
+
+ /// index into externally defined symbols
+ pub iextdefsym: U32<E>,
+ /// number of externally defined symbols
+ pub nextdefsym: U32<E>,
+ /// index into reference symbol table
+ pub irefsym: U32<E>,
+ /// number of reference symbol table entries
+ pub nrefsym: U32<E>,
+ /// index into symbols for local symbols
+ pub ilocalsym: U32<E>,
+ /// number of local symbols
+ pub nlocalsym: U32<E>,
+
+ /// index into external relocation entries
+ pub iextrel: U32<E>,
+ /// number of external relocation entries
+ pub nextrel: U32<E>,
+
+ /// low 16 bits are the index into the init section, high 16 bits are the index into the term section
+ pub iinit_iterm: U32<E>,
+ /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries
+ pub ninit_nterm: U32<E>,
+
+ /// for this module size of the (__OBJC,__module_info) section
+ pub objc_module_info_size: U32<E>,
+ /// for this module address of the start of the (__OBJC,__module_info) section
+ pub objc_module_info_addr: U64<E>,
+}
+
+/*
+ * The entries in the reference symbol table are used when loading the module
+ * (both by the static and dynamic link editors) and if the module is unloaded
+ * or replaced. Therefore all external symbols (defined and undefined) are
+ * listed in the module's reference table. The flags describe the type of
+ * reference that is being made. The constants for the flags are defined in
+ * <mach-o/nlist.h> as they are also used for symbol table entries.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DylibReference<E: Endian> {
+ /* TODO:
+ uint32_t isym:24, /* index into the symbol table */
+ flags:8; /* flags to indicate the type of reference */
+ */
+ pub bitfield: U32<E>,
+}
+
+/*
+ * The TwolevelHintsCommand contains the offset and number of hints in the
+ * two-level namespace lookup hints table.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct TwolevelHintsCommand<E: Endian> {
+ /// LC_TWOLEVEL_HINTS
+ pub cmd: U32<E>,
+ /// sizeof(struct TwolevelHintsCommand)
+ pub cmdsize: U32<E>,
+ /// offset to the hint table
+ pub offset: U32<E>,
+ /// number of hints in the hint table
+ pub nhints: U32<E>,
+}
+
+/*
+ * The entries in the two-level namespace lookup hints table are TwolevelHint
+ * structs. These provide hints to the dynamic link editor where to start
+ * looking for an undefined symbol in a two-level namespace image. The
+ * isub_image field is an index into the sub-images (sub-frameworks and
+ * sub-umbrellas list) that made up the two-level image that the undefined
+ * symbol was found in when it was built by the static link editor. If
+ * isub-image is 0 the the symbol is expected to be defined in library and not
+ * in the sub-images. If isub-image is non-zero it is an index into the array
+ * of sub-images for the umbrella with the first index in the sub-images being
+ * 1. The array of sub-images is the ordered list of sub-images of the umbrella
+ * that would be searched for a symbol that has the umbrella recorded as its
+ * primary library. The table of contents index is an index into the
+ * library's table of contents. This is used as the starting point of the
+ * binary search or a directed linear search.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct TwolevelHint<E: Endian> {
+ /* TODO:
+ uint32_t
+ isub_image:8, /* index into the sub images */
+ itoc:24; /* index into the table of contents */
+ */
+ pub bitfield: U32<E>,
+}
+
+/*
+ * The PrebindCksumCommand contains the value of the original check sum for
+ * prebound files or zero. When a prebound file is first created or modified
+ * for other than updating its prebinding information the value of the check sum
+ * is set to zero. When the file has it prebinding re-done and if the value of
+ * the check sum is zero the original check sum is calculated and stored in
+ * cksum field of this load command in the output file. If when the prebinding
+ * is re-done and the cksum field is non-zero it is left unchanged from the
+ * input file.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct PrebindCksumCommand<E: Endian> {
+ /// LC_PREBIND_CKSUM
+ pub cmd: U32<E>,
+ /// sizeof(struct PrebindCksumCommand)
+ pub cmdsize: U32<E>,
+ /// the check sum or zero
+ pub cksum: U32<E>,
+}
+
+/*
+ * The uuid load command contains a single 128-bit unique random number that
+ * identifies an object produced by the static link editor.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct UuidCommand<E: Endian> {
+ /// LC_UUID
+ pub cmd: U32<E>,
+ /// sizeof(struct UuidCommand)
+ pub cmdsize: U32<E>,
+ /// the 128-bit uuid
+ pub uuid: [u8; 16],
+}
+
+/*
+ * The RpathCommand contains a path which at runtime should be added to
+ * the current run path used to find @rpath prefixed dylibs.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct RpathCommand<E: Endian> {
+ /// LC_RPATH
+ pub cmd: U32<E>,
+ /// includes string
+ pub cmdsize: U32<E>,
+ /// path to add to run path
+ pub path: LcStr<E>,
+}
+
+/*
+ * The LinkeditDataCommand contains the offsets and sizes of a blob
+ * of data in the __LINKEDIT segment.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct LinkeditDataCommand<E: Endian> {
+ /// `LC_CODE_SIGNATURE`, `LC_SEGMENT_SPLIT_INFO`, `LC_FUNCTION_STARTS`,
+ /// `LC_DATA_IN_CODE`, `LC_DYLIB_CODE_SIGN_DRS`, `LC_LINKER_OPTIMIZATION_HINT`,
+ /// `LC_DYLD_EXPORTS_TRIE`, or `LC_DYLD_CHAINED_FIXUPS`.
+ pub cmd: U32<E>,
+ /// sizeof(struct LinkeditDataCommand)
+ pub cmdsize: U32<E>,
+ /// file offset of data in __LINKEDIT segment
+ pub dataoff: U32<E>,
+ /// file size of data in __LINKEDIT segment
+ pub datasize: U32<E>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FilesetEntryCommand<E: Endian> {
+ // LC_FILESET_ENTRY
+ pub cmd: U32<E>,
+ /// includes id string
+ pub cmdsize: U32<E>,
+ /// memory address of the dylib
+ pub vmaddr: U64<E>,
+ /// file offset of the dylib
+ pub fileoff: U64<E>,
+ /// contained entry id
+ pub entry_id: LcStr<E>,
+ /// entry_id is 32-bits long, so this is the reserved padding
+ pub reserved: U32<E>,
+}
+
+/*
+ * The EncryptionInfoCommand32 contains the file offset and size of an
+ * of an encrypted segment.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct EncryptionInfoCommand32<E: Endian> {
+ /// LC_ENCRYPTION_INFO
+ pub cmd: U32<E>,
+ /// sizeof(struct EncryptionInfoCommand32)
+ pub cmdsize: U32<E>,
+ /// file offset of encrypted range
+ pub cryptoff: U32<E>,
+ /// file size of encrypted range
+ pub cryptsize: U32<E>,
+ /// which enryption system, 0 means not-encrypted yet
+ pub cryptid: U32<E>,
+}
+
+/*
+ * The EncryptionInfoCommand64 contains the file offset and size of an
+ * of an encrypted segment (for use in x86_64 targets).
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct EncryptionInfoCommand64<E: Endian> {
+ /// LC_ENCRYPTION_INFO_64
+ pub cmd: U32<E>,
+ /// sizeof(struct EncryptionInfoCommand64)
+ pub cmdsize: U32<E>,
+ /// file offset of encrypted range
+ pub cryptoff: U32<E>,
+ /// file size of encrypted range
+ pub cryptsize: U32<E>,
+ /// which enryption system, 0 means not-encrypted yet
+ pub cryptid: U32<E>,
+ /// padding to make this struct's size a multiple of 8 bytes
+ pub pad: U32<E>,
+}
+
+/*
+ * The VersionMinCommand contains the min OS version on which this
+ * binary was built to run.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct VersionMinCommand<E: Endian> {
+ /// LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_WATCHOS or LC_VERSION_MIN_TVOS
+ pub cmd: U32<E>,
+ /// sizeof(struct VersionMinCommand)
+ pub cmdsize: U32<E>,
+ /// X.Y.Z is encoded in nibbles xxxx.yy.zz
+ pub version: U32<E>,
+ /// X.Y.Z is encoded in nibbles xxxx.yy.zz
+ pub sdk: U32<E>,
+}
+
+/*
+ * The BuildVersionCommand contains the min OS version on which this
+ * binary was built to run for its platform. The list of known platforms and
+ * tool values following it.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct BuildVersionCommand<E: Endian> {
+ /// LC_BUILD_VERSION
+ pub cmd: U32<E>,
+ /// sizeof(struct BuildVersionCommand) plus ntools * sizeof(struct BuildToolVersion)
+ pub cmdsize: U32<E>,
+ /// platform
+ pub platform: U32<E>,
+ /// X.Y.Z is encoded in nibbles xxxx.yy.zz
+ pub minos: U32<E>,
+ /// X.Y.Z is encoded in nibbles xxxx.yy.zz
+ pub sdk: U32<E>,
+ /// number of tool entries following this
+ pub ntools: U32<E>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct BuildToolVersion<E: Endian> {
+ /// enum for the tool
+ pub tool: U32<E>,
+ /// version number of the tool
+ pub version: U32<E>,
+}
+
+/* Known values for the platform field above. */
+pub const PLATFORM_MACOS: u32 = 1;
+pub const PLATFORM_IOS: u32 = 2;
+pub const PLATFORM_TVOS: u32 = 3;
+pub const PLATFORM_WATCHOS: u32 = 4;
+pub const PLATFORM_BRIDGEOS: u32 = 5;
+pub const PLATFORM_MACCATALYST: u32 = 6;
+pub const PLATFORM_IOSSIMULATOR: u32 = 7;
+pub const PLATFORM_TVOSSIMULATOR: u32 = 8;
+pub const PLATFORM_WATCHOSSIMULATOR: u32 = 9;
+pub const PLATFORM_DRIVERKIT: u32 = 10;
+
+/* Known values for the tool field above. */
+pub const TOOL_CLANG: u32 = 1;
+pub const TOOL_SWIFT: u32 = 2;
+pub const TOOL_LD: u32 = 3;
+
+/*
+ * The DyldInfoCommand contains the file offsets and sizes of
+ * the new compressed form of the information dyld needs to
+ * load the image. This information is used by dyld on Mac OS X
+ * 10.6 and later. All information pointed to by this command
+ * is encoded using byte streams, so no endian swapping is needed
+ * to interpret it.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DyldInfoCommand<E: Endian> {
+ /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY
+ pub cmd: U32<E>,
+ /// sizeof(struct DyldInfoCommand)
+ pub cmdsize: U32<E>,
+
+ /*
+ * Dyld rebases an image whenever dyld loads it at an address different
+ * from its preferred address. The rebase information is a stream
+ * of byte sized opcodes whose symbolic names start with REBASE_OPCODE_.
+ * Conceptually the rebase information is a table of tuples:
+ * <seg-index, seg-offset, type>
+ * The opcodes are a compressed way to encode the table by only
+ * encoding when a column changes. In addition simple patterns
+ * like "every n'th offset for m times" can be encoded in a few
+ * bytes.
+ */
+ /// file offset to rebase info
+ pub rebase_off: U32<E>,
+ /// size of rebase info
+ pub rebase_size: U32<E>,
+
+ /*
+ * Dyld binds an image during the loading process, if the image
+ * requires any pointers to be initialized to symbols in other images.
+ * The bind information is a stream of byte sized
+ * opcodes whose symbolic names start with BIND_OPCODE_.
+ * Conceptually the bind information is a table of tuples:
+ * <seg-index, seg-offset, type, symbol-library-ordinal, symbol-name, addend>
+ * The opcodes are a compressed way to encode the table by only
+ * encoding when a column changes. In addition simple patterns
+ * like for runs of pointers initialized to the same value can be
+ * encoded in a few bytes.
+ */
+ /// file offset to binding info
+ pub bind_off: U32<E>,
+ /// size of binding info
+ pub bind_size: U32<E>,
+
+ /*
+ * Some C++ programs require dyld to unique symbols so that all
+ * images in the process use the same copy of some code/data.
+ * This step is done after binding. The content of the weak_bind
+ * info is an opcode stream like the bind_info. But it is sorted
+ * alphabetically by symbol name. This enable dyld to walk
+ * all images with weak binding information in order and look
+ * for collisions. If there are no collisions, dyld does
+ * no updating. That means that some fixups are also encoded
+ * in the bind_info. For instance, all calls to "operator new"
+ * are first bound to libstdc++.dylib using the information
+ * in bind_info. Then if some image overrides operator new
+ * that is detected when the weak_bind information is processed
+ * and the call to operator new is then rebound.
+ */
+ /// file offset to weak binding info
+ pub weak_bind_off: U32<E>,
+ /// size of weak binding info
+ pub weak_bind_size: U32<E>,
+
+ /*
+ * Some uses of external symbols do not need to be bound immediately.
+ * Instead they can be lazily bound on first use. The lazy_bind
+ * are contains a stream of BIND opcodes to bind all lazy symbols.
+ * Normal use is that dyld ignores the lazy_bind section when
+ * loading an image. Instead the static linker arranged for the
+ * lazy pointer to initially point to a helper function which
+ * pushes the offset into the lazy_bind area for the symbol
+ * needing to be bound, then jumps to dyld which simply adds
+ * the offset to lazy_bind_off to get the information on what
+ * to bind.
+ */
+ /// file offset to lazy binding info
+ pub lazy_bind_off: U32<E>,
+ /// size of lazy binding infs
+ pub lazy_bind_size: U32<E>,
+
+ /*
+ * The symbols exported by a dylib are encoded in a trie. This
+ * is a compact representation that factors out common prefixes.
+ * It also reduces LINKEDIT pages in RAM because it encodes all
+ * information (name, address, flags) in one small, contiguous range.
+ * The export area is a stream of nodes. The first node sequentially
+ * is the start node for the trie.
+ *
+ * Nodes for a symbol start with a uleb128 that is the length of
+ * the exported symbol information for the string so far.
+ * If there is no exported symbol, the node starts with a zero byte.
+ * If there is exported info, it follows the length.
+ *
+ * First is a uleb128 containing flags. Normally, it is followed by
+ * a uleb128 encoded offset which is location of the content named
+ * by the symbol from the mach_header for the image. If the flags
+ * is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
+ * a uleb128 encoded library ordinal, then a zero terminated
+ * UTF8 string. If the string is zero length, then the symbol
+ * is re-export from the specified dylib with the same name.
+ * If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
+ * the flags is two uleb128s: the stub offset and the resolver offset.
+ * The stub is used by non-lazy pointers. The resolver is used
+ * by lazy pointers and must be called to get the actual address to use.
+ *
+ * After the optional exported symbol information is a byte of
+ * how many edges (0-255) that this node has leaving it,
+ * followed by each edge.
+ * Each edge is a zero terminated UTF8 of the addition chars
+ * in the symbol, followed by a uleb128 offset for the node that
+ * edge points to.
+ *
+ */
+ /// file offset to lazy binding info
+ pub export_off: U32<E>,
+ /// size of lazy binding infs
+ pub export_size: U32<E>,
+}
+
+/*
+ * The following are used to encode rebasing information
+ */
+pub const REBASE_TYPE_POINTER: u8 = 1;
+pub const REBASE_TYPE_TEXT_ABSOLUTE32: u8 = 2;
+pub const REBASE_TYPE_TEXT_PCREL32: u8 = 3;
+
+pub const REBASE_OPCODE_MASK: u8 = 0xF0;
+pub const REBASE_IMMEDIATE_MASK: u8 = 0x0F;
+pub const REBASE_OPCODE_DONE: u8 = 0x00;
+pub const REBASE_OPCODE_SET_TYPE_IMM: u8 = 0x10;
+pub const REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x20;
+pub const REBASE_OPCODE_ADD_ADDR_ULEB: u8 = 0x30;
+pub const REBASE_OPCODE_ADD_ADDR_IMM_SCALED: u8 = 0x40;
+pub const REBASE_OPCODE_DO_REBASE_IMM_TIMES: u8 = 0x50;
+pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES: u8 = 0x60;
+pub const REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: u8 = 0x70;
+pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: u8 = 0x80;
+
+/*
+ * The following are used to encode binding information
+ */
+pub const BIND_TYPE_POINTER: u8 = 1;
+pub const BIND_TYPE_TEXT_ABSOLUTE32: u8 = 2;
+pub const BIND_TYPE_TEXT_PCREL32: u8 = 3;
+
+pub const BIND_SPECIAL_DYLIB_SELF: i8 = 0;
+pub const BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE: i8 = -1;
+pub const BIND_SPECIAL_DYLIB_FLAT_LOOKUP: i8 = -2;
+pub const BIND_SPECIAL_DYLIB_WEAK_LOOKUP: i8 = -3;
+
+pub const BIND_SYMBOL_FLAGS_WEAK_IMPORT: u8 = 0x1;
+pub const BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION: u8 = 0x8;
+
+pub const BIND_OPCODE_MASK: u8 = 0xF0;
+pub const BIND_IMMEDIATE_MASK: u8 = 0x0F;
+pub const BIND_OPCODE_DONE: u8 = 0x00;
+pub const BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: u8 = 0x10;
+pub const BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: u8 = 0x20;
+pub const BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: u8 = 0x30;
+pub const BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: u8 = 0x40;
+pub const BIND_OPCODE_SET_TYPE_IMM: u8 = 0x50;
+pub const BIND_OPCODE_SET_ADDEND_SLEB: u8 = 0x60;
+pub const BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x70;
+pub const BIND_OPCODE_ADD_ADDR_ULEB: u8 = 0x80;
+pub const BIND_OPCODE_DO_BIND: u8 = 0x90;
+pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xA0;
+pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xB0;
+pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = 0xC0;
+pub const BIND_OPCODE_THREADED: u8 = 0xD0;
+pub const BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB: u8 = 0x00;
+pub const BIND_SUBOPCODE_THREADED_APPLY: u8 = 0x01;
+
+/*
+ * The following are used on the flags byte of a terminal node
+ * in the export information.
+ */
+pub const EXPORT_SYMBOL_FLAGS_KIND_MASK: u32 = 0x03;
+pub const EXPORT_SYMBOL_FLAGS_KIND_REGULAR: u32 = 0x00;
+pub const EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: u32 = 0x01;
+pub const EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: u32 = 0x02;
+pub const EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION: u32 = 0x04;
+pub const EXPORT_SYMBOL_FLAGS_REEXPORT: u32 = 0x08;
+pub const EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER: u32 = 0x10;
+
+/*
+ * The LinkerOptionCommand contains linker options embedded in object files.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct LinkerOptionCommand<E: Endian> {
+ /// LC_LINKER_OPTION only used in MH_OBJECT filetypes
+ pub cmd: U32<E>,
+ pub cmdsize: U32<E>,
+ /// number of strings
+ pub count: U32<E>,
+ /* concatenation of zero terminated UTF8 strings.
+ Zero filled at end to align */
+}
+
+/*
+ * The SymsegCommand contains the offset and size of the GNU style
+ * symbol table information as described in the header file <symseg.h>.
+ * The symbol roots of the symbol segments must also be aligned properly
+ * in the file. So the requirement of keeping the offsets aligned to a
+ * multiple of a 4 bytes translates to the length field of the symbol
+ * roots also being a multiple of a long. Also the padding must again be
+ * zeroed. (THIS IS OBSOLETE and no longer supported).
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SymsegCommand<E: Endian> {
+ /// LC_SYMSEG
+ pub cmd: U32<E>,
+ /// sizeof(struct SymsegCommand)
+ pub cmdsize: U32<E>,
+ /// symbol segment offset
+ pub offset: U32<E>,
+ /// symbol segment size in bytes
+ pub size: U32<E>,
+}
+
+/*
+ * The IdentCommand contains a free format string table following the
+ * IdentCommand structure. The strings are null terminated and the size of
+ * the command is padded out with zero bytes to a multiple of 4 bytes/
+ * (THIS IS OBSOLETE and no longer supported).
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct IdentCommand<E: Endian> {
+ /// LC_IDENT
+ pub cmd: U32<E>,
+ /// strings that follow this command
+ pub cmdsize: U32<E>,
+}
+
+/*
+ * The FvmfileCommand contains a reference to a file to be loaded at the
+ * specified virtual address. (Presently, this command is reserved for
+ * internal use. The kernel ignores this command when loading a program into
+ * memory).
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FvmfileCommand<E: Endian> {
+ /// LC_FVMFILE
+ pub cmd: U32<E>,
+ /// includes pathname string
+ pub cmdsize: U32<E>,
+ /// files pathname
+ pub name: LcStr<E>,
+ /// files virtual address
+ pub header_addr: U32<E>,
+}
+
+/*
+ * The EntryPointCommand is a replacement for thread_command.
+ * It is used for main executables to specify the location (file offset)
+ * of main(). If -stack_size was used at link time, the stacksize
+ * field will contain the stack size need for the main thread.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct EntryPointCommand<E: Endian> {
+ /// LC_MAIN only used in MH_EXECUTE filetypes
+ pub cmd: U32<E>,
+ /// 24
+ pub cmdsize: U32<E>,
+ /// file (__TEXT) offset of main()
+ pub entryoff: U64<E>,
+ /// if not zero, initial stack size
+ pub stacksize: U64<E>,
+}
+
+/*
+ * The SourceVersionCommand is an optional load command containing
+ * the version of the sources used to build the binary.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SourceVersionCommand<E: Endian> {
+ /// LC_SOURCE_VERSION
+ pub cmd: U32<E>,
+ /// 16
+ pub cmdsize: U32<E>,
+ /// A.B.C.D.E packed as a24.b10.c10.d10.e10
+ pub version: U64<E>,
+}
+
+/*
+ * The LC_DATA_IN_CODE load commands uses a LinkeditDataCommand
+ * to point to an array of DataInCodeEntry entries. Each entry
+ * describes a range of data in a code section.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DataInCodeEntry<E: Endian> {
+ /// from mach_header to start of data range
+ pub offset: U32<E>,
+ /// number of bytes in data range
+ pub length: U16<E>,
+ /// a DICE_KIND_* value
+ pub kind: U16<E>,
+}
+pub const DICE_KIND_DATA: u32 = 0x0001;
+pub const DICE_KIND_JUMP_TABLE8: u32 = 0x0002;
+pub const DICE_KIND_JUMP_TABLE16: u32 = 0x0003;
+pub const DICE_KIND_JUMP_TABLE32: u32 = 0x0004;
+pub const DICE_KIND_ABS_JUMP_TABLE32: u32 = 0x0005;
+
+/*
+ * Sections of type S_THREAD_LOCAL_VARIABLES contain an array
+ * of TlvDescriptor structures.
+ */
+/* TODO:
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct TlvDescriptor<E: Endian>
+{
+ void* (*thunk)(struct TlvDescriptor*);
+ unsigned long key;
+ unsigned long offset;
+}
+*/
+
+/*
+ * LC_NOTE commands describe a region of arbitrary data included in a Mach-O
+ * file. Its initial use is to record extra data in MH_CORE files.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct NoteCommand<E: Endian> {
+ /// LC_NOTE
+ pub cmd: U32<E>,
+ /// sizeof(struct NoteCommand)
+ pub cmdsize: U32<E>,
+ /// owner name for this LC_NOTE
+ pub data_owner: [u8; 16],
+ /// file offset of this data
+ pub offset: U64<E>,
+ /// length of data region
+ pub size: U64<E>,
+}
+
+// Definitions from "/usr/include/mach-o/nlist.h".
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Nlist32<E: Endian> {
+ /// index into the string table
+ pub n_strx: U32<E>,
+ /// type flag, see below
+ pub n_type: u8,
+ /// section number or NO_SECT
+ pub n_sect: u8,
+ /// see <mach-o/stab.h>
+ pub n_desc: U16<E>,
+ /// value of this symbol (or stab offset)
+ pub n_value: U32<E>,
+}
+
+/*
+ * This is the symbol table entry structure for 64-bit architectures.
+ */
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Nlist64<E: Endian> {
+ /// index into the string table
+ pub n_strx: U32<E>,
+ /// type flag, see below
+ pub n_type: u8,
+ /// section number or NO_SECT
+ pub n_sect: u8,
+ /// see <mach-o/stab.h>
+ pub n_desc: U16<E>,
+ /// value of this symbol (or stab offset)
+ // Note: 4 byte alignment has been observed in practice.
+ pub n_value: U64Bytes<E>,
+}
+
+/*
+ * Symbols with a index into the string table of zero (n_un.n_strx == 0) are
+ * defined to have a null, "", name. Therefore all string indexes to non null
+ * names must not have a zero string index. This is bit historical information
+ * that has never been well documented.
+ */
+
+/*
+ * The n_type field really contains four fields:
+ * unsigned char N_STAB:3,
+ * N_PEXT:1,
+ * N_TYPE:3,
+ * N_EXT:1;
+ * which are used via the following masks.
+ */
+/// if any of these bits set, a symbolic debugging entry
+pub const N_STAB: u8 = 0xe0;
+/// private external symbol bit
+pub const N_PEXT: u8 = 0x10;
+/// mask for the type bits
+pub const N_TYPE: u8 = 0x0e;
+/// external symbol bit, set for external symbols
+pub const N_EXT: u8 = 0x01;
+
+/*
+ * Only symbolic debugging entries have some of the N_STAB bits set and if any
+ * of these bits are set then it is a symbolic debugging entry (a stab). In
+ * which case then the values of the n_type field (the entire field) are given
+ * in <mach-o/stab.h>
+ */
+
+/*
+ * Values for N_TYPE bits of the n_type field.
+ */
+/// undefined, n_sect == NO_SECT
+pub const N_UNDF: u8 = 0x0;
+/// absolute, n_sect == NO_SECT
+pub const N_ABS: u8 = 0x2;
+/// defined in section number n_sect
+pub const N_SECT: u8 = 0xe;
+/// prebound undefined (defined in a dylib)
+pub const N_PBUD: u8 = 0xc;
+/// indirect
+pub const N_INDR: u8 = 0xa;
+
+/*
+ * If the type is N_INDR then the symbol is defined to be the same as another
+ * symbol. In this case the n_value field is an index into the string table
+ * of the other symbol's name. When the other symbol is defined then they both
+ * take on the defined type and value.
+ */
+
+/*
+ * If the type is N_SECT then the n_sect field contains an ordinal of the
+ * section the symbol is defined in. The sections are numbered from 1 and
+ * refer to sections in order they appear in the load commands for the file
+ * they are in. This means the same ordinal may very well refer to different
+ * sections in different files.
+ *
+ * The n_value field for all symbol table entries (including N_STAB's) gets
+ * updated by the link editor based on the value of it's n_sect field and where
+ * the section n_sect references gets relocated. If the value of the n_sect
+ * field is NO_SECT then it's n_value field is not changed by the link editor.
+ */
+/// symbol is not in any section
+pub const NO_SECT: u8 = 0;
+/// 1 thru 255 inclusive
+pub const MAX_SECT: u8 = 255;
+
+/*
+ * Common symbols are represented by undefined (N_UNDF) external (N_EXT) types
+ * who's values (n_value) are non-zero. In which case the value of the n_value
+ * field is the size (in bytes) of the common symbol. The n_sect field is set
+ * to NO_SECT. The alignment of a common symbol may be set as a power of 2
+ * between 2^1 and 2^15 as part of the n_desc field using the macros below. If
+ * the alignment is not set (a value of zero) then natural alignment based on
+ * the size is used.
+ */
+/* TODO:
+#define GET_COMM_ALIGN(n_desc) (((n_desc) >> 8) & 0x0f)
+#define SET_COMM_ALIGN(n_desc,align) \
+ (n_desc) = (((n_desc) & 0xf0ff) | (((align) & 0x0f) << 8))
+ */
+
+/*
+ * To support the lazy binding of undefined symbols in the dynamic link-editor,
+ * the undefined symbols in the symbol table (the nlist structures) are marked
+ * with the indication if the undefined reference is a lazy reference or
+ * non-lazy reference. If both a non-lazy reference and a lazy reference is
+ * made to the same symbol the non-lazy reference takes precedence. A reference
+ * is lazy only when all references to that symbol are made through a symbol
+ * pointer in a lazy symbol pointer section.
+ *
+ * The implementation of marking nlist structures in the symbol table for
+ * undefined symbols will be to use some of the bits of the n_desc field as a
+ * reference type. The mask REFERENCE_TYPE will be applied to the n_desc field
+ * of an nlist structure for an undefined symbol to determine the type of
+ * undefined reference (lazy or non-lazy).
+ *
+ * The constants for the REFERENCE FLAGS are propagated to the reference table
+ * in a shared library file. In that case the constant for a defined symbol,
+ * REFERENCE_FLAG_DEFINED, is also used.
+ */
+/* Reference type bits of the n_desc field of undefined symbols */
+pub const REFERENCE_TYPE: u16 = 0x7;
+/* types of references */
+pub const REFERENCE_FLAG_UNDEFINED_NON_LAZY: u16 = 0;
+pub const REFERENCE_FLAG_UNDEFINED_LAZY: u16 = 1;
+pub const REFERENCE_FLAG_DEFINED: u16 = 2;
+pub const REFERENCE_FLAG_PRIVATE_DEFINED: u16 = 3;
+pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY: u16 = 4;
+pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY: u16 = 5;
+
+/*
+ * To simplify stripping of objects that use are used with the dynamic link
+ * editor, the static link editor marks the symbols defined an object that are
+ * referenced by a dynamically bound object (dynamic shared libraries, bundles).
+ * With this marking strip knows not to strip these symbols.
+ */
+pub const REFERENCED_DYNAMICALLY: u16 = 0x0010;
+
+/*
+ * For images created by the static link editor with the -twolevel_namespace
+ * option in effect the flags field of the mach header is marked with
+ * MH_TWOLEVEL. And the binding of the undefined references of the image are
+ * determined by the static link editor. Which library an undefined symbol is
+ * bound to is recorded by the static linker in the high 8 bits of the n_desc
+ * field using the SET_LIBRARY_ORDINAL macro below. The ordinal recorded
+ * references the libraries listed in the Mach-O's LC_LOAD_DYLIB,
+ * LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB, and
+ * LC_LAZY_LOAD_DYLIB, etc. load commands in the order they appear in the
+ * headers. The library ordinals start from 1.
+ * For a dynamic library that is built as a two-level namespace image the
+ * undefined references from module defined in another use the same nlist struct
+ * an in that case SELF_LIBRARY_ORDINAL is used as the library ordinal. For
+ * defined symbols in all images they also must have the library ordinal set to
+ * SELF_LIBRARY_ORDINAL. The EXECUTABLE_ORDINAL refers to the executable
+ * image for references from plugins that refer to the executable that loads
+ * them.
+ *
+ * The DYNAMIC_LOOKUP_ORDINAL is for undefined symbols in a two-level namespace
+ * image that are looked up by the dynamic linker with flat namespace semantics.
+ * This ordinal was added as a feature in Mac OS X 10.3 by reducing the
+ * value of MAX_LIBRARY_ORDINAL by one. So it is legal for existing binaries
+ * or binaries built with older tools to have 0xfe (254) dynamic libraries. In
+ * this case the ordinal value 0xfe (254) must be treated as a library ordinal
+ * for compatibility.
+ */
+/* TODO:
+#define GET_LIBRARY_ORDINAL(n_desc) (((n_desc) >> 8) & 0xff)
+#define SET_LIBRARY_ORDINAL(n_desc,ordinal) \
+ (n_desc) = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8))
+ */
+pub const SELF_LIBRARY_ORDINAL: u8 = 0x0;
+pub const MAX_LIBRARY_ORDINAL: u8 = 0xfd;
+pub const DYNAMIC_LOOKUP_ORDINAL: u8 = 0xfe;
+pub const EXECUTABLE_ORDINAL: u8 = 0xff;
+
+/*
+ * The bit 0x0020 of the n_desc field is used for two non-overlapping purposes
+ * and has two different symbolic names, N_NO_DEAD_STRIP and N_DESC_DISCARDED.
+ */
+
+/*
+ * The N_NO_DEAD_STRIP bit of the n_desc field only ever appears in a
+ * relocatable .o file (MH_OBJECT filetype). And is used to indicate to the
+ * static link editor it is never to dead strip the symbol.
+ */
+/// symbol is not to be dead stripped
+pub const N_NO_DEAD_STRIP: u16 = 0x0020;
+
+/*
+ * The N_DESC_DISCARDED bit of the n_desc field never appears in linked image.
+ * But is used in very rare cases by the dynamic link editor to mark an in
+ * memory symbol as discared and longer used for linking.
+ */
+/// symbol is discarded
+pub const N_DESC_DISCARDED: u16 = 0x0020;
+
+/*
+ * The N_WEAK_REF bit of the n_desc field indicates to the dynamic linker that
+ * the undefined symbol is allowed to be missing and is to have the address of
+ * zero when missing.
+ */
+/// symbol is weak referenced
+pub const N_WEAK_REF: u16 = 0x0040;
+
+/*
+ * The N_WEAK_DEF bit of the n_desc field indicates to the static and dynamic
+ * linkers that the symbol definition is weak, allowing a non-weak symbol to
+ * also be used which causes the weak definition to be discared. Currently this
+ * is only supported for symbols in coalesced sections.
+ */
+/// coalesced symbol is a weak definition
+pub const N_WEAK_DEF: u16 = 0x0080;
+
+/*
+ * The N_REF_TO_WEAK bit of the n_desc field indicates to the dynamic linker
+ * that the undefined symbol should be resolved using flat namespace searching.
+ */
+/// reference to a weak symbol
+pub const N_REF_TO_WEAK: u16 = 0x0080;
+
+/*
+ * The N_ARM_THUMB_DEF bit of the n_desc field indicates that the symbol is
+ * a definition of a Thumb function.
+ */
+/// symbol is a Thumb function (ARM)
+pub const N_ARM_THUMB_DEF: u16 = 0x0008;
+
+/*
+ * The N_SYMBOL_RESOLVER bit of the n_desc field indicates that the
+ * that the function is actually a resolver function and should
+ * be called to get the address of the real function to use.
+ * This bit is only available in .o files (MH_OBJECT filetype)
+ */
+pub const N_SYMBOL_RESOLVER: u16 = 0x0100;
+
+/*
+ * The N_ALT_ENTRY bit of the n_desc field indicates that the
+ * symbol is pinned to the previous content.
+ */
+pub const N_ALT_ENTRY: u16 = 0x0200;
+
+// Definitions from "/usr/include/mach-o/stab.h".
+
+/*
+ * This file gives definitions supplementing <nlist.h> for permanent symbol
+ * table entries of Mach-O files. Modified from the BSD definitions. The
+ * modifications from the original definitions were changing what the values of
+ * what was the n_other field (an unused field) which is now the n_sect field.
+ * These modifications are required to support symbols in an arbitrary number of
+ * sections not just the three sections (text, data and bss) in a BSD file.
+ * The values of the defined constants have NOT been changed.
+ *
+ * These must have one of the N_STAB bits on. The n_value fields are subject
+ * to relocation according to the value of their n_sect field. So for types
+ * that refer to things in sections the n_sect field must be filled in with the
+ * proper section ordinal. For types that are not to have their n_value field
+ * relocatated the n_sect field must be NO_SECT.
+ */
+
+/*
+ * Symbolic debugger symbols. The comments give the conventional use for
+ *
+ * .stabs "n_name", n_type, n_sect, n_desc, n_value
+ *
+ * where n_type is the defined constant and not listed in the comment. Other
+ * fields not listed are zero. n_sect is the section ordinal the entry is
+ * referring to.
+ */
+/// global symbol: name,,NO_SECT,type,0
+pub const N_GSYM: u8 = 0x20;
+/// procedure name (f77 kludge): name,,NO_SECT,0,0
+pub const N_FNAME: u8 = 0x22;
+/// procedure: name,,n_sect,linenumber,address
+pub const N_FUN: u8 = 0x24;
+/// static symbol: name,,n_sect,type,address
+pub const N_STSYM: u8 = 0x26;
+/// .lcomm symbol: name,,n_sect,type,address
+pub const N_LCSYM: u8 = 0x28;
+/// begin nsect sym: 0,,n_sect,0,address
+pub const N_BNSYM: u8 = 0x2e;
+/// AST file path: name,,NO_SECT,0,0
+pub const N_AST: u8 = 0x32;
+/// emitted with gcc2_compiled and in gcc source
+pub const N_OPT: u8 = 0x3c;
+/// register sym: name,,NO_SECT,type,register
+pub const N_RSYM: u8 = 0x40;
+/// src line: 0,,n_sect,linenumber,address
+pub const N_SLINE: u8 = 0x44;
+/// end nsect sym: 0,,n_sect,0,address
+pub const N_ENSYM: u8 = 0x4e;
+/// structure elt: name,,NO_SECT,type,struct_offset
+pub const N_SSYM: u8 = 0x60;
+/// source file name: name,,n_sect,0,address
+pub const N_SO: u8 = 0x64;
+/// object file name: name,,0,0,st_mtime
+pub const N_OSO: u8 = 0x66;
+/// local sym: name,,NO_SECT,type,offset
+pub const N_LSYM: u8 = 0x80;
+/// include file beginning: name,,NO_SECT,0,sum
+pub const N_BINCL: u8 = 0x82;
+/// #included file name: name,,n_sect,0,address
+pub const N_SOL: u8 = 0x84;
+/// compiler parameters: name,,NO_SECT,0,0
+pub const N_PARAMS: u8 = 0x86;
+/// compiler version: name,,NO_SECT,0,0
+pub const N_VERSION: u8 = 0x88;
+/// compiler -O level: name,,NO_SECT,0,0
+pub const N_OLEVEL: u8 = 0x8A;
+/// parameter: name,,NO_SECT,type,offset
+pub const N_PSYM: u8 = 0xa0;
+/// include file end: name,,NO_SECT,0,0
+pub const N_EINCL: u8 = 0xa2;
+/// alternate entry: name,,n_sect,linenumber,address
+pub const N_ENTRY: u8 = 0xa4;
+/// left bracket: 0,,NO_SECT,nesting level,address
+pub const N_LBRAC: u8 = 0xc0;
+/// deleted include file: name,,NO_SECT,0,sum
+pub const N_EXCL: u8 = 0xc2;
+/// right bracket: 0,,NO_SECT,nesting level,address
+pub const N_RBRAC: u8 = 0xe0;
+/// begin common: name,,NO_SECT,0,0
+pub const N_BCOMM: u8 = 0xe2;
+/// end common: name,,n_sect,0,0
+pub const N_ECOMM: u8 = 0xe4;
+/// end common (local name): 0,,n_sect,0,address
+pub const N_ECOML: u8 = 0xe8;
+/// second stab entry with length information
+pub const N_LENG: u8 = 0xfe;
+
+/*
+ * for the berkeley pascal compiler, pc(1):
+ */
+/// global pascal symbol: name,,NO_SECT,subtype,line
+pub const N_PC: u8 = 0x30;
+
+// Definitions from "/usr/include/mach-o/reloc.h".
+
+/// A relocation entry.
+///
+/// Mach-O relocations have plain and scattered variants, with the
+/// meaning of the fields depending on the variant.
+///
+/// This type provides functions for determining whether the relocation
+/// is scattered, and for accessing the fields of each variant.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Relocation<E: Endian> {
+ pub r_word0: U32<E>,
+ pub r_word1: U32<E>,
+}
+
+impl<E: Endian> Relocation<E> {
+ /// Determine whether this is a scattered relocation.
+ #[inline]
+ pub fn r_scattered(self, endian: E, cputype: u32) -> bool {
+ if cputype == CPU_TYPE_X86_64 {
+ false
+ } else {
+ self.r_word0.get(endian) & R_SCATTERED != 0
+ }
+ }
+
+ /// Return the fields of a plain relocation.
+ pub fn info(self, endian: E) -> RelocationInfo {
+ let r_address = self.r_word0.get(endian);
+ let r_word1 = self.r_word1.get(endian);
+ if endian.is_little_endian() {
+ RelocationInfo {
+ r_address,
+ r_symbolnum: r_word1 & 0x00ff_ffff,
+ r_pcrel: ((r_word1 >> 24) & 0x1) != 0,
+ r_length: ((r_word1 >> 25) & 0x3) as u8,
+ r_extern: ((r_word1 >> 27) & 0x1) != 0,
+ r_type: (r_word1 >> 28) as u8,
+ }
+ } else {
+ RelocationInfo {
+ r_address,
+ r_symbolnum: r_word1 >> 8,
+ r_pcrel: ((r_word1 >> 7) & 0x1) != 0,
+ r_length: ((r_word1 >> 5) & 0x3) as u8,
+ r_extern: ((r_word1 >> 4) & 0x1) != 0,
+ r_type: (r_word1 & 0xf) as u8,
+ }
+ }
+ }
+
+ /// Return the fields of a scattered relocation.
+ pub fn scattered_info(self, endian: E) -> ScatteredRelocationInfo {
+ let r_word0 = self.r_word0.get(endian);
+ let r_value = self.r_word1.get(endian);
+ ScatteredRelocationInfo {
+ r_address: r_word0 & 0x00ff_ffff,
+ r_type: ((r_word0 >> 24) & 0xf) as u8,
+ r_length: ((r_word0 >> 28) & 0x3) as u8,
+ r_pcrel: ((r_word0 >> 30) & 0x1) != 0,
+ r_value,
+ }
+ }
+}
+
+/*
+ * Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD
+ * format. The modifications from the original format were changing the value
+ * of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
+ * This modification is required to support symbols in an arbitrary number of
+ * sections not just the three sections (text, data and bss) in a 4.3BSD file.
+ * Also the last 4 bits have had the r_type tag added to them.
+ */
+
+#[derive(Debug, Clone, Copy)]
+pub struct RelocationInfo {
+ /// offset in the section to what is being relocated
+ pub r_address: u32,
+ /// symbol index if r_extern == 1 or section ordinal if r_extern == 0
+ pub r_symbolnum: u32,
+ /// was relocated pc relative already
+ pub r_pcrel: bool,
+ /// 0=byte, 1=word, 2=long, 3=quad
+ pub r_length: u8,
+ /// does not include value of sym referenced
+ pub r_extern: bool,
+ /// if not 0, machine specific relocation type
+ pub r_type: u8,
+}
+
+impl RelocationInfo {
+ /// Combine the fields into a `Relocation`.
+ pub fn relocation<E: Endian>(self, endian: E) -> Relocation<E> {
+ let r_word0 = U32::new(endian, self.r_address);
+ let r_word1 = U32::new(
+ endian,
+ if endian.is_little_endian() {
+ self.r_symbolnum & 0x00ff_ffff
+ | u32::from(self.r_pcrel) << 24
+ | u32::from(self.r_length & 0x3) << 25
+ | u32::from(self.r_extern) << 27
+ | u32::from(self.r_type) << 28
+ } else {
+ self.r_symbolnum >> 8
+ | u32::from(self.r_pcrel) << 7
+ | u32::from(self.r_length & 0x3) << 5
+ | u32::from(self.r_extern) << 4
+ | u32::from(self.r_type) & 0xf
+ },
+ );
+ Relocation { r_word0, r_word1 }
+ }
+}
+
+/// absolute relocation type for Mach-O files
+pub const R_ABS: u8 = 0;
+
+/*
+ * The r_address is not really the address as it's name indicates but an offset.
+ * In 4.3BSD a.out objects this offset is from the start of the "segment" for
+ * which relocation entry is for (text or data). For Mach-O object files it is
+ * also an offset but from the start of the "section" for which the relocation
+ * entry is for. See comments in <mach-o/loader.h> about the r_address feild
+ * in images for used with the dynamic linker.
+ *
+ * In 4.3BSD a.out objects if r_extern is zero then r_symbolnum is an ordinal
+ * for the segment the symbol being relocated is in. These ordinals are the
+ * symbol types N_TEXT, N_DATA, N_BSS or N_ABS. In Mach-O object files these
+ * ordinals refer to the sections in the object file in the order their section
+ * structures appear in the headers of the object file they are in. The first
+ * section has the ordinal 1, the second 2, and so on. This means that the
+ * same ordinal in two different object files could refer to two different
+ * sections. And further could have still different ordinals when combined
+ * by the link-editor. The value R_ABS is used for relocation entries for
+ * absolute symbols which need no further relocation.
+ */
+
+/*
+ * For RISC machines some of the references are split across two instructions
+ * and the instruction does not contain the complete value of the reference.
+ * In these cases a second, or paired relocation entry, follows each of these
+ * relocation entries, using a PAIR r_type, which contains the other part of the
+ * reference not contained in the instruction. This other part is stored in the
+ * pair's r_address field. The exact number of bits of the other part of the
+ * reference store in the r_address field is dependent on the particular
+ * relocation type for the particular architecture.
+ */
+
+/*
+ * To make scattered loading by the link editor work correctly "local"
+ * relocation entries can't be used when the item to be relocated is the value
+ * of a symbol plus an offset (where the resulting expression is outside the
+ * block the link editor is moving, a blocks are divided at symbol addresses).
+ * In this case. where the item is a symbol value plus offset, the link editor
+ * needs to know more than just the section the symbol was defined. What is
+ * needed is the actual value of the symbol without the offset so it can do the
+ * relocation correctly based on where the value of the symbol got relocated to
+ * not the value of the expression (with the offset added to the symbol value).
+ * So for the NeXT 2.0 release no "local" relocation entries are ever used when
+ * there is a non-zero offset added to a symbol. The "external" and "local"
+ * relocation entries remain unchanged.
+ *
+ * The implementation is quite messy given the compatibility with the existing
+ * relocation entry format. The ASSUMPTION is that a section will never be
+ * bigger than 2**24 - 1 (0x00ffffff or 16,777,215) bytes. This assumption
+ * allows the r_address (which is really an offset) to fit in 24 bits and high
+ * bit of the r_address field in the relocation_info structure to indicate
+ * it is really a scattered_relocation_info structure. Since these are only
+ * used in places where "local" relocation entries are used and not where
+ * "external" relocation entries are used the r_extern field has been removed.
+ *
+ * For scattered loading to work on a RISC machine where some of the references
+ * are split across two instructions the link editor needs to be assured that
+ * each reference has a unique 32 bit reference (that more than one reference is
+ * NOT sharing the same high 16 bits for example) so it move each referenced
+ * item independent of each other. Some compilers guarantees this but the
+ * compilers don't so scattered loading can be done on those that do guarantee
+ * this.
+ */
+
+/// Bit set in `Relocation::r_word0` for scattered relocations.
+pub const R_SCATTERED: u32 = 0x8000_0000;
+
+#[derive(Debug, Clone, Copy)]
+pub struct ScatteredRelocationInfo {
+ /// offset in the section to what is being relocated
+ pub r_address: u32,
+ /// if not 0, machine specific relocation type
+ pub r_type: u8,
+ /// 0=byte, 1=word, 2=long, 3=quad
+ pub r_length: u8,
+ /// was relocated pc relative already
+ pub r_pcrel: bool,
+ /// the value the item to be relocated is referring to (without any offset added)
+ pub r_value: u32,
+}
+
+impl ScatteredRelocationInfo {
+ /// Combine the fields into a `Relocation`.
+ pub fn relocation<E: Endian>(self, endian: E) -> Relocation<E> {
+ let r_word0 = U32::new(
+ endian,
+ self.r_address & 0x00ff_ffff
+ | u32::from(self.r_type & 0xf) << 24
+ | u32::from(self.r_length & 0x3) << 28
+ | u32::from(self.r_pcrel) << 30
+ | R_SCATTERED,
+ );
+ let r_word1 = U32::new(endian, self.r_value);
+ Relocation { r_word0, r_word1 }
+ }
+}
+
+/*
+ * Relocation types used in a generic implementation. Relocation entries for
+ * normal things use the generic relocation as described above and their r_type
+ * is GENERIC_RELOC_VANILLA (a value of zero).
+ *
+ * Another type of generic relocation, GENERIC_RELOC_SECTDIFF, is to support
+ * the difference of two symbols defined in different sections. That is the
+ * expression "symbol1 - symbol2 + constant" is a relocatable expression when
+ * both symbols are defined in some section. For this type of relocation the
+ * both relocations entries are scattered relocation entries. The value of
+ * symbol1 is stored in the first relocation entry's r_value field and the
+ * value of symbol2 is stored in the pair's r_value field.
+ *
+ * A special case for a prebound lazy pointer is needed to beable to set the
+ * value of the lazy pointer back to its non-prebound state. This is done
+ * using the GENERIC_RELOC_PB_LA_PTR r_type. This is a scattered relocation
+ * entry where the r_value feild is the value of the lazy pointer not prebound.
+ */
+/// generic relocation as described above
+pub const GENERIC_RELOC_VANILLA: u8 = 0;
+/// Only follows a GENERIC_RELOC_SECTDIFF
+pub const GENERIC_RELOC_PAIR: u8 = 1;
+pub const GENERIC_RELOC_SECTDIFF: u8 = 2;
+/// prebound lazy pointer
+pub const GENERIC_RELOC_PB_LA_PTR: u8 = 3;
+pub const GENERIC_RELOC_LOCAL_SECTDIFF: u8 = 4;
+/// thread local variables
+pub const GENERIC_RELOC_TLV: u8 = 5;
+
+// Definitions from "/usr/include/mach-o/arm/reloc.h".
+
+/*
+ * Relocation types used in the arm implementation. Relocation entries for
+ * things other than instructions use the same generic relocation as described
+ * in <mach-o/reloc.h> and their r_type is ARM_RELOC_VANILLA, one of the
+ * *_SECTDIFF or the *_PB_LA_PTR types. The rest of the relocation types are
+ * for instructions. Since they are for instructions the r_address field
+ * indicates the 32 bit instruction that the relocation is to be performed on.
+ */
+/// generic relocation as described above
+pub const ARM_RELOC_VANILLA: u8 = 0;
+/// the second relocation entry of a pair
+pub const ARM_RELOC_PAIR: u8 = 1;
+/// a PAIR follows with subtract symbol value
+pub const ARM_RELOC_SECTDIFF: u8 = 2;
+/// like ARM_RELOC_SECTDIFF, but the symbol referenced was local.
+pub const ARM_RELOC_LOCAL_SECTDIFF: u8 = 3;
+/// prebound lazy pointer
+pub const ARM_RELOC_PB_LA_PTR: u8 = 4;
+/// 24 bit branch displacement (to a word address)
+pub const ARM_RELOC_BR24: u8 = 5;
+/// 22 bit branch displacement (to a half-word address)
+pub const ARM_THUMB_RELOC_BR22: u8 = 6;
+/// obsolete - a thumb 32-bit branch instruction possibly needing page-spanning branch workaround
+pub const ARM_THUMB_32BIT_BRANCH: u8 = 7;
+
+/*
+ * For these two r_type relocations they always have a pair following them
+ * and the r_length bits are used differently. The encoding of the
+ * r_length is as follows:
+ * low bit of r_length:
+ * 0 - :lower16: for movw instructions
+ * 1 - :upper16: for movt instructions
+ * high bit of r_length:
+ * 0 - arm instructions
+ * 1 - thumb instructions
+ * the other half of the relocated expression is in the following pair
+ * relocation entry in the the low 16 bits of r_address field.
+ */
+pub const ARM_RELOC_HALF: u8 = 8;
+pub const ARM_RELOC_HALF_SECTDIFF: u8 = 9;
+
+// Definitions from "/usr/include/mach-o/arm64/reloc.h".
+
+/*
+ * Relocation types used in the arm64 implementation.
+ */
+/// for pointers
+pub const ARM64_RELOC_UNSIGNED: u8 = 0;
+/// must be followed by a ARM64_RELOC_UNSIGNED
+pub const ARM64_RELOC_SUBTRACTOR: u8 = 1;
+/// a B/BL instruction with 26-bit displacement
+pub const ARM64_RELOC_BRANCH26: u8 = 2;
+/// pc-rel distance to page of target
+pub const ARM64_RELOC_PAGE21: u8 = 3;
+/// offset within page, scaled by r_length
+pub const ARM64_RELOC_PAGEOFF12: u8 = 4;
+/// pc-rel distance to page of GOT slot
+pub const ARM64_RELOC_GOT_LOAD_PAGE21: u8 = 5;
+/// offset within page of GOT slot, scaled by r_length
+pub const ARM64_RELOC_GOT_LOAD_PAGEOFF12: u8 = 6;
+/// for pointers to GOT slots
+pub const ARM64_RELOC_POINTER_TO_GOT: u8 = 7;
+/// pc-rel distance to page of TLVP slot
+pub const ARM64_RELOC_TLVP_LOAD_PAGE21: u8 = 8;
+/// offset within page of TLVP slot, scaled by r_length
+pub const ARM64_RELOC_TLVP_LOAD_PAGEOFF12: u8 = 9;
+/// must be followed by PAGE21 or PAGEOFF12
+pub const ARM64_RELOC_ADDEND: u8 = 10;
+
+// An arm64e authenticated pointer.
+//
+// Represents a pointer to a symbol (like ARM64_RELOC_UNSIGNED).
+// Additionally, the resulting pointer is signed. The signature is
+// specified in the target location: the addend is restricted to the lower
+// 32 bits (instead of the full 64 bits for ARM64_RELOC_UNSIGNED):
+//
+// |63|62|61-51|50-49| 48 |47 - 32|31 - 0|
+// | 1| 0| 0 | key | addr | discriminator | addend |
+//
+// The key is one of:
+// IA: 00 IB: 01
+// DA: 10 DB: 11
+//
+// The discriminator field is used as extra signature diversification.
+//
+// The addr field indicates whether the target address should be blended
+// into the discriminator.
+//
+pub const ARM64_RELOC_AUTHENTICATED_POINTER: u8 = 11;
+
+// Definitions from "/usr/include/mach-o/ppc/reloc.h".
+
+/*
+ * Relocation types used in the ppc implementation. Relocation entries for
+ * things other than instructions use the same generic relocation as described
+ * above and their r_type is RELOC_VANILLA. The rest of the relocation types
+ * are for instructions. Since they are for instructions the r_address field
+ * indicates the 32 bit instruction that the relocation is to be performed on.
+ * The fields r_pcrel and r_length are ignored for non-RELOC_VANILLA r_types
+ * except for PPC_RELOC_BR14.
+ *
+ * For PPC_RELOC_BR14 if the r_length is the unused value 3, then the branch was
+ * statically predicted setting or clearing the Y-bit based on the sign of the
+ * displacement or the opcode. If this is the case the static linker must flip
+ * the value of the Y-bit if the sign of the displacement changes for non-branch
+ * always conditions.
+ */
+/// generic relocation as described above
+pub const PPC_RELOC_VANILLA: u8 = 0;
+/// the second relocation entry of a pair
+pub const PPC_RELOC_PAIR: u8 = 1;
+/// 14 bit branch displacement (to a word address)
+pub const PPC_RELOC_BR14: u8 = 2;
+/// 24 bit branch displacement (to a word address)
+pub const PPC_RELOC_BR24: u8 = 3;
+/// a PAIR follows with the low half
+pub const PPC_RELOC_HI16: u8 = 4;
+/// a PAIR follows with the high half
+pub const PPC_RELOC_LO16: u8 = 5;
+/// Same as the RELOC_HI16 except the low 16 bits and the high 16 bits are added together
+/// with the low 16 bits sign extended first. This means if bit 15 of the low 16 bits is
+/// set the high 16 bits stored in the instruction will be adjusted.
+pub const PPC_RELOC_HA16: u8 = 6;
+/// Same as the LO16 except that the low 2 bits are not stored in the instruction and are
+/// always zero. This is used in double word load/store instructions.
+pub const PPC_RELOC_LO14: u8 = 7;
+/// a PAIR follows with subtract symbol value
+pub const PPC_RELOC_SECTDIFF: u8 = 8;
+/// prebound lazy pointer
+pub const PPC_RELOC_PB_LA_PTR: u8 = 9;
+/// section difference forms of above. a PAIR
+pub const PPC_RELOC_HI16_SECTDIFF: u8 = 10;
+/// follows these with subtract symbol value
+pub const PPC_RELOC_LO16_SECTDIFF: u8 = 11;
+pub const PPC_RELOC_HA16_SECTDIFF: u8 = 12;
+pub const PPC_RELOC_JBSR: u8 = 13;
+pub const PPC_RELOC_LO14_SECTDIFF: u8 = 14;
+/// like PPC_RELOC_SECTDIFF, but the symbol referenced was local.
+pub const PPC_RELOC_LOCAL_SECTDIFF: u8 = 15;
+
+// Definitions from "/usr/include/mach-o/x86_64/reloc.h".
+
+/*
+ * Relocations for x86_64 are a bit different than for other architectures in
+ * Mach-O: Scattered relocations are not used. Almost all relocations produced
+ * by the compiler are external relocations. An external relocation has the
+ * r_extern bit set to 1 and the r_symbolnum field contains the symbol table
+ * index of the target label.
+ *
+ * When the assembler is generating relocations, if the target label is a local
+ * label (begins with 'L'), then the previous non-local label in the same
+ * section is used as the target of the external relocation. An addend is used
+ * with the distance from that non-local label to the target label. Only when
+ * there is no previous non-local label in the section is an internal
+ * relocation used.
+ *
+ * The addend (i.e. the 4 in _foo+4) is encoded in the instruction (Mach-O does
+ * not have RELA relocations). For PC-relative relocations, the addend is
+ * stored directly in the instruction. This is different from other Mach-O
+ * architectures, which encode the addend minus the current section offset.
+ *
+ * The relocation types are:
+ *
+ * X86_64_RELOC_UNSIGNED // for absolute addresses
+ * X86_64_RELOC_SIGNED // for signed 32-bit displacement
+ * X86_64_RELOC_BRANCH // a CALL/JMP instruction with 32-bit displacement
+ * X86_64_RELOC_GOT_LOAD // a MOVQ load of a GOT entry
+ * X86_64_RELOC_GOT // other GOT references
+ * X86_64_RELOC_SUBTRACTOR // must be followed by a X86_64_RELOC_UNSIGNED
+ *
+ * The following are sample assembly instructions, followed by the relocation
+ * and section content they generate in an object file:
+ *
+ * call _foo
+ * r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * E8 00 00 00 00
+ *
+ * call _foo+4
+ * r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * E8 04 00 00 00
+ *
+ * movq _foo@GOTPCREL(%rip), %rax
+ * r_type=X86_64_RELOC_GOT_LOAD, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 48 8B 05 00 00 00 00
+ *
+ * pushq _foo@GOTPCREL(%rip)
+ * r_type=X86_64_RELOC_GOT, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * FF 35 00 00 00 00
+ *
+ * movl _foo(%rip), %eax
+ * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 8B 05 00 00 00 00
+ *
+ * movl _foo+4(%rip), %eax
+ * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 8B 05 04 00 00 00
+ *
+ * movb $0x12, _foo(%rip)
+ * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * C6 05 FF FF FF FF 12
+ *
+ * movl $0x12345678, _foo(%rip)
+ * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * C7 05 FC FF FF FF 78 56 34 12
+ *
+ * .quad _foo
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 00 00 00 00 00 00 00 00
+ *
+ * .quad _foo+4
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 04 00 00 00 00 00 00 00
+ *
+ * .quad _foo - _bar
+ * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 00 00 00 00 00 00 00 00
+ *
+ * .quad _foo - _bar + 4
+ * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 04 00 00 00 00 00 00 00
+ *
+ * .long _foo - _bar
+ * r_type=X86_64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_bar
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 00 00 00 00
+ *
+ * lea L1(%rip), %rax
+ * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_prev
+ * 48 8d 05 12 00 00 00
+ * // assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ * lea L0(%rip), %rax
+ * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3
+ * 48 8d 05 56 00 00 00
+ * // assumes L0 is in third section and there is no previous non-local label.
+ * // The rip-relative-offset of 0x00000056 is L0-address_of_next_instruction.
+ * // address_of_next_instruction is the address of the relocation + 4.
+ *
+ * add $6,L0(%rip)
+ * r_type=X86_64_RELOC_SIGNED_1, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3
+ * 83 05 18 00 00 00 06
+ * // assumes L0 is in third section and there is no previous non-local label.
+ * // The rip-relative-offset of 0x00000018 is L0-address_of_next_instruction.
+ * // address_of_next_instruction is the address of the relocation + 4 + 1.
+ * // The +1 comes from SIGNED_1. This is used because the relocation is not
+ * // at the end of the instruction.
+ *
+ * .quad L1
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
+ * 12 00 00 00 00 00 00 00
+ * // assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ * .quad L0
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=0, r_pcrel=0, r_symbolnum=3
+ * 56 00 00 00 00 00 00 00
+ * // assumes L0 is in third section, has an address of 0x00000056 in .o
+ * // file, and there is no previous non-local label
+ *
+ * .quad _foo - .
+ * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * EE FF FF FF FF FF FF FF
+ * // assumes _prev is the first non-local label 0x12 bytes before this
+ * // .quad
+ *
+ * .quad _foo - L1
+ * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * EE FF FF FF FF FF FF FF
+ * // assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ * .quad L1 - _prev
+ * // No relocations. This is an assembly time constant.
+ * 12 00 00 00 00 00 00 00
+ * // assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ *
+ *
+ * In final linked images, there are only two valid relocation kinds:
+ *
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=1, r_symbolnum=sym_index
+ * This tells dyld to add the address of a symbol to a pointer sized (8-byte)
+ * piece of data (i.e on disk the 8-byte piece of data contains the addend). The
+ * r_symbolnum contains the index into the symbol table of the target symbol.
+ *
+ * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=0, r_symbolnum=0
+ * This tells dyld to adjust the pointer sized (8-byte) piece of data by the amount
+ * the containing image was loaded from its base address (e.g. slide).
+ *
+ */
+/// for absolute addresses
+pub const X86_64_RELOC_UNSIGNED: u8 = 0;
+/// for signed 32-bit displacement
+pub const X86_64_RELOC_SIGNED: u8 = 1;
+/// a CALL/JMP instruction with 32-bit displacement
+pub const X86_64_RELOC_BRANCH: u8 = 2;
+/// a MOVQ load of a GOT entry
+pub const X86_64_RELOC_GOT_LOAD: u8 = 3;
+/// other GOT references
+pub const X86_64_RELOC_GOT: u8 = 4;
+/// must be followed by a X86_64_RELOC_UNSIGNED
+pub const X86_64_RELOC_SUBTRACTOR: u8 = 5;
+/// for signed 32-bit displacement with a -1 addend
+pub const X86_64_RELOC_SIGNED_1: u8 = 6;
+/// for signed 32-bit displacement with a -2 addend
+pub const X86_64_RELOC_SIGNED_2: u8 = 7;
+/// for signed 32-bit displacement with a -4 addend
+pub const X86_64_RELOC_SIGNED_4: u8 = 8;
+/// for thread local variables
+pub const X86_64_RELOC_TLV: u8 = 9;
+
+unsafe_impl_pod!(FatHeader, FatArch32, FatArch64,);
+unsafe_impl_endian_pod!(
+ DyldCacheHeader,
+ DyldCacheMappingInfo,
+ DyldCacheImageInfo,
+ DyldSubCacheInfo,
+ MachHeader32,
+ MachHeader64,
+ LoadCommand,
+ LcStr,
+ SegmentCommand32,
+ SegmentCommand64,
+ Section32,
+ Section64,
+ Fvmlib,
+ FvmlibCommand,
+ Dylib,
+ DylibCommand,
+ SubFrameworkCommand,
+ SubClientCommand,
+ SubUmbrellaCommand,
+ SubLibraryCommand,
+ PreboundDylibCommand,
+ DylinkerCommand,
+ ThreadCommand,
+ RoutinesCommand32,
+ RoutinesCommand64,
+ SymtabCommand,
+ DysymtabCommand,
+ DylibTableOfContents,
+ DylibModule32,
+ DylibModule64,
+ DylibReference,
+ TwolevelHintsCommand,
+ TwolevelHint,
+ PrebindCksumCommand,
+ UuidCommand,
+ RpathCommand,
+ LinkeditDataCommand,
+ FilesetEntryCommand,
+ EncryptionInfoCommand32,
+ EncryptionInfoCommand64,
+ VersionMinCommand,
+ BuildVersionCommand,
+ BuildToolVersion,
+ DyldInfoCommand,
+ LinkerOptionCommand,
+ SymsegCommand,
+ IdentCommand,
+ FvmfileCommand,
+ EntryPointCommand,
+ SourceVersionCommand,
+ DataInCodeEntry,
+ //TlvDescriptor,
+ NoteCommand,
+ Nlist32,
+ Nlist64,
+ Relocation,
+);
diff --git a/third_party/rust/object/src/pe.rs b/third_party/rust/object/src/pe.rs
new file mode 100644
index 0000000000..f274d2270b
--- /dev/null
+++ b/third_party/rust/object/src/pe.rs
@@ -0,0 +1,3054 @@
+//! PE/COFF definitions.
+//!
+//! These definitions are independent of read/write support, although we do implement
+//! some traits useful for those.
+//!
+//! This module is based heavily on "winnt.h" (10.0.17763.0).
+
+#![allow(missing_docs)]
+
+use core::convert::TryInto;
+
+use crate::endian::{I32Bytes, LittleEndian as LE, U16Bytes, U32Bytes, I32, U16, U32, U64};
+use crate::pod::Pod;
+
+/// MZ
+pub const IMAGE_DOS_SIGNATURE: u16 = 0x5A4D;
+/// NE
+pub const IMAGE_OS2_SIGNATURE: u16 = 0x454E;
+/// LE
+pub const IMAGE_OS2_SIGNATURE_LE: u16 = 0x454C;
+/// LE
+pub const IMAGE_VXD_SIGNATURE: u16 = 0x454C;
+/// PE00
+pub const IMAGE_NT_SIGNATURE: u32 = 0x0000_4550;
+
+/// DOS .EXE header
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDosHeader {
+ /// Magic number
+ pub e_magic: U16<LE>,
+ /// Bytes on last page of file
+ pub e_cblp: U16<LE>,
+ /// Pages in file
+ pub e_cp: U16<LE>,
+ /// Relocations
+ pub e_crlc: U16<LE>,
+ /// Size of header in paragraphs
+ pub e_cparhdr: U16<LE>,
+ /// Minimum extra paragraphs needed
+ pub e_minalloc: U16<LE>,
+ /// Maximum extra paragraphs needed
+ pub e_maxalloc: U16<LE>,
+ /// Initial (relative) SS value
+ pub e_ss: U16<LE>,
+ /// Initial SP value
+ pub e_sp: U16<LE>,
+ /// Checksum
+ pub e_csum: U16<LE>,
+ /// Initial IP value
+ pub e_ip: U16<LE>,
+ /// Initial (relative) CS value
+ pub e_cs: U16<LE>,
+ /// File address of relocation table
+ pub e_lfarlc: U16<LE>,
+ /// Overlay number
+ pub e_ovno: U16<LE>,
+ /// Reserved words
+ pub e_res: [U16<LE>; 4],
+ /// OEM identifier (for e_oeminfo)
+ pub e_oemid: U16<LE>,
+ /// OEM information; e_oemid specific
+ pub e_oeminfo: U16<LE>,
+ /// Reserved words
+ pub e_res2: [U16<LE>; 10],
+ /// File address of new exe header
+ pub e_lfanew: U32<LE>,
+}
+
+/// OS/2 .EXE header
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageOs2Header {
+ /// Magic number
+ pub ne_magic: U16<LE>,
+ /// Version number
+ pub ne_ver: i8,
+ /// Revision number
+ pub ne_rev: i8,
+ /// Offset of Entry Table
+ pub ne_enttab: U16<LE>,
+ /// Number of bytes in Entry Table
+ pub ne_cbenttab: U16<LE>,
+ /// Checksum of whole file
+ pub ne_crc: I32<LE>,
+ /// Flag word
+ pub ne_flags: U16<LE>,
+ /// Automatic data segment number
+ pub ne_autodata: U16<LE>,
+ /// Initial heap allocation
+ pub ne_heap: U16<LE>,
+ /// Initial stack allocation
+ pub ne_stack: U16<LE>,
+ /// Initial CS:IP setting
+ pub ne_csip: I32<LE>,
+ /// Initial SS:SP setting
+ pub ne_sssp: I32<LE>,
+ /// Count of file segments
+ pub ne_cseg: U16<LE>,
+ /// Entries in Module Reference Table
+ pub ne_cmod: U16<LE>,
+ /// Size of non-resident name table
+ pub ne_cbnrestab: U16<LE>,
+ /// Offset of Segment Table
+ pub ne_segtab: U16<LE>,
+ /// Offset of Resource Table
+ pub ne_rsrctab: U16<LE>,
+ /// Offset of resident name table
+ pub ne_restab: U16<LE>,
+ /// Offset of Module Reference Table
+ pub ne_modtab: U16<LE>,
+ /// Offset of Imported Names Table
+ pub ne_imptab: U16<LE>,
+ /// Offset of Non-resident Names Table
+ pub ne_nrestab: I32<LE>,
+ /// Count of movable entries
+ pub ne_cmovent: U16<LE>,
+ /// Segment alignment shift count
+ pub ne_align: U16<LE>,
+ /// Count of resource segments
+ pub ne_cres: U16<LE>,
+ /// Target Operating system
+ pub ne_exetyp: u8,
+ /// Other .EXE flags
+ pub ne_flagsothers: u8,
+ /// offset to return thunks
+ pub ne_pretthunks: U16<LE>,
+ /// offset to segment ref. bytes
+ pub ne_psegrefbytes: U16<LE>,
+ /// Minimum code swap area size
+ pub ne_swaparea: U16<LE>,
+ /// Expected Windows version number
+ pub ne_expver: U16<LE>,
+}
+
+/// Windows VXD header
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageVxdHeader {
+ /// Magic number
+ pub e32_magic: U16<LE>,
+ /// The byte ordering for the VXD
+ pub e32_border: u8,
+ /// The word ordering for the VXD
+ pub e32_worder: u8,
+ /// The EXE format level for now = 0
+ pub e32_level: U32<LE>,
+ /// The CPU type
+ pub e32_cpu: U16<LE>,
+ /// The OS type
+ pub e32_os: U16<LE>,
+ /// Module version
+ pub e32_ver: U32<LE>,
+ /// Module flags
+ pub e32_mflags: U32<LE>,
+ /// Module # pages
+ pub e32_mpages: U32<LE>,
+ /// Object # for instruction pointer
+ pub e32_startobj: U32<LE>,
+ /// Extended instruction pointer
+ pub e32_eip: U32<LE>,
+ /// Object # for stack pointer
+ pub e32_stackobj: U32<LE>,
+ /// Extended stack pointer
+ pub e32_esp: U32<LE>,
+ /// VXD page size
+ pub e32_pagesize: U32<LE>,
+ /// Last page size in VXD
+ pub e32_lastpagesize: U32<LE>,
+ /// Fixup section size
+ pub e32_fixupsize: U32<LE>,
+ /// Fixup section checksum
+ pub e32_fixupsum: U32<LE>,
+ /// Loader section size
+ pub e32_ldrsize: U32<LE>,
+ /// Loader section checksum
+ pub e32_ldrsum: U32<LE>,
+ /// Object table offset
+ pub e32_objtab: U32<LE>,
+ /// Number of objects in module
+ pub e32_objcnt: U32<LE>,
+ /// Object page map offset
+ pub e32_objmap: U32<LE>,
+ /// Object iterated data map offset
+ pub e32_itermap: U32<LE>,
+ /// Offset of Resource Table
+ pub e32_rsrctab: U32<LE>,
+ /// Number of resource entries
+ pub e32_rsrccnt: U32<LE>,
+ /// Offset of resident name table
+ pub e32_restab: U32<LE>,
+ /// Offset of Entry Table
+ pub e32_enttab: U32<LE>,
+ /// Offset of Module Directive Table
+ pub e32_dirtab: U32<LE>,
+ /// Number of module directives
+ pub e32_dircnt: U32<LE>,
+ /// Offset of Fixup Page Table
+ pub e32_fpagetab: U32<LE>,
+ /// Offset of Fixup Record Table
+ pub e32_frectab: U32<LE>,
+ /// Offset of Import Module Name Table
+ pub e32_impmod: U32<LE>,
+ /// Number of entries in Import Module Name Table
+ pub e32_impmodcnt: U32<LE>,
+ /// Offset of Import Procedure Name Table
+ pub e32_impproc: U32<LE>,
+ /// Offset of Per-Page Checksum Table
+ pub e32_pagesum: U32<LE>,
+ /// Offset of Enumerated Data Pages
+ pub e32_datapage: U32<LE>,
+ /// Number of preload pages
+ pub e32_preload: U32<LE>,
+ /// Offset of Non-resident Names Table
+ pub e32_nrestab: U32<LE>,
+ /// Size of Non-resident Name Table
+ pub e32_cbnrestab: U32<LE>,
+ /// Non-resident Name Table Checksum
+ pub e32_nressum: U32<LE>,
+ /// Object # for automatic data object
+ pub e32_autodata: U32<LE>,
+ /// Offset of the debugging information
+ pub e32_debuginfo: U32<LE>,
+ /// The length of the debugging info. in bytes
+ pub e32_debuglen: U32<LE>,
+ /// Number of instance pages in preload section of VXD file
+ pub e32_instpreload: U32<LE>,
+ /// Number of instance pages in demand load section of VXD file
+ pub e32_instdemand: U32<LE>,
+ /// Size of heap - for 16-bit apps
+ pub e32_heapsize: U32<LE>,
+ /// Reserved words
+ pub e32_res3: [u8; 12],
+ pub e32_winresoff: U32<LE>,
+ pub e32_winreslen: U32<LE>,
+ /// Device ID for VxD
+ pub e32_devid: U16<LE>,
+ /// DDK version for VxD
+ pub e32_ddkver: U16<LE>,
+}
+
+/// A PE rich header entry.
+///
+/// Rich headers have no official documentation, but have been heavily
+/// reversed-engineered and documented in the wild, e.g.:
+/// * `http://www.ntcore.com/files/richsign.htm`
+/// * `https://www.researchgate.net/figure/Structure-of-the-Rich-Header_fig1_318145388`
+///
+/// This data is "masked", i.e. XORed with a checksum derived from the file data.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct MaskedRichHeaderEntry {
+ pub masked_comp_id: U32<LE>,
+ pub masked_count: U32<LE>,
+}
+
+//
+// File header format.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageFileHeader {
+ pub machine: U16<LE>,
+ pub number_of_sections: U16<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub pointer_to_symbol_table: U32<LE>,
+ pub number_of_symbols: U32<LE>,
+ pub size_of_optional_header: U16<LE>,
+ pub characteristics: U16<LE>,
+}
+
+pub const IMAGE_SIZEOF_FILE_HEADER: usize = 20;
+
+/// Relocation info stripped from file.
+pub const IMAGE_FILE_RELOCS_STRIPPED: u16 = 0x0001;
+/// File is executable (i.e. no unresolved external references).
+pub const IMAGE_FILE_EXECUTABLE_IMAGE: u16 = 0x0002;
+/// Line numbers stripped from file.
+pub const IMAGE_FILE_LINE_NUMS_STRIPPED: u16 = 0x0004;
+/// Local symbols stripped from file.
+pub const IMAGE_FILE_LOCAL_SYMS_STRIPPED: u16 = 0x0008;
+/// Aggressively trim working set
+pub const IMAGE_FILE_AGGRESIVE_WS_TRIM: u16 = 0x0010;
+/// App can handle >2gb addresses
+pub const IMAGE_FILE_LARGE_ADDRESS_AWARE: u16 = 0x0020;
+/// Bytes of machine word are reversed.
+pub const IMAGE_FILE_BYTES_REVERSED_LO: u16 = 0x0080;
+/// 32 bit word machine.
+pub const IMAGE_FILE_32BIT_MACHINE: u16 = 0x0100;
+/// Debugging info stripped from file in .DBG file
+pub const IMAGE_FILE_DEBUG_STRIPPED: u16 = 0x0200;
+/// If Image is on removable media, copy and run from the swap file.
+pub const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP: u16 = 0x0400;
+/// If Image is on Net, copy and run from the swap file.
+pub const IMAGE_FILE_NET_RUN_FROM_SWAP: u16 = 0x0800;
+/// System File.
+pub const IMAGE_FILE_SYSTEM: u16 = 0x1000;
+/// File is a DLL.
+pub const IMAGE_FILE_DLL: u16 = 0x2000;
+/// File should only be run on a UP machine
+pub const IMAGE_FILE_UP_SYSTEM_ONLY: u16 = 0x4000;
+/// Bytes of machine word are reversed.
+pub const IMAGE_FILE_BYTES_REVERSED_HI: u16 = 0x8000;
+
+pub const IMAGE_FILE_MACHINE_UNKNOWN: u16 = 0;
+/// Useful for indicating we want to interact with the host and not a WoW guest.
+pub const IMAGE_FILE_MACHINE_TARGET_HOST: u16 = 0x0001;
+/// Intel 386.
+pub const IMAGE_FILE_MACHINE_I386: u16 = 0x014c;
+/// MIPS little-endian, 0x160 big-endian
+pub const IMAGE_FILE_MACHINE_R3000: u16 = 0x0162;
+/// MIPS little-endian
+pub const IMAGE_FILE_MACHINE_R4000: u16 = 0x0166;
+/// MIPS little-endian
+pub const IMAGE_FILE_MACHINE_R10000: u16 = 0x0168;
+/// MIPS little-endian WCE v2
+pub const IMAGE_FILE_MACHINE_WCEMIPSV2: u16 = 0x0169;
+/// Alpha_AXP
+pub const IMAGE_FILE_MACHINE_ALPHA: u16 = 0x0184;
+/// SH3 little-endian
+pub const IMAGE_FILE_MACHINE_SH3: u16 = 0x01a2;
+pub const IMAGE_FILE_MACHINE_SH3DSP: u16 = 0x01a3;
+/// SH3E little-endian
+pub const IMAGE_FILE_MACHINE_SH3E: u16 = 0x01a4;
+/// SH4 little-endian
+pub const IMAGE_FILE_MACHINE_SH4: u16 = 0x01a6;
+/// SH5
+pub const IMAGE_FILE_MACHINE_SH5: u16 = 0x01a8;
+/// ARM Little-Endian
+pub const IMAGE_FILE_MACHINE_ARM: u16 = 0x01c0;
+/// ARM Thumb/Thumb-2 Little-Endian
+pub const IMAGE_FILE_MACHINE_THUMB: u16 = 0x01c2;
+/// ARM Thumb-2 Little-Endian
+pub const IMAGE_FILE_MACHINE_ARMNT: u16 = 0x01c4;
+pub const IMAGE_FILE_MACHINE_AM33: u16 = 0x01d3;
+/// IBM PowerPC Little-Endian
+pub const IMAGE_FILE_MACHINE_POWERPC: u16 = 0x01F0;
+pub const IMAGE_FILE_MACHINE_POWERPCFP: u16 = 0x01f1;
+/// Intel 64
+pub const IMAGE_FILE_MACHINE_IA64: u16 = 0x0200;
+/// MIPS
+pub const IMAGE_FILE_MACHINE_MIPS16: u16 = 0x0266;
+/// ALPHA64
+pub const IMAGE_FILE_MACHINE_ALPHA64: u16 = 0x0284;
+/// MIPS
+pub const IMAGE_FILE_MACHINE_MIPSFPU: u16 = 0x0366;
+/// MIPS
+pub const IMAGE_FILE_MACHINE_MIPSFPU16: u16 = 0x0466;
+pub const IMAGE_FILE_MACHINE_AXP64: u16 = IMAGE_FILE_MACHINE_ALPHA64;
+/// Infineon
+pub const IMAGE_FILE_MACHINE_TRICORE: u16 = 0x0520;
+pub const IMAGE_FILE_MACHINE_CEF: u16 = 0x0CEF;
+/// EFI Byte Code
+pub const IMAGE_FILE_MACHINE_EBC: u16 = 0x0EBC;
+/// AMD64 (K8)
+pub const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
+/// M32R little-endian
+pub const IMAGE_FILE_MACHINE_M32R: u16 = 0x9041;
+/// ARM64 Little-Endian
+pub const IMAGE_FILE_MACHINE_ARM64: u16 = 0xAA64;
+pub const IMAGE_FILE_MACHINE_CEE: u16 = 0xC0EE;
+/// RISCV32
+pub const IMAGE_FILE_MACHINE_RISCV32: u16 = 0x5032;
+/// RISCV64
+pub const IMAGE_FILE_MACHINE_RISCV64: u16 = 0x5064;
+/// RISCV128
+pub const IMAGE_FILE_MACHINE_RISCV128: u16 = 0x5128;
+
+//
+// Directory format.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDataDirectory {
+ pub virtual_address: U32<LE>,
+ pub size: U32<LE>,
+}
+
+pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES: usize = 16;
+
+//
+// Optional header format.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageOptionalHeader32 {
+ // Standard fields.
+ pub magic: U16<LE>,
+ pub major_linker_version: u8,
+ pub minor_linker_version: u8,
+ pub size_of_code: U32<LE>,
+ pub size_of_initialized_data: U32<LE>,
+ pub size_of_uninitialized_data: U32<LE>,
+ pub address_of_entry_point: U32<LE>,
+ pub base_of_code: U32<LE>,
+ pub base_of_data: U32<LE>,
+
+ // NT additional fields.
+ pub image_base: U32<LE>,
+ pub section_alignment: U32<LE>,
+ pub file_alignment: U32<LE>,
+ pub major_operating_system_version: U16<LE>,
+ pub minor_operating_system_version: U16<LE>,
+ pub major_image_version: U16<LE>,
+ pub minor_image_version: U16<LE>,
+ pub major_subsystem_version: U16<LE>,
+ pub minor_subsystem_version: U16<LE>,
+ pub win32_version_value: U32<LE>,
+ pub size_of_image: U32<LE>,
+ pub size_of_headers: U32<LE>,
+ pub check_sum: U32<LE>,
+ pub subsystem: U16<LE>,
+ pub dll_characteristics: U16<LE>,
+ pub size_of_stack_reserve: U32<LE>,
+ pub size_of_stack_commit: U32<LE>,
+ pub size_of_heap_reserve: U32<LE>,
+ pub size_of_heap_commit: U32<LE>,
+ pub loader_flags: U32<LE>,
+ pub number_of_rva_and_sizes: U32<LE>,
+ //pub data_directory: [ImageDataDirectory; IMAGE_NUMBEROF_DIRECTORY_ENTRIES],
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageRomOptionalHeader {
+ pub magic: U16<LE>,
+ pub major_linker_version: u8,
+ pub minor_linker_version: u8,
+ pub size_of_code: U32<LE>,
+ pub size_of_initialized_data: U32<LE>,
+ pub size_of_uninitialized_data: U32<LE>,
+ pub address_of_entry_point: U32<LE>,
+ pub base_of_code: U32<LE>,
+ pub base_of_data: U32<LE>,
+ pub base_of_bss: U32<LE>,
+ pub gpr_mask: U32<LE>,
+ pub cpr_mask: [U32<LE>; 4],
+ pub gp_value: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageOptionalHeader64 {
+ pub magic: U16<LE>,
+ pub major_linker_version: u8,
+ pub minor_linker_version: u8,
+ pub size_of_code: U32<LE>,
+ pub size_of_initialized_data: U32<LE>,
+ pub size_of_uninitialized_data: U32<LE>,
+ pub address_of_entry_point: U32<LE>,
+ pub base_of_code: U32<LE>,
+ pub image_base: U64<LE>,
+ pub section_alignment: U32<LE>,
+ pub file_alignment: U32<LE>,
+ pub major_operating_system_version: U16<LE>,
+ pub minor_operating_system_version: U16<LE>,
+ pub major_image_version: U16<LE>,
+ pub minor_image_version: U16<LE>,
+ pub major_subsystem_version: U16<LE>,
+ pub minor_subsystem_version: U16<LE>,
+ pub win32_version_value: U32<LE>,
+ pub size_of_image: U32<LE>,
+ pub size_of_headers: U32<LE>,
+ pub check_sum: U32<LE>,
+ pub subsystem: U16<LE>,
+ pub dll_characteristics: U16<LE>,
+ pub size_of_stack_reserve: U64<LE>,
+ pub size_of_stack_commit: U64<LE>,
+ pub size_of_heap_reserve: U64<LE>,
+ pub size_of_heap_commit: U64<LE>,
+ pub loader_flags: U32<LE>,
+ pub number_of_rva_and_sizes: U32<LE>,
+ //pub data_directory: [ImageDataDirectory; IMAGE_NUMBEROF_DIRECTORY_ENTRIES],
+}
+
+pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC: u16 = 0x10b;
+pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC: u16 = 0x20b;
+pub const IMAGE_ROM_OPTIONAL_HDR_MAGIC: u16 = 0x107;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageNtHeaders64 {
+ pub signature: U32<LE>,
+ pub file_header: ImageFileHeader,
+ pub optional_header: ImageOptionalHeader64,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageNtHeaders32 {
+ pub signature: U32<LE>,
+ pub file_header: ImageFileHeader,
+ pub optional_header: ImageOptionalHeader32,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageRomHeaders {
+ pub file_header: ImageFileHeader,
+ pub optional_header: ImageRomOptionalHeader,
+}
+
+// Values for `ImageOptionalHeader*::subsystem`.
+
+/// Unknown subsystem.
+pub const IMAGE_SUBSYSTEM_UNKNOWN: u16 = 0;
+/// Image doesn't require a subsystem.
+pub const IMAGE_SUBSYSTEM_NATIVE: u16 = 1;
+/// Image runs in the Windows GUI subsystem.
+pub const IMAGE_SUBSYSTEM_WINDOWS_GUI: u16 = 2;
+/// Image runs in the Windows character subsystem.
+pub const IMAGE_SUBSYSTEM_WINDOWS_CUI: u16 = 3;
+/// image runs in the OS/2 character subsystem.
+pub const IMAGE_SUBSYSTEM_OS2_CUI: u16 = 5;
+/// image runs in the Posix character subsystem.
+pub const IMAGE_SUBSYSTEM_POSIX_CUI: u16 = 7;
+/// image is a native Win9x driver.
+pub const IMAGE_SUBSYSTEM_NATIVE_WINDOWS: u16 = 8;
+/// Image runs in the Windows CE subsystem.
+pub const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: u16 = 9;
+pub const IMAGE_SUBSYSTEM_EFI_APPLICATION: u16 = 10;
+pub const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: u16 = 11;
+pub const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: u16 = 12;
+pub const IMAGE_SUBSYSTEM_EFI_ROM: u16 = 13;
+pub const IMAGE_SUBSYSTEM_XBOX: u16 = 14;
+pub const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: u16 = 16;
+pub const IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG: u16 = 17;
+
+// Values for `ImageOptionalHeader*::dll_characteristics`.
+
+// IMAGE_LIBRARY_PROCESS_INIT 0x0001 // Reserved.
+// IMAGE_LIBRARY_PROCESS_TERM 0x0002 // Reserved.
+// IMAGE_LIBRARY_THREAD_INIT 0x0004 // Reserved.
+// IMAGE_LIBRARY_THREAD_TERM 0x0008 // Reserved.
+/// Image can handle a high entropy 64-bit virtual address space.
+pub const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA: u16 = 0x0020;
+/// DLL can move.
+pub const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE: u16 = 0x0040;
+/// Code Integrity Image
+pub const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY: u16 = 0x0080;
+/// Image is NX compatible
+pub const IMAGE_DLLCHARACTERISTICS_NX_COMPAT: u16 = 0x0100;
+/// Image understands isolation and doesn't want it
+pub const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION: u16 = 0x0200;
+/// Image does not use SEH. No SE handler may reside in this image
+pub const IMAGE_DLLCHARACTERISTICS_NO_SEH: u16 = 0x0400;
+/// Do not bind this image.
+pub const IMAGE_DLLCHARACTERISTICS_NO_BIND: u16 = 0x0800;
+/// Image should execute in an AppContainer
+pub const IMAGE_DLLCHARACTERISTICS_APPCONTAINER: u16 = 0x1000;
+/// Driver uses WDM model
+pub const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER: u16 = 0x2000;
+/// Image supports Control Flow Guard.
+pub const IMAGE_DLLCHARACTERISTICS_GUARD_CF: u16 = 0x4000;
+pub const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE: u16 = 0x8000;
+
+// Indices for `ImageOptionalHeader*::data_directory`.
+
+/// Export Directory
+pub const IMAGE_DIRECTORY_ENTRY_EXPORT: usize = 0;
+/// Import Directory
+pub const IMAGE_DIRECTORY_ENTRY_IMPORT: usize = 1;
+/// Resource Directory
+pub const IMAGE_DIRECTORY_ENTRY_RESOURCE: usize = 2;
+/// Exception Directory
+pub const IMAGE_DIRECTORY_ENTRY_EXCEPTION: usize = 3;
+/// Security Directory
+pub const IMAGE_DIRECTORY_ENTRY_SECURITY: usize = 4;
+/// Base Relocation Table
+pub const IMAGE_DIRECTORY_ENTRY_BASERELOC: usize = 5;
+/// Debug Directory
+pub const IMAGE_DIRECTORY_ENTRY_DEBUG: usize = 6;
+// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
+/// Architecture Specific Data
+pub const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: usize = 7;
+/// RVA of GP
+pub const IMAGE_DIRECTORY_ENTRY_GLOBALPTR: usize = 8;
+/// TLS Directory
+pub const IMAGE_DIRECTORY_ENTRY_TLS: usize = 9;
+/// Load Configuration Directory
+pub const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: usize = 10;
+/// Bound Import Directory in headers
+pub const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: usize = 11;
+/// Import Address Table
+pub const IMAGE_DIRECTORY_ENTRY_IAT: usize = 12;
+/// Delay Load Import Descriptors
+pub const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: usize = 13;
+/// COM Runtime descriptor
+pub const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: usize = 14;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(C)]
+pub struct Guid(pub [u8; 16]);
+
+impl Guid {
+ #[inline]
+ pub fn data1(self) -> U32<LE> {
+ U32::from_bytes(self.0[0..4].try_into().unwrap())
+ }
+
+ #[inline]
+ pub fn data2(self) -> U16<LE> {
+ U16::from_bytes(self.0[4..6].try_into().unwrap())
+ }
+
+ #[inline]
+ pub fn data3(self) -> U16<LE> {
+ U16::from_bytes(self.0[6..8].try_into().unwrap())
+ }
+
+ #[inline]
+ pub fn data4(self) -> [u8; 8] {
+ self.0[8..16].try_into().unwrap()
+ }
+}
+
+pub use Guid as ClsId;
+
+/// Non-COFF Object file header
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AnonObjectHeader {
+ /// Must be IMAGE_FILE_MACHINE_UNKNOWN
+ pub sig1: U16<LE>,
+ /// Must be 0xffff
+ pub sig2: U16<LE>,
+ /// >= 1 (implies the ClsId field is present)
+ pub version: U16<LE>,
+ pub machine: U16<LE>,
+ pub time_date_stamp: U32<LE>,
+ /// Used to invoke CoCreateInstance
+ pub class_id: ClsId,
+ /// Size of data that follows the header
+ pub size_of_data: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AnonObjectHeaderV2 {
+ /// Must be IMAGE_FILE_MACHINE_UNKNOWN
+ pub sig1: U16<LE>,
+ /// Must be 0xffff
+ pub sig2: U16<LE>,
+ /// >= 2 (implies the Flags field is present - otherwise V1)
+ pub version: U16<LE>,
+ pub machine: U16<LE>,
+ pub time_date_stamp: U32<LE>,
+ /// Used to invoke CoCreateInstance
+ pub class_id: ClsId,
+ /// Size of data that follows the header
+ pub size_of_data: U32<LE>,
+ /// 0x1 -> contains metadata
+ pub flags: U32<LE>,
+ /// Size of CLR metadata
+ pub meta_data_size: U32<LE>,
+ /// Offset of CLR metadata
+ pub meta_data_offset: U32<LE>,
+}
+
+/// The required value of `AnonObjectHeaderBigobj::class_id`.
+pub const ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID: ClsId = ClsId([
+ 0xC7, 0xA1, 0xBA, 0xD1, 0xEE, 0xBA, 0xA9, 0x4B, 0xAF, 0x20, 0xFA, 0xF6, 0x6A, 0xA4, 0xDC, 0xB8,
+]);
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AnonObjectHeaderBigobj {
+ /* same as ANON_OBJECT_HEADER_V2 */
+ /// Must be IMAGE_FILE_MACHINE_UNKNOWN
+ pub sig1: U16<LE>,
+ /// Must be 0xffff
+ pub sig2: U16<LE>,
+ /// >= 2 (implies the Flags field is present)
+ pub version: U16<LE>,
+ /// Actual machine - IMAGE_FILE_MACHINE_xxx
+ pub machine: U16<LE>,
+ pub time_date_stamp: U32<LE>,
+ /// Must be `ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID`.
+ pub class_id: ClsId,
+ /// Size of data that follows the header
+ pub size_of_data: U32<LE>,
+ /// 0x1 -> contains metadata
+ pub flags: U32<LE>,
+ /// Size of CLR metadata
+ pub meta_data_size: U32<LE>,
+ /// Offset of CLR metadata
+ pub meta_data_offset: U32<LE>,
+
+ /* bigobj specifics */
+ /// extended from WORD
+ pub number_of_sections: U32<LE>,
+ pub pointer_to_symbol_table: U32<LE>,
+ pub number_of_symbols: U32<LE>,
+}
+
+pub const IMAGE_SIZEOF_SHORT_NAME: usize = 8;
+
+//
+// Section header format.
+//
+
+#[derive(Debug, Default, Clone, Copy)]
+#[repr(C)]
+pub struct ImageSectionHeader {
+ pub name: [u8; IMAGE_SIZEOF_SHORT_NAME],
+ pub virtual_size: U32<LE>,
+ pub virtual_address: U32<LE>,
+ pub size_of_raw_data: U32<LE>,
+ pub pointer_to_raw_data: U32<LE>,
+ pub pointer_to_relocations: U32<LE>,
+ pub pointer_to_linenumbers: U32<LE>,
+ pub number_of_relocations: U16<LE>,
+ pub number_of_linenumbers: U16<LE>,
+ pub characteristics: U32<LE>,
+}
+
+pub const IMAGE_SIZEOF_SECTION_HEADER: usize = 40;
+
+// Values for `ImageSectionHeader::characteristics`.
+
+// IMAGE_SCN_TYPE_REG 0x00000000 // Reserved.
+// IMAGE_SCN_TYPE_DSECT 0x00000001 // Reserved.
+// IMAGE_SCN_TYPE_NOLOAD 0x00000002 // Reserved.
+// IMAGE_SCN_TYPE_GROUP 0x00000004 // Reserved.
+/// Reserved.
+pub const IMAGE_SCN_TYPE_NO_PAD: u32 = 0x0000_0008;
+// IMAGE_SCN_TYPE_COPY 0x00000010 // Reserved.
+
+/// Section contains code.
+pub const IMAGE_SCN_CNT_CODE: u32 = 0x0000_0020;
+/// Section contains initialized data.
+pub const IMAGE_SCN_CNT_INITIALIZED_DATA: u32 = 0x0000_0040;
+/// Section contains uninitialized data.
+pub const IMAGE_SCN_CNT_UNINITIALIZED_DATA: u32 = 0x0000_0080;
+
+/// Reserved.
+pub const IMAGE_SCN_LNK_OTHER: u32 = 0x0000_0100;
+/// Section contains comments or some other type of information.
+pub const IMAGE_SCN_LNK_INFO: u32 = 0x0000_0200;
+// IMAGE_SCN_TYPE_OVER 0x00000400 // Reserved.
+/// Section contents will not become part of image.
+pub const IMAGE_SCN_LNK_REMOVE: u32 = 0x0000_0800;
+/// Section contents comdat.
+pub const IMAGE_SCN_LNK_COMDAT: u32 = 0x0000_1000;
+// 0x00002000 // Reserved.
+// IMAGE_SCN_MEM_PROTECTED - Obsolete 0x00004000
+/// Reset speculative exceptions handling bits in the TLB entries for this section.
+pub const IMAGE_SCN_NO_DEFER_SPEC_EXC: u32 = 0x0000_4000;
+/// Section content can be accessed relative to GP
+pub const IMAGE_SCN_GPREL: u32 = 0x0000_8000;
+pub const IMAGE_SCN_MEM_FARDATA: u32 = 0x0000_8000;
+// IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000
+pub const IMAGE_SCN_MEM_PURGEABLE: u32 = 0x0002_0000;
+pub const IMAGE_SCN_MEM_16BIT: u32 = 0x0002_0000;
+pub const IMAGE_SCN_MEM_LOCKED: u32 = 0x0004_0000;
+pub const IMAGE_SCN_MEM_PRELOAD: u32 = 0x0008_0000;
+
+pub const IMAGE_SCN_ALIGN_1BYTES: u32 = 0x0010_0000;
+pub const IMAGE_SCN_ALIGN_2BYTES: u32 = 0x0020_0000;
+pub const IMAGE_SCN_ALIGN_4BYTES: u32 = 0x0030_0000;
+pub const IMAGE_SCN_ALIGN_8BYTES: u32 = 0x0040_0000;
+/// Default alignment if no others are specified.
+pub const IMAGE_SCN_ALIGN_16BYTES: u32 = 0x0050_0000;
+pub const IMAGE_SCN_ALIGN_32BYTES: u32 = 0x0060_0000;
+pub const IMAGE_SCN_ALIGN_64BYTES: u32 = 0x0070_0000;
+pub const IMAGE_SCN_ALIGN_128BYTES: u32 = 0x0080_0000;
+pub const IMAGE_SCN_ALIGN_256BYTES: u32 = 0x0090_0000;
+pub const IMAGE_SCN_ALIGN_512BYTES: u32 = 0x00A0_0000;
+pub const IMAGE_SCN_ALIGN_1024BYTES: u32 = 0x00B0_0000;
+pub const IMAGE_SCN_ALIGN_2048BYTES: u32 = 0x00C0_0000;
+pub const IMAGE_SCN_ALIGN_4096BYTES: u32 = 0x00D0_0000;
+pub const IMAGE_SCN_ALIGN_8192BYTES: u32 = 0x00E0_0000;
+// Unused 0x00F0_0000
+pub const IMAGE_SCN_ALIGN_MASK: u32 = 0x00F0_0000;
+
+/// Section contains extended relocations.
+pub const IMAGE_SCN_LNK_NRELOC_OVFL: u32 = 0x0100_0000;
+/// Section can be discarded.
+pub const IMAGE_SCN_MEM_DISCARDABLE: u32 = 0x0200_0000;
+/// Section is not cacheable.
+pub const IMAGE_SCN_MEM_NOT_CACHED: u32 = 0x0400_0000;
+/// Section is not pageable.
+pub const IMAGE_SCN_MEM_NOT_PAGED: u32 = 0x0800_0000;
+/// Section is shareable.
+pub const IMAGE_SCN_MEM_SHARED: u32 = 0x1000_0000;
+/// Section is executable.
+pub const IMAGE_SCN_MEM_EXECUTE: u32 = 0x2000_0000;
+/// Section is readable.
+pub const IMAGE_SCN_MEM_READ: u32 = 0x4000_0000;
+/// Section is writeable.
+pub const IMAGE_SCN_MEM_WRITE: u32 = 0x8000_0000;
+
+//
+// TLS Characteristic Flags
+//
+/// Tls index is scaled
+pub const IMAGE_SCN_SCALE_INDEX: u32 = 0x0000_0001;
+
+//
+// Symbol format.
+//
+
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageSymbol {
+ /// If first 4 bytes are 0, then second 4 bytes are offset into string table.
+ pub name: [u8; 8],
+ pub value: U32Bytes<LE>,
+ pub section_number: U16Bytes<LE>,
+ pub typ: U16Bytes<LE>,
+ pub storage_class: u8,
+ pub number_of_aux_symbols: u8,
+}
+
+pub const IMAGE_SIZEOF_SYMBOL: usize = 18;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageSymbolBytes(pub [u8; IMAGE_SIZEOF_SYMBOL]);
+
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageSymbolEx {
+ /// If first 4 bytes are 0, then second 4 bytes are offset into string table.
+ pub name: [u8; 8],
+ pub value: U32Bytes<LE>,
+ pub section_number: I32Bytes<LE>,
+ pub typ: U16Bytes<LE>,
+ pub storage_class: u8,
+ pub number_of_aux_symbols: u8,
+}
+
+pub const IMAGE_SIZEOF_SYMBOL_EX: usize = 20;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageSymbolExBytes(pub [u8; IMAGE_SIZEOF_SYMBOL_EX]);
+
+// Values for `ImageSymbol::section_number`.
+//
+// Symbols have a section number of the section in which they are
+// defined. Otherwise, section numbers have the following meanings:
+
+/// Symbol is undefined or is common.
+pub const IMAGE_SYM_UNDEFINED: i32 = 0;
+/// Symbol is an absolute value.
+pub const IMAGE_SYM_ABSOLUTE: i32 = -1;
+/// Symbol is a special debug item.
+pub const IMAGE_SYM_DEBUG: i32 = -2;
+/// Values 0xFF00-0xFFFF are special
+pub const IMAGE_SYM_SECTION_MAX: u16 = 0xFEFF;
+pub const IMAGE_SYM_SECTION_MAX_EX: u32 = 0x7fff_ffff;
+
+// Values for `ImageSymbol::typ` (basic component).
+
+/// no type.
+pub const IMAGE_SYM_TYPE_NULL: u16 = 0x0000;
+pub const IMAGE_SYM_TYPE_VOID: u16 = 0x0001;
+/// type character.
+pub const IMAGE_SYM_TYPE_CHAR: u16 = 0x0002;
+/// type short integer.
+pub const IMAGE_SYM_TYPE_SHORT: u16 = 0x0003;
+pub const IMAGE_SYM_TYPE_INT: u16 = 0x0004;
+pub const IMAGE_SYM_TYPE_LONG: u16 = 0x0005;
+pub const IMAGE_SYM_TYPE_FLOAT: u16 = 0x0006;
+pub const IMAGE_SYM_TYPE_DOUBLE: u16 = 0x0007;
+pub const IMAGE_SYM_TYPE_STRUCT: u16 = 0x0008;
+pub const IMAGE_SYM_TYPE_UNION: u16 = 0x0009;
+/// enumeration.
+pub const IMAGE_SYM_TYPE_ENUM: u16 = 0x000A;
+/// member of enumeration.
+pub const IMAGE_SYM_TYPE_MOE: u16 = 0x000B;
+pub const IMAGE_SYM_TYPE_BYTE: u16 = 0x000C;
+pub const IMAGE_SYM_TYPE_WORD: u16 = 0x000D;
+pub const IMAGE_SYM_TYPE_UINT: u16 = 0x000E;
+pub const IMAGE_SYM_TYPE_DWORD: u16 = 0x000F;
+pub const IMAGE_SYM_TYPE_PCODE: u16 = 0x8000;
+
+// Values for `ImageSymbol::typ` (derived component).
+
+/// no derived type.
+pub const IMAGE_SYM_DTYPE_NULL: u16 = 0;
+/// pointer.
+pub const IMAGE_SYM_DTYPE_POINTER: u16 = 1;
+/// function.
+pub const IMAGE_SYM_DTYPE_FUNCTION: u16 = 2;
+/// array.
+pub const IMAGE_SYM_DTYPE_ARRAY: u16 = 3;
+
+// Values for `ImageSymbol::storage_class`.
+pub const IMAGE_SYM_CLASS_END_OF_FUNCTION: u8 = 0xff;
+pub const IMAGE_SYM_CLASS_NULL: u8 = 0x00;
+pub const IMAGE_SYM_CLASS_AUTOMATIC: u8 = 0x01;
+pub const IMAGE_SYM_CLASS_EXTERNAL: u8 = 0x02;
+pub const IMAGE_SYM_CLASS_STATIC: u8 = 0x03;
+pub const IMAGE_SYM_CLASS_REGISTER: u8 = 0x04;
+pub const IMAGE_SYM_CLASS_EXTERNAL_DEF: u8 = 0x05;
+pub const IMAGE_SYM_CLASS_LABEL: u8 = 0x06;
+pub const IMAGE_SYM_CLASS_UNDEFINED_LABEL: u8 = 0x07;
+pub const IMAGE_SYM_CLASS_MEMBER_OF_STRUCT: u8 = 0x08;
+pub const IMAGE_SYM_CLASS_ARGUMENT: u8 = 0x09;
+pub const IMAGE_SYM_CLASS_STRUCT_TAG: u8 = 0x0A;
+pub const IMAGE_SYM_CLASS_MEMBER_OF_UNION: u8 = 0x0B;
+pub const IMAGE_SYM_CLASS_UNION_TAG: u8 = 0x0C;
+pub const IMAGE_SYM_CLASS_TYPE_DEFINITION: u8 = 0x0D;
+pub const IMAGE_SYM_CLASS_UNDEFINED_STATIC: u8 = 0x0E;
+pub const IMAGE_SYM_CLASS_ENUM_TAG: u8 = 0x0F;
+pub const IMAGE_SYM_CLASS_MEMBER_OF_ENUM: u8 = 0x10;
+pub const IMAGE_SYM_CLASS_REGISTER_PARAM: u8 = 0x11;
+pub const IMAGE_SYM_CLASS_BIT_FIELD: u8 = 0x12;
+
+pub const IMAGE_SYM_CLASS_FAR_EXTERNAL: u8 = 0x44;
+
+pub const IMAGE_SYM_CLASS_BLOCK: u8 = 0x64;
+pub const IMAGE_SYM_CLASS_FUNCTION: u8 = 0x65;
+pub const IMAGE_SYM_CLASS_END_OF_STRUCT: u8 = 0x66;
+pub const IMAGE_SYM_CLASS_FILE: u8 = 0x67;
+// new
+pub const IMAGE_SYM_CLASS_SECTION: u8 = 0x68;
+pub const IMAGE_SYM_CLASS_WEAK_EXTERNAL: u8 = 0x69;
+
+pub const IMAGE_SYM_CLASS_CLR_TOKEN: u8 = 0x6B;
+
+// type packing constants
+
+pub const N_BTMASK: u16 = 0x000F;
+pub const N_TMASK: u16 = 0x0030;
+pub const N_TMASK1: u16 = 0x00C0;
+pub const N_TMASK2: u16 = 0x00F0;
+pub const N_BTSHFT: usize = 4;
+pub const N_TSHIFT: usize = 2;
+
+pub const IMAGE_SYM_DTYPE_SHIFT: usize = N_BTSHFT;
+
+//
+// Auxiliary entry format.
+//
+
+// Used for both ImageSymbol and ImageSymbolEx (with padding).
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAuxSymbolTokenDef {
+ /// IMAGE_AUX_SYMBOL_TYPE
+ pub aux_type: u8,
+ /// Must be 0
+ pub reserved1: u8,
+ pub symbol_table_index: U32Bytes<LE>,
+ /// Must be 0
+ pub reserved2: [u8; 12],
+}
+
+pub const IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF: u16 = 1;
+
+/// Auxiliary symbol format 1: function definitions.
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAuxSymbolFunction {
+ pub tag_index: U32Bytes<LE>,
+ pub total_size: U32Bytes<LE>,
+ pub pointer_to_linenumber: U32Bytes<LE>,
+ pub pointer_to_next_function: U32Bytes<LE>,
+ pub unused: [u8; 2],
+}
+
+/// Auxiliary symbol format 2: .bf and .ef symbols.
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAuxSymbolFunctionBeginEnd {
+ pub unused1: [u8; 4],
+ /// declaration line number
+ pub linenumber: U16Bytes<LE>,
+ pub unused2: [u8; 6],
+ pub pointer_to_next_function: U32Bytes<LE>,
+ pub unused3: [u8; 2],
+}
+
+/// Auxiliary symbol format 3: weak externals.
+///
+/// Used for both `ImageSymbol` and `ImageSymbolEx` (both with padding).
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAuxSymbolWeak {
+ /// the weak extern default symbol index
+ pub weak_default_sym_index: U32Bytes<LE>,
+ pub weak_search_type: U32Bytes<LE>,
+}
+
+/// Auxiliary symbol format 5: sections.
+///
+/// Used for both `ImageSymbol` and `ImageSymbolEx` (with padding).
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAuxSymbolSection {
+ /// section length
+ pub length: U32Bytes<LE>,
+ /// number of relocation entries
+ pub number_of_relocations: U16Bytes<LE>,
+ /// number of line numbers
+ pub number_of_linenumbers: U16Bytes<LE>,
+ /// checksum for communal
+ pub check_sum: U32Bytes<LE>,
+ /// section number to associate with
+ pub number: U16Bytes<LE>,
+ /// communal selection type
+ pub selection: u8,
+ pub reserved: u8,
+ /// high bits of the section number
+ pub high_number: U16Bytes<LE>,
+}
+
+// Used for both ImageSymbol and ImageSymbolEx (both with padding).
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAuxSymbolCrc {
+ pub crc: U32Bytes<LE>,
+}
+
+//
+// Communal selection types.
+//
+
+pub const IMAGE_COMDAT_SELECT_NODUPLICATES: u8 = 1;
+pub const IMAGE_COMDAT_SELECT_ANY: u8 = 2;
+pub const IMAGE_COMDAT_SELECT_SAME_SIZE: u8 = 3;
+pub const IMAGE_COMDAT_SELECT_EXACT_MATCH: u8 = 4;
+pub const IMAGE_COMDAT_SELECT_ASSOCIATIVE: u8 = 5;
+pub const IMAGE_COMDAT_SELECT_LARGEST: u8 = 6;
+pub const IMAGE_COMDAT_SELECT_NEWEST: u8 = 7;
+
+pub const IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY: u16 = 1;
+pub const IMAGE_WEAK_EXTERN_SEARCH_LIBRARY: u16 = 2;
+pub const IMAGE_WEAK_EXTERN_SEARCH_ALIAS: u16 = 3;
+pub const IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY: u16 = 4;
+
+//
+// Relocation format.
+//
+
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageRelocation {
+ /// Also `RelocCount` when IMAGE_SCN_LNK_NRELOC_OVFL is set
+ pub virtual_address: U32Bytes<LE>,
+ pub symbol_table_index: U32Bytes<LE>,
+ pub typ: U16Bytes<LE>,
+}
+
+//
+// I386 relocation types.
+//
+/// Reference is absolute, no relocation is necessary
+pub const IMAGE_REL_I386_ABSOLUTE: u16 = 0x0000;
+/// Direct 16-bit reference to the symbols virtual address
+pub const IMAGE_REL_I386_DIR16: u16 = 0x0001;
+/// PC-relative 16-bit reference to the symbols virtual address
+pub const IMAGE_REL_I386_REL16: u16 = 0x0002;
+/// Direct 32-bit reference to the symbols virtual address
+pub const IMAGE_REL_I386_DIR32: u16 = 0x0006;
+/// Direct 32-bit reference to the symbols virtual address, base not included
+pub const IMAGE_REL_I386_DIR32NB: u16 = 0x0007;
+/// Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
+pub const IMAGE_REL_I386_SEG12: u16 = 0x0009;
+pub const IMAGE_REL_I386_SECTION: u16 = 0x000A;
+pub const IMAGE_REL_I386_SECREL: u16 = 0x000B;
+/// clr token
+pub const IMAGE_REL_I386_TOKEN: u16 = 0x000C;
+/// 7 bit offset from base of section containing target
+pub const IMAGE_REL_I386_SECREL7: u16 = 0x000D;
+/// PC-relative 32-bit reference to the symbols virtual address
+pub const IMAGE_REL_I386_REL32: u16 = 0x0014;
+
+//
+// MIPS relocation types.
+//
+/// Reference is absolute, no relocation is necessary
+pub const IMAGE_REL_MIPS_ABSOLUTE: u16 = 0x0000;
+pub const IMAGE_REL_MIPS_REFHALF: u16 = 0x0001;
+pub const IMAGE_REL_MIPS_REFWORD: u16 = 0x0002;
+pub const IMAGE_REL_MIPS_JMPADDR: u16 = 0x0003;
+pub const IMAGE_REL_MIPS_REFHI: u16 = 0x0004;
+pub const IMAGE_REL_MIPS_REFLO: u16 = 0x0005;
+pub const IMAGE_REL_MIPS_GPREL: u16 = 0x0006;
+pub const IMAGE_REL_MIPS_LITERAL: u16 = 0x0007;
+pub const IMAGE_REL_MIPS_SECTION: u16 = 0x000A;
+pub const IMAGE_REL_MIPS_SECREL: u16 = 0x000B;
+/// Low 16-bit section relative reference (used for >32k TLS)
+pub const IMAGE_REL_MIPS_SECRELLO: u16 = 0x000C;
+/// High 16-bit section relative reference (used for >32k TLS)
+pub const IMAGE_REL_MIPS_SECRELHI: u16 = 0x000D;
+/// clr token
+pub const IMAGE_REL_MIPS_TOKEN: u16 = 0x000E;
+pub const IMAGE_REL_MIPS_JMPADDR16: u16 = 0x0010;
+pub const IMAGE_REL_MIPS_REFWORDNB: u16 = 0x0022;
+pub const IMAGE_REL_MIPS_PAIR: u16 = 0x0025;
+
+//
+// Alpha Relocation types.
+//
+pub const IMAGE_REL_ALPHA_ABSOLUTE: u16 = 0x0000;
+pub const IMAGE_REL_ALPHA_REFLONG: u16 = 0x0001;
+pub const IMAGE_REL_ALPHA_REFQUAD: u16 = 0x0002;
+pub const IMAGE_REL_ALPHA_GPREL32: u16 = 0x0003;
+pub const IMAGE_REL_ALPHA_LITERAL: u16 = 0x0004;
+pub const IMAGE_REL_ALPHA_LITUSE: u16 = 0x0005;
+pub const IMAGE_REL_ALPHA_GPDISP: u16 = 0x0006;
+pub const IMAGE_REL_ALPHA_BRADDR: u16 = 0x0007;
+pub const IMAGE_REL_ALPHA_HINT: u16 = 0x0008;
+pub const IMAGE_REL_ALPHA_INLINE_REFLONG: u16 = 0x0009;
+pub const IMAGE_REL_ALPHA_REFHI: u16 = 0x000A;
+pub const IMAGE_REL_ALPHA_REFLO: u16 = 0x000B;
+pub const IMAGE_REL_ALPHA_PAIR: u16 = 0x000C;
+pub const IMAGE_REL_ALPHA_MATCH: u16 = 0x000D;
+pub const IMAGE_REL_ALPHA_SECTION: u16 = 0x000E;
+pub const IMAGE_REL_ALPHA_SECREL: u16 = 0x000F;
+pub const IMAGE_REL_ALPHA_REFLONGNB: u16 = 0x0010;
+/// Low 16-bit section relative reference
+pub const IMAGE_REL_ALPHA_SECRELLO: u16 = 0x0011;
+/// High 16-bit section relative reference
+pub const IMAGE_REL_ALPHA_SECRELHI: u16 = 0x0012;
+/// High 16 bits of 48 bit reference
+pub const IMAGE_REL_ALPHA_REFQ3: u16 = 0x0013;
+/// Middle 16 bits of 48 bit reference
+pub const IMAGE_REL_ALPHA_REFQ2: u16 = 0x0014;
+/// Low 16 bits of 48 bit reference
+pub const IMAGE_REL_ALPHA_REFQ1: u16 = 0x0015;
+/// Low 16-bit GP relative reference
+pub const IMAGE_REL_ALPHA_GPRELLO: u16 = 0x0016;
+/// High 16-bit GP relative reference
+pub const IMAGE_REL_ALPHA_GPRELHI: u16 = 0x0017;
+
+//
+// IBM PowerPC relocation types.
+//
+/// NOP
+pub const IMAGE_REL_PPC_ABSOLUTE: u16 = 0x0000;
+/// 64-bit address
+pub const IMAGE_REL_PPC_ADDR64: u16 = 0x0001;
+/// 32-bit address
+pub const IMAGE_REL_PPC_ADDR32: u16 = 0x0002;
+/// 26-bit address, shifted left 2 (branch absolute)
+pub const IMAGE_REL_PPC_ADDR24: u16 = 0x0003;
+/// 16-bit address
+pub const IMAGE_REL_PPC_ADDR16: u16 = 0x0004;
+/// 16-bit address, shifted left 2 (load doubleword)
+pub const IMAGE_REL_PPC_ADDR14: u16 = 0x0005;
+/// 26-bit PC-relative offset, shifted left 2 (branch relative)
+pub const IMAGE_REL_PPC_REL24: u16 = 0x0006;
+/// 16-bit PC-relative offset, shifted left 2 (br cond relative)
+pub const IMAGE_REL_PPC_REL14: u16 = 0x0007;
+/// 16-bit offset from TOC base
+pub const IMAGE_REL_PPC_TOCREL16: u16 = 0x0008;
+/// 16-bit offset from TOC base, shifted left 2 (load doubleword)
+pub const IMAGE_REL_PPC_TOCREL14: u16 = 0x0009;
+
+/// 32-bit addr w/o image base
+pub const IMAGE_REL_PPC_ADDR32NB: u16 = 0x000A;
+/// va of containing section (as in an image sectionhdr)
+pub const IMAGE_REL_PPC_SECREL: u16 = 0x000B;
+/// sectionheader number
+pub const IMAGE_REL_PPC_SECTION: u16 = 0x000C;
+/// substitute TOC restore instruction iff symbol is glue code
+pub const IMAGE_REL_PPC_IFGLUE: u16 = 0x000D;
+/// symbol is glue code; virtual address is TOC restore instruction
+pub const IMAGE_REL_PPC_IMGLUE: u16 = 0x000E;
+/// va of containing section (limited to 16 bits)
+pub const IMAGE_REL_PPC_SECREL16: u16 = 0x000F;
+pub const IMAGE_REL_PPC_REFHI: u16 = 0x0010;
+pub const IMAGE_REL_PPC_REFLO: u16 = 0x0011;
+pub const IMAGE_REL_PPC_PAIR: u16 = 0x0012;
+/// Low 16-bit section relative reference (used for >32k TLS)
+pub const IMAGE_REL_PPC_SECRELLO: u16 = 0x0013;
+/// High 16-bit section relative reference (used for >32k TLS)
+pub const IMAGE_REL_PPC_SECRELHI: u16 = 0x0014;
+pub const IMAGE_REL_PPC_GPREL: u16 = 0x0015;
+/// clr token
+pub const IMAGE_REL_PPC_TOKEN: u16 = 0x0016;
+
+/// mask to isolate above values in IMAGE_RELOCATION.Type
+pub const IMAGE_REL_PPC_TYPEMASK: u16 = 0x00FF;
+
+// Flag bits in `ImageRelocation::typ`.
+
+/// subtract reloc value rather than adding it
+pub const IMAGE_REL_PPC_NEG: u16 = 0x0100;
+/// fix branch prediction bit to predict branch taken
+pub const IMAGE_REL_PPC_BRTAKEN: u16 = 0x0200;
+/// fix branch prediction bit to predict branch not taken
+pub const IMAGE_REL_PPC_BRNTAKEN: u16 = 0x0400;
+/// toc slot defined in file (or, data in toc)
+pub const IMAGE_REL_PPC_TOCDEFN: u16 = 0x0800;
+
+//
+// Hitachi SH3 relocation types.
+//
+/// No relocation
+pub const IMAGE_REL_SH3_ABSOLUTE: u16 = 0x0000;
+/// 16 bit direct
+pub const IMAGE_REL_SH3_DIRECT16: u16 = 0x0001;
+/// 32 bit direct
+pub const IMAGE_REL_SH3_DIRECT32: u16 = 0x0002;
+/// 8 bit direct, -128..255
+pub const IMAGE_REL_SH3_DIRECT8: u16 = 0x0003;
+/// 8 bit direct .W (0 ext.)
+pub const IMAGE_REL_SH3_DIRECT8_WORD: u16 = 0x0004;
+/// 8 bit direct .L (0 ext.)
+pub const IMAGE_REL_SH3_DIRECT8_LONG: u16 = 0x0005;
+/// 4 bit direct (0 ext.)
+pub const IMAGE_REL_SH3_DIRECT4: u16 = 0x0006;
+/// 4 bit direct .W (0 ext.)
+pub const IMAGE_REL_SH3_DIRECT4_WORD: u16 = 0x0007;
+/// 4 bit direct .L (0 ext.)
+pub const IMAGE_REL_SH3_DIRECT4_LONG: u16 = 0x0008;
+/// 8 bit PC relative .W
+pub const IMAGE_REL_SH3_PCREL8_WORD: u16 = 0x0009;
+/// 8 bit PC relative .L
+pub const IMAGE_REL_SH3_PCREL8_LONG: u16 = 0x000A;
+/// 12 LSB PC relative .W
+pub const IMAGE_REL_SH3_PCREL12_WORD: u16 = 0x000B;
+/// Start of EXE section
+pub const IMAGE_REL_SH3_STARTOF_SECTION: u16 = 0x000C;
+/// Size of EXE section
+pub const IMAGE_REL_SH3_SIZEOF_SECTION: u16 = 0x000D;
+/// Section table index
+pub const IMAGE_REL_SH3_SECTION: u16 = 0x000E;
+/// Offset within section
+pub const IMAGE_REL_SH3_SECREL: u16 = 0x000F;
+/// 32 bit direct not based
+pub const IMAGE_REL_SH3_DIRECT32_NB: u16 = 0x0010;
+/// GP-relative addressing
+pub const IMAGE_REL_SH3_GPREL4_LONG: u16 = 0x0011;
+/// clr token
+pub const IMAGE_REL_SH3_TOKEN: u16 = 0x0012;
+/// Offset from current instruction in longwords
+/// if not NOMODE, insert the inverse of the low bit at bit 32 to select PTA/PTB
+pub const IMAGE_REL_SHM_PCRELPT: u16 = 0x0013;
+/// Low bits of 32-bit address
+pub const IMAGE_REL_SHM_REFLO: u16 = 0x0014;
+/// High bits of 32-bit address
+pub const IMAGE_REL_SHM_REFHALF: u16 = 0x0015;
+/// Low bits of relative reference
+pub const IMAGE_REL_SHM_RELLO: u16 = 0x0016;
+/// High bits of relative reference
+pub const IMAGE_REL_SHM_RELHALF: u16 = 0x0017;
+/// offset operand for relocation
+pub const IMAGE_REL_SHM_PAIR: u16 = 0x0018;
+
+/// relocation ignores section mode
+pub const IMAGE_REL_SH_NOMODE: u16 = 0x8000;
+
+/// No relocation required
+pub const IMAGE_REL_ARM_ABSOLUTE: u16 = 0x0000;
+/// 32 bit address
+pub const IMAGE_REL_ARM_ADDR32: u16 = 0x0001;
+/// 32 bit address w/o image base
+pub const IMAGE_REL_ARM_ADDR32NB: u16 = 0x0002;
+/// 24 bit offset << 2 & sign ext.
+pub const IMAGE_REL_ARM_BRANCH24: u16 = 0x0003;
+/// Thumb: 2 11 bit offsets
+pub const IMAGE_REL_ARM_BRANCH11: u16 = 0x0004;
+/// clr token
+pub const IMAGE_REL_ARM_TOKEN: u16 = 0x0005;
+/// GP-relative addressing (ARM)
+pub const IMAGE_REL_ARM_GPREL12: u16 = 0x0006;
+/// GP-relative addressing (Thumb)
+pub const IMAGE_REL_ARM_GPREL7: u16 = 0x0007;
+pub const IMAGE_REL_ARM_BLX24: u16 = 0x0008;
+pub const IMAGE_REL_ARM_BLX11: u16 = 0x0009;
+/// 32-bit relative address from byte following reloc
+pub const IMAGE_REL_ARM_REL32: u16 = 0x000A;
+/// Section table index
+pub const IMAGE_REL_ARM_SECTION: u16 = 0x000E;
+/// Offset within section
+pub const IMAGE_REL_ARM_SECREL: u16 = 0x000F;
+/// ARM: MOVW/MOVT
+pub const IMAGE_REL_ARM_MOV32A: u16 = 0x0010;
+/// ARM: MOVW/MOVT (deprecated)
+pub const IMAGE_REL_ARM_MOV32: u16 = 0x0010;
+/// Thumb: MOVW/MOVT
+pub const IMAGE_REL_ARM_MOV32T: u16 = 0x0011;
+/// Thumb: MOVW/MOVT (deprecated)
+pub const IMAGE_REL_THUMB_MOV32: u16 = 0x0011;
+/// Thumb: 32-bit conditional B
+pub const IMAGE_REL_ARM_BRANCH20T: u16 = 0x0012;
+/// Thumb: 32-bit conditional B (deprecated)
+pub const IMAGE_REL_THUMB_BRANCH20: u16 = 0x0012;
+/// Thumb: 32-bit B or BL
+pub const IMAGE_REL_ARM_BRANCH24T: u16 = 0x0014;
+/// Thumb: 32-bit B or BL (deprecated)
+pub const IMAGE_REL_THUMB_BRANCH24: u16 = 0x0014;
+/// Thumb: BLX immediate
+pub const IMAGE_REL_ARM_BLX23T: u16 = 0x0015;
+/// Thumb: BLX immediate (deprecated)
+pub const IMAGE_REL_THUMB_BLX23: u16 = 0x0015;
+
+pub const IMAGE_REL_AM_ABSOLUTE: u16 = 0x0000;
+pub const IMAGE_REL_AM_ADDR32: u16 = 0x0001;
+pub const IMAGE_REL_AM_ADDR32NB: u16 = 0x0002;
+pub const IMAGE_REL_AM_CALL32: u16 = 0x0003;
+pub const IMAGE_REL_AM_FUNCINFO: u16 = 0x0004;
+pub const IMAGE_REL_AM_REL32_1: u16 = 0x0005;
+pub const IMAGE_REL_AM_REL32_2: u16 = 0x0006;
+pub const IMAGE_REL_AM_SECREL: u16 = 0x0007;
+pub const IMAGE_REL_AM_SECTION: u16 = 0x0008;
+pub const IMAGE_REL_AM_TOKEN: u16 = 0x0009;
+
+//
+// ARM64 relocations types.
+//
+
+/// No relocation required
+pub const IMAGE_REL_ARM64_ABSOLUTE: u16 = 0x0000;
+/// 32 bit address. Review! do we need it?
+pub const IMAGE_REL_ARM64_ADDR32: u16 = 0x0001;
+/// 32 bit address w/o image base (RVA: for Data/PData/XData)
+pub const IMAGE_REL_ARM64_ADDR32NB: u16 = 0x0002;
+/// 26 bit offset << 2 & sign ext. for B & BL
+pub const IMAGE_REL_ARM64_BRANCH26: u16 = 0x0003;
+/// ADRP
+pub const IMAGE_REL_ARM64_PAGEBASE_REL21: u16 = 0x0004;
+/// ADR
+pub const IMAGE_REL_ARM64_REL21: u16 = 0x0005;
+/// ADD/ADDS (immediate) with zero shift, for page offset
+pub const IMAGE_REL_ARM64_PAGEOFFSET_12A: u16 = 0x0006;
+/// LDR (indexed, unsigned immediate), for page offset
+pub const IMAGE_REL_ARM64_PAGEOFFSET_12L: u16 = 0x0007;
+/// Offset within section
+pub const IMAGE_REL_ARM64_SECREL: u16 = 0x0008;
+/// ADD/ADDS (immediate) with zero shift, for bit 0:11 of section offset
+pub const IMAGE_REL_ARM64_SECREL_LOW12A: u16 = 0x0009;
+/// ADD/ADDS (immediate) with zero shift, for bit 12:23 of section offset
+pub const IMAGE_REL_ARM64_SECREL_HIGH12A: u16 = 0x000A;
+/// LDR (indexed, unsigned immediate), for bit 0:11 of section offset
+pub const IMAGE_REL_ARM64_SECREL_LOW12L: u16 = 0x000B;
+pub const IMAGE_REL_ARM64_TOKEN: u16 = 0x000C;
+/// Section table index
+pub const IMAGE_REL_ARM64_SECTION: u16 = 0x000D;
+/// 64 bit address
+pub const IMAGE_REL_ARM64_ADDR64: u16 = 0x000E;
+/// 19 bit offset << 2 & sign ext. for conditional B
+pub const IMAGE_REL_ARM64_BRANCH19: u16 = 0x000F;
+/// TBZ/TBNZ
+pub const IMAGE_REL_ARM64_BRANCH14: u16 = 0x0010;
+/// 32-bit relative address from byte following reloc
+pub const IMAGE_REL_ARM64_REL32: u16 = 0x0011;
+
+//
+// x64 relocations
+//
+/// Reference is absolute, no relocation is necessary
+pub const IMAGE_REL_AMD64_ABSOLUTE: u16 = 0x0000;
+/// 64-bit address (VA).
+pub const IMAGE_REL_AMD64_ADDR64: u16 = 0x0001;
+/// 32-bit address (VA).
+pub const IMAGE_REL_AMD64_ADDR32: u16 = 0x0002;
+/// 32-bit address w/o image base (RVA).
+pub const IMAGE_REL_AMD64_ADDR32NB: u16 = 0x0003;
+/// 32-bit relative address from byte following reloc
+pub const IMAGE_REL_AMD64_REL32: u16 = 0x0004;
+/// 32-bit relative address from byte distance 1 from reloc
+pub const IMAGE_REL_AMD64_REL32_1: u16 = 0x0005;
+/// 32-bit relative address from byte distance 2 from reloc
+pub const IMAGE_REL_AMD64_REL32_2: u16 = 0x0006;
+/// 32-bit relative address from byte distance 3 from reloc
+pub const IMAGE_REL_AMD64_REL32_3: u16 = 0x0007;
+/// 32-bit relative address from byte distance 4 from reloc
+pub const IMAGE_REL_AMD64_REL32_4: u16 = 0x0008;
+/// 32-bit relative address from byte distance 5 from reloc
+pub const IMAGE_REL_AMD64_REL32_5: u16 = 0x0009;
+/// Section index
+pub const IMAGE_REL_AMD64_SECTION: u16 = 0x000A;
+/// 32 bit offset from base of section containing target
+pub const IMAGE_REL_AMD64_SECREL: u16 = 0x000B;
+/// 7 bit unsigned offset from base of section containing target
+pub const IMAGE_REL_AMD64_SECREL7: u16 = 0x000C;
+/// 32 bit metadata token
+pub const IMAGE_REL_AMD64_TOKEN: u16 = 0x000D;
+/// 32 bit signed span-dependent value emitted into object
+pub const IMAGE_REL_AMD64_SREL32: u16 = 0x000E;
+pub const IMAGE_REL_AMD64_PAIR: u16 = 0x000F;
+/// 32 bit signed span-dependent value applied at link time
+pub const IMAGE_REL_AMD64_SSPAN32: u16 = 0x0010;
+pub const IMAGE_REL_AMD64_EHANDLER: u16 = 0x0011;
+/// Indirect branch to an import
+pub const IMAGE_REL_AMD64_IMPORT_BR: u16 = 0x0012;
+/// Indirect call to an import
+pub const IMAGE_REL_AMD64_IMPORT_CALL: u16 = 0x0013;
+/// Indirect branch to a CFG check
+pub const IMAGE_REL_AMD64_CFG_BR: u16 = 0x0014;
+/// Indirect branch to a CFG check, with REX.W prefix
+pub const IMAGE_REL_AMD64_CFG_BR_REX: u16 = 0x0015;
+/// Indirect call to a CFG check
+pub const IMAGE_REL_AMD64_CFG_CALL: u16 = 0x0016;
+/// Indirect branch to a target in RAX (no CFG)
+pub const IMAGE_REL_AMD64_INDIR_BR: u16 = 0x0017;
+/// Indirect branch to a target in RAX, with REX.W prefix (no CFG)
+pub const IMAGE_REL_AMD64_INDIR_BR_REX: u16 = 0x0018;
+/// Indirect call to a target in RAX (no CFG)
+pub const IMAGE_REL_AMD64_INDIR_CALL: u16 = 0x0019;
+/// Indirect branch for a switch table using Reg 0 (RAX)
+pub const IMAGE_REL_AMD64_INDIR_BR_SWITCHTABLE_FIRST: u16 = 0x0020;
+/// Indirect branch for a switch table using Reg 15 (R15)
+pub const IMAGE_REL_AMD64_INDIR_BR_SWITCHTABLE_LAST: u16 = 0x002F;
+
+//
+// IA64 relocation types.
+//
+pub const IMAGE_REL_IA64_ABSOLUTE: u16 = 0x0000;
+pub const IMAGE_REL_IA64_IMM14: u16 = 0x0001;
+pub const IMAGE_REL_IA64_IMM22: u16 = 0x0002;
+pub const IMAGE_REL_IA64_IMM64: u16 = 0x0003;
+pub const IMAGE_REL_IA64_DIR32: u16 = 0x0004;
+pub const IMAGE_REL_IA64_DIR64: u16 = 0x0005;
+pub const IMAGE_REL_IA64_PCREL21B: u16 = 0x0006;
+pub const IMAGE_REL_IA64_PCREL21M: u16 = 0x0007;
+pub const IMAGE_REL_IA64_PCREL21F: u16 = 0x0008;
+pub const IMAGE_REL_IA64_GPREL22: u16 = 0x0009;
+pub const IMAGE_REL_IA64_LTOFF22: u16 = 0x000A;
+pub const IMAGE_REL_IA64_SECTION: u16 = 0x000B;
+pub const IMAGE_REL_IA64_SECREL22: u16 = 0x000C;
+pub const IMAGE_REL_IA64_SECREL64I: u16 = 0x000D;
+pub const IMAGE_REL_IA64_SECREL32: u16 = 0x000E;
+//
+pub const IMAGE_REL_IA64_DIR32NB: u16 = 0x0010;
+pub const IMAGE_REL_IA64_SREL14: u16 = 0x0011;
+pub const IMAGE_REL_IA64_SREL22: u16 = 0x0012;
+pub const IMAGE_REL_IA64_SREL32: u16 = 0x0013;
+pub const IMAGE_REL_IA64_UREL32: u16 = 0x0014;
+/// This is always a BRL and never converted
+pub const IMAGE_REL_IA64_PCREL60X: u16 = 0x0015;
+/// If possible, convert to MBB bundle with NOP.B in slot 1
+pub const IMAGE_REL_IA64_PCREL60B: u16 = 0x0016;
+/// If possible, convert to MFB bundle with NOP.F in slot 1
+pub const IMAGE_REL_IA64_PCREL60F: u16 = 0x0017;
+/// If possible, convert to MIB bundle with NOP.I in slot 1
+pub const IMAGE_REL_IA64_PCREL60I: u16 = 0x0018;
+/// If possible, convert to MMB bundle with NOP.M in slot 1
+pub const IMAGE_REL_IA64_PCREL60M: u16 = 0x0019;
+pub const IMAGE_REL_IA64_IMMGPREL64: u16 = 0x001A;
+/// clr token
+pub const IMAGE_REL_IA64_TOKEN: u16 = 0x001B;
+pub const IMAGE_REL_IA64_GPREL32: u16 = 0x001C;
+pub const IMAGE_REL_IA64_ADDEND: u16 = 0x001F;
+
+//
+// CEF relocation types.
+//
+/// Reference is absolute, no relocation is necessary
+pub const IMAGE_REL_CEF_ABSOLUTE: u16 = 0x0000;
+/// 32-bit address (VA).
+pub const IMAGE_REL_CEF_ADDR32: u16 = 0x0001;
+/// 64-bit address (VA).
+pub const IMAGE_REL_CEF_ADDR64: u16 = 0x0002;
+/// 32-bit address w/o image base (RVA).
+pub const IMAGE_REL_CEF_ADDR32NB: u16 = 0x0003;
+/// Section index
+pub const IMAGE_REL_CEF_SECTION: u16 = 0x0004;
+/// 32 bit offset from base of section containing target
+pub const IMAGE_REL_CEF_SECREL: u16 = 0x0005;
+/// 32 bit metadata token
+pub const IMAGE_REL_CEF_TOKEN: u16 = 0x0006;
+
+//
+// clr relocation types.
+//
+/// Reference is absolute, no relocation is necessary
+pub const IMAGE_REL_CEE_ABSOLUTE: u16 = 0x0000;
+/// 32-bit address (VA).
+pub const IMAGE_REL_CEE_ADDR32: u16 = 0x0001;
+/// 64-bit address (VA).
+pub const IMAGE_REL_CEE_ADDR64: u16 = 0x0002;
+/// 32-bit address w/o image base (RVA).
+pub const IMAGE_REL_CEE_ADDR32NB: u16 = 0x0003;
+/// Section index
+pub const IMAGE_REL_CEE_SECTION: u16 = 0x0004;
+/// 32 bit offset from base of section containing target
+pub const IMAGE_REL_CEE_SECREL: u16 = 0x0005;
+/// 32 bit metadata token
+pub const IMAGE_REL_CEE_TOKEN: u16 = 0x0006;
+
+/// No relocation required
+pub const IMAGE_REL_M32R_ABSOLUTE: u16 = 0x0000;
+/// 32 bit address
+pub const IMAGE_REL_M32R_ADDR32: u16 = 0x0001;
+/// 32 bit address w/o image base
+pub const IMAGE_REL_M32R_ADDR32NB: u16 = 0x0002;
+/// 24 bit address
+pub const IMAGE_REL_M32R_ADDR24: u16 = 0x0003;
+/// GP relative addressing
+pub const IMAGE_REL_M32R_GPREL16: u16 = 0x0004;
+/// 24 bit offset << 2 & sign ext.
+pub const IMAGE_REL_M32R_PCREL24: u16 = 0x0005;
+/// 16 bit offset << 2 & sign ext.
+pub const IMAGE_REL_M32R_PCREL16: u16 = 0x0006;
+/// 8 bit offset << 2 & sign ext.
+pub const IMAGE_REL_M32R_PCREL8: u16 = 0x0007;
+/// 16 MSBs
+pub const IMAGE_REL_M32R_REFHALF: u16 = 0x0008;
+/// 16 MSBs; adj for LSB sign ext.
+pub const IMAGE_REL_M32R_REFHI: u16 = 0x0009;
+/// 16 LSBs
+pub const IMAGE_REL_M32R_REFLO: u16 = 0x000A;
+/// Link HI and LO
+pub const IMAGE_REL_M32R_PAIR: u16 = 0x000B;
+/// Section table index
+pub const IMAGE_REL_M32R_SECTION: u16 = 0x000C;
+/// 32 bit section relative reference
+pub const IMAGE_REL_M32R_SECREL32: u16 = 0x000D;
+/// clr token
+pub const IMAGE_REL_M32R_TOKEN: u16 = 0x000E;
+
+/// No relocation required
+pub const IMAGE_REL_EBC_ABSOLUTE: u16 = 0x0000;
+/// 32 bit address w/o image base
+pub const IMAGE_REL_EBC_ADDR32NB: u16 = 0x0001;
+/// 32-bit relative address from byte following reloc
+pub const IMAGE_REL_EBC_REL32: u16 = 0x0002;
+/// Section table index
+pub const IMAGE_REL_EBC_SECTION: u16 = 0x0003;
+/// Offset within section
+pub const IMAGE_REL_EBC_SECREL: u16 = 0x0004;
+
+/*
+// TODO?
+#define EXT_IMM64(Value, Address, Size, InstPos, ValPos) /* Intel-IA64-Filler */ \
+ Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) // Intel-IA64-Filler
+
+#define INS_IMM64(Value, Address, Size, InstPos, ValPos) /* Intel-IA64-Filler */\
+ *(PDWORD)Address = (*(PDWORD)Address & ~(((1 << Size) - 1) << InstPos)) | /* Intel-IA64-Filler */\
+ ((DWORD)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) // Intel-IA64-Filler
+*/
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM7B_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM7B_SIZE_X: u16 = 7;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X: u16 = 4;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM7B_VAL_POS_X: u16 = 0;
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM9D_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM9D_SIZE_X: u16 = 9;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X: u16 = 18;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM9D_VAL_POS_X: u16 = 7;
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM5C_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM5C_SIZE_X: u16 = 5;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X: u16 = 13;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM5C_VAL_POS_X: u16 = 16;
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IC_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IC_SIZE_X: u16 = 1;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IC_INST_WORD_POS_X: u16 = 12;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IC_VAL_POS_X: u16 = 21;
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41A_INST_WORD_X: u16 = 1;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41A_SIZE_X: u16 = 10;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41A_INST_WORD_POS_X: u16 = 14;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41A_VAL_POS_X: u16 = 22;
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41B_INST_WORD_X: u16 = 1;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41B_SIZE_X: u16 = 8;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41B_INST_WORD_POS_X: u16 = 24;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41B_VAL_POS_X: u16 = 32;
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41C_INST_WORD_X: u16 = 2;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41C_SIZE_X: u16 = 23;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41C_INST_WORD_POS_X: u16 = 0;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_IMM41C_VAL_POS_X: u16 = 40;
+
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_SIGN_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_SIGN_SIZE_X: u16 = 1;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_SIGN_INST_WORD_POS_X: u16 = 27;
+/// Intel-IA64-Filler
+pub const EMARCH_ENC_I17_SIGN_VAL_POS_X: u16 = 63;
+
+/// Intel-IA64-Filler
+pub const X3_OPCODE_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const X3_OPCODE_SIZE_X: u16 = 4;
+/// Intel-IA64-Filler
+pub const X3_OPCODE_INST_WORD_POS_X: u16 = 28;
+/// Intel-IA64-Filler
+pub const X3_OPCODE_SIGN_VAL_POS_X: u16 = 0;
+
+/// Intel-IA64-Filler
+pub const X3_I_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const X3_I_SIZE_X: u16 = 1;
+/// Intel-IA64-Filler
+pub const X3_I_INST_WORD_POS_X: u16 = 27;
+/// Intel-IA64-Filler
+pub const X3_I_SIGN_VAL_POS_X: u16 = 59;
+
+/// Intel-IA64-Filler
+pub const X3_D_WH_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const X3_D_WH_SIZE_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const X3_D_WH_INST_WORD_POS_X: u16 = 24;
+/// Intel-IA64-Filler
+pub const X3_D_WH_SIGN_VAL_POS_X: u16 = 0;
+
+/// Intel-IA64-Filler
+pub const X3_IMM20_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const X3_IMM20_SIZE_X: u16 = 20;
+/// Intel-IA64-Filler
+pub const X3_IMM20_INST_WORD_POS_X: u16 = 4;
+/// Intel-IA64-Filler
+pub const X3_IMM20_SIGN_VAL_POS_X: u16 = 0;
+
+/// Intel-IA64-Filler
+pub const X3_IMM39_1_INST_WORD_X: u16 = 2;
+/// Intel-IA64-Filler
+pub const X3_IMM39_1_SIZE_X: u16 = 23;
+/// Intel-IA64-Filler
+pub const X3_IMM39_1_INST_WORD_POS_X: u16 = 0;
+/// Intel-IA64-Filler
+pub const X3_IMM39_1_SIGN_VAL_POS_X: u16 = 36;
+
+/// Intel-IA64-Filler
+pub const X3_IMM39_2_INST_WORD_X: u16 = 1;
+/// Intel-IA64-Filler
+pub const X3_IMM39_2_SIZE_X: u16 = 16;
+/// Intel-IA64-Filler
+pub const X3_IMM39_2_INST_WORD_POS_X: u16 = 16;
+/// Intel-IA64-Filler
+pub const X3_IMM39_2_SIGN_VAL_POS_X: u16 = 20;
+
+/// Intel-IA64-Filler
+pub const X3_P_INST_WORD_X: u16 = 3;
+/// Intel-IA64-Filler
+pub const X3_P_SIZE_X: u16 = 4;
+/// Intel-IA64-Filler
+pub const X3_P_INST_WORD_POS_X: u16 = 0;
+/// Intel-IA64-Filler
+pub const X3_P_SIGN_VAL_POS_X: u16 = 0;
+
+/// Intel-IA64-Filler
+pub const X3_TMPLT_INST_WORD_X: u16 = 0;
+/// Intel-IA64-Filler
+pub const X3_TMPLT_SIZE_X: u16 = 4;
+/// Intel-IA64-Filler
+pub const X3_TMPLT_INST_WORD_POS_X: u16 = 0;
+/// Intel-IA64-Filler
+pub const X3_TMPLT_SIGN_VAL_POS_X: u16 = 0;
+
+/// Intel-IA64-Filler
+pub const X3_BTYPE_QP_INST_WORD_X: u16 = 2;
+/// Intel-IA64-Filler
+pub const X3_BTYPE_QP_SIZE_X: u16 = 9;
+/// Intel-IA64-Filler
+pub const X3_BTYPE_QP_INST_WORD_POS_X: u16 = 23;
+/// Intel-IA64-Filler
+pub const X3_BTYPE_QP_INST_VAL_POS_X: u16 = 0;
+
+/// Intel-IA64-Filler
+pub const X3_EMPTY_INST_WORD_X: u16 = 1;
+/// Intel-IA64-Filler
+pub const X3_EMPTY_SIZE_X: u16 = 2;
+/// Intel-IA64-Filler
+pub const X3_EMPTY_INST_WORD_POS_X: u16 = 14;
+/// Intel-IA64-Filler
+pub const X3_EMPTY_INST_VAL_POS_X: u16 = 0;
+
+//
+// Line number format.
+//
+
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageLinenumber {
+ /// Symbol table index of function name if Linenumber is 0.
+ /// Otherwise virtual address of line number.
+ pub symbol_table_index_or_virtual_address: U32Bytes<LE>,
+ /// Line number.
+ pub linenumber: U16Bytes<LE>,
+}
+
+//
+// Based relocation format.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageBaseRelocation {
+ pub virtual_address: U32<LE>,
+ pub size_of_block: U32<LE>,
+ // pub type_offset[1]: U16<LE>,
+}
+
+//
+// Based relocation types.
+//
+
+pub const IMAGE_REL_BASED_ABSOLUTE: u16 = 0;
+pub const IMAGE_REL_BASED_HIGH: u16 = 1;
+pub const IMAGE_REL_BASED_LOW: u16 = 2;
+pub const IMAGE_REL_BASED_HIGHLOW: u16 = 3;
+pub const IMAGE_REL_BASED_HIGHADJ: u16 = 4;
+pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_5: u16 = 5;
+pub const IMAGE_REL_BASED_RESERVED: u16 = 6;
+pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_7: u16 = 7;
+pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_8: u16 = 8;
+pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_9: u16 = 9;
+pub const IMAGE_REL_BASED_DIR64: u16 = 10;
+
+//
+// Platform-specific based relocation types.
+//
+
+pub const IMAGE_REL_BASED_IA64_IMM64: u16 = 9;
+
+pub const IMAGE_REL_BASED_MIPS_JMPADDR: u16 = 5;
+pub const IMAGE_REL_BASED_MIPS_JMPADDR16: u16 = 9;
+
+pub const IMAGE_REL_BASED_ARM_MOV32: u16 = 5;
+pub const IMAGE_REL_BASED_THUMB_MOV32: u16 = 7;
+
+pub const IMAGE_REL_BASED_RISCV_HIGH20: u16 = 5;
+pub const IMAGE_REL_BASED_RISCV_LOW12I: u16 = 7;
+pub const IMAGE_REL_BASED_RISCV_LOW12S: u16 = 8;
+
+//
+// Archive format.
+//
+
+pub const IMAGE_ARCHIVE_START_SIZE: usize = 8;
+pub const IMAGE_ARCHIVE_START: &[u8; 8] = b"!<arch>\n";
+pub const IMAGE_ARCHIVE_END: &[u8] = b"`\n";
+pub const IMAGE_ARCHIVE_PAD: &[u8] = b"\n";
+pub const IMAGE_ARCHIVE_LINKER_MEMBER: &[u8; 16] = b"/ ";
+pub const IMAGE_ARCHIVE_LONGNAMES_MEMBER: &[u8; 16] = b"// ";
+pub const IMAGE_ARCHIVE_HYBRIDMAP_MEMBER: &[u8; 16] = b"/<HYBRIDMAP>/ ";
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageArchiveMemberHeader {
+ /// File member name - `/' terminated.
+ pub name: [u8; 16],
+ /// File member date - decimal.
+ pub date: [u8; 12],
+ /// File member user id - decimal.
+ pub user_id: [u8; 6],
+ /// File member group id - decimal.
+ pub group_id: [u8; 6],
+ /// File member mode - octal.
+ pub mode: [u8; 8],
+ /// File member size - decimal.
+ pub size: [u8; 10],
+ /// String to end header.
+ pub end_header: [u8; 2],
+}
+
+pub const IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR: u16 = 60;
+
+//
+// DLL support.
+//
+
+//
+// Export Format
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageExportDirectory {
+ pub characteristics: U32<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub major_version: U16<LE>,
+ pub minor_version: U16<LE>,
+ pub name: U32<LE>,
+ pub base: U32<LE>,
+ pub number_of_functions: U32<LE>,
+ pub number_of_names: U32<LE>,
+ /// RVA from base of image
+ pub address_of_functions: U32<LE>,
+ /// RVA from base of image
+ pub address_of_names: U32<LE>,
+ /// RVA from base of image
+ pub address_of_name_ordinals: U32<LE>,
+}
+
+//
+// Import Format
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageImportByName {
+ pub hint: U16<LE>,
+ //pub name: [i8; 1],
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageThunkData64(pub U64<LE>);
+/*
+ union {
+/// PBYTE
+ pub forwarder_string: U64<LE>,
+/// PDWORD
+ pub function: U64<LE>,
+ pub ordinal: U64<LE>,
+/// PIMAGE_IMPORT_BY_NAME
+ pub address_of_data: U64<LE>,
+ } u1;
+*/
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageThunkData32(pub U32<LE>);
+/*
+ union {
+/// PBYTE
+ pub forwarder_string: U32<LE>,
+/// PDWORD
+ pub function: U32<LE>,
+ pub ordinal: U32<LE>,
+/// PIMAGE_IMPORT_BY_NAME
+ pub address_of_data: U32<LE>,
+ } u1;
+}
+*/
+
+pub const IMAGE_ORDINAL_FLAG64: u64 = 0x8000000000000000;
+pub const IMAGE_ORDINAL_FLAG32: u32 = 0x80000000;
+
+/*
+#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffff)
+#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff)
+#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0)
+#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0)
+
+*/
+
+//
+// Thread Local Storage
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageTlsDirectory64 {
+ pub start_address_of_raw_data: U64<LE>,
+ pub end_address_of_raw_data: U64<LE>,
+ /// PDWORD
+ pub address_of_index: U64<LE>,
+ /// PIMAGE_TLS_CALLBACK *;
+ pub address_of_call_backs: U64<LE>,
+ pub size_of_zero_fill: U32<LE>,
+ pub characteristics: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageTlsDirectory32 {
+ pub start_address_of_raw_data: U32<LE>,
+ pub end_address_of_raw_data: U32<LE>,
+ /// PDWORD
+ pub address_of_index: U32<LE>,
+ /// PIMAGE_TLS_CALLBACK *
+ pub address_of_call_backs: U32<LE>,
+ pub size_of_zero_fill: U32<LE>,
+ pub characteristics: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageImportDescriptor {
+ /// RVA to original unbound IAT (`ImageThunkData32`/`ImageThunkData64`)
+ /// 0 for terminating null import descriptor
+ pub original_first_thunk: U32Bytes<LE>,
+ /// 0 if not bound,
+ /// -1 if bound, and real date\time stamp
+ /// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
+ /// O.W. date/time stamp of DLL bound to (Old BIND)
+ pub time_date_stamp: U32Bytes<LE>,
+ /// -1 if no forwarders
+ pub forwarder_chain: U32Bytes<LE>,
+ pub name: U32Bytes<LE>,
+ /// RVA to IAT (if bound this IAT has actual addresses)
+ pub first_thunk: U32Bytes<LE>,
+}
+
+impl ImageImportDescriptor {
+ /// Tell whether this import descriptor is the null descriptor
+ /// (used to mark the end of the iterator array in a PE)
+ pub fn is_null(&self) -> bool {
+ self.original_first_thunk.get(LE) == 0
+ && self.time_date_stamp.get(LE) == 0
+ && self.forwarder_chain.get(LE) == 0
+ && self.name.get(LE) == 0
+ && self.first_thunk.get(LE) == 0
+ }
+}
+
+//
+// New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ]
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageBoundImportDescriptor {
+ pub time_date_stamp: U32<LE>,
+ pub offset_module_name: U16<LE>,
+ pub number_of_module_forwarder_refs: U16<LE>,
+ // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageBoundForwarderRef {
+ pub time_date_stamp: U32<LE>,
+ pub offset_module_name: U16<LE>,
+ pub reserved: U16<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDelayloadDescriptor {
+ pub attributes: U32<LE>,
+
+ /// RVA to the name of the target library (NULL-terminate ASCII string)
+ pub dll_name_rva: U32<LE>,
+ /// RVA to the HMODULE caching location (PHMODULE)
+ pub module_handle_rva: U32<LE>,
+ /// RVA to the start of the IAT (PIMAGE_THUNK_DATA)
+ pub import_address_table_rva: U32<LE>,
+ /// RVA to the start of the name table (PIMAGE_THUNK_DATA::AddressOfData)
+ pub import_name_table_rva: U32<LE>,
+ /// RVA to an optional bound IAT
+ pub bound_import_address_table_rva: U32<LE>,
+ /// RVA to an optional unload info table
+ pub unload_information_table_rva: U32<LE>,
+ /// 0 if not bound, otherwise, date/time of the target DLL
+ pub time_date_stamp: U32<LE>,
+}
+
+impl ImageDelayloadDescriptor {
+ /// Tell whether this delay-load import descriptor is the null descriptor
+ /// (used to mark the end of the iterator array in a PE)
+ pub fn is_null(&self) -> bool {
+ self.attributes.get(LE) == 0
+ && self.dll_name_rva.get(LE) == 0
+ && self.module_handle_rva.get(LE) == 0
+ && self.import_address_table_rva.get(LE) == 0
+ && self.import_name_table_rva.get(LE) == 0
+ && self.bound_import_address_table_rva.get(LE) == 0
+ && self.unload_information_table_rva.get(LE) == 0
+ && self.time_date_stamp.get(LE) == 0
+ }
+}
+
+/// Delay load version 2 flag for `ImageDelayloadDescriptor::attributes`.
+pub const IMAGE_DELAYLOAD_RVA_BASED: u32 = 0x8000_0000;
+
+//
+// Resource Format.
+//
+
+//
+// Resource directory consists of two counts, following by a variable length
+// array of directory entries. The first count is the number of entries at
+// beginning of the array that have actual names associated with each entry.
+// The entries are in ascending order, case insensitive strings. The second
+// count is the number of entries that immediately follow the named entries.
+// This second count identifies the number of entries that have 16-bit integer
+// Ids as their name. These entries are also sorted in ascending order.
+//
+// This structure allows fast lookup by either name or number, but for any
+// given resource entry only one form of lookup is supported, not both.
+// This is consistent with the syntax of the .RC file and the .RES file.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageResourceDirectory {
+ pub characteristics: U32<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub major_version: U16<LE>,
+ pub minor_version: U16<LE>,
+ pub number_of_named_entries: U16<LE>,
+ pub number_of_id_entries: U16<LE>,
+}
+
+pub const IMAGE_RESOURCE_NAME_IS_STRING: u32 = 0x8000_0000;
+pub const IMAGE_RESOURCE_DATA_IS_DIRECTORY: u32 = 0x8000_0000;
+//
+// Each directory contains the 32-bit Name of the entry and an offset,
+// relative to the beginning of the resource directory of the data associated
+// with this directory entry. If the name of the entry is an actual text
+// string instead of an integer Id, then the high order bit of the name field
+// is set to one and the low order 31-bits are an offset, relative to the
+// beginning of the resource directory of the string, which is of type
+// IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the
+// low-order 16-bits are the integer Id that identify this resource directory
+// entry. If the directory entry is yet another resource directory (i.e. a
+// subdirectory), then the high order bit of the offset field will be
+// set to indicate this. Otherwise the high bit is clear and the offset
+// field points to a resource data entry.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageResourceDirectoryEntry {
+ pub name_or_id: U32<LE>,
+ pub offset_to_data_or_directory: U32<LE>,
+}
+
+//
+// For resource directory entries that have actual string names, the Name
+// field of the directory entry points to an object of the following type.
+// All of these string objects are stored together after the last resource
+// directory entry and before the first resource data object. This minimizes
+// the impact of these variable length objects on the alignment of the fixed
+// size directory entry objects.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageResourceDirectoryString {
+ pub length: U16<LE>,
+ //pub name_string: [i8; 1],
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageResourceDirStringU {
+ pub length: U16<LE>,
+ //pub name_string: [U16<LE>; 1],
+}
+
+//
+// Each resource data entry describes a leaf node in the resource directory
+// tree. It contains an offset, relative to the beginning of the resource
+// directory of the data for the resource, a size field that gives the number
+// of bytes of data at that offset, a CodePage that should be used when
+// decoding code point values within the resource data. Typically for new
+// applications the code page would be the unicode code page.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageResourceDataEntry {
+ /// RVA of the data.
+ pub offset_to_data: U32<LE>,
+ pub size: U32<LE>,
+ pub code_page: U32<LE>,
+ pub reserved: U32<LE>,
+}
+
+// Resource type: https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types
+
+/// ID for: Hardware-dependent cursor resource.
+pub const RT_CURSOR: u16 = 1;
+/// ID for: Bitmap resource.
+pub const RT_BITMAP: u16 = 2;
+/// ID for: Hardware-dependent icon resource.
+pub const RT_ICON: u16 = 3;
+/// ID for: Menu resource.
+pub const RT_MENU: u16 = 4;
+/// ID for: Dialog box.
+pub const RT_DIALOG: u16 = 5;
+/// ID for: String-table entry.
+pub const RT_STRING: u16 = 6;
+/// ID for: Font directory resource.
+pub const RT_FONTDIR: u16 = 7;
+/// ID for: Font resource.
+pub const RT_FONT: u16 = 8;
+/// ID for: Accelerator table.
+pub const RT_ACCELERATOR: u16 = 9;
+/// ID for: Application-defined resource (raw data).
+pub const RT_RCDATA: u16 = 10;
+/// ID for: Message-table entry.
+pub const RT_MESSAGETABLE: u16 = 11;
+/// ID for: Hardware-independent cursor resource.
+pub const RT_GROUP_CURSOR: u16 = 12;
+/// ID for: Hardware-independent icon resource.
+pub const RT_GROUP_ICON: u16 = 14;
+/// ID for: Version resource.
+pub const RT_VERSION: u16 = 16;
+/// ID for: Allows a resource editing tool to associate a string with an .rc file.
+pub const RT_DLGINCLUDE: u16 = 17;
+/// ID for: Plug and Play resource.
+pub const RT_PLUGPLAY: u16 = 19;
+/// ID for: VXD.
+pub const RT_VXD: u16 = 20;
+/// ID for: Animated cursor.
+pub const RT_ANICURSOR: u16 = 21;
+/// ID for: Animated icon.
+pub const RT_ANIICON: u16 = 22;
+/// ID for: HTML resource.
+pub const RT_HTML: u16 = 23;
+/// ID for: Side-by-Side Assembly Manifest.
+pub const RT_MANIFEST: u16 = 24;
+
+//
+// Code Integrity in loadconfig (CI)
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageLoadConfigCodeIntegrity {
+ /// Flags to indicate if CI information is available, etc.
+ pub flags: U16<LE>,
+ /// 0xFFFF means not available
+ pub catalog: U16<LE>,
+ pub catalog_offset: U32<LE>,
+ /// Additional bitmask to be defined later
+ pub reserved: U32<LE>,
+}
+
+//
+// Dynamic value relocation table in loadconfig
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDynamicRelocationTable {
+ pub version: U32<LE>,
+ pub size: U32<LE>,
+ // DynamicRelocations: [ImageDynamicRelocation; 0],
+}
+
+//
+// Dynamic value relocation entries following IMAGE_DYNAMIC_RELOCATION_TABLE
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDynamicRelocation32 {
+ pub symbol: U32<LE>,
+ pub base_reloc_size: U32<LE>,
+ // BaseRelocations: [ImageBaseRelocation; 0],
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDynamicRelocation64 {
+ pub symbol: U64<LE>,
+ pub base_reloc_size: U32<LE>,
+ // BaseRelocations: [ImageBaseRelocation; 0],
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDynamicRelocation32V2 {
+ pub header_size: U32<LE>,
+ pub fixup_info_size: U32<LE>,
+ pub symbol: U32<LE>,
+ pub symbol_group: U32<LE>,
+ pub flags: U32<LE>,
+ // ... variable length header fields
+ // pub fixup_info: [u8; fixup_info_size]
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDynamicRelocation64V2 {
+ pub header_size: U32<LE>,
+ pub fixup_info_size: U32<LE>,
+ pub symbol: U64<LE>,
+ pub symbol_group: U32<LE>,
+ pub flags: U32<LE>,
+ // ... variable length header fields
+ // pub fixup_info[u8; fixup_info_size]
+}
+
+//
+// Defined symbolic dynamic relocation entries.
+//
+
+pub const IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE: u32 = 0x0000_0001;
+pub const IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE: u32 = 0x0000_0002;
+pub const IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER: u32 = 0x0000_0003;
+pub const IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER: u32 = 0x0000_0004;
+pub const IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH: u32 = 0x0000_0005;
+
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImagePrologueDynamicRelocationHeader {
+ pub prologue_byte_count: u8,
+ // pub prologue_bytes: [u8; prologue_byte_count],
+}
+
+// This struct has alignment 1.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageEpilogueDynamicRelocationHeader {
+ pub epilogue_count: U32Bytes<LE>,
+ pub epilogue_byte_count: u8,
+ pub branch_descriptor_element_size: u8,
+ pub branch_descriptor_count: U16Bytes<LE>,
+ // pub branch_descriptors[...],
+ // pub branch_descriptor_bit_map[...],
+}
+
+/*
+// TODO? bitfields
+// TODO: unaligned?
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageImportControlTransferDynamicRelocation {
+ DWORD PageRelativeOffset : 12;
+ DWORD IndirectCall : 1;
+ DWORD IATIndex : 19;
+}
+
+// TODO: unaligned?
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageIndirControlTransferDynamicRelocation {
+ WORD PageRelativeOffset : 12;
+ WORD IndirectCall : 1;
+ WORD RexWPrefix : 1;
+ WORD CfgCheck : 1;
+ WORD Reserved : 1;
+}
+
+// TODO: unaligned?
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageSwitchtableBranchDynamicRelocation {
+ WORD PageRelativeOffset : 12;
+ WORD RegisterNumber : 4;
+}
+*/
+
+//
+// Load Configuration Directory Entry
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageLoadConfigDirectory32 {
+ pub size: U32<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub major_version: U16<LE>,
+ pub minor_version: U16<LE>,
+ pub global_flags_clear: U32<LE>,
+ pub global_flags_set: U32<LE>,
+ pub critical_section_default_timeout: U32<LE>,
+ pub de_commit_free_block_threshold: U32<LE>,
+ pub de_commit_total_free_threshold: U32<LE>,
+ /// VA
+ pub lock_prefix_table: U32<LE>,
+ pub maximum_allocation_size: U32<LE>,
+ pub virtual_memory_threshold: U32<LE>,
+ pub process_heap_flags: U32<LE>,
+ pub process_affinity_mask: U32<LE>,
+ pub csd_version: U16<LE>,
+ pub dependent_load_flags: U16<LE>,
+ /// VA
+ pub edit_list: U32<LE>,
+ /// VA
+ pub security_cookie: U32<LE>,
+ /// VA
+ pub sehandler_table: U32<LE>,
+ pub sehandler_count: U32<LE>,
+ /// VA
+ pub guard_cf_check_function_pointer: U32<LE>,
+ /// VA
+ pub guard_cf_dispatch_function_pointer: U32<LE>,
+ /// VA
+ pub guard_cf_function_table: U32<LE>,
+ pub guard_cf_function_count: U32<LE>,
+ pub guard_flags: U32<LE>,
+ pub code_integrity: ImageLoadConfigCodeIntegrity,
+ /// VA
+ pub guard_address_taken_iat_entry_table: U32<LE>,
+ pub guard_address_taken_iat_entry_count: U32<LE>,
+ /// VA
+ pub guard_long_jump_target_table: U32<LE>,
+ pub guard_long_jump_target_count: U32<LE>,
+ /// VA
+ pub dynamic_value_reloc_table: U32<LE>,
+ pub chpe_metadata_pointer: U32<LE>,
+ /// VA
+ pub guard_rf_failure_routine: U32<LE>,
+ /// VA
+ pub guard_rf_failure_routine_function_pointer: U32<LE>,
+ pub dynamic_value_reloc_table_offset: U32<LE>,
+ pub dynamic_value_reloc_table_section: U16<LE>,
+ pub reserved2: U16<LE>,
+ /// VA
+ pub guard_rf_verify_stack_pointer_function_pointer: U32<LE>,
+ pub hot_patch_table_offset: U32<LE>,
+ pub reserved3: U32<LE>,
+ /// VA
+ pub enclave_configuration_pointer: U32<LE>,
+ /// VA
+ pub volatile_metadata_pointer: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageLoadConfigDirectory64 {
+ pub size: U32<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub major_version: U16<LE>,
+ pub minor_version: U16<LE>,
+ pub global_flags_clear: U32<LE>,
+ pub global_flags_set: U32<LE>,
+ pub critical_section_default_timeout: U32<LE>,
+ pub de_commit_free_block_threshold: U64<LE>,
+ pub de_commit_total_free_threshold: U64<LE>,
+ /// VA
+ pub lock_prefix_table: U64<LE>,
+ pub maximum_allocation_size: U64<LE>,
+ pub virtual_memory_threshold: U64<LE>,
+ pub process_affinity_mask: U64<LE>,
+ pub process_heap_flags: U32<LE>,
+ pub csd_version: U16<LE>,
+ pub dependent_load_flags: U16<LE>,
+ /// VA
+ pub edit_list: U64<LE>,
+ /// VA
+ pub security_cookie: U64<LE>,
+ /// VA
+ pub sehandler_table: U64<LE>,
+ pub sehandler_count: U64<LE>,
+ /// VA
+ pub guard_cf_check_function_pointer: U64<LE>,
+ /// VA
+ pub guard_cf_dispatch_function_pointer: U64<LE>,
+ /// VA
+ pub guard_cf_function_table: U64<LE>,
+ pub guard_cf_function_count: U64<LE>,
+ pub guard_flags: U32<LE>,
+ pub code_integrity: ImageLoadConfigCodeIntegrity,
+ /// VA
+ pub guard_address_taken_iat_entry_table: U64<LE>,
+ pub guard_address_taken_iat_entry_count: U64<LE>,
+ /// VA
+ pub guard_long_jump_target_table: U64<LE>,
+ pub guard_long_jump_target_count: U64<LE>,
+ /// VA
+ pub dynamic_value_reloc_table: U64<LE>,
+ /// VA
+ pub chpe_metadata_pointer: U64<LE>,
+ /// VA
+ pub guard_rf_failure_routine: U64<LE>,
+ /// VA
+ pub guard_rf_failure_routine_function_pointer: U64<LE>,
+ pub dynamic_value_reloc_table_offset: U32<LE>,
+ pub dynamic_value_reloc_table_section: U16<LE>,
+ pub reserved2: U16<LE>,
+ /// VA
+ pub guard_rf_verify_stack_pointer_function_pointer: U64<LE>,
+ pub hot_patch_table_offset: U32<LE>,
+ pub reserved3: U32<LE>,
+ /// VA
+ pub enclave_configuration_pointer: U64<LE>,
+ /// VA
+ pub volatile_metadata_pointer: U64<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageHotPatchInfo {
+ pub version: U32<LE>,
+ pub size: U32<LE>,
+ pub sequence_number: U32<LE>,
+ pub base_image_list: U32<LE>,
+ pub base_image_count: U32<LE>,
+ /// Version 2 and later
+ pub buffer_offset: U32<LE>,
+ /// Version 3 and later
+ pub extra_patch_size: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageHotPatchBase {
+ pub sequence_number: U32<LE>,
+ pub flags: U32<LE>,
+ pub original_time_date_stamp: U32<LE>,
+ pub original_check_sum: U32<LE>,
+ pub code_integrity_info: U32<LE>,
+ pub code_integrity_size: U32<LE>,
+ pub patch_table: U32<LE>,
+ /// Version 2 and later
+ pub buffer_offset: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageHotPatchHashes {
+ pub sha256: [u8; 32],
+ pub sha1: [u8; 20],
+}
+
+pub const IMAGE_HOT_PATCH_BASE_OBLIGATORY: u32 = 0x0000_0001;
+pub const IMAGE_HOT_PATCH_BASE_CAN_ROLL_BACK: u32 = 0x0000_0002;
+
+pub const IMAGE_HOT_PATCH_CHUNK_INVERSE: u32 = 0x8000_0000;
+pub const IMAGE_HOT_PATCH_CHUNK_OBLIGATORY: u32 = 0x4000_0000;
+pub const IMAGE_HOT_PATCH_CHUNK_RESERVED: u32 = 0x3FF0_3000;
+pub const IMAGE_HOT_PATCH_CHUNK_TYPE: u32 = 0x000F_C000;
+pub const IMAGE_HOT_PATCH_CHUNK_SOURCE_RVA: u32 = 0x0000_8000;
+pub const IMAGE_HOT_PATCH_CHUNK_TARGET_RVA: u32 = 0x0000_4000;
+pub const IMAGE_HOT_PATCH_CHUNK_SIZE: u32 = 0x0000_0FFF;
+
+pub const IMAGE_HOT_PATCH_NONE: u32 = 0x0000_0000;
+pub const IMAGE_HOT_PATCH_FUNCTION: u32 = 0x0001_C000;
+pub const IMAGE_HOT_PATCH_ABSOLUTE: u32 = 0x0002_C000;
+pub const IMAGE_HOT_PATCH_REL32: u32 = 0x0003_C000;
+pub const IMAGE_HOT_PATCH_CALL_TARGET: u32 = 0x0004_4000;
+pub const IMAGE_HOT_PATCH_INDIRECT: u32 = 0x0005_C000;
+pub const IMAGE_HOT_PATCH_NO_CALL_TARGET: u32 = 0x0006_4000;
+pub const IMAGE_HOT_PATCH_DYNAMIC_VALUE: u32 = 0x0007_8000;
+
+/// Module performs control flow integrity checks using system-supplied support
+pub const IMAGE_GUARD_CF_INSTRUMENTED: u32 = 0x0000_0100;
+/// Module performs control flow and write integrity checks
+pub const IMAGE_GUARD_CFW_INSTRUMENTED: u32 = 0x0000_0200;
+/// Module contains valid control flow target metadata
+pub const IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT: u32 = 0x0000_0400;
+/// Module does not make use of the /GS security cookie
+pub const IMAGE_GUARD_SECURITY_COOKIE_UNUSED: u32 = 0x0000_0800;
+/// Module supports read only delay load IAT
+pub const IMAGE_GUARD_PROTECT_DELAYLOAD_IAT: u32 = 0x0000_1000;
+/// Delayload import table in its own .didat section (with nothing else in it) that can be freely reprotected
+pub const IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION: u32 = 0x0000_2000;
+/// Module contains suppressed export information.
+///
+/// This also infers that the address taken taken IAT table is also present in the load config.
+pub const IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT: u32 = 0x0000_4000;
+/// Module enables suppression of exports
+pub const IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION: u32 = 0x0000_8000;
+/// Module contains longjmp target information
+pub const IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT: u32 = 0x0001_0000;
+/// Module contains return flow instrumentation and metadata
+pub const IMAGE_GUARD_RF_INSTRUMENTED: u32 = 0x0002_0000;
+/// Module requests that the OS enable return flow protection
+pub const IMAGE_GUARD_RF_ENABLE: u32 = 0x0004_0000;
+/// Module requests that the OS enable return flow protection in strict mode
+pub const IMAGE_GUARD_RF_STRICT: u32 = 0x0008_0000;
+/// Module was built with retpoline support
+pub const IMAGE_GUARD_RETPOLINE_PRESENT: u32 = 0x0010_0000;
+
+/// Stride of Guard CF function table encoded in these bits (additional count of bytes per element)
+pub const IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK: u32 = 0xF000_0000;
+/// Shift to right-justify Guard CF function table stride
+pub const IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT: u32 = 28;
+
+//
+// GFIDS table entry flags.
+//
+
+/// The containing GFID entry is suppressed
+pub const IMAGE_GUARD_FLAG_FID_SUPPRESSED: u16 = 0x01;
+/// The containing GFID entry is export suppressed
+pub const IMAGE_GUARD_FLAG_EXPORT_SUPPRESSED: u16 = 0x02;
+
+//
+// WIN CE Exception table format
+//
+
+//
+// Function table entry format. Function table is pointed to by the
+// IMAGE_DIRECTORY_ENTRY_EXCEPTION directory entry.
+//
+
+/*
+// TODO? bitfields
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageCeRuntimeFunctionEntry {
+ pub func_start: U32<LE>,
+ DWORD PrologLen : 8;
+ DWORD FuncLen : 22;
+ DWORD ThirtyTwoBit : 1;
+ DWORD ExceptionFlag : 1;
+}
+*/
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageArmRuntimeFunctionEntry {
+ pub begin_address: U32<LE>,
+ pub unwind_data: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageArm64RuntimeFunctionEntry {
+ pub begin_address: U32<LE>,
+ pub unwind_data: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAlpha64RuntimeFunctionEntry {
+ pub begin_address: U64<LE>,
+ pub end_address: U64<LE>,
+ pub exception_handler: U64<LE>,
+ pub handler_data: U64<LE>,
+ pub prolog_end_address: U64<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageAlphaRuntimeFunctionEntry {
+ pub begin_address: U32<LE>,
+ pub end_address: U32<LE>,
+ pub exception_handler: U32<LE>,
+ pub handler_data: U32<LE>,
+ pub prolog_end_address: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageRuntimeFunctionEntry {
+ pub begin_address: U32<LE>,
+ pub end_address: U32<LE>,
+ pub unwind_info_address_or_data: U32<LE>,
+}
+
+//
+// Software enclave information
+//
+
+pub const IMAGE_ENCLAVE_LONG_ID_LENGTH: usize = 32;
+pub const IMAGE_ENCLAVE_SHORT_ID_LENGTH: usize = 16;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageEnclaveConfig32 {
+ pub size: U32<LE>,
+ pub minimum_required_config_size: U32<LE>,
+ pub policy_flags: U32<LE>,
+ pub number_of_imports: U32<LE>,
+ pub import_list: U32<LE>,
+ pub import_entry_size: U32<LE>,
+ pub family_id: [u8; IMAGE_ENCLAVE_SHORT_ID_LENGTH],
+ pub image_id: [u8; IMAGE_ENCLAVE_SHORT_ID_LENGTH],
+ pub image_version: U32<LE>,
+ pub security_version: U32<LE>,
+ pub enclave_size: U32<LE>,
+ pub number_of_threads: U32<LE>,
+ pub enclave_flags: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageEnclaveConfig64 {
+ pub size: U32<LE>,
+ pub minimum_required_config_size: U32<LE>,
+ pub policy_flags: U32<LE>,
+ pub number_of_imports: U32<LE>,
+ pub import_list: U32<LE>,
+ pub import_entry_size: U32<LE>,
+ pub family_id: [u8; IMAGE_ENCLAVE_SHORT_ID_LENGTH],
+ pub image_id: [u8; IMAGE_ENCLAVE_SHORT_ID_LENGTH],
+ pub image_version: U32<LE>,
+ pub security_version: U32<LE>,
+ pub enclave_size: U64<LE>,
+ pub number_of_threads: U32<LE>,
+ pub enclave_flags: U32<LE>,
+}
+
+//pub const IMAGE_ENCLAVE_MINIMUM_CONFIG_SIZE: usize = FIELD_OFFSET(IMAGE_ENCLAVE_CONFIG, EnclaveFlags);
+
+pub const IMAGE_ENCLAVE_POLICY_DEBUGGABLE: u32 = 0x0000_0001;
+
+pub const IMAGE_ENCLAVE_FLAG_PRIMARY_IMAGE: u32 = 0x0000_0001;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageEnclaveImport {
+ pub match_type: U32<LE>,
+ pub minimum_security_version: U32<LE>,
+ pub unique_or_author_id: [u8; IMAGE_ENCLAVE_LONG_ID_LENGTH],
+ pub family_id: [u8; IMAGE_ENCLAVE_SHORT_ID_LENGTH],
+ pub image_id: [u8; IMAGE_ENCLAVE_SHORT_ID_LENGTH],
+ pub import_name: U32<LE>,
+ pub reserved: U32<LE>,
+}
+
+pub const IMAGE_ENCLAVE_IMPORT_MATCH_NONE: u32 = 0x0000_0000;
+pub const IMAGE_ENCLAVE_IMPORT_MATCH_UNIQUE_ID: u32 = 0x0000_0001;
+pub const IMAGE_ENCLAVE_IMPORT_MATCH_AUTHOR_ID: u32 = 0x0000_0002;
+pub const IMAGE_ENCLAVE_IMPORT_MATCH_FAMILY_ID: u32 = 0x0000_0003;
+pub const IMAGE_ENCLAVE_IMPORT_MATCH_IMAGE_ID: u32 = 0x0000_0004;
+
+//
+// Debug Format
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDebugDirectory {
+ pub characteristics: U32<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub major_version: U16<LE>,
+ pub minor_version: U16<LE>,
+ pub typ: U32<LE>,
+ pub size_of_data: U32<LE>,
+ pub address_of_raw_data: U32<LE>,
+ pub pointer_to_raw_data: U32<LE>,
+}
+
+pub const IMAGE_DEBUG_TYPE_UNKNOWN: u32 = 0;
+pub const IMAGE_DEBUG_TYPE_COFF: u32 = 1;
+pub const IMAGE_DEBUG_TYPE_CODEVIEW: u32 = 2;
+pub const IMAGE_DEBUG_TYPE_FPO: u32 = 3;
+pub const IMAGE_DEBUG_TYPE_MISC: u32 = 4;
+pub const IMAGE_DEBUG_TYPE_EXCEPTION: u32 = 5;
+pub const IMAGE_DEBUG_TYPE_FIXUP: u32 = 6;
+pub const IMAGE_DEBUG_TYPE_OMAP_TO_SRC: u32 = 7;
+pub const IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: u32 = 8;
+pub const IMAGE_DEBUG_TYPE_BORLAND: u32 = 9;
+pub const IMAGE_DEBUG_TYPE_RESERVED10: u32 = 10;
+pub const IMAGE_DEBUG_TYPE_CLSID: u32 = 11;
+pub const IMAGE_DEBUG_TYPE_VC_FEATURE: u32 = 12;
+pub const IMAGE_DEBUG_TYPE_POGO: u32 = 13;
+pub const IMAGE_DEBUG_TYPE_ILTCG: u32 = 14;
+pub const IMAGE_DEBUG_TYPE_MPX: u32 = 15;
+pub const IMAGE_DEBUG_TYPE_REPRO: u32 = 16;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageCoffSymbolsHeader {
+ pub number_of_symbols: U32<LE>,
+ pub lva_to_first_symbol: U32<LE>,
+ pub number_of_linenumbers: U32<LE>,
+ pub lva_to_first_linenumber: U32<LE>,
+ pub rva_to_first_byte_of_code: U32<LE>,
+ pub rva_to_last_byte_of_code: U32<LE>,
+ pub rva_to_first_byte_of_data: U32<LE>,
+ pub rva_to_last_byte_of_data: U32<LE>,
+}
+
+pub const FRAME_FPO: u16 = 0;
+pub const FRAME_TRAP: u16 = 1;
+pub const FRAME_TSS: u16 = 2;
+pub const FRAME_NONFPO: u16 = 3;
+
+/*
+// TODO? bitfields
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FpoData {
+/// offset 1st byte of function code
+ pub ul_off_start: U32<LE>,
+/// # bytes in function
+ pub cb_proc_size: U32<LE>,
+/// # bytes in locals/4
+ pub cdw_locals: U32<LE>,
+/// # bytes in params/4
+ pub cdw_params: U16<LE>,
+/// # bytes in prolog
+ WORD cbProlog : 8;
+/// # regs saved
+ WORD cbRegs : 3;
+/// TRUE if SEH in func
+ WORD fHasSEH : 1;
+/// TRUE if EBP has been allocated
+ WORD fUseBP : 1;
+/// reserved for future use
+ WORD reserved : 1;
+/// frame type
+ WORD cbFrame : 2;
+}
+pub const SIZEOF_RFPO_DATA: usize = 16;
+*/
+
+pub const IMAGE_DEBUG_MISC_EXENAME: u16 = 1;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageDebugMisc {
+ /// type of misc data, see defines
+ pub data_type: U32<LE>,
+ /// total length of record, rounded to four byte multiple.
+ pub length: U32<LE>,
+ /// TRUE if data is unicode string
+ pub unicode: u8,
+ pub reserved: [u8; 3],
+ // Actual data
+ //pub data: [u8; 1],
+}
+
+//
+// Function table extracted from MIPS/ALPHA/IA64 images. Does not contain
+// information needed only for runtime support. Just those fields for
+// each entry needed by a debugger.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageFunctionEntry {
+ pub starting_address: U32<LE>,
+ pub ending_address: U32<LE>,
+ pub end_of_prologue: U32<LE>,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageFunctionEntry64 {
+ pub starting_address: U64<LE>,
+ pub ending_address: U64<LE>,
+ pub end_of_prologue_or_unwind_info_address: U64<LE>,
+}
+
+//
+// Debugging information can be stripped from an image file and placed
+// in a separate .DBG file, whose file name part is the same as the
+// image file name part (e.g. symbols for CMD.EXE could be stripped
+// and placed in CMD.DBG). This is indicated by the IMAGE_FILE_DEBUG_STRIPPED
+// flag in the Characteristics field of the file header. The beginning of
+// the .DBG file contains the following structure which captures certain
+// information from the image file. This allows a debug to proceed even if
+// the original image file is not accessible. This header is followed by
+// zero of more IMAGE_SECTION_HEADER structures, followed by zero or more
+// IMAGE_DEBUG_DIRECTORY structures. The latter structures and those in
+// the image file contain file offsets relative to the beginning of the
+// .DBG file.
+//
+// If symbols have been stripped from an image, the IMAGE_DEBUG_MISC structure
+// is left in the image file, but not mapped. This allows a debugger to
+// compute the name of the .DBG file, from the name of the image in the
+// IMAGE_DEBUG_MISC structure.
+//
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageSeparateDebugHeader {
+ pub signature: U16<LE>,
+ pub flags: U16<LE>,
+ pub machine: U16<LE>,
+ pub characteristics: U16<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub check_sum: U32<LE>,
+ pub image_base: U32<LE>,
+ pub size_of_image: U32<LE>,
+ pub number_of_sections: U32<LE>,
+ pub exported_names_size: U32<LE>,
+ pub debug_directory_size: U32<LE>,
+ pub section_alignment: U32<LE>,
+ pub reserved: [U32<LE>; 2],
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct NonPagedDebugInfo {
+ pub signature: U16<LE>,
+ pub flags: U16<LE>,
+ pub size: U32<LE>,
+ pub machine: U16<LE>,
+ pub characteristics: U16<LE>,
+ pub time_date_stamp: U32<LE>,
+ pub check_sum: U32<LE>,
+ pub size_of_image: U32<LE>,
+ pub image_base: U64<LE>,
+ //debug_directory_size
+ //ImageDebugDirectory
+}
+
+pub const IMAGE_SEPARATE_DEBUG_SIGNATURE: u16 = 0x4944;
+pub const NON_PAGED_DEBUG_SIGNATURE: u16 = 0x494E;
+
+pub const IMAGE_SEPARATE_DEBUG_FLAGS_MASK: u16 = 0x8000;
+/// when DBG was updated, the old checksum didn't match.
+pub const IMAGE_SEPARATE_DEBUG_MISMATCH: u16 = 0x8000;
+
+//
+// The .arch section is made up of headers, each describing an amask position/value
+// pointing to an array of IMAGE_ARCHITECTURE_ENTRY's. Each "array" (both the header
+// and entry arrays) are terminiated by a quadword of 0xffffffffL.
+//
+// NOTE: There may be quadwords of 0 sprinkled around and must be skipped.
+//
+
+/*
+// TODO? bitfields
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageArchitectureHeader {
+ /// 1 -> code section depends on mask bit
+ /// 0 -> new instruction depends on mask bit
+ unsigned int AmaskValue: 1;
+ /// MBZ
+ int :7;
+ /// Amask bit in question for this fixup
+ unsigned int AmaskShift: 8;
+ /// MBZ
+ int :16;
+ /// RVA into .arch section to array of ARCHITECTURE_ENTRY's
+ pub first_entry_rva: U32<LE>,
+}
+*/
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageArchitectureEntry {
+ /// RVA of instruction to fixup
+ pub fixup_inst_rva: U32<LE>,
+ /// fixup instruction (see alphaops.h)
+ pub new_inst: U32<LE>,
+}
+
+// The following structure defines the new import object. Note the values of the first two fields,
+// which must be set as stated in order to differentiate old and new import members.
+// Following this structure, the linker emits two null-terminated strings used to recreate the
+// import at the time of use. The first string is the import's name, the second is the dll's name.
+
+pub const IMPORT_OBJECT_HDR_SIG2: u16 = 0xffff;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImportObjectHeader {
+ /// Must be IMAGE_FILE_MACHINE_UNKNOWN
+ pub sig1: U16<LE>,
+ /// Must be IMPORT_OBJECT_HDR_SIG2.
+ pub sig2: U16<LE>,
+ pub version: U16<LE>,
+ pub machine: U16<LE>,
+ /// Time/date stamp
+ pub time_date_stamp: U32<LE>,
+ /// particularly useful for incremental links
+ pub size_of_data: U32<LE>,
+
+ /// if grf & IMPORT_OBJECT_ORDINAL
+ pub ordinal_or_hint: U16<LE>,
+
+ // WORD Type : 2;
+ // WORD NameType : 3;
+ // WORD Reserved : 11;
+ pub name_type: U16<LE>,
+}
+
+pub const IMPORT_OBJECT_TYPE_MASK: u16 = 0b11;
+pub const IMPORT_OBJECT_TYPE_SHIFT: u16 = 0;
+pub const IMPORT_OBJECT_CODE: u16 = 0;
+pub const IMPORT_OBJECT_DATA: u16 = 1;
+pub const IMPORT_OBJECT_CONST: u16 = 2;
+
+pub const IMPORT_OBJECT_NAME_MASK: u16 = 0b111;
+pub const IMPORT_OBJECT_NAME_SHIFT: u16 = 2;
+/// Import by ordinal
+pub const IMPORT_OBJECT_ORDINAL: u16 = 0;
+/// Import name == public symbol name.
+pub const IMPORT_OBJECT_NAME: u16 = 1;
+/// Import name == public symbol name skipping leading ?, @, or optionally _.
+pub const IMPORT_OBJECT_NAME_NO_PREFIX: u16 = 2;
+/// Import name == public symbol name skipping leading ?, @, or optionally _ and truncating at first @.
+pub const IMPORT_OBJECT_NAME_UNDECORATE: u16 = 3;
+/// Import name == a name is explicitly provided after the DLL name.
+pub const IMPORT_OBJECT_NAME_EXPORTAS: u16 = 4;
+
+// COM+ Header entry point flags.
+pub const COMIMAGE_FLAGS_ILONLY: u32 = 0x0000_0001;
+pub const COMIMAGE_FLAGS_32BITREQUIRED: u32 = 0x0000_0002;
+pub const COMIMAGE_FLAGS_IL_LIBRARY: u32 = 0x0000_0004;
+pub const COMIMAGE_FLAGS_STRONGNAMESIGNED: u32 = 0x0000_0008;
+pub const COMIMAGE_FLAGS_NATIVE_ENTRYPOINT: u32 = 0x0000_0010;
+pub const COMIMAGE_FLAGS_TRACKDEBUGDATA: u32 = 0x0001_0000;
+pub const COMIMAGE_FLAGS_32BITPREFERRED: u32 = 0x0002_0000;
+
+// Version flags for image.
+pub const COR_VERSION_MAJOR_V2: u16 = 2;
+pub const COR_VERSION_MAJOR: u16 = COR_VERSION_MAJOR_V2;
+pub const COR_VERSION_MINOR: u16 = 5;
+pub const COR_DELETED_NAME_LENGTH: usize = 8;
+pub const COR_VTABLEGAP_NAME_LENGTH: usize = 8;
+
+// Maximum size of a NativeType descriptor.
+pub const NATIVE_TYPE_MAX_CB: u16 = 1;
+pub const COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE: u16 = 0xFF;
+
+// Consts for the MIH FLAGS
+pub const IMAGE_COR_MIH_METHODRVA: u16 = 0x01;
+pub const IMAGE_COR_MIH_EHRVA: u16 = 0x02;
+pub const IMAGE_COR_MIH_BASICBLOCK: u16 = 0x08;
+
+// V-table constants
+/// V-table slots are 32-bits in size.
+pub const COR_VTABLE_32BIT: u16 = 0x01;
+/// V-table slots are 64-bits in size.
+pub const COR_VTABLE_64BIT: u16 = 0x02;
+/// If set, transition from unmanaged.
+pub const COR_VTABLE_FROM_UNMANAGED: u16 = 0x04;
+/// If set, transition from unmanaged with keeping the current appdomain.
+pub const COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN: u16 = 0x08;
+/// Call most derived method described by
+pub const COR_VTABLE_CALL_MOST_DERIVED: u16 = 0x10;
+
+// EATJ constants
+/// Size of a jump thunk reserved range.
+pub const IMAGE_COR_EATJ_THUNK_SIZE: usize = 32;
+
+// Max name lengths
+pub const MAX_CLASS_NAME: usize = 1024;
+pub const MAX_PACKAGE_NAME: usize = 1024;
+
+// CLR 2.0 header structure.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ImageCor20Header {
+ // Header versioning
+ pub cb: U32<LE>,
+ pub major_runtime_version: U16<LE>,
+ pub minor_runtime_version: U16<LE>,
+
+ // Symbol table and startup information
+ pub meta_data: ImageDataDirectory,
+ pub flags: U32<LE>,
+
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint.
+ pub entry_point_token_or_rva: U32<LE>,
+
+ // Binding information
+ pub resources: ImageDataDirectory,
+ pub strong_name_signature: ImageDataDirectory,
+
+ // Regular fixup and binding information
+ pub code_manager_table: ImageDataDirectory,
+ pub vtable_fixups: ImageDataDirectory,
+ pub export_address_table_jumps: ImageDataDirectory,
+
+ // Precompiled image info (internal use only - set to zero)
+ pub managed_native_header: ImageDataDirectory,
+}
+
+unsafe_impl_pod!(
+ ImageDosHeader,
+ ImageOs2Header,
+ ImageVxdHeader,
+ ImageFileHeader,
+ ImageDataDirectory,
+ ImageOptionalHeader32,
+ ImageRomOptionalHeader,
+ ImageOptionalHeader64,
+ ImageNtHeaders64,
+ ImageNtHeaders32,
+ ImageRomHeaders,
+ Guid,
+ AnonObjectHeader,
+ AnonObjectHeaderV2,
+ AnonObjectHeaderBigobj,
+ ImageSectionHeader,
+ ImageSymbol,
+ ImageSymbolBytes,
+ ImageSymbolEx,
+ ImageSymbolExBytes,
+ ImageAuxSymbolTokenDef,
+ ImageAuxSymbolFunction,
+ ImageAuxSymbolFunctionBeginEnd,
+ ImageAuxSymbolWeak,
+ ImageAuxSymbolSection,
+ ImageAuxSymbolCrc,
+ ImageRelocation,
+ ImageLinenumber,
+ ImageBaseRelocation,
+ ImageArchiveMemberHeader,
+ ImageExportDirectory,
+ ImageImportByName,
+ ImageThunkData64,
+ ImageThunkData32,
+ ImageTlsDirectory64,
+ ImageTlsDirectory32,
+ ImageImportDescriptor,
+ ImageBoundImportDescriptor,
+ ImageBoundForwarderRef,
+ ImageDelayloadDescriptor,
+ ImageResourceDirectory,
+ ImageResourceDirectoryEntry,
+ ImageResourceDirectoryString,
+ ImageResourceDirStringU,
+ ImageResourceDataEntry,
+ ImageLoadConfigCodeIntegrity,
+ ImageDynamicRelocationTable,
+ ImageDynamicRelocation32,
+ ImageDynamicRelocation64,
+ ImageDynamicRelocation32V2,
+ ImageDynamicRelocation64V2,
+ ImagePrologueDynamicRelocationHeader,
+ ImageEpilogueDynamicRelocationHeader,
+ //ImageImportControlTransferDynamicRelocation,
+ //ImageIndirControlTransferDynamicRelocation,
+ //ImageSwitchtableBranchDynamicRelocation,
+ ImageLoadConfigDirectory32,
+ ImageLoadConfigDirectory64,
+ ImageHotPatchInfo,
+ ImageHotPatchBase,
+ ImageHotPatchHashes,
+ //ImageCeRuntimeFunctionEntry,
+ ImageArmRuntimeFunctionEntry,
+ ImageArm64RuntimeFunctionEntry,
+ ImageAlpha64RuntimeFunctionEntry,
+ ImageAlphaRuntimeFunctionEntry,
+ ImageRuntimeFunctionEntry,
+ ImageEnclaveConfig32,
+ ImageEnclaveConfig64,
+ ImageEnclaveImport,
+ ImageDebugDirectory,
+ ImageCoffSymbolsHeader,
+ //FpoData,
+ ImageDebugMisc,
+ ImageFunctionEntry,
+ ImageFunctionEntry64,
+ ImageSeparateDebugHeader,
+ NonPagedDebugInfo,
+ //ImageArchitectureHeader,
+ ImageArchitectureEntry,
+ ImportObjectHeader,
+ ImageCor20Header,
+ MaskedRichHeaderEntry,
+);
diff --git a/third_party/rust/object/src/pod.rs b/third_party/rust/object/src/pod.rs
new file mode 100644
index 0000000000..8ee78164f5
--- /dev/null
+++ b/third_party/rust/object/src/pod.rs
@@ -0,0 +1,239 @@
+//! Tools for converting file format structures to and from bytes.
+//!
+//! This module should be replaced once rust provides safe transmutes.
+
+// This module provides functions for both read and write features.
+#![cfg_attr(
+ not(all(feature = "read_core", feature = "write_core")),
+ allow(dead_code)
+)]
+
+use core::{mem, result, slice};
+
+type Result<T> = result::Result<T, ()>;
+
+/// A trait for types that can safely be converted from and to byte slices.
+///
+/// # Safety
+/// A type that is `Pod` must:
+/// - be `#[repr(C)]` or `#[repr(transparent)]`
+/// - have no invalid byte values
+/// - have no padding
+pub unsafe trait Pod: Copy + 'static {}
+
+/// Cast a byte slice to a `Pod` type.
+///
+/// Returns the type and the tail of the slice.
+#[inline]
+pub fn from_bytes<T: Pod>(data: &[u8]) -> Result<(&T, &[u8])> {
+ let size = mem::size_of::<T>();
+ let tail = data.get(size..).ok_or(())?;
+ let ptr = data.as_ptr();
+ if (ptr as usize) % mem::align_of::<T>() != 0 {
+ return Err(());
+ }
+ // Safety:
+ // The alignment and size are checked by this function.
+ // The Pod trait ensures the type is valid to cast from bytes.
+ let val = unsafe { &*ptr.cast() };
+ Ok((val, tail))
+}
+
+/// Cast a mutable byte slice to a `Pod` type.
+///
+/// Returns the type and the tail of the slice.
+#[inline]
+pub fn from_bytes_mut<T: Pod>(data: &mut [u8]) -> Result<(&mut T, &mut [u8])> {
+ let size = mem::size_of::<T>();
+ if size > data.len() {
+ return Err(());
+ }
+ let (data, tail) = data.split_at_mut(size);
+ let ptr = data.as_mut_ptr();
+ if (ptr as usize) % mem::align_of::<T>() != 0 {
+ return Err(());
+ }
+ // Safety:
+ // The alignment and size are checked by this function.
+ // The Pod trait ensures the type is valid to cast from bytes.
+ let val = unsafe { &mut *ptr.cast() };
+ Ok((val, tail))
+}
+
+/// Cast a byte slice to a slice of a `Pod` type.
+///
+/// Returns the type slice and the tail of the byte slice.
+#[inline]
+pub fn slice_from_bytes<T: Pod>(data: &[u8], count: usize) -> Result<(&[T], &[u8])> {
+ let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?;
+ let tail = data.get(size..).ok_or(())?;
+ let ptr = data.as_ptr();
+ if (ptr as usize) % mem::align_of::<T>() != 0 {
+ return Err(());
+ }
+ // Safety:
+ // The alignment and size are checked by this function.
+ // The Pod trait ensures the type is valid to cast from bytes.
+ let slice = unsafe { slice::from_raw_parts(ptr.cast(), count) };
+ Ok((slice, tail))
+}
+
+/// Cast a mutable byte slice to a slice of a `Pod` type.
+///
+/// Returns the type slice and the tail of the byte slice.
+#[inline]
+pub fn slice_from_bytes_mut<T: Pod>(
+ data: &mut [u8],
+ count: usize,
+) -> Result<(&mut [T], &mut [u8])> {
+ let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?;
+ if size > data.len() {
+ return Err(());
+ }
+ let (data, tail) = data.split_at_mut(size);
+ let ptr = data.as_mut_ptr();
+ if (ptr as usize) % mem::align_of::<T>() != 0 {
+ return Err(());
+ }
+ // Safety:
+ // The alignment and size are checked by this function.
+ // The Pod trait ensures the type is valid to cast from bytes.
+ let slice = unsafe { slice::from_raw_parts_mut(ptr.cast(), count) };
+ Ok((slice, tail))
+}
+
+/// Cast a `Pod` type to a byte slice.
+#[inline]
+pub fn bytes_of<T: Pod>(val: &T) -> &[u8] {
+ let size = mem::size_of::<T>();
+ // Safety:
+ // Any alignment is allowed.
+ // The size is determined in this function.
+ // The Pod trait ensures the type is valid to cast to bytes.
+ unsafe { slice::from_raw_parts(slice::from_ref(val).as_ptr().cast(), size) }
+}
+
+/// Cast a `Pod` type to a mutable byte slice.
+#[inline]
+pub fn bytes_of_mut<T: Pod>(val: &mut T) -> &mut [u8] {
+ let size = mem::size_of::<T>();
+ // Safety:
+ // Any alignment is allowed.
+ // The size is determined in this function.
+ // The Pod trait ensures the type is valid to cast to bytes.
+ unsafe { slice::from_raw_parts_mut(slice::from_mut(val).as_mut_ptr().cast(), size) }
+}
+
+/// Cast a slice of a `Pod` type to a byte slice.
+#[inline]
+pub fn bytes_of_slice<T: Pod>(val: &[T]) -> &[u8] {
+ let size = val.len().wrapping_mul(mem::size_of::<T>());
+ // Safety:
+ // Any alignment is allowed.
+ // The size is determined in this function.
+ // The Pod trait ensures the type is valid to cast to bytes.
+ unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) }
+}
+
+/// Cast a slice of a `Pod` type to a mutable byte slice.
+#[inline]
+pub fn bytes_of_slice_mut<T: Pod>(val: &mut [T]) -> &mut [u8] {
+ let size = val.len().wrapping_mul(mem::size_of::<T>());
+ // Safety:
+ // Any alignment is allowed.
+ // The size is determined in this function.
+ // The Pod trait ensures the type is valid to cast to bytes.
+ unsafe { slice::from_raw_parts_mut(val.as_mut_ptr().cast(), size) }
+}
+
+macro_rules! unsafe_impl_pod {
+ ($($struct_name:ident),+ $(,)?) => {
+ $(
+ unsafe impl Pod for $struct_name { }
+ )+
+ }
+}
+
+unsafe_impl_pod!(u8, u16, u32, u64);
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn single() {
+ let x = u32::to_be(0x0123_4567);
+ let mut x_mut = x;
+ let bytes = bytes_of(&x);
+ let bytes_mut = bytes_of_mut(&mut x_mut);
+ assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67]);
+ assert_eq!(bytes, bytes_mut);
+
+ let x16 = [u16::to_be(0x0123), u16::to_be(0x4567)];
+
+ let (y, tail) = from_bytes::<u32>(bytes).unwrap();
+ let (y_mut, tail_mut) = from_bytes_mut::<u32>(bytes_mut).unwrap();
+ assert_eq!(*y, x);
+ assert_eq!(y, y_mut);
+ assert_eq!(tail, &[]);
+ assert_eq!(tail, tail_mut);
+
+ let (y, tail) = from_bytes::<u16>(bytes).unwrap();
+ let (y_mut, tail_mut) = from_bytes_mut::<u16>(bytes_mut).unwrap();
+ assert_eq!(*y, x16[0]);
+ assert_eq!(y, y_mut);
+ assert_eq!(tail, &bytes[2..]);
+ assert_eq!(tail, tail_mut);
+
+ let (y, tail) = from_bytes::<u16>(&bytes[2..]).unwrap();
+ let (y_mut, tail_mut) = from_bytes_mut::<u16>(&mut bytes_mut[2..]).unwrap();
+ assert_eq!(*y, x16[1]);
+ assert_eq!(y, y_mut);
+ assert_eq!(tail, &[]);
+ assert_eq!(tail, tail_mut);
+
+ assert_eq!(from_bytes::<u16>(&bytes[1..]), Err(()));
+ assert_eq!(from_bytes::<u16>(&bytes[3..]), Err(()));
+ assert_eq!(from_bytes::<u16>(&bytes[4..]), Err(()));
+ assert_eq!(from_bytes_mut::<u16>(&mut bytes_mut[1..]), Err(()));
+ assert_eq!(from_bytes_mut::<u16>(&mut bytes_mut[3..]), Err(()));
+ assert_eq!(from_bytes_mut::<u16>(&mut bytes_mut[4..]), Err(()));
+ }
+
+ #[test]
+ fn slice() {
+ let x = [
+ u16::to_be(0x0123),
+ u16::to_be(0x4567),
+ u16::to_be(0x89ab),
+ u16::to_be(0xcdef),
+ ];
+ let mut x_mut = x;
+
+ let bytes = bytes_of_slice(&x);
+ let bytes_mut = bytes_of_slice_mut(&mut x_mut);
+ assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
+ assert_eq!(bytes, bytes_mut);
+
+ let (y, tail) = slice_from_bytes::<u16>(bytes, 4).unwrap();
+ let (y_mut, tail_mut) = slice_from_bytes_mut::<u16>(bytes_mut, 4).unwrap();
+ assert_eq!(y, x);
+ assert_eq!(y, y_mut);
+ assert_eq!(tail, &[]);
+ assert_eq!(tail, tail_mut);
+
+ let (y, tail) = slice_from_bytes::<u16>(&bytes[2..], 2).unwrap();
+ let (y_mut, tail_mut) = slice_from_bytes::<u16>(&mut bytes_mut[2..], 2).unwrap();
+ assert_eq!(y, &x[1..3]);
+ assert_eq!(y, y_mut);
+ assert_eq!(tail, &bytes[6..]);
+ assert_eq!(tail, tail_mut);
+
+ assert_eq!(slice_from_bytes::<u16>(bytes, 5), Err(()));
+ assert_eq!(slice_from_bytes::<u16>(&bytes[2..], 4), Err(()));
+ assert_eq!(slice_from_bytes::<u16>(&bytes[1..], 2), Err(()));
+ assert_eq!(slice_from_bytes_mut::<u16>(bytes_mut, 5), Err(()));
+ assert_eq!(slice_from_bytes_mut::<u16>(&mut bytes_mut[2..], 4), Err(()));
+ assert_eq!(slice_from_bytes_mut::<u16>(&mut bytes_mut[1..], 2), Err(()));
+ }
+}
diff --git a/third_party/rust/object/src/read/any.rs b/third_party/rust/object/src/read/any.rs
new file mode 100644
index 0000000000..2e147c6727
--- /dev/null
+++ b/third_party/rust/object/src/read/any.rs
@@ -0,0 +1,1314 @@
+use alloc::fmt;
+use alloc::vec::Vec;
+use core::marker::PhantomData;
+
+#[cfg(feature = "coff")]
+use crate::read::coff;
+#[cfg(feature = "elf")]
+use crate::read::elf;
+#[cfg(feature = "macho")]
+use crate::read::macho;
+#[cfg(feature = "pe")]
+use crate::read::pe;
+#[cfg(feature = "wasm")]
+use crate::read::wasm;
+#[cfg(feature = "xcoff")]
+use crate::read::xcoff;
+use crate::read::{
+ self, Architecture, BinaryFormat, CodeView, ComdatKind, CompressedData, CompressedFileRange,
+ Error, Export, FileFlags, FileKind, Import, Object, ObjectComdat, ObjectKind, ObjectMap,
+ ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadRef, Relocation, Result,
+ SectionFlags, SectionIndex, SectionKind, SegmentFlags, SymbolFlags, SymbolIndex, SymbolKind,
+ SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
+};
+#[allow(unused_imports)]
+use crate::{AddressSize, Endian, Endianness};
+
+/// Evaluate an expression on the contents of a file format enum.
+///
+/// This is a hack to avoid virtual calls.
+macro_rules! with_inner {
+ ($inner:expr, $enum:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ #[cfg(feature = "coff")]
+ $enum::Coff(ref $var) => $body,
+ #[cfg(feature = "coff")]
+ $enum::CoffBig(ref $var) => $body,
+ #[cfg(feature = "elf")]
+ $enum::Elf32(ref $var) => $body,
+ #[cfg(feature = "elf")]
+ $enum::Elf64(ref $var) => $body,
+ #[cfg(feature = "macho")]
+ $enum::MachO32(ref $var) => $body,
+ #[cfg(feature = "macho")]
+ $enum::MachO64(ref $var) => $body,
+ #[cfg(feature = "pe")]
+ $enum::Pe32(ref $var) => $body,
+ #[cfg(feature = "pe")]
+ $enum::Pe64(ref $var) => $body,
+ #[cfg(feature = "wasm")]
+ $enum::Wasm(ref $var) => $body,
+ #[cfg(feature = "xcoff")]
+ $enum::Xcoff32(ref $var) => $body,
+ #[cfg(feature = "xcoff")]
+ $enum::Xcoff64(ref $var) => $body,
+ }
+ };
+}
+
+macro_rules! with_inner_mut {
+ ($inner:expr, $enum:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ #[cfg(feature = "coff")]
+ $enum::Coff(ref mut $var) => $body,
+ #[cfg(feature = "coff")]
+ $enum::CoffBig(ref mut $var) => $body,
+ #[cfg(feature = "elf")]
+ $enum::Elf32(ref mut $var) => $body,
+ #[cfg(feature = "elf")]
+ $enum::Elf64(ref mut $var) => $body,
+ #[cfg(feature = "macho")]
+ $enum::MachO32(ref mut $var) => $body,
+ #[cfg(feature = "macho")]
+ $enum::MachO64(ref mut $var) => $body,
+ #[cfg(feature = "pe")]
+ $enum::Pe32(ref mut $var) => $body,
+ #[cfg(feature = "pe")]
+ $enum::Pe64(ref mut $var) => $body,
+ #[cfg(feature = "wasm")]
+ $enum::Wasm(ref mut $var) => $body,
+ #[cfg(feature = "xcoff")]
+ $enum::Xcoff32(ref mut $var) => $body,
+ #[cfg(feature = "xcoff")]
+ $enum::Xcoff64(ref mut $var) => $body,
+ }
+ };
+}
+
+/// Like `with_inner!`, but wraps the result in another enum.
+macro_rules! map_inner {
+ ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ #[cfg(feature = "coff")]
+ $from::Coff(ref $var) => $to::Coff($body),
+ #[cfg(feature = "coff")]
+ $from::CoffBig(ref $var) => $to::CoffBig($body),
+ #[cfg(feature = "elf")]
+ $from::Elf32(ref $var) => $to::Elf32($body),
+ #[cfg(feature = "elf")]
+ $from::Elf64(ref $var) => $to::Elf64($body),
+ #[cfg(feature = "macho")]
+ $from::MachO32(ref $var) => $to::MachO32($body),
+ #[cfg(feature = "macho")]
+ $from::MachO64(ref $var) => $to::MachO64($body),
+ #[cfg(feature = "pe")]
+ $from::Pe32(ref $var) => $to::Pe32($body),
+ #[cfg(feature = "pe")]
+ $from::Pe64(ref $var) => $to::Pe64($body),
+ #[cfg(feature = "wasm")]
+ $from::Wasm(ref $var) => $to::Wasm($body),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff32(ref $var) => $to::Xcoff32($body),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff64(ref $var) => $to::Xcoff64($body),
+ }
+ };
+}
+
+/// Like `map_inner!`, but the result is a Result or Option.
+macro_rules! map_inner_option {
+ ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ #[cfg(feature = "coff")]
+ $from::Coff(ref $var) => $body.map($to::Coff),
+ #[cfg(feature = "coff")]
+ $from::CoffBig(ref $var) => $body.map($to::CoffBig),
+ #[cfg(feature = "elf")]
+ $from::Elf32(ref $var) => $body.map($to::Elf32),
+ #[cfg(feature = "elf")]
+ $from::Elf64(ref $var) => $body.map($to::Elf64),
+ #[cfg(feature = "macho")]
+ $from::MachO32(ref $var) => $body.map($to::MachO32),
+ #[cfg(feature = "macho")]
+ $from::MachO64(ref $var) => $body.map($to::MachO64),
+ #[cfg(feature = "pe")]
+ $from::Pe32(ref $var) => $body.map($to::Pe32),
+ #[cfg(feature = "pe")]
+ $from::Pe64(ref $var) => $body.map($to::Pe64),
+ #[cfg(feature = "wasm")]
+ $from::Wasm(ref $var) => $body.map($to::Wasm),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff32(ref $var) => $body.map($to::Xcoff32),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff64(ref $var) => $body.map($to::Xcoff64),
+ }
+ };
+}
+
+macro_rules! map_inner_option_mut {
+ ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => {
+ match $inner {
+ #[cfg(feature = "coff")]
+ $from::Coff(ref mut $var) => $body.map($to::Coff),
+ #[cfg(feature = "coff")]
+ $from::CoffBig(ref mut $var) => $body.map($to::CoffBig),
+ #[cfg(feature = "elf")]
+ $from::Elf32(ref mut $var) => $body.map($to::Elf32),
+ #[cfg(feature = "elf")]
+ $from::Elf64(ref mut $var) => $body.map($to::Elf64),
+ #[cfg(feature = "macho")]
+ $from::MachO32(ref mut $var) => $body.map($to::MachO32),
+ #[cfg(feature = "macho")]
+ $from::MachO64(ref mut $var) => $body.map($to::MachO64),
+ #[cfg(feature = "pe")]
+ $from::Pe32(ref mut $var) => $body.map($to::Pe32),
+ #[cfg(feature = "pe")]
+ $from::Pe64(ref mut $var) => $body.map($to::Pe64),
+ #[cfg(feature = "wasm")]
+ $from::Wasm(ref mut $var) => $body.map($to::Wasm),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff32(ref mut $var) => $body.map($to::Xcoff32),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff64(ref mut $var) => $body.map($to::Xcoff64),
+ }
+ };
+}
+
+/// Call `next` for a file format iterator.
+macro_rules! next_inner {
+ ($inner:expr, $from:ident, $to:ident) => {
+ match $inner {
+ #[cfg(feature = "coff")]
+ $from::Coff(ref mut iter) => iter.next().map($to::Coff),
+ #[cfg(feature = "coff")]
+ $from::CoffBig(ref mut iter) => iter.next().map($to::CoffBig),
+ #[cfg(feature = "elf")]
+ $from::Elf32(ref mut iter) => iter.next().map($to::Elf32),
+ #[cfg(feature = "elf")]
+ $from::Elf64(ref mut iter) => iter.next().map($to::Elf64),
+ #[cfg(feature = "macho")]
+ $from::MachO32(ref mut iter) => iter.next().map($to::MachO32),
+ #[cfg(feature = "macho")]
+ $from::MachO64(ref mut iter) => iter.next().map($to::MachO64),
+ #[cfg(feature = "pe")]
+ $from::Pe32(ref mut iter) => iter.next().map($to::Pe32),
+ #[cfg(feature = "pe")]
+ $from::Pe64(ref mut iter) => iter.next().map($to::Pe64),
+ #[cfg(feature = "wasm")]
+ $from::Wasm(ref mut iter) => iter.next().map($to::Wasm),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff32(ref mut iter) => iter.next().map($to::Xcoff32),
+ #[cfg(feature = "xcoff")]
+ $from::Xcoff64(ref mut iter) => iter.next().map($to::Xcoff64),
+ }
+ };
+}
+
+/// An object file.
+///
+/// Most functionality is provided by the `Object` trait implementation.
+#[derive(Debug)]
+#[non_exhaustive]
+#[allow(missing_docs)]
+pub enum File<'data, R: ReadRef<'data> = &'data [u8]> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffFile<'data, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigFile<'data, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfFile32<'data, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfFile64<'data, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOFile32<'data, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOFile64<'data, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeFile32<'data, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeFile64<'data, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmFile<'data, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffFile32<'data, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffFile64<'data, R>),
+}
+
+impl<'data, R: ReadRef<'data>> File<'data, R> {
+ /// Parse the raw file data.
+ pub fn parse(data: R) -> Result<Self> {
+ Ok(match FileKind::parse(data)? {
+ #[cfg(feature = "elf")]
+ FileKind::Elf32 => File::Elf32(elf::ElfFile32::parse(data)?),
+ #[cfg(feature = "elf")]
+ FileKind::Elf64 => File::Elf64(elf::ElfFile64::parse(data)?),
+ #[cfg(feature = "macho")]
+ FileKind::MachO32 => File::MachO32(macho::MachOFile32::parse(data)?),
+ #[cfg(feature = "macho")]
+ FileKind::MachO64 => File::MachO64(macho::MachOFile64::parse(data)?),
+ #[cfg(feature = "wasm")]
+ FileKind::Wasm => File::Wasm(wasm::WasmFile::parse(data)?),
+ #[cfg(feature = "pe")]
+ FileKind::Pe32 => File::Pe32(pe::PeFile32::parse(data)?),
+ #[cfg(feature = "pe")]
+ FileKind::Pe64 => File::Pe64(pe::PeFile64::parse(data)?),
+ #[cfg(feature = "coff")]
+ FileKind::Coff => File::Coff(coff::CoffFile::parse(data)?),
+ #[cfg(feature = "coff")]
+ FileKind::CoffBig => File::CoffBig(coff::CoffBigFile::parse(data)?),
+ #[cfg(feature = "xcoff")]
+ FileKind::Xcoff32 => File::Xcoff32(xcoff::XcoffFile32::parse(data)?),
+ #[cfg(feature = "xcoff")]
+ FileKind::Xcoff64 => File::Xcoff64(xcoff::XcoffFile64::parse(data)?),
+ #[allow(unreachable_patterns)]
+ _ => return Err(Error("Unsupported file format")),
+ })
+ }
+
+ /// Parse a Mach-O image from the dyld shared cache.
+ #[cfg(feature = "macho")]
+ pub fn parse_dyld_cache_image<'cache, E: Endian>(
+ image: &macho::DyldCacheImage<'data, 'cache, E, R>,
+ ) -> Result<Self> {
+ Ok(match image.cache.architecture().address_size() {
+ Some(AddressSize::U64) => {
+ File::MachO64(macho::MachOFile64::parse_dyld_cache_image(image)?)
+ }
+ Some(AddressSize::U32) => {
+ File::MachO32(macho::MachOFile32::parse_dyld_cache_image(image)?)
+ }
+ _ => return Err(Error("Unsupported file format")),
+ })
+ }
+
+ /// Return the file format.
+ pub fn format(&self) -> BinaryFormat {
+ match self {
+ #[cfg(feature = "coff")]
+ File::Coff(_) | File::CoffBig(_) => BinaryFormat::Coff,
+ #[cfg(feature = "elf")]
+ File::Elf32(_) | File::Elf64(_) => BinaryFormat::Elf,
+ #[cfg(feature = "macho")]
+ File::MachO32(_) | File::MachO64(_) => BinaryFormat::MachO,
+ #[cfg(feature = "pe")]
+ File::Pe32(_) | File::Pe64(_) => BinaryFormat::Pe,
+ #[cfg(feature = "wasm")]
+ File::Wasm(_) => BinaryFormat::Wasm,
+ #[cfg(feature = "xcoff")]
+ File::Xcoff32(_) | File::Xcoff64(_) => BinaryFormat::Xcoff,
+ }
+ }
+}
+
+impl<'data, R: ReadRef<'data>> read::private::Sealed for File<'data, R> {}
+
+impl<'data, 'file, R> Object<'data, 'file> for File<'data, R>
+where
+ 'data: 'file,
+ R: 'file + ReadRef<'data>,
+{
+ type Segment = Segment<'data, 'file, R>;
+ type SegmentIterator = SegmentIterator<'data, 'file, R>;
+ type Section = Section<'data, 'file, R>;
+ type SectionIterator = SectionIterator<'data, 'file, R>;
+ type Comdat = Comdat<'data, 'file, R>;
+ type ComdatIterator = ComdatIterator<'data, 'file, R>;
+ type Symbol = Symbol<'data, 'file, R>;
+ type SymbolIterator = SymbolIterator<'data, 'file, R>;
+ type SymbolTable = SymbolTable<'data, 'file, R>;
+ type DynamicRelocationIterator = DynamicRelocationIterator<'data, 'file, R>;
+
+ fn architecture(&self) -> Architecture {
+ with_inner!(self, File, |x| x.architecture())
+ }
+
+ fn is_little_endian(&self) -> bool {
+ with_inner!(self, File, |x| x.is_little_endian())
+ }
+
+ fn is_64(&self) -> bool {
+ with_inner!(self, File, |x| x.is_64())
+ }
+
+ fn kind(&self) -> ObjectKind {
+ with_inner!(self, File, |x| x.kind())
+ }
+
+ fn segments(&'file self) -> SegmentIterator<'data, 'file, R> {
+ SegmentIterator {
+ inner: map_inner!(self, File, SegmentIteratorInternal, |x| x.segments()),
+ }
+ }
+
+ fn section_by_name_bytes(&'file self, section_name: &[u8]) -> Option<Section<'data, 'file, R>> {
+ map_inner_option!(self, File, SectionInternal, |x| x
+ .section_by_name_bytes(section_name))
+ .map(|inner| Section { inner })
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Result<Section<'data, 'file, R>> {
+ map_inner_option!(self, File, SectionInternal, |x| x.section_by_index(index))
+ .map(|inner| Section { inner })
+ }
+
+ fn sections(&'file self) -> SectionIterator<'data, 'file, R> {
+ SectionIterator {
+ inner: map_inner!(self, File, SectionIteratorInternal, |x| x.sections()),
+ }
+ }
+
+ fn comdats(&'file self) -> ComdatIterator<'data, 'file, R> {
+ ComdatIterator {
+ inner: map_inner!(self, File, ComdatIteratorInternal, |x| x.comdats()),
+ }
+ }
+
+ fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Symbol<'data, 'file, R>> {
+ map_inner_option!(self, File, SymbolInternal, |x| x
+ .symbol_by_index(index)
+ .map(|x| (x, PhantomData)))
+ .map(|inner| Symbol { inner })
+ }
+
+ fn symbols(&'file self) -> SymbolIterator<'data, 'file, R> {
+ SymbolIterator {
+ inner: map_inner!(self, File, SymbolIteratorInternal, |x| (
+ x.symbols(),
+ PhantomData
+ )),
+ }
+ }
+
+ fn symbol_table(&'file self) -> Option<SymbolTable<'data, 'file, R>> {
+ map_inner_option!(self, File, SymbolTableInternal, |x| x
+ .symbol_table()
+ .map(|x| (x, PhantomData)))
+ .map(|inner| SymbolTable { inner })
+ }
+
+ fn dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file, R> {
+ SymbolIterator {
+ inner: map_inner!(self, File, SymbolIteratorInternal, |x| (
+ x.dynamic_symbols(),
+ PhantomData
+ )),
+ }
+ }
+
+ fn dynamic_symbol_table(&'file self) -> Option<SymbolTable<'data, 'file, R>> {
+ map_inner_option!(self, File, SymbolTableInternal, |x| x
+ .dynamic_symbol_table()
+ .map(|x| (x, PhantomData)))
+ .map(|inner| SymbolTable { inner })
+ }
+
+ #[cfg(feature = "elf")]
+ fn dynamic_relocations(&'file self) -> Option<DynamicRelocationIterator<'data, 'file, R>> {
+ let inner = match self {
+ File::Elf32(ref elf) => {
+ DynamicRelocationIteratorInternal::Elf32(elf.dynamic_relocations()?)
+ }
+ File::Elf64(ref elf) => {
+ DynamicRelocationIteratorInternal::Elf64(elf.dynamic_relocations()?)
+ }
+ #[allow(unreachable_patterns)]
+ _ => return None,
+ };
+ Some(DynamicRelocationIterator { inner })
+ }
+
+ #[cfg(not(feature = "elf"))]
+ fn dynamic_relocations(&'file self) -> Option<DynamicRelocationIterator<'data, 'file, R>> {
+ None
+ }
+
+ fn symbol_map(&self) -> SymbolMap<SymbolMapName<'data>> {
+ with_inner!(self, File, |x| x.symbol_map())
+ }
+
+ fn object_map(&self) -> ObjectMap<'data> {
+ with_inner!(self, File, |x| x.object_map())
+ }
+
+ fn imports(&self) -> Result<Vec<Import<'data>>> {
+ with_inner!(self, File, |x| x.imports())
+ }
+
+ fn exports(&self) -> Result<Vec<Export<'data>>> {
+ with_inner!(self, File, |x| x.exports())
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ with_inner!(self, File, |x| x.has_debug_symbols())
+ }
+
+ #[inline]
+ fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
+ with_inner!(self, File, |x| x.mach_uuid())
+ }
+
+ #[inline]
+ fn build_id(&self) -> Result<Option<&'data [u8]>> {
+ with_inner!(self, File, |x| x.build_id())
+ }
+
+ #[inline]
+ fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> {
+ with_inner!(self, File, |x| x.gnu_debuglink())
+ }
+
+ #[inline]
+ fn gnu_debugaltlink(&self) -> Result<Option<(&'data [u8], &'data [u8])>> {
+ with_inner!(self, File, |x| x.gnu_debugaltlink())
+ }
+
+ #[inline]
+ fn pdb_info(&self) -> Result<Option<CodeView<'_>>> {
+ with_inner!(self, File, |x| x.pdb_info())
+ }
+
+ fn relative_address_base(&self) -> u64 {
+ with_inner!(self, File, |x| x.relative_address_base())
+ }
+
+ fn entry(&self) -> u64 {
+ with_inner!(self, File, |x| x.entry())
+ }
+
+ fn flags(&self) -> FileFlags {
+ with_inner!(self, File, |x| x.flags())
+ }
+}
+
+/// An iterator over the segments of a `File`.
+#[derive(Debug)]
+pub struct SegmentIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: SegmentIteratorInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum SegmentIteratorInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffSegmentIterator<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigSegmentIterator<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfSegmentIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfSegmentIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOSegmentIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOSegmentIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeSegmentIterator32<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeSegmentIterator64<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSegmentIterator<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffSegmentIterator32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffSegmentIterator64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> Iterator for SegmentIterator<'data, 'file, R> {
+ type Item = Segment<'data, 'file, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ next_inner!(self.inner, SegmentIteratorInternal, SegmentInternal)
+ .map(|inner| Segment { inner })
+ }
+}
+
+/// A segment of a `File`.
+pub struct Segment<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: SegmentInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum SegmentInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffSegment<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigSegment<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfSegment32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfSegment64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOSegment32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOSegment64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeSegment32<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeSegment64<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSegment<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffSegment32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffSegment64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> fmt::Debug for Segment<'data, 'file, R> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // It's painful to do much better than this
+ let mut s = f.debug_struct("Segment");
+ match self.name() {
+ Ok(Some(ref name)) => {
+ s.field("name", name);
+ }
+ Ok(None) => {}
+ Err(_) => {
+ s.field("name", &"<invalid>");
+ }
+ }
+ s.field("address", &self.address())
+ .field("size", &self.size())
+ .finish()
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for Segment<'data, 'file, R> {}
+
+impl<'data, 'file, R: ReadRef<'data>> ObjectSegment<'data> for Segment<'data, 'file, R> {
+ fn address(&self) -> u64 {
+ with_inner!(self.inner, SegmentInternal, |x| x.address())
+ }
+
+ fn size(&self) -> u64 {
+ with_inner!(self.inner, SegmentInternal, |x| x.size())
+ }
+
+ fn align(&self) -> u64 {
+ with_inner!(self.inner, SegmentInternal, |x| x.align())
+ }
+
+ fn file_range(&self) -> (u64, u64) {
+ with_inner!(self.inner, SegmentInternal, |x| x.file_range())
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ with_inner!(self.inner, SegmentInternal, |x| x.data())
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ with_inner!(self.inner, SegmentInternal, |x| x.data_range(address, size))
+ }
+
+ fn name_bytes(&self) -> Result<Option<&[u8]>> {
+ with_inner!(self.inner, SegmentInternal, |x| x.name_bytes())
+ }
+
+ fn name(&self) -> Result<Option<&str>> {
+ with_inner!(self.inner, SegmentInternal, |x| x.name())
+ }
+
+ fn flags(&self) -> SegmentFlags {
+ with_inner!(self.inner, SegmentInternal, |x| x.flags())
+ }
+}
+
+/// An iterator of the sections of a `File`.
+#[derive(Debug)]
+pub struct SectionIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: SectionIteratorInternal<'data, 'file, R>,
+}
+
+// we wrap our enums in a struct so that they are kept private.
+#[derive(Debug)]
+enum SectionIteratorInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffSectionIterator<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigSectionIterator<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfSectionIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfSectionIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOSectionIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOSectionIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeSectionIterator32<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeSectionIterator64<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSectionIterator<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffSectionIterator32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffSectionIterator64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> Iterator for SectionIterator<'data, 'file, R> {
+ type Item = Section<'data, 'file, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ next_inner!(self.inner, SectionIteratorInternal, SectionInternal)
+ .map(|inner| Section { inner })
+ }
+}
+
+/// A Section of a File
+pub struct Section<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: SectionInternal<'data, 'file, R>,
+}
+
+enum SectionInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffSection<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigSection<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfSection32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfSection64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOSection32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOSection64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeSection32<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeSection64<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmSection<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffSection32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffSection64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> fmt::Debug for Section<'data, 'file, R> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // It's painful to do much better than this
+ let mut s = f.debug_struct("Section");
+ match self.segment_name() {
+ Ok(Some(ref name)) => {
+ s.field("segment", name);
+ }
+ Ok(None) => {}
+ Err(_) => {
+ s.field("segment", &"<invalid>");
+ }
+ }
+ s.field("name", &self.name().unwrap_or("<invalid>"))
+ .field("address", &self.address())
+ .field("size", &self.size())
+ .field("align", &self.align())
+ .field("kind", &self.kind())
+ .field("flags", &self.flags())
+ .finish()
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for Section<'data, 'file, R> {}
+
+impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for Section<'data, 'file, R> {
+ type RelocationIterator = SectionRelocationIterator<'data, 'file, R>;
+
+ fn index(&self) -> SectionIndex {
+ with_inner!(self.inner, SectionInternal, |x| x.index())
+ }
+
+ fn address(&self) -> u64 {
+ with_inner!(self.inner, SectionInternal, |x| x.address())
+ }
+
+ fn size(&self) -> u64 {
+ with_inner!(self.inner, SectionInternal, |x| x.size())
+ }
+
+ fn align(&self) -> u64 {
+ with_inner!(self.inner, SectionInternal, |x| x.align())
+ }
+
+ fn file_range(&self) -> Option<(u64, u64)> {
+ with_inner!(self.inner, SectionInternal, |x| x.file_range())
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ with_inner!(self.inner, SectionInternal, |x| x.data())
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ with_inner!(self.inner, SectionInternal, |x| x.data_range(address, size))
+ }
+
+ fn compressed_file_range(&self) -> Result<CompressedFileRange> {
+ with_inner!(self.inner, SectionInternal, |x| x.compressed_file_range())
+ }
+
+ fn compressed_data(&self) -> Result<CompressedData<'data>> {
+ with_inner!(self.inner, SectionInternal, |x| x.compressed_data())
+ }
+
+ fn name_bytes(&self) -> Result<&[u8]> {
+ with_inner!(self.inner, SectionInternal, |x| x.name_bytes())
+ }
+
+ fn name(&self) -> Result<&str> {
+ with_inner!(self.inner, SectionInternal, |x| x.name())
+ }
+
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
+ with_inner!(self.inner, SectionInternal, |x| x.segment_name_bytes())
+ }
+
+ fn segment_name(&self) -> Result<Option<&str>> {
+ with_inner!(self.inner, SectionInternal, |x| x.segment_name())
+ }
+
+ fn kind(&self) -> SectionKind {
+ with_inner!(self.inner, SectionInternal, |x| x.kind())
+ }
+
+ fn relocations(&self) -> SectionRelocationIterator<'data, 'file, R> {
+ SectionRelocationIterator {
+ inner: map_inner!(
+ self.inner,
+ SectionInternal,
+ SectionRelocationIteratorInternal,
+ |x| x.relocations()
+ ),
+ }
+ }
+
+ fn flags(&self) -> SectionFlags {
+ with_inner!(self.inner, SectionInternal, |x| x.flags())
+ }
+}
+
+/// An iterator of the COMDAT section groups of a `File`.
+#[derive(Debug)]
+pub struct ComdatIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: ComdatIteratorInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum ComdatIteratorInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffComdatIterator<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigComdatIterator<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfComdatIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfComdatIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOComdatIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOComdatIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeComdatIterator32<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeComdatIterator64<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmComdatIterator<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffComdatIterator32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffComdatIterator64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> Iterator for ComdatIterator<'data, 'file, R> {
+ type Item = Comdat<'data, 'file, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ next_inner!(self.inner, ComdatIteratorInternal, ComdatInternal)
+ .map(|inner| Comdat { inner })
+ }
+}
+
+/// A COMDAT section group of a `File`.
+pub struct Comdat<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: ComdatInternal<'data, 'file, R>,
+}
+
+enum ComdatInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffComdat<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigComdat<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfComdat32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfComdat64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOComdat32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOComdat64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeComdat32<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeComdat64<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmComdat<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffComdat32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffComdat64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> fmt::Debug for Comdat<'data, 'file, R> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut s = f.debug_struct("Comdat");
+ s.field("symbol", &self.symbol())
+ .field("name", &self.name().unwrap_or("<invalid>"))
+ .field("kind", &self.kind())
+ .finish()
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for Comdat<'data, 'file, R> {}
+
+impl<'data, 'file, R: ReadRef<'data>> ObjectComdat<'data> for Comdat<'data, 'file, R> {
+ type SectionIterator = ComdatSectionIterator<'data, 'file, R>;
+
+ fn kind(&self) -> ComdatKind {
+ with_inner!(self.inner, ComdatInternal, |x| x.kind())
+ }
+
+ fn symbol(&self) -> SymbolIndex {
+ with_inner!(self.inner, ComdatInternal, |x| x.symbol())
+ }
+
+ fn name_bytes(&self) -> Result<&[u8]> {
+ with_inner!(self.inner, ComdatInternal, |x| x.name_bytes())
+ }
+
+ fn name(&self) -> Result<&str> {
+ with_inner!(self.inner, ComdatInternal, |x| x.name())
+ }
+
+ fn sections(&self) -> ComdatSectionIterator<'data, 'file, R> {
+ ComdatSectionIterator {
+ inner: map_inner!(
+ self.inner,
+ ComdatInternal,
+ ComdatSectionIteratorInternal,
+ |x| x.sections()
+ ),
+ }
+ }
+}
+
+/// An iterator over COMDAT section entries.
+#[derive(Debug)]
+pub struct ComdatSectionIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: ComdatSectionIteratorInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum ComdatSectionIteratorInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffComdatSectionIterator<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigComdatSectionIterator<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfComdatSectionIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfComdatSectionIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachOComdatSectionIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachOComdatSectionIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeComdatSectionIterator32<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeComdatSectionIterator64<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmComdatSectionIterator<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffComdatSectionIterator32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffComdatSectionIterator64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> Iterator for ComdatSectionIterator<'data, 'file, R> {
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ with_inner_mut!(self.inner, ComdatSectionIteratorInternal, |x| x.next())
+ }
+}
+
+/// A symbol table.
+#[derive(Debug)]
+pub struct SymbolTable<'data, 'file, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ inner: SymbolTableInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum SymbolTableInternal<'data, 'file, R>
+where
+ R: ReadRef<'data>,
+{
+ #[cfg(feature = "coff")]
+ Coff((coff::CoffSymbolTable<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "coff")]
+ CoffBig((coff::CoffBigSymbolTable<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "elf")]
+ Elf32(
+ (
+ elf::ElfSymbolTable32<'data, 'file, Endianness, R>,
+ PhantomData<R>,
+ ),
+ ),
+ #[cfg(feature = "elf")]
+ Elf64(
+ (
+ elf::ElfSymbolTable64<'data, 'file, Endianness, R>,
+ PhantomData<R>,
+ ),
+ ),
+ #[cfg(feature = "macho")]
+ MachO32(
+ (
+ macho::MachOSymbolTable32<'data, 'file, Endianness, R>,
+ PhantomData<()>,
+ ),
+ ),
+ #[cfg(feature = "macho")]
+ MachO64(
+ (
+ macho::MachOSymbolTable64<'data, 'file, Endianness, R>,
+ PhantomData<()>,
+ ),
+ ),
+ #[cfg(feature = "pe")]
+ Pe32((coff::CoffSymbolTable<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "pe")]
+ Pe64((coff::CoffSymbolTable<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "wasm")]
+ Wasm((wasm::WasmSymbolTable<'data, 'file>, PhantomData<R>)),
+ #[cfg(feature = "xcoff")]
+ Xcoff32((xcoff::XcoffSymbolTable32<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "xcoff")]
+ Xcoff64((xcoff::XcoffSymbolTable64<'data, 'file, R>, PhantomData<R>)),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for SymbolTable<'data, 'file, R> {}
+
+impl<'data, 'file, R: ReadRef<'data>> ObjectSymbolTable<'data> for SymbolTable<'data, 'file, R> {
+ type Symbol = Symbol<'data, 'file, R>;
+ type SymbolIterator = SymbolIterator<'data, 'file, R>;
+
+ fn symbols(&self) -> Self::SymbolIterator {
+ SymbolIterator {
+ inner: map_inner!(
+ self.inner,
+ SymbolTableInternal,
+ SymbolIteratorInternal,
+ |x| (x.0.symbols(), PhantomData)
+ ),
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> {
+ map_inner_option!(self.inner, SymbolTableInternal, SymbolInternal, |x| x
+ .0
+ .symbol_by_index(index)
+ .map(|x| (x, PhantomData)))
+ .map(|inner| Symbol { inner })
+ }
+}
+
+/// An iterator over symbol table entries.
+#[derive(Debug)]
+pub struct SymbolIterator<'data, 'file, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ inner: SymbolIteratorInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum SymbolIteratorInternal<'data, 'file, R>
+where
+ R: ReadRef<'data>,
+{
+ #[cfg(feature = "coff")]
+ Coff((coff::CoffSymbolIterator<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "coff")]
+ CoffBig((coff::CoffBigSymbolIterator<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "elf")]
+ Elf32(
+ (
+ elf::ElfSymbolIterator32<'data, 'file, Endianness, R>,
+ PhantomData<R>,
+ ),
+ ),
+ #[cfg(feature = "elf")]
+ Elf64(
+ (
+ elf::ElfSymbolIterator64<'data, 'file, Endianness, R>,
+ PhantomData<R>,
+ ),
+ ),
+ #[cfg(feature = "macho")]
+ MachO32(
+ (
+ macho::MachOSymbolIterator32<'data, 'file, Endianness, R>,
+ PhantomData<()>,
+ ),
+ ),
+ #[cfg(feature = "macho")]
+ MachO64(
+ (
+ macho::MachOSymbolIterator64<'data, 'file, Endianness, R>,
+ PhantomData<()>,
+ ),
+ ),
+ #[cfg(feature = "pe")]
+ Pe32((coff::CoffSymbolIterator<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "pe")]
+ Pe64((coff::CoffSymbolIterator<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "wasm")]
+ Wasm((wasm::WasmSymbolIterator<'data, 'file>, PhantomData<R>)),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(
+ (
+ xcoff::XcoffSymbolIterator32<'data, 'file, R>,
+ PhantomData<R>,
+ ),
+ ),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(
+ (
+ xcoff::XcoffSymbolIterator64<'data, 'file, R>,
+ PhantomData<R>,
+ ),
+ ),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> Iterator for SymbolIterator<'data, 'file, R> {
+ type Item = Symbol<'data, 'file, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ map_inner_option_mut!(self.inner, SymbolIteratorInternal, SymbolInternal, |iter| {
+ iter.0.next().map(|x| (x, PhantomData))
+ })
+ .map(|inner| Symbol { inner })
+ }
+}
+
+/// A symbol table entry.
+pub struct Symbol<'data, 'file, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ inner: SymbolInternal<'data, 'file, R>,
+}
+
+enum SymbolInternal<'data, 'file, R>
+where
+ R: ReadRef<'data>,
+{
+ #[cfg(feature = "coff")]
+ Coff((coff::CoffSymbol<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "coff")]
+ CoffBig((coff::CoffBigSymbol<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "elf")]
+ Elf32(
+ (
+ elf::ElfSymbol32<'data, 'file, Endianness, R>,
+ PhantomData<R>,
+ ),
+ ),
+ #[cfg(feature = "elf")]
+ Elf64(
+ (
+ elf::ElfSymbol64<'data, 'file, Endianness, R>,
+ PhantomData<R>,
+ ),
+ ),
+ #[cfg(feature = "macho")]
+ MachO32(
+ (
+ macho::MachOSymbol32<'data, 'file, Endianness, R>,
+ PhantomData<()>,
+ ),
+ ),
+ #[cfg(feature = "macho")]
+ MachO64(
+ (
+ macho::MachOSymbol64<'data, 'file, Endianness, R>,
+ PhantomData<()>,
+ ),
+ ),
+ #[cfg(feature = "pe")]
+ Pe32((coff::CoffSymbol<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "pe")]
+ Pe64((coff::CoffSymbol<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "wasm")]
+ Wasm((wasm::WasmSymbol<'data, 'file>, PhantomData<R>)),
+ #[cfg(feature = "xcoff")]
+ Xcoff32((xcoff::XcoffSymbol32<'data, 'file, R>, PhantomData<R>)),
+ #[cfg(feature = "xcoff")]
+ Xcoff64((xcoff::XcoffSymbol64<'data, 'file, R>, PhantomData<R>)),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> fmt::Debug for Symbol<'data, 'file, R> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Symbol")
+ .field("name", &self.name().unwrap_or("<invalid>"))
+ .field("address", &self.address())
+ .field("size", &self.size())
+ .field("kind", &self.kind())
+ .field("section", &self.section())
+ .field("scope", &self.scope())
+ .field("weak", &self.is_weak())
+ .field("flags", &self.flags())
+ .finish()
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for Symbol<'data, 'file, R> {}
+
+impl<'data, 'file, R: ReadRef<'data>> ObjectSymbol<'data> for Symbol<'data, 'file, R> {
+ fn index(&self) -> SymbolIndex {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.index())
+ }
+
+ fn name_bytes(&self) -> Result<&'data [u8]> {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.name_bytes())
+ }
+
+ fn name(&self) -> Result<&'data str> {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.name())
+ }
+
+ fn address(&self) -> u64 {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.address())
+ }
+
+ fn size(&self) -> u64 {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.size())
+ }
+
+ fn kind(&self) -> SymbolKind {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.kind())
+ }
+
+ fn section(&self) -> SymbolSection {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.section())
+ }
+
+ fn is_undefined(&self) -> bool {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.is_undefined())
+ }
+
+ fn is_definition(&self) -> bool {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.is_definition())
+ }
+
+ fn is_common(&self) -> bool {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.is_common())
+ }
+
+ fn is_weak(&self) -> bool {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.is_weak())
+ }
+
+ fn scope(&self) -> SymbolScope {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.scope())
+ }
+
+ fn is_global(&self) -> bool {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.is_global())
+ }
+
+ fn is_local(&self) -> bool {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.is_local())
+ }
+
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
+ with_inner!(self.inner, SymbolInternal, |x| x.0.flags())
+ }
+}
+
+/// An iterator over dynamic relocation entries.
+#[derive(Debug)]
+pub struct DynamicRelocationIterator<'data, 'file, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ inner: DynamicRelocationIteratorInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum DynamicRelocationIteratorInternal<'data, 'file, R>
+where
+ R: ReadRef<'data>,
+{
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfDynamicRelocationIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfDynamicRelocationIterator64<'data, 'file, Endianness, R>),
+ // We need to always use the lifetime parameters.
+ #[allow(unused)]
+ None(PhantomData<(&'data (), &'file (), R)>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> Iterator for DynamicRelocationIterator<'data, 'file, R> {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.inner {
+ #[cfg(feature = "elf")]
+ DynamicRelocationIteratorInternal::Elf32(ref mut elf) => elf.next(),
+ #[cfg(feature = "elf")]
+ DynamicRelocationIteratorInternal::Elf64(ref mut elf) => elf.next(),
+ DynamicRelocationIteratorInternal::None(_) => None,
+ }
+ }
+}
+
+/// An iterator over section relocation entries.
+#[derive(Debug)]
+pub struct SectionRelocationIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
+ inner: SectionRelocationIteratorInternal<'data, 'file, R>,
+}
+
+#[derive(Debug)]
+enum SectionRelocationIteratorInternal<'data, 'file, R: ReadRef<'data>> {
+ #[cfg(feature = "coff")]
+ Coff(coff::CoffRelocationIterator<'data, 'file, R>),
+ #[cfg(feature = "coff")]
+ CoffBig(coff::CoffBigRelocationIterator<'data, 'file, R>),
+ #[cfg(feature = "elf")]
+ Elf32(elf::ElfSectionRelocationIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "elf")]
+ Elf64(elf::ElfSectionRelocationIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO32(macho::MachORelocationIterator32<'data, 'file, Endianness, R>),
+ #[cfg(feature = "macho")]
+ MachO64(macho::MachORelocationIterator64<'data, 'file, Endianness, R>),
+ #[cfg(feature = "pe")]
+ Pe32(pe::PeRelocationIterator<'data, 'file, R>),
+ #[cfg(feature = "pe")]
+ Pe64(pe::PeRelocationIterator<'data, 'file, R>),
+ #[cfg(feature = "wasm")]
+ Wasm(wasm::WasmRelocationIterator<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff32(xcoff::XcoffRelocationIterator32<'data, 'file, R>),
+ #[cfg(feature = "xcoff")]
+ Xcoff64(xcoff::XcoffRelocationIterator64<'data, 'file, R>),
+}
+
+impl<'data, 'file, R: ReadRef<'data>> Iterator for SectionRelocationIterator<'data, 'file, R> {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ with_inner_mut!(self.inner, SectionRelocationIteratorInternal, |x| x.next())
+ }
+}
diff --git a/third_party/rust/object/src/read/archive.rs b/third_party/rust/object/src/read/archive.rs
new file mode 100644
index 0000000000..f5aaa9b190
--- /dev/null
+++ b/third_party/rust/object/src/read/archive.rs
@@ -0,0 +1,739 @@
+//! Support for archive files.
+
+use core::convert::TryInto;
+
+use crate::archive;
+use crate::read::{self, Bytes, Error, ReadError, ReadRef};
+
+/// The kind of archive format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum ArchiveKind {
+ /// There are no special files that indicate the archive format.
+ Unknown,
+ /// The GNU (or System V) archive format.
+ Gnu,
+ /// The GNU (or System V) archive format with 64-bit symbol table.
+ Gnu64,
+ /// The BSD archive format.
+ Bsd,
+ /// The BSD archive format with 64-bit symbol table.
+ ///
+ /// This is used for Darwin.
+ Bsd64,
+ /// The Windows COFF archive format.
+ Coff,
+ /// The AIX big archive format.
+ AixBig,
+}
+
+/// The list of members in the archive.
+#[derive(Debug, Clone, Copy)]
+enum Members<'data> {
+ Common {
+ offset: u64,
+ end_offset: u64,
+ },
+ AixBig {
+ index: &'data [archive::AixMemberOffset],
+ },
+}
+
+/// A partially parsed archive file.
+#[derive(Debug, Clone, Copy)]
+pub struct ArchiveFile<'data, R: ReadRef<'data> = &'data [u8]> {
+ data: R,
+ kind: ArchiveKind,
+ members: Members<'data>,
+ symbols: (u64, u64),
+ names: &'data [u8],
+}
+
+impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> {
+ /// Parse the archive header and special members.
+ pub fn parse(data: R) -> read::Result<Self> {
+ let len = data.len().read_error("Unknown archive length")?;
+ let mut tail = 0;
+ let magic = data
+ .read_bytes(&mut tail, archive::MAGIC.len() as u64)
+ .read_error("Invalid archive size")?;
+
+ if magic == archive::AIX_BIG_MAGIC {
+ return Self::parse_aixbig(data);
+ } else if magic != archive::MAGIC {
+ return Err(Error("Unsupported archive identifier"));
+ }
+
+ let mut members_offset = tail;
+ let members_end_offset = len;
+
+ let mut file = ArchiveFile {
+ data,
+ kind: ArchiveKind::Unknown,
+ members: Members::Common {
+ offset: 0,
+ end_offset: 0,
+ },
+ symbols: (0, 0),
+ names: &[],
+ };
+
+ // The first few members may be special, so parse them.
+ // GNU has:
+ // - "/" or "/SYM64/": symbol table (optional)
+ // - "//": names table (optional)
+ // COFF has:
+ // - "/": first linker member
+ // - "/": second linker member
+ // - "//": names table
+ // BSD has:
+ // - "__.SYMDEF" or "__.SYMDEF SORTED": symbol table (optional)
+ // BSD 64-bit has:
+ // - "__.SYMDEF_64" or "__.SYMDEF_64 SORTED": symbol table (optional)
+ // BSD may use the extended name for the symbol table. This is handled
+ // by `ArchiveMember::parse`.
+ if tail < len {
+ let member = ArchiveMember::parse(data, &mut tail, &[])?;
+ if member.name == b"/" {
+ // GNU symbol table (unless we later determine this is COFF).
+ file.kind = ArchiveKind::Gnu;
+ file.symbols = member.file_range();
+ members_offset = tail;
+
+ if tail < len {
+ let member = ArchiveMember::parse(data, &mut tail, &[])?;
+ if member.name == b"/" {
+ // COFF linker member.
+ file.kind = ArchiveKind::Coff;
+ file.symbols = member.file_range();
+ members_offset = tail;
+
+ if tail < len {
+ let member = ArchiveMember::parse(data, &mut tail, &[])?;
+ if member.name == b"//" {
+ // COFF names table.
+ file.names = member.data(data)?;
+ members_offset = tail;
+ }
+ }
+ } else if member.name == b"//" {
+ // GNU names table.
+ file.names = member.data(data)?;
+ members_offset = tail;
+ }
+ }
+ } else if member.name == b"/SYM64/" {
+ // GNU 64-bit symbol table.
+ file.kind = ArchiveKind::Gnu64;
+ file.symbols = member.file_range();
+ members_offset = tail;
+
+ if tail < len {
+ let member = ArchiveMember::parse(data, &mut tail, &[])?;
+ if member.name == b"//" {
+ // GNU names table.
+ file.names = member.data(data)?;
+ members_offset = tail;
+ }
+ }
+ } else if member.name == b"//" {
+ // GNU names table.
+ file.kind = ArchiveKind::Gnu;
+ file.names = member.data(data)?;
+ members_offset = tail;
+ } else if member.name == b"__.SYMDEF" || member.name == b"__.SYMDEF SORTED" {
+ // BSD symbol table.
+ file.kind = ArchiveKind::Bsd;
+ file.symbols = member.file_range();
+ members_offset = tail;
+ } else if member.name == b"__.SYMDEF_64" || member.name == b"__.SYMDEF_64 SORTED" {
+ // BSD 64-bit symbol table.
+ file.kind = ArchiveKind::Bsd64;
+ file.symbols = member.file_range();
+ members_offset = tail;
+ } else {
+ // TODO: This could still be a BSD file. We leave this as unknown for now.
+ }
+ }
+ file.members = Members::Common {
+ offset: members_offset,
+ end_offset: members_end_offset,
+ };
+ Ok(file)
+ }
+
+ fn parse_aixbig(data: R) -> read::Result<Self> {
+ let mut tail = 0;
+
+ let file_header = data
+ .read::<archive::AixFileHeader>(&mut tail)
+ .read_error("Invalid AIX big archive file header")?;
+ // Caller already validated this.
+ debug_assert_eq!(file_header.magic, archive::AIX_BIG_MAGIC);
+
+ let mut file = ArchiveFile {
+ data,
+ kind: ArchiveKind::AixBig,
+ members: Members::AixBig { index: &[] },
+ symbols: (0, 0),
+ names: &[],
+ };
+
+ // Read the span of symbol table.
+ let symtbl64 = parse_u64_digits(&file_header.gst64off, 10)
+ .read_error("Invalid offset to 64-bit symbol table in AIX big archive")?;
+ if symtbl64 > 0 {
+ // The symbol table is also a file with header.
+ let member = ArchiveMember::parse_aixbig(data, symtbl64)?;
+ file.symbols = member.file_range();
+ } else {
+ let symtbl = parse_u64_digits(&file_header.gstoff, 10)
+ .read_error("Invalid offset to symbol table in AIX big archive")?;
+ if symtbl > 0 {
+ // The symbol table is also a file with header.
+ let member = ArchiveMember::parse_aixbig(data, symtbl)?;
+ file.symbols = member.file_range();
+ }
+ }
+
+ // Big archive member index table lists file entries with offsets and names.
+ // To avoid potential infinite loop (members are double-linked list), the
+ // iterator goes through the index instead of real members.
+ let member_table_offset = parse_u64_digits(&file_header.memoff, 10)
+ .read_error("Invalid offset for member table of AIX big archive")?;
+ if member_table_offset == 0 {
+ // The offset would be zero if archive contains no file.
+ return Ok(file);
+ }
+
+ // The member index table is also a file with header.
+ let member = ArchiveMember::parse_aixbig(data, member_table_offset)?;
+ let mut member_data = Bytes(member.data(data)?);
+
+ // Structure of member index table:
+ // Number of entries (20 bytes)
+ // Offsets of each entry (20*N bytes)
+ // Names string table (the rest of bytes to fill size defined in header)
+ let members_count_bytes = member_data
+ .read_slice::<u8>(20)
+ .read_error("Missing member count in AIX big archive")?;
+ let members_count = parse_u64_digits(members_count_bytes, 10)
+ .and_then(|size| size.try_into().ok())
+ .read_error("Invalid member count in AIX big archive")?;
+ let index = member_data
+ .read_slice::<archive::AixMemberOffset>(members_count)
+ .read_error("Member count overflow in AIX big archive")?;
+ file.members = Members::AixBig { index };
+
+ Ok(file)
+ }
+
+ /// Return the archive format.
+ #[inline]
+ pub fn kind(&self) -> ArchiveKind {
+ self.kind
+ }
+
+ /// Iterate over the members of the archive.
+ ///
+ /// This does not return special members.
+ #[inline]
+ pub fn members(&self) -> ArchiveMemberIterator<'data, R> {
+ ArchiveMemberIterator {
+ data: self.data,
+ members: self.members,
+ names: self.names,
+ }
+ }
+}
+
+/// An iterator over the members of an archive.
+#[derive(Debug)]
+pub struct ArchiveMemberIterator<'data, R: ReadRef<'data> = &'data [u8]> {
+ data: R,
+ members: Members<'data>,
+ names: &'data [u8],
+}
+
+impl<'data, R: ReadRef<'data>> Iterator for ArchiveMemberIterator<'data, R> {
+ type Item = read::Result<ArchiveMember<'data>>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match &mut self.members {
+ Members::Common {
+ ref mut offset,
+ ref mut end_offset,
+ } => {
+ if *offset >= *end_offset {
+ return None;
+ }
+ let member = ArchiveMember::parse(self.data, offset, self.names);
+ if member.is_err() {
+ *offset = *end_offset;
+ }
+ Some(member)
+ }
+ Members::AixBig { ref mut index } => match **index {
+ [] => None,
+ [ref first, ref rest @ ..] => {
+ *index = rest;
+ let member = ArchiveMember::parse_aixbig_index(self.data, first);
+ if member.is_err() {
+ *index = &[];
+ }
+ Some(member)
+ }
+ },
+ }
+ }
+}
+
+/// An archive member header.
+#[derive(Debug, Clone, Copy)]
+enum MemberHeader<'data> {
+ /// Common header used by many formats.
+ Common(&'data archive::Header),
+ /// AIX big archive header
+ AixBig(&'data archive::AixHeader),
+}
+
+/// A partially parsed archive member.
+#[derive(Debug)]
+pub struct ArchiveMember<'data> {
+ header: MemberHeader<'data>,
+ name: &'data [u8],
+ offset: u64,
+ size: u64,
+}
+
+impl<'data> ArchiveMember<'data> {
+ /// Parse the member header, name, and file data in an archive with the common format.
+ ///
+ /// This reads the extended name (if any) and adjusts the file size.
+ fn parse<R: ReadRef<'data>>(
+ data: R,
+ offset: &mut u64,
+ names: &'data [u8],
+ ) -> read::Result<Self> {
+ let header = data
+ .read::<archive::Header>(offset)
+ .read_error("Invalid archive member header")?;
+ if header.terminator != archive::TERMINATOR {
+ return Err(Error("Invalid archive terminator"));
+ }
+
+ let mut file_offset = *offset;
+ let mut file_size =
+ parse_u64_digits(&header.size, 10).read_error("Invalid archive member size")?;
+ *offset = offset
+ .checked_add(file_size)
+ .read_error("Archive member size is too large")?;
+ // Entries are padded to an even number of bytes.
+ if (file_size & 1) != 0 {
+ *offset = offset.saturating_add(1);
+ }
+
+ let name = if header.name[0] == b'/' && (header.name[1] as char).is_ascii_digit() {
+ // Read file name from the names table.
+ parse_sysv_extended_name(&header.name[1..], names)
+ .read_error("Invalid archive extended name offset")?
+ } else if &header.name[..3] == b"#1/" && (header.name[3] as char).is_ascii_digit() {
+ // Read file name from the start of the file data.
+ parse_bsd_extended_name(&header.name[3..], data, &mut file_offset, &mut file_size)
+ .read_error("Invalid archive extended name length")?
+ } else if header.name[0] == b'/' {
+ let name_len = memchr::memchr(b' ', &header.name).unwrap_or(header.name.len());
+ &header.name[..name_len]
+ } else {
+ let name_len = memchr::memchr(b'/', &header.name)
+ .or_else(|| memchr::memchr(b' ', &header.name))
+ .unwrap_or(header.name.len());
+ &header.name[..name_len]
+ };
+
+ Ok(ArchiveMember {
+ header: MemberHeader::Common(header),
+ name,
+ offset: file_offset,
+ size: file_size,
+ })
+ }
+
+ /// Parse a member index entry in an AIX big archive,
+ /// and then parse the member header, name, and file data.
+ fn parse_aixbig_index<R: ReadRef<'data>>(
+ data: R,
+ index: &archive::AixMemberOffset,
+ ) -> read::Result<Self> {
+ let offset = parse_u64_digits(&index.0, 10)
+ .read_error("Invalid AIX big archive file member offset")?;
+ Self::parse_aixbig(data, offset)
+ }
+
+ /// Parse the member header, name, and file data in an AIX big archive.
+ fn parse_aixbig<R: ReadRef<'data>>(data: R, mut offset: u64) -> read::Result<Self> {
+ // The format was described at
+ // https://www.ibm.com/docs/en/aix/7.3?topic=formats-ar-file-format-big
+ let header = data
+ .read::<archive::AixHeader>(&mut offset)
+ .read_error("Invalid AIX big archive member header")?;
+ let name_length = parse_u64_digits(&header.namlen, 10)
+ .read_error("Invalid AIX big archive member name length")?;
+ let name = data
+ .read_bytes(&mut offset, name_length)
+ .read_error("Invalid AIX big archive member name")?;
+
+ // The actual data for a file member begins at the first even-byte boundary beyond the
+ // member header and continues for the number of bytes specified by the ar_size field. The
+ // ar command inserts null bytes for padding where necessary.
+ if offset & 1 != 0 {
+ offset = offset.saturating_add(1);
+ }
+ // Because of the even-byte boundary, we have to read and check terminator after header.
+ let terminator = data
+ .read_bytes(&mut offset, 2)
+ .read_error("Invalid AIX big archive terminator")?;
+ if terminator != archive::TERMINATOR {
+ return Err(Error("Invalid AIX big archive terminator"));
+ }
+
+ let size = parse_u64_digits(&header.size, 10)
+ .read_error("Invalid archive member size in AIX big archive")?;
+ Ok(ArchiveMember {
+ header: MemberHeader::AixBig(header),
+ name,
+ offset,
+ size,
+ })
+ }
+
+ /// Return the raw header that is common to many archive formats.
+ ///
+ /// Returns `None` if this archive does not use the common header format.
+ #[inline]
+ pub fn header(&self) -> Option<&'data archive::Header> {
+ match self.header {
+ MemberHeader::Common(header) => Some(header),
+ _ => None,
+ }
+ }
+
+ /// Return the raw header for AIX big archives.
+ ///
+ /// Returns `None` if this is not an AIX big archive.
+ #[inline]
+ pub fn aix_header(&self) -> Option<&'data archive::AixHeader> {
+ match self.header {
+ MemberHeader::AixBig(header) => Some(header),
+ _ => None,
+ }
+ }
+
+ /// Return the parsed file name.
+ ///
+ /// This may be an extended file name.
+ #[inline]
+ pub fn name(&self) -> &'data [u8] {
+ self.name
+ }
+
+ /// Parse the file modification timestamp from the header.
+ #[inline]
+ pub fn date(&self) -> Option<u64> {
+ match &self.header {
+ MemberHeader::Common(header) => parse_u64_digits(&header.date, 10),
+ MemberHeader::AixBig(header) => parse_u64_digits(&header.date, 10),
+ }
+ }
+
+ /// Parse the user ID from the header.
+ #[inline]
+ pub fn uid(&self) -> Option<u64> {
+ match &self.header {
+ MemberHeader::Common(header) => parse_u64_digits(&header.uid, 10),
+ MemberHeader::AixBig(header) => parse_u64_digits(&header.uid, 10),
+ }
+ }
+
+ /// Parse the group ID from the header.
+ #[inline]
+ pub fn gid(&self) -> Option<u64> {
+ match &self.header {
+ MemberHeader::Common(header) => parse_u64_digits(&header.gid, 10),
+ MemberHeader::AixBig(header) => parse_u64_digits(&header.gid, 10),
+ }
+ }
+
+ /// Parse the file mode from the header.
+ #[inline]
+ pub fn mode(&self) -> Option<u64> {
+ match &self.header {
+ MemberHeader::Common(header) => parse_u64_digits(&header.mode, 8),
+ MemberHeader::AixBig(header) => parse_u64_digits(&header.mode, 8),
+ }
+ }
+
+ /// Return the offset and size of the file data.
+ pub fn file_range(&self) -> (u64, u64) {
+ (self.offset, self.size)
+ }
+
+ /// Return the file data.
+ #[inline]
+ pub fn data<R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [u8]> {
+ data.read_bytes_at(self.offset, self.size)
+ .read_error("Archive member size is too large")
+ }
+}
+
+// Ignores bytes starting from the first space.
+fn parse_u64_digits(digits: &[u8], radix: u32) -> Option<u64> {
+ if let [b' ', ..] = digits {
+ return None;
+ }
+ let mut result: u64 = 0;
+ for &c in digits {
+ if c == b' ' {
+ return Some(result);
+ } else {
+ let x = (c as char).to_digit(radix)?;
+ result = result
+ .checked_mul(u64::from(radix))?
+ .checked_add(u64::from(x))?;
+ }
+ }
+ Some(result)
+}
+
+fn parse_sysv_extended_name<'data>(digits: &[u8], names: &'data [u8]) -> Result<&'data [u8], ()> {
+ let offset = parse_u64_digits(digits, 10).ok_or(())?;
+ let offset = offset.try_into().map_err(|_| ())?;
+ let name_data = names.get(offset..).ok_or(())?;
+ let name = match memchr::memchr2(b'/', b'\0', name_data) {
+ Some(len) => &name_data[..len],
+ None => name_data,
+ };
+ Ok(name)
+}
+
+/// Modifies `data` to start after the extended name.
+fn parse_bsd_extended_name<'data, R: ReadRef<'data>>(
+ digits: &[u8],
+ data: R,
+ offset: &mut u64,
+ size: &mut u64,
+) -> Result<&'data [u8], ()> {
+ let len = parse_u64_digits(digits, 10).ok_or(())?;
+ *size = size.checked_sub(len).ok_or(())?;
+ let name_data = data.read_bytes(offset, len)?;
+ let name = match memchr::memchr(b'\0', name_data) {
+ Some(len) => &name_data[..len],
+ None => name_data,
+ };
+ Ok(name)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn kind() {
+ let data = b"!<arch>\n";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Unknown);
+
+ let data = b"\
+ !<arch>\n\
+ / 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Gnu);
+
+ let data = b"\
+ !<arch>\n\
+ // 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Gnu);
+
+ let data = b"\
+ !<arch>\n\
+ / 4 `\n\
+ 0000\
+ // 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Gnu);
+
+ let data = b"\
+ !<arch>\n\
+ /SYM64/ 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Gnu64);
+
+ let data = b"\
+ !<arch>\n\
+ /SYM64/ 4 `\n\
+ 0000\
+ // 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Gnu64);
+
+ let data = b"\
+ !<arch>\n\
+ __.SYMDEF 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Bsd);
+
+ let data = b"\
+ !<arch>\n\
+ #1/9 13 `\n\
+ __.SYMDEF0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Bsd);
+
+ let data = b"\
+ !<arch>\n\
+ #1/16 20 `\n\
+ __.SYMDEF SORTED0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Bsd);
+
+ let data = b"\
+ !<arch>\n\
+ __.SYMDEF_64 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Bsd64);
+
+ let data = b"\
+ !<arch>\n\
+ #1/12 16 `\n\
+ __.SYMDEF_640000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Bsd64);
+
+ let data = b"\
+ !<arch>\n\
+ #1/19 23 `\n\
+ __.SYMDEF_64 SORTED0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Bsd64);
+
+ let data = b"\
+ !<arch>\n\
+ / 4 `\n\
+ 0000\
+ / 4 `\n\
+ 0000\
+ // 4 `\n\
+ 0000";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Coff);
+
+ let data = b"\
+ <bigaf>\n\
+ 0 0 \
+ 0 0 \
+ 0 128 \
+ 6 0 \
+ 0 \0\0\0\0\0\0\0\0\0\0\0\0\
+ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+ let archive = ArchiveFile::parse(&data[..]).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::AixBig);
+ }
+
+ #[test]
+ fn gnu_names() {
+ let data = b"\
+ !<arch>\n\
+ // 18 `\n\
+ 0123456789abcdef/\n\
+ s p a c e/ 0 0 0 644 4 `\n\
+ 0000\
+ 0123456789abcde/0 0 0 644 3 `\n\
+ odd\n\
+ /0 0 0 0 644 4 `\n\
+ even";
+ let data = &data[..];
+ let archive = ArchiveFile::parse(data).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Gnu);
+ let mut members = archive.members();
+
+ let member = members.next().unwrap().unwrap();
+ assert_eq!(member.name(), b"s p a c e");
+ assert_eq!(member.data(data).unwrap(), &b"0000"[..]);
+
+ let member = members.next().unwrap().unwrap();
+ assert_eq!(member.name(), b"0123456789abcde");
+ assert_eq!(member.data(data).unwrap(), &b"odd"[..]);
+
+ let member = members.next().unwrap().unwrap();
+ assert_eq!(member.name(), b"0123456789abcdef");
+ assert_eq!(member.data(data).unwrap(), &b"even"[..]);
+
+ assert!(members.next().is_none());
+ }
+
+ #[test]
+ fn bsd_names() {
+ let data = b"\
+ !<arch>\n\
+ 0123456789abcde 0 0 0 644 3 `\n\
+ odd\n\
+ #1/16 0 0 0 644 20 `\n\
+ 0123456789abcdefeven";
+ let data = &data[..];
+ let archive = ArchiveFile::parse(data).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::Unknown);
+ let mut members = archive.members();
+
+ let member = members.next().unwrap().unwrap();
+ assert_eq!(member.name(), b"0123456789abcde");
+ assert_eq!(member.data(data).unwrap(), &b"odd"[..]);
+
+ let member = members.next().unwrap().unwrap();
+ assert_eq!(member.name(), b"0123456789abcdef");
+ assert_eq!(member.data(data).unwrap(), &b"even"[..]);
+
+ assert!(members.next().is_none());
+ }
+
+ #[test]
+ fn aix_names() {
+ let data = b"\
+ <bigaf>\n\
+ 396 0 0 \
+ 128 262 0 \
+ 4 262 0 \
+ 1662610370 223 1 644 16 \
+ 0123456789abcdef`\nord\n\
+ 4 396 128 \
+ 1662610374 223 1 644 16 \
+ fedcba9876543210`\nrev\n\
+ 94 0 262 \
+ 0 0 0 0 0 \
+ `\n2 128 \
+ 262 0123456789abcdef\0fedcba9876543210\0";
+ let data = &data[..];
+ let archive = ArchiveFile::parse(data).unwrap();
+ assert_eq!(archive.kind(), ArchiveKind::AixBig);
+ let mut members = archive.members();
+
+ let member = members.next().unwrap().unwrap();
+ assert_eq!(member.name(), b"0123456789abcdef");
+ assert_eq!(member.data(data).unwrap(), &b"ord\n"[..]);
+
+ let member = members.next().unwrap().unwrap();
+ assert_eq!(member.name(), b"fedcba9876543210");
+ assert_eq!(member.data(data).unwrap(), &b"rev\n"[..]);
+
+ assert!(members.next().is_none());
+ }
+}
diff --git a/third_party/rust/object/src/read/coff/comdat.rs b/third_party/rust/object/src/read/coff/comdat.rs
new file mode 100644
index 0000000000..22e061a236
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/comdat.rs
@@ -0,0 +1,207 @@
+use core::str;
+
+use crate::endian::LittleEndian as LE;
+use crate::pe;
+use crate::read::{
+ self, ComdatKind, ObjectComdat, ReadError, ReadRef, Result, SectionIndex, SymbolIndex,
+};
+
+use super::{CoffFile, CoffHeader, ImageSymbol};
+
+/// An iterator over the COMDAT section groups of a `CoffBigFile`.
+pub type CoffBigComdatIterator<'data, 'file, R = &'data [u8]> =
+ CoffComdatIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// An iterator over the COMDAT section groups of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffComdatIterator<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ pub(super) file: &'file CoffFile<'data, R, Coff>,
+ pub(super) index: usize,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffComdatIterator<'data, 'file, R, Coff>
+{
+ type Item = CoffComdat<'data, 'file, R, Coff>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ let index = self.index;
+ let symbol = self.file.common.symbols.symbol(index).ok()?;
+ self.index += 1 + symbol.number_of_aux_symbols() as usize;
+ if let Some(comdat) = CoffComdat::parse(self.file, symbol, index) {
+ return Some(comdat);
+ }
+ }
+ }
+}
+
+/// A COMDAT section group of a `CoffBigFile`.
+pub type CoffBigComdat<'data, 'file, R = &'data [u8]> =
+ CoffComdat<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// A COMDAT section group of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffComdat<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ file: &'file CoffFile<'data, R, Coff>,
+ symbol_index: SymbolIndex,
+ symbol: &'data Coff::ImageSymbol,
+ selection: u8,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdat<'data, 'file, R, Coff> {
+ fn parse(
+ file: &'file CoffFile<'data, R, Coff>,
+ section_symbol: &'data Coff::ImageSymbol,
+ index: usize,
+ ) -> Option<CoffComdat<'data, 'file, R, Coff>> {
+ // Must be a section symbol.
+ if !section_symbol.has_aux_section() {
+ return None;
+ }
+
+ // Auxiliary record must have a non-associative selection.
+ let aux = file.common.symbols.aux_section(index).ok()?;
+ let selection = aux.selection;
+ if selection == 0 || selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE {
+ return None;
+ }
+
+ // Find the COMDAT symbol.
+ let mut symbol_index = index;
+ let mut symbol = section_symbol;
+ let section_number = section_symbol.section_number();
+ loop {
+ symbol_index += 1 + symbol.number_of_aux_symbols() as usize;
+ symbol = file.common.symbols.symbol(symbol_index).ok()?;
+ if section_number == symbol.section_number() {
+ break;
+ }
+ }
+
+ Some(CoffComdat {
+ file,
+ symbol_index: SymbolIndex(symbol_index),
+ symbol,
+ selection,
+ })
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
+ for CoffComdat<'data, 'file, R, Coff>
+{
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectComdat<'data>
+ for CoffComdat<'data, 'file, R, Coff>
+{
+ type SectionIterator = CoffComdatSectionIterator<'data, 'file, R, Coff>;
+
+ #[inline]
+ fn kind(&self) -> ComdatKind {
+ match self.selection {
+ pe::IMAGE_COMDAT_SELECT_NODUPLICATES => ComdatKind::NoDuplicates,
+ pe::IMAGE_COMDAT_SELECT_ANY => ComdatKind::Any,
+ pe::IMAGE_COMDAT_SELECT_SAME_SIZE => ComdatKind::SameSize,
+ pe::IMAGE_COMDAT_SELECT_EXACT_MATCH => ComdatKind::ExactMatch,
+ pe::IMAGE_COMDAT_SELECT_LARGEST => ComdatKind::Largest,
+ pe::IMAGE_COMDAT_SELECT_NEWEST => ComdatKind::Newest,
+ _ => ComdatKind::Unknown,
+ }
+ }
+
+ #[inline]
+ fn symbol(&self) -> SymbolIndex {
+ self.symbol_index
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ // Find the name of first symbol referring to the section.
+ self.symbol.name(self.file.common.symbols.strings())
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ let bytes = self.name_bytes()?;
+ str::from_utf8(bytes)
+ .ok()
+ .read_error("Non UTF-8 COFF COMDAT name")
+ }
+
+ #[inline]
+ fn sections(&self) -> Self::SectionIterator {
+ CoffComdatSectionIterator {
+ file: self.file,
+ section_number: self.symbol.section_number(),
+ index: 0,
+ }
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of a `CoffBigFile`.
+pub type CoffBigComdatSectionIterator<'data, 'file, R = &'data [u8]> =
+ CoffComdatSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// An iterator over the sections in a COMDAT section group of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffComdatSectionIterator<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ file: &'file CoffFile<'data, R, Coff>,
+ section_number: i32,
+ index: usize,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffComdatSectionIterator<'data, 'file, R, Coff>
+{
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // Find associated COMDAT symbols.
+ // TODO: it seems gcc doesn't use associated symbols for this
+ loop {
+ let index = self.index;
+ let symbol = self.file.common.symbols.symbol(index).ok()?;
+ self.index += 1 + symbol.number_of_aux_symbols() as usize;
+
+ // Must be a section symbol.
+ if !symbol.has_aux_section() {
+ continue;
+ }
+
+ let section_number = symbol.section_number();
+
+ let aux = self.file.common.symbols.aux_section(index).ok()?;
+ if aux.selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE {
+ let number = if Coff::is_type_bigobj() {
+ u32::from(aux.number.get(LE)) | (u32::from(aux.high_number.get(LE)) << 16)
+ } else {
+ u32::from(aux.number.get(LE))
+ };
+ if number as i32 == self.section_number {
+ return Some(SectionIndex(section_number as usize));
+ }
+ } else if aux.selection != 0 {
+ if section_number == self.section_number {
+ return Some(SectionIndex(section_number as usize));
+ }
+ }
+ }
+ }
+}
diff --git a/third_party/rust/object/src/read/coff/file.rs b/third_party/rust/object/src/read/coff/file.rs
new file mode 100644
index 0000000000..4219f8f027
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/file.rs
@@ -0,0 +1,364 @@
+use alloc::vec::Vec;
+use core::fmt::Debug;
+
+use crate::read::{
+ self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, ObjectKind,
+ ObjectSection, ReadError, ReadRef, Result, SectionIndex, SymbolIndex,
+};
+use crate::{pe, LittleEndian as LE, Pod};
+
+use super::{
+ CoffComdat, CoffComdatIterator, CoffSection, CoffSectionIterator, CoffSegment,
+ CoffSegmentIterator, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, ImageSymbol,
+ SectionTable, SymbolTable,
+};
+
+/// The common parts of `PeFile` and `CoffFile`.
+#[derive(Debug)]
+pub(crate) struct CoffCommon<'data, R: ReadRef<'data>, Coff: CoffHeader = pe::ImageFileHeader> {
+ pub(crate) sections: SectionTable<'data>,
+ pub(crate) symbols: SymbolTable<'data, R, Coff>,
+ pub(crate) image_base: u64,
+}
+
+/// A COFF bigobj object file with 32-bit section numbers.
+pub type CoffBigFile<'data, R = &'data [u8]> = CoffFile<'data, R, pe::AnonObjectHeaderBigobj>;
+
+/// A COFF object file.
+#[derive(Debug)]
+pub struct CoffFile<'data, R: ReadRef<'data> = &'data [u8], Coff: CoffHeader = pe::ImageFileHeader>
+{
+ pub(super) header: &'data Coff,
+ pub(super) common: CoffCommon<'data, R, Coff>,
+ pub(super) data: R,
+}
+
+impl<'data, R: ReadRef<'data>, Coff: CoffHeader> CoffFile<'data, R, Coff> {
+ /// Parse the raw COFF file data.
+ pub fn parse(data: R) -> Result<Self> {
+ let mut offset = 0;
+ let header = Coff::parse(data, &mut offset)?;
+ let sections = header.sections(data, offset)?;
+ let symbols = header.symbols(data)?;
+
+ Ok(CoffFile {
+ header,
+ common: CoffCommon {
+ sections,
+ symbols,
+ image_base: 0,
+ },
+ data,
+ })
+ }
+}
+
+impl<'data, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
+ for CoffFile<'data, R, Coff>
+{
+}
+
+impl<'data, 'file, R, Coff> Object<'data, 'file> for CoffFile<'data, R, Coff>
+where
+ 'data: 'file,
+ R: 'file + ReadRef<'data>,
+ Coff: CoffHeader,
+{
+ type Segment = CoffSegment<'data, 'file, R, Coff>;
+ type SegmentIterator = CoffSegmentIterator<'data, 'file, R, Coff>;
+ type Section = CoffSection<'data, 'file, R, Coff>;
+ type SectionIterator = CoffSectionIterator<'data, 'file, R, Coff>;
+ type Comdat = CoffComdat<'data, 'file, R, Coff>;
+ type ComdatIterator = CoffComdatIterator<'data, 'file, R, Coff>;
+ type Symbol = CoffSymbol<'data, 'file, R, Coff>;
+ type SymbolIterator = CoffSymbolIterator<'data, 'file, R, Coff>;
+ type SymbolTable = CoffSymbolTable<'data, 'file, R, Coff>;
+ type DynamicRelocationIterator = NoDynamicRelocationIterator;
+
+ fn architecture(&self) -> Architecture {
+ match self.header.machine() {
+ pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm,
+ pe::IMAGE_FILE_MACHINE_ARM64 => Architecture::Aarch64,
+ pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
+ pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ // Windows COFF is always 32-bit, even for 64-bit architectures. This could be confusing.
+ false
+ }
+
+ fn kind(&self) -> ObjectKind {
+ ObjectKind::Relocatable
+ }
+
+ fn segments(&'file self) -> CoffSegmentIterator<'data, 'file, R, Coff> {
+ CoffSegmentIterator {
+ file: self,
+ iter: self.common.sections.iter(),
+ }
+ }
+
+ fn section_by_name_bytes(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<CoffSection<'data, 'file, R, Coff>> {
+ self.sections()
+ .find(|section| section.name_bytes() == Ok(section_name))
+ }
+
+ fn section_by_index(
+ &'file self,
+ index: SectionIndex,
+ ) -> Result<CoffSection<'data, 'file, R, Coff>> {
+ let section = self.common.sections.section(index.0)?;
+ Ok(CoffSection {
+ file: self,
+ index,
+ section,
+ })
+ }
+
+ fn sections(&'file self) -> CoffSectionIterator<'data, 'file, R, Coff> {
+ CoffSectionIterator {
+ file: self,
+ iter: self.common.sections.iter().enumerate(),
+ }
+ }
+
+ fn comdats(&'file self) -> CoffComdatIterator<'data, 'file, R, Coff> {
+ CoffComdatIterator {
+ file: self,
+ index: 0,
+ }
+ }
+
+ fn symbol_by_index(
+ &'file self,
+ index: SymbolIndex,
+ ) -> Result<CoffSymbol<'data, 'file, R, Coff>> {
+ let symbol = self.common.symbols.symbol(index.0)?;
+ Ok(CoffSymbol {
+ file: &self.common,
+ index,
+ symbol,
+ })
+ }
+
+ fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R, Coff> {
+ CoffSymbolIterator {
+ file: &self.common,
+ index: 0,
+ }
+ }
+
+ #[inline]
+ fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R, Coff>> {
+ Some(CoffSymbolTable { file: &self.common })
+ }
+
+ fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R, Coff> {
+ CoffSymbolIterator {
+ file: &self.common,
+ // Hack: don't return any.
+ index: self.common.symbols.len(),
+ }
+ }
+
+ #[inline]
+ fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R, Coff>> {
+ None
+ }
+
+ #[inline]
+ fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> {
+ None
+ }
+
+ #[inline]
+ fn imports(&self) -> Result<Vec<Import<'data>>> {
+ // TODO: this could return undefined symbols, but not needed yet.
+ Ok(Vec::new())
+ }
+
+ #[inline]
+ fn exports(&self) -> Result<Vec<Export<'data>>> {
+ // TODO: this could return global symbols, but not needed yet.
+ Ok(Vec::new())
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ self.section_by_name(".debug_info").is_some()
+ }
+
+ fn relative_address_base(&self) -> u64 {
+ 0
+ }
+
+ #[inline]
+ fn entry(&self) -> u64 {
+ 0
+ }
+
+ fn flags(&self) -> FileFlags {
+ FileFlags::Coff {
+ characteristics: self.header.characteristics(),
+ }
+ }
+}
+
+/// Read the `class_id` field from an anon object header.
+///
+/// This can be used to determine the format of the header.
+pub fn anon_object_class_id<'data, R: ReadRef<'data>>(data: R) -> Result<pe::ClsId> {
+ let header = data
+ .read_at::<pe::AnonObjectHeader>(0)
+ .read_error("Invalid anon object header size or alignment")?;
+ Ok(header.class_id)
+}
+
+/// A trait for generic access to `ImageFileHeader` and `AnonObjectHeaderBigobj`.
+#[allow(missing_docs)]
+pub trait CoffHeader: Debug + Pod {
+ type ImageSymbol: ImageSymbol;
+ type ImageSymbolBytes: Debug + Pod;
+
+ /// Return true if this type is `AnonObjectHeaderBigobj`.
+ ///
+ /// This is a property of the type, not a value in the header data.
+ fn is_type_bigobj() -> bool;
+
+ fn machine(&self) -> u16;
+ fn number_of_sections(&self) -> u32;
+ fn pointer_to_symbol_table(&self) -> u32;
+ fn number_of_symbols(&self) -> u32;
+ fn characteristics(&self) -> u16;
+
+ /// Read the file header.
+ ///
+ /// `data` must be the entire file data.
+ /// `offset` must be the file header offset. It is updated to point after the optional header,
+ /// which is where the section headers are located.
+ fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self>;
+
+ /// Read the section table.
+ ///
+ /// `data` must be the entire file data.
+ /// `offset` must be after the optional file header.
+ #[inline]
+ fn sections<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: u64,
+ ) -> read::Result<SectionTable<'data>> {
+ SectionTable::parse(self, data, offset)
+ }
+
+ /// Read the symbol table and string table.
+ ///
+ /// `data` must be the entire file data.
+ #[inline]
+ fn symbols<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ ) -> read::Result<SymbolTable<'data, R, Self>> {
+ SymbolTable::parse(self, data)
+ }
+}
+
+impl CoffHeader for pe::ImageFileHeader {
+ type ImageSymbol = pe::ImageSymbol;
+ type ImageSymbolBytes = pe::ImageSymbolBytes;
+
+ fn is_type_bigobj() -> bool {
+ false
+ }
+
+ fn machine(&self) -> u16 {
+ self.machine.get(LE)
+ }
+
+ fn number_of_sections(&self) -> u32 {
+ self.number_of_sections.get(LE).into()
+ }
+
+ fn pointer_to_symbol_table(&self) -> u32 {
+ self.pointer_to_symbol_table.get(LE)
+ }
+
+ fn number_of_symbols(&self) -> u32 {
+ self.number_of_symbols.get(LE)
+ }
+
+ fn characteristics(&self) -> u16 {
+ self.characteristics.get(LE)
+ }
+
+ fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
+ let header = data
+ .read::<pe::ImageFileHeader>(offset)
+ .read_error("Invalid COFF file header size or alignment")?;
+
+ // Skip over the optional header.
+ *offset = offset
+ .checked_add(header.size_of_optional_header.get(LE).into())
+ .read_error("Invalid COFF optional header size")?;
+
+ // TODO: maybe validate that the machine is known?
+ Ok(header)
+ }
+}
+
+impl CoffHeader for pe::AnonObjectHeaderBigobj {
+ type ImageSymbol = pe::ImageSymbolEx;
+ type ImageSymbolBytes = pe::ImageSymbolExBytes;
+
+ fn is_type_bigobj() -> bool {
+ true
+ }
+
+ fn machine(&self) -> u16 {
+ self.machine.get(LE)
+ }
+
+ fn number_of_sections(&self) -> u32 {
+ self.number_of_sections.get(LE)
+ }
+
+ fn pointer_to_symbol_table(&self) -> u32 {
+ self.pointer_to_symbol_table.get(LE)
+ }
+
+ fn number_of_symbols(&self) -> u32 {
+ self.number_of_symbols.get(LE)
+ }
+
+ fn characteristics(&self) -> u16 {
+ 0
+ }
+
+ fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
+ let header = data
+ .read::<pe::AnonObjectHeaderBigobj>(offset)
+ .read_error("Invalid COFF bigobj file header size or alignment")?;
+
+ if header.sig1.get(LE) != pe::IMAGE_FILE_MACHINE_UNKNOWN
+ || header.sig2.get(LE) != 0xffff
+ || header.version.get(LE) < 2
+ || header.class_id != pe::ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID
+ {
+ return Err(read::Error("Invalid COFF bigobj header values"));
+ }
+
+ // TODO: maybe validate that the machine is known?
+ Ok(header)
+ }
+}
diff --git a/third_party/rust/object/src/read/coff/import.rs b/third_party/rust/object/src/read/coff/import.rs
new file mode 100644
index 0000000000..d635e7592a
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/import.rs
@@ -0,0 +1,209 @@
+//! Support for reading short import files.
+//!
+//! These are used by some Windows linkers as a more compact way to describe
+//! dynamically imported symbols.
+
+use crate::read::{Architecture, Error, ReadError, ReadRef, Result};
+use crate::{pe, ByteString, Bytes, LittleEndian as LE};
+
+/// A Windows short form description of a symbol to import.
+///
+/// Used in Windows import libraries to provide a mapping from
+/// a symbol name to a DLL export. This is not an object file.
+#[derive(Debug, Clone)]
+pub struct ImportFile<'data> {
+ header: &'data pe::ImportObjectHeader,
+ kind: ImportType,
+ dll: ByteString<'data>,
+ symbol: ByteString<'data>,
+ import: Option<ByteString<'data>>,
+}
+
+impl<'data> ImportFile<'data> {
+ /// Parse it.
+ pub fn parse<R: ReadRef<'data>>(data: R) -> Result<Self> {
+ let mut offset = 0;
+ let header = pe::ImportObjectHeader::parse(data, &mut offset)?;
+ let data = header.parse_data(data, &mut offset)?;
+
+ // Unmangles a name by removing a `?`, `@` or `_` prefix.
+ fn strip_prefix(s: &[u8]) -> &[u8] {
+ match s.split_first() {
+ Some((b, rest)) if [b'?', b'@', b'_'].contains(b) => rest,
+ _ => s,
+ }
+ }
+ Ok(Self {
+ header,
+ dll: data.dll,
+ symbol: data.symbol,
+ kind: match header.import_type() {
+ pe::IMPORT_OBJECT_CODE => ImportType::Code,
+ pe::IMPORT_OBJECT_DATA => ImportType::Data,
+ pe::IMPORT_OBJECT_CONST => ImportType::Const,
+ _ => return Err(Error("Invalid COFF import library import type")),
+ },
+ import: match header.name_type() {
+ pe::IMPORT_OBJECT_ORDINAL => None,
+ pe::IMPORT_OBJECT_NAME => Some(data.symbol()),
+ pe::IMPORT_OBJECT_NAME_NO_PREFIX => Some(strip_prefix(data.symbol())),
+ pe::IMPORT_OBJECT_NAME_UNDECORATE => Some(
+ strip_prefix(data.symbol())
+ .split(|&b| b == b'@')
+ .next()
+ .unwrap(),
+ ),
+ pe::IMPORT_OBJECT_NAME_EXPORTAS => data.export(),
+ _ => return Err(Error("Unknown COFF import library name type")),
+ }
+ .map(ByteString),
+ })
+ }
+
+ /// Get the machine type.
+ pub fn architecture(&self) -> Architecture {
+ match self.header.machine.get(LE) {
+ pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm,
+ pe::IMAGE_FILE_MACHINE_ARM64 => Architecture::Aarch64,
+ pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
+ pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ /// The public symbol name.
+ pub fn symbol(&self) -> &'data [u8] {
+ self.symbol.0
+ }
+
+ /// The name of the DLL to import the symbol from.
+ pub fn dll(&self) -> &'data [u8] {
+ self.dll.0
+ }
+
+ /// The name exported from the DLL.
+ pub fn import(&self) -> ImportName<'data> {
+ match self.import {
+ Some(name) => ImportName::Name(name.0),
+ None => ImportName::Ordinal(self.header.ordinal_or_hint.get(LE)),
+ }
+ }
+
+ /// The type of import. Usually either a function or data.
+ pub fn import_type(&self) -> ImportType {
+ self.kind
+ }
+}
+
+/// The name or ordinal to import from a DLL.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ImportName<'data> {
+ /// Import by ordinal. Ordinarily this is a 1-based index.
+ Ordinal(u16),
+ /// Import by name.
+ Name(&'data [u8]),
+}
+
+/// The kind of import symbol.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ImportType {
+ /// An executable code symbol.
+ Code,
+ /// A data symbol.
+ Data,
+ /// A constant value.
+ Const,
+}
+
+impl pe::ImportObjectHeader {
+ /// Read the short import header.
+ ///
+ /// Also checks that the signature and version are valid.
+ /// Directly following this header will be the string data.
+ pub fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> Result<&'data Self> {
+ let header = data
+ .read::<pe::ImportObjectHeader>(offset)
+ .read_error("Invalid COFF import library header size")?;
+ if header.sig1.get(LE) != 0 || header.sig2.get(LE) != pe::IMPORT_OBJECT_HDR_SIG2 {
+ Err(Error("Invalid COFF import library header"))
+ } else if header.version.get(LE) != 0 {
+ Err(Error("Unknown COFF import library header version"))
+ } else {
+ Ok(header)
+ }
+ }
+
+ /// Parse the data following the header.
+ pub fn parse_data<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: &mut u64,
+ ) -> Result<ImportObjectData<'data>> {
+ let mut data = Bytes(
+ data.read_bytes(offset, u64::from(self.size_of_data.get(LE)))
+ .read_error("Invalid COFF import library data size")?,
+ );
+ let symbol = data
+ .read_string()
+ .map(ByteString)
+ .read_error("Could not read COFF import library symbol name")?;
+ let dll = data
+ .read_string()
+ .map(ByteString)
+ .read_error("Could not read COFF import library DLL name")?;
+ let export = if self.name_type() == pe::IMPORT_OBJECT_NAME_EXPORTAS {
+ data.read_string()
+ .map(ByteString)
+ .map(Some)
+ .read_error("Could not read COFF import library export name")?
+ } else {
+ None
+ };
+ Ok(ImportObjectData {
+ symbol,
+ dll,
+ export,
+ })
+ }
+
+ /// The type of import.
+ ///
+ /// This is one of the `IMPORT_OBJECT_*` constants.
+ pub fn import_type(&self) -> u16 {
+ self.name_type.get(LE) & pe::IMPORT_OBJECT_TYPE_MASK
+ }
+
+ /// The type of import name.
+ ///
+ /// This is one of the `IMPORT_OBJECT_*` constants.
+ pub fn name_type(&self) -> u16 {
+ (self.name_type.get(LE) >> pe::IMPORT_OBJECT_NAME_SHIFT) & pe::IMPORT_OBJECT_NAME_MASK
+ }
+}
+
+/// The data following `ImportObjectHeader`.
+#[derive(Debug, Clone)]
+pub struct ImportObjectData<'data> {
+ symbol: ByteString<'data>,
+ dll: ByteString<'data>,
+ export: Option<ByteString<'data>>,
+}
+
+impl<'data> ImportObjectData<'data> {
+ /// The public symbol name.
+ pub fn symbol(&self) -> &'data [u8] {
+ self.symbol.0
+ }
+
+ /// The name of the DLL to import the symbol from.
+ pub fn dll(&self) -> &'data [u8] {
+ self.dll.0
+ }
+
+ /// The name exported from the DLL.
+ ///
+ /// This is only set if the name is not derived from the symbol name.
+ pub fn export(&self) -> Option<&'data [u8]> {
+ self.export.map(|export| export.0)
+ }
+}
diff --git a/third_party/rust/object/src/read/coff/mod.rs b/third_party/rust/object/src/read/coff/mod.rs
new file mode 100644
index 0000000000..26020d7974
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/mod.rs
@@ -0,0 +1,21 @@
+//! Support for reading Windows COFF files.
+//!
+//! Provides `CoffFile` and related types which implement the `Object` trait.
+
+mod file;
+pub use file::*;
+
+mod section;
+pub use section::*;
+
+mod symbol;
+pub use symbol::*;
+
+mod relocation;
+pub use relocation::*;
+
+mod comdat;
+pub use comdat::*;
+
+mod import;
+pub use import::*;
diff --git a/third_party/rust/object/src/read/coff/relocation.rs b/third_party/rust/object/src/read/coff/relocation.rs
new file mode 100644
index 0000000000..44d2c68d06
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/relocation.rs
@@ -0,0 +1,104 @@
+use alloc::fmt;
+use core::slice;
+
+use crate::endian::LittleEndian as LE;
+use crate::pe;
+use crate::read::{
+ ReadRef, Relocation, RelocationEncoding, RelocationKind, RelocationTarget, SymbolIndex,
+};
+
+use super::{CoffFile, CoffHeader};
+
+/// An iterator over the relocations in a `CoffBigSection`.
+pub type CoffBigRelocationIterator<'data, 'file, R = &'data [u8]> =
+ CoffRelocationIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// An iterator over the relocations in a `CoffSection`.
+pub struct CoffRelocationIterator<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ pub(super) file: &'file CoffFile<'data, R, Coff>,
+ pub(super) iter: slice::Iter<'data, pe::ImageRelocation>,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffRelocationIterator<'data, 'file, R, Coff>
+{
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|relocation| {
+ let (kind, size, addend) = match self.file.header.machine() {
+ pe::IMAGE_FILE_MACHINE_ARMNT => match relocation.typ.get(LE) {
+ pe::IMAGE_REL_ARM_ADDR32 => (RelocationKind::Absolute, 32, 0),
+ pe::IMAGE_REL_ARM_ADDR32NB => (RelocationKind::ImageOffset, 32, 0),
+ pe::IMAGE_REL_ARM_REL32 => (RelocationKind::Relative, 32, -4),
+ pe::IMAGE_REL_ARM_SECTION => (RelocationKind::SectionIndex, 16, 0),
+ pe::IMAGE_REL_ARM_SECREL => (RelocationKind::SectionOffset, 32, 0),
+ typ => (RelocationKind::Coff(typ), 0, 0),
+ },
+ pe::IMAGE_FILE_MACHINE_ARM64 => match relocation.typ.get(LE) {
+ pe::IMAGE_REL_ARM64_ADDR32 => (RelocationKind::Absolute, 32, 0),
+ pe::IMAGE_REL_ARM64_ADDR32NB => (RelocationKind::ImageOffset, 32, 0),
+ pe::IMAGE_REL_ARM64_SECREL => (RelocationKind::SectionOffset, 32, 0),
+ pe::IMAGE_REL_ARM64_SECTION => (RelocationKind::SectionIndex, 16, 0),
+ pe::IMAGE_REL_ARM64_ADDR64 => (RelocationKind::Absolute, 64, 0),
+ pe::IMAGE_REL_ARM64_REL32 => (RelocationKind::Relative, 32, -4),
+ typ => (RelocationKind::Coff(typ), 0, 0),
+ },
+ pe::IMAGE_FILE_MACHINE_I386 => match relocation.typ.get(LE) {
+ pe::IMAGE_REL_I386_DIR16 => (RelocationKind::Absolute, 16, 0),
+ pe::IMAGE_REL_I386_REL16 => (RelocationKind::Relative, 16, 0),
+ pe::IMAGE_REL_I386_DIR32 => (RelocationKind::Absolute, 32, 0),
+ pe::IMAGE_REL_I386_DIR32NB => (RelocationKind::ImageOffset, 32, 0),
+ pe::IMAGE_REL_I386_SECTION => (RelocationKind::SectionIndex, 16, 0),
+ pe::IMAGE_REL_I386_SECREL => (RelocationKind::SectionOffset, 32, 0),
+ pe::IMAGE_REL_I386_SECREL7 => (RelocationKind::SectionOffset, 7, 0),
+ pe::IMAGE_REL_I386_REL32 => (RelocationKind::Relative, 32, -4),
+ typ => (RelocationKind::Coff(typ), 0, 0),
+ },
+ pe::IMAGE_FILE_MACHINE_AMD64 => match relocation.typ.get(LE) {
+ pe::IMAGE_REL_AMD64_ADDR64 => (RelocationKind::Absolute, 64, 0),
+ pe::IMAGE_REL_AMD64_ADDR32 => (RelocationKind::Absolute, 32, 0),
+ pe::IMAGE_REL_AMD64_ADDR32NB => (RelocationKind::ImageOffset, 32, 0),
+ pe::IMAGE_REL_AMD64_REL32 => (RelocationKind::Relative, 32, -4),
+ pe::IMAGE_REL_AMD64_REL32_1 => (RelocationKind::Relative, 32, -5),
+ pe::IMAGE_REL_AMD64_REL32_2 => (RelocationKind::Relative, 32, -6),
+ pe::IMAGE_REL_AMD64_REL32_3 => (RelocationKind::Relative, 32, -7),
+ pe::IMAGE_REL_AMD64_REL32_4 => (RelocationKind::Relative, 32, -8),
+ pe::IMAGE_REL_AMD64_REL32_5 => (RelocationKind::Relative, 32, -9),
+ pe::IMAGE_REL_AMD64_SECTION => (RelocationKind::SectionIndex, 16, 0),
+ pe::IMAGE_REL_AMD64_SECREL => (RelocationKind::SectionOffset, 32, 0),
+ pe::IMAGE_REL_AMD64_SECREL7 => (RelocationKind::SectionOffset, 7, 0),
+ typ => (RelocationKind::Coff(typ), 0, 0),
+ },
+ _ => (RelocationKind::Coff(relocation.typ.get(LE)), 0, 0),
+ };
+ let target = RelocationTarget::Symbol(SymbolIndex(
+ relocation.symbol_table_index.get(LE) as usize,
+ ));
+ (
+ u64::from(relocation.virtual_address.get(LE)),
+ Relocation {
+ kind,
+ encoding: RelocationEncoding::Generic,
+ size,
+ target,
+ addend,
+ implicit_addend: true,
+ },
+ )
+ })
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> fmt::Debug
+ for CoffRelocationIterator<'data, 'file, R, Coff>
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("CoffRelocationIterator").finish()
+ }
+}
diff --git a/third_party/rust/object/src/read/coff/section.rs b/third_party/rust/object/src/read/coff/section.rs
new file mode 100644
index 0000000000..75804034b8
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/section.rs
@@ -0,0 +1,574 @@
+use core::convert::TryFrom;
+use core::{iter, result, slice, str};
+
+use crate::endian::LittleEndian as LE;
+use crate::pe;
+use crate::read::util::StringTable;
+use crate::read::{
+ self, CompressedData, CompressedFileRange, Error, ObjectSection, ObjectSegment, ReadError,
+ ReadRef, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
+};
+
+use super::{CoffFile, CoffHeader, CoffRelocationIterator};
+
+/// The table of section headers in a COFF or PE file.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct SectionTable<'data> {
+ sections: &'data [pe::ImageSectionHeader],
+}
+
+impl<'data> SectionTable<'data> {
+ /// Parse the section table.
+ ///
+ /// `data` must be the entire file data.
+ /// `offset` must be after the optional file header.
+ pub fn parse<Coff: CoffHeader, R: ReadRef<'data>>(
+ header: &Coff,
+ data: R,
+ offset: u64,
+ ) -> Result<Self> {
+ let sections = data
+ .read_slice_at(offset, header.number_of_sections() as usize)
+ .read_error("Invalid COFF/PE section headers")?;
+ Ok(SectionTable { sections })
+ }
+
+ /// Iterate over the section headers.
+ ///
+ /// Warning: sections indices start at 1.
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'data, pe::ImageSectionHeader> {
+ self.sections.iter()
+ }
+
+ /// Return true if the section table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.sections.is_empty()
+ }
+
+ /// The number of section headers.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.sections.len()
+ }
+
+ /// Return the section header at the given index.
+ ///
+ /// The index is 1-based.
+ pub fn section(&self, index: usize) -> read::Result<&'data pe::ImageSectionHeader> {
+ self.sections
+ .get(index.wrapping_sub(1))
+ .read_error("Invalid COFF/PE section index")
+ }
+
+ /// Return the section header with the given name.
+ ///
+ /// The returned index is 1-based.
+ ///
+ /// Ignores sections with invalid names.
+ pub fn section_by_name<R: ReadRef<'data>>(
+ &self,
+ strings: StringTable<'data, R>,
+ name: &[u8],
+ ) -> Option<(usize, &'data pe::ImageSectionHeader)> {
+ self.sections
+ .iter()
+ .enumerate()
+ .find(|(_, section)| section.name(strings) == Ok(name))
+ .map(|(index, section)| (index + 1, section))
+ }
+
+ /// Compute the maximum file offset used by sections.
+ ///
+ /// This will usually match the end of file, unless the PE file has a
+ /// [data overlay](https://security.stackexchange.com/questions/77336/how-is-the-file-overlay-read-by-an-exe-virus)
+ pub fn max_section_file_offset(&self) -> u64 {
+ let mut max = 0;
+ for section in self.iter() {
+ match (section.pointer_to_raw_data.get(LE) as u64)
+ .checked_add(section.size_of_raw_data.get(LE) as u64)
+ {
+ None => {
+ // This cannot happen, we're suming two u32 into a u64
+ continue;
+ }
+ Some(end_of_section) => {
+ if end_of_section > max {
+ max = end_of_section;
+ }
+ }
+ }
+ }
+ max
+ }
+}
+
+/// An iterator over the loadable sections of a `CoffBigFile`.
+pub type CoffBigSegmentIterator<'data, 'file, R = &'data [u8]> =
+ CoffSegmentIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// An iterator over the loadable sections of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSegmentIterator<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ pub(super) file: &'file CoffFile<'data, R, Coff>,
+ pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffSegmentIterator<'data, 'file, R, Coff>
+{
+ type Item = CoffSegment<'data, 'file, R, Coff>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|section| CoffSegment {
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A loadable section of a `CoffBigFile`.
+pub type CoffBigSegment<'data, 'file, R = &'data [u8]> =
+ CoffSegment<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// A loadable section of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSegment<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ pub(super) file: &'file CoffFile<'data, R, Coff>,
+ pub(super) section: &'data pe::ImageSectionHeader,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffSegment<'data, 'file, R, Coff> {
+ fn bytes(&self) -> Result<&'data [u8]> {
+ self.section
+ .coff_data(self.file.data)
+ .read_error("Invalid COFF section offset or size")
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
+ for CoffSegment<'data, 'file, R, Coff>
+{
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSegment<'data>
+ for CoffSegment<'data, 'file, R, Coff>
+{
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address.get(LE))
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ u64::from(self.section.virtual_size.get(LE))
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.section.coff_alignment()
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ let (offset, size) = self.section.coff_file_range().unwrap_or((0, 0));
+ (u64::from(offset), u64::from(size))
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<Option<&[u8]>> {
+ self.section
+ .name(self.file.common.symbols.strings())
+ .map(Some)
+ }
+
+ #[inline]
+ fn name(&self) -> Result<Option<&str>> {
+ let name = self.section.name(self.file.common.symbols.strings())?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 COFF section name")
+ .map(Some)
+ }
+
+ #[inline]
+ fn flags(&self) -> SegmentFlags {
+ let characteristics = self.section.characteristics.get(LE);
+ SegmentFlags::Coff { characteristics }
+ }
+}
+
+/// An iterator over the sections of a `CoffBigFile`.
+pub type CoffBigSectionIterator<'data, 'file, R = &'data [u8]> =
+ CoffSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// An iterator over the sections of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSectionIterator<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ pub(super) file: &'file CoffFile<'data, R, Coff>,
+ pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffSectionIterator<'data, 'file, R, Coff>
+{
+ type Item = CoffSection<'data, 'file, R, Coff>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| CoffSection {
+ file: self.file,
+ index: SectionIndex(index + 1),
+ section,
+ })
+ }
+}
+
+/// A section of a `CoffBigFile`.
+pub type CoffBigSection<'data, 'file, R = &'data [u8]> =
+ CoffSection<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// A section of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffSection<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ pub(super) file: &'file CoffFile<'data, R, Coff>,
+ pub(super) index: SectionIndex,
+ pub(super) section: &'data pe::ImageSectionHeader,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffSection<'data, 'file, R, Coff> {
+ fn bytes(&self) -> Result<&'data [u8]> {
+ self.section
+ .coff_data(self.file.data)
+ .read_error("Invalid COFF section offset or size")
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
+ for CoffSection<'data, 'file, R, Coff>
+{
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSection<'data>
+ for CoffSection<'data, 'file, R, Coff>
+{
+ type RelocationIterator = CoffRelocationIterator<'data, 'file, R, Coff>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address.get(LE))
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ // TODO: This may need to be the length from the auxiliary symbol for this section.
+ u64::from(self.section.size_of_raw_data.get(LE))
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.section.coff_alignment()
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ let (offset, size) = self.section.coff_file_range()?;
+ Some((u64::from(offset), u64::from(size)))
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ #[inline]
+ fn compressed_file_range(&self) -> Result<CompressedFileRange> {
+ Ok(CompressedFileRange::none(self.file_range()))
+ }
+
+ #[inline]
+ fn compressed_data(&self) -> Result<CompressedData<'data>> {
+ self.data().map(CompressedData::none)
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ self.section.name(self.file.common.symbols.strings())
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 COFF section name")
+ }
+
+ #[inline]
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Result<Option<&str>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn kind(&self) -> SectionKind {
+ self.section.kind()
+ }
+
+ fn relocations(&self) -> CoffRelocationIterator<'data, 'file, R, Coff> {
+ let relocations = self.section.coff_relocations(self.file.data).unwrap_or(&[]);
+ CoffRelocationIterator {
+ file: self.file,
+ iter: relocations.iter(),
+ }
+ }
+
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::Coff {
+ characteristics: self.section.characteristics.get(LE),
+ }
+ }
+}
+
+impl pe::ImageSectionHeader {
+ pub(crate) fn kind(&self) -> SectionKind {
+ let characteristics = self.characteristics.get(LE);
+ if characteristics & (pe::IMAGE_SCN_CNT_CODE | pe::IMAGE_SCN_MEM_EXECUTE) != 0 {
+ SectionKind::Text
+ } else if characteristics & pe::IMAGE_SCN_CNT_INITIALIZED_DATA != 0 {
+ if characteristics & pe::IMAGE_SCN_MEM_DISCARDABLE != 0 {
+ SectionKind::Other
+ } else if characteristics & pe::IMAGE_SCN_MEM_WRITE != 0 {
+ SectionKind::Data
+ } else {
+ SectionKind::ReadOnlyData
+ }
+ } else if characteristics & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 {
+ SectionKind::UninitializedData
+ } else if characteristics & pe::IMAGE_SCN_LNK_INFO != 0 {
+ SectionKind::Linker
+ } else {
+ SectionKind::Unknown
+ }
+ }
+}
+
+impl pe::ImageSectionHeader {
+ /// Return the string table offset of the section name.
+ ///
+ /// Returns `Ok(None)` if the name doesn't use the string table
+ /// and can be obtained with `raw_name` instead.
+ pub fn name_offset(&self) -> Result<Option<u32>> {
+ let bytes = &self.name;
+ if bytes[0] != b'/' {
+ return Ok(None);
+ }
+
+ if bytes[1] == b'/' {
+ let mut offset = 0;
+ for byte in bytes[2..].iter() {
+ let digit = match byte {
+ b'A'..=b'Z' => byte - b'A',
+ b'a'..=b'z' => byte - b'a' + 26,
+ b'0'..=b'9' => byte - b'0' + 52,
+ b'+' => 62,
+ b'/' => 63,
+ _ => return Err(Error("Invalid COFF section name base-64 offset")),
+ };
+ offset = offset * 64 + digit as u64;
+ }
+ u32::try_from(offset)
+ .ok()
+ .read_error("Invalid COFF section name base-64 offset")
+ .map(Some)
+ } else {
+ let mut offset = 0;
+ for byte in bytes[1..].iter() {
+ let digit = match byte {
+ b'0'..=b'9' => byte - b'0',
+ 0 => break,
+ _ => return Err(Error("Invalid COFF section name base-10 offset")),
+ };
+ offset = offset * 10 + digit as u32;
+ }
+ Ok(Some(offset))
+ }
+ }
+
+ /// Return the section name.
+ ///
+ /// This handles decoding names that are offsets into the symbol string table.
+ pub fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ if let Some(offset) = self.name_offset()? {
+ strings
+ .get(offset)
+ .read_error("Invalid COFF section name offset")
+ } else {
+ Ok(self.raw_name())
+ }
+ }
+
+ /// Return the raw section name.
+ pub fn raw_name(&self) -> &[u8] {
+ let bytes = &self.name;
+ match memchr::memchr(b'\0', bytes) {
+ Some(end) => &bytes[..end],
+ None => &bytes[..],
+ }
+ }
+
+ /// Return the offset and size of the section in a COFF file.
+ ///
+ /// Returns `None` for sections that have no data in the file.
+ pub fn coff_file_range(&self) -> Option<(u32, u32)> {
+ if self.characteristics.get(LE) & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 {
+ None
+ } else {
+ let offset = self.pointer_to_raw_data.get(LE);
+ // Note: virtual size is not used for COFF.
+ let size = self.size_of_raw_data.get(LE);
+ Some((offset, size))
+ }
+ }
+
+ /// Return the section data in a COFF file.
+ ///
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values.
+ pub fn coff_data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> {
+ if let Some((offset, size)) = self.coff_file_range() {
+ data.read_bytes_at(offset.into(), size.into())
+ } else {
+ Ok(&[])
+ }
+ }
+
+ /// Return the section alignment in bytes.
+ ///
+ /// This is only valid for sections in a COFF file.
+ pub fn coff_alignment(&self) -> u64 {
+ match self.characteristics.get(LE) & pe::IMAGE_SCN_ALIGN_MASK {
+ pe::IMAGE_SCN_ALIGN_1BYTES => 1,
+ pe::IMAGE_SCN_ALIGN_2BYTES => 2,
+ pe::IMAGE_SCN_ALIGN_4BYTES => 4,
+ pe::IMAGE_SCN_ALIGN_8BYTES => 8,
+ pe::IMAGE_SCN_ALIGN_16BYTES => 16,
+ pe::IMAGE_SCN_ALIGN_32BYTES => 32,
+ pe::IMAGE_SCN_ALIGN_64BYTES => 64,
+ pe::IMAGE_SCN_ALIGN_128BYTES => 128,
+ pe::IMAGE_SCN_ALIGN_256BYTES => 256,
+ pe::IMAGE_SCN_ALIGN_512BYTES => 512,
+ pe::IMAGE_SCN_ALIGN_1024BYTES => 1024,
+ pe::IMAGE_SCN_ALIGN_2048BYTES => 2048,
+ pe::IMAGE_SCN_ALIGN_4096BYTES => 4096,
+ pe::IMAGE_SCN_ALIGN_8192BYTES => 8192,
+ _ => 16,
+ }
+ }
+
+ /// Read the relocations in a COFF file.
+ ///
+ /// `data` must be the entire file data.
+ pub fn coff_relocations<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ ) -> read::Result<&'data [pe::ImageRelocation]> {
+ let mut pointer = self.pointer_to_relocations.get(LE).into();
+ let mut number: usize = self.number_of_relocations.get(LE).into();
+ if number == core::u16::MAX.into()
+ && self.characteristics.get(LE) & pe::IMAGE_SCN_LNK_NRELOC_OVFL != 0
+ {
+ // Extended relocations. Read first relocation (which contains extended count) & adjust
+ // relocations pointer.
+ let extended_relocation_info = data
+ .read_at::<pe::ImageRelocation>(pointer)
+ .read_error("Invalid COFF relocation offset or number")?;
+ number = extended_relocation_info.virtual_address.get(LE) as usize;
+ if number == 0 {
+ return Err(Error("Invalid COFF relocation number"));
+ }
+ pointer += core::mem::size_of::<pe::ImageRelocation>() as u64;
+ // Extended relocation info does not contribute to the count of sections.
+ number -= 1;
+ }
+ data.read_slice_at(pointer, number)
+ .read_error("Invalid COFF relocation offset or number")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn name_offset() {
+ let mut section = pe::ImageSectionHeader::default();
+ section.name = *b"xxxxxxxx";
+ assert_eq!(section.name_offset(), Ok(None));
+ section.name = *b"/0\0\0\0\0\0\0";
+ assert_eq!(section.name_offset(), Ok(Some(0)));
+ section.name = *b"/9999999";
+ assert_eq!(section.name_offset(), Ok(Some(999_9999)));
+ section.name = *b"//AAAAAA";
+ assert_eq!(section.name_offset(), Ok(Some(0)));
+ section.name = *b"//D/////";
+ assert_eq!(section.name_offset(), Ok(Some(0xffff_ffff)));
+ section.name = *b"//EAAAAA";
+ assert!(section.name_offset().is_err());
+ section.name = *b"////////";
+ assert!(section.name_offset().is_err());
+ }
+}
diff --git a/third_party/rust/object/src/read/coff/symbol.rs b/third_party/rust/object/src/read/coff/symbol.rs
new file mode 100644
index 0000000000..e95468d7eb
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/symbol.rs
@@ -0,0 +1,626 @@
+use alloc::fmt;
+use alloc::vec::Vec;
+use core::convert::TryInto;
+use core::fmt::Debug;
+use core::str;
+
+use super::{CoffCommon, CoffHeader, SectionTable};
+use crate::endian::{LittleEndian as LE, U32Bytes};
+use crate::pe;
+use crate::pod::{bytes_of, bytes_of_slice, Pod};
+use crate::read::util::StringTable;
+use crate::read::{
+ self, Bytes, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex,
+ SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection,
+};
+
+/// A table of symbol entries in a COFF or PE file.
+///
+/// Also includes the string table used for the symbol names.
+#[derive(Debug)]
+pub struct SymbolTable<'data, R = &'data [u8], Coff = pe::ImageFileHeader>
+where
+ R: ReadRef<'data>,
+ Coff: CoffHeader,
+{
+ symbols: &'data [Coff::ImageSymbolBytes],
+ strings: StringTable<'data, R>,
+}
+
+impl<'data, R: ReadRef<'data>, Coff: CoffHeader> Default for SymbolTable<'data, R, Coff> {
+ fn default() -> Self {
+ Self {
+ symbols: &[],
+ strings: StringTable::default(),
+ }
+ }
+}
+
+impl<'data, R: ReadRef<'data>, Coff: CoffHeader> SymbolTable<'data, R, Coff> {
+ /// Read the symbol table.
+ pub fn parse(header: &Coff, data: R) -> Result<Self> {
+ // The symbol table may not be present.
+ let mut offset = header.pointer_to_symbol_table().into();
+ let (symbols, strings) = if offset != 0 {
+ let symbols = data
+ .read_slice(&mut offset, header.number_of_symbols() as usize)
+ .read_error("Invalid COFF symbol table offset or size")?;
+
+ // Note: don't update data when reading length; the length includes itself.
+ let length = data
+ .read_at::<U32Bytes<_>>(offset)
+ .read_error("Missing COFF string table")?
+ .get(LE);
+ let str_end = offset
+ .checked_add(length as u64)
+ .read_error("Invalid COFF string table length")?;
+ let strings = StringTable::new(data, offset, str_end);
+
+ (symbols, strings)
+ } else {
+ (&[][..], StringTable::default())
+ };
+
+ Ok(SymbolTable { symbols, strings })
+ }
+
+ /// Return the string table used for the symbol names.
+ #[inline]
+ pub fn strings(&self) -> StringTable<'data, R> {
+ self.strings
+ }
+
+ /// Return true if the symbol table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.symbols.is_empty()
+ }
+
+ /// The number of symbol table entries.
+ ///
+ /// This includes auxiliary symbol table entries.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.symbols.len()
+ }
+
+ /// Iterate over the symbols.
+ #[inline]
+ pub fn iter<'table>(&'table self) -> SymbolIterator<'data, 'table, R, Coff> {
+ SymbolIterator {
+ symbols: self,
+ index: 0,
+ }
+ }
+
+ /// Return the symbol table entry at the given index.
+ #[inline]
+ pub fn symbol(&self, index: usize) -> Result<&'data Coff::ImageSymbol> {
+ self.get::<Coff::ImageSymbol>(index, 0)
+ }
+
+ /// Return the auxiliary function symbol for the symbol table entry at the given index.
+ ///
+ /// Note that the index is of the symbol, not the first auxiliary record.
+ #[inline]
+ pub fn aux_function(&self, index: usize) -> Result<&'data pe::ImageAuxSymbolFunction> {
+ self.get::<pe::ImageAuxSymbolFunction>(index, 1)
+ }
+
+ /// Return the auxiliary section symbol for the symbol table entry at the given index.
+ ///
+ /// Note that the index is of the symbol, not the first auxiliary record.
+ #[inline]
+ pub fn aux_section(&self, index: usize) -> Result<&'data pe::ImageAuxSymbolSection> {
+ self.get::<pe::ImageAuxSymbolSection>(index, 1)
+ }
+
+ /// Return the auxiliary file name for the symbol table entry at the given index.
+ ///
+ /// Note that the index is of the symbol, not the first auxiliary record.
+ pub fn aux_file_name(&self, index: usize, aux_count: u8) -> Result<&'data [u8]> {
+ let entries = index
+ .checked_add(1)
+ .and_then(|x| Some(x..x.checked_add(aux_count.into())?))
+ .and_then(|x| self.symbols.get(x))
+ .read_error("Invalid COFF symbol index")?;
+ let bytes = bytes_of_slice(entries);
+ // The name is padded with nulls.
+ Ok(match memchr::memchr(b'\0', bytes) {
+ Some(end) => &bytes[..end],
+ None => bytes,
+ })
+ }
+
+ /// Return the symbol table entry or auxiliary record at the given index and offset.
+ pub fn get<T: Pod>(&self, index: usize, offset: usize) -> Result<&'data T> {
+ let bytes = index
+ .checked_add(offset)
+ .and_then(|x| self.symbols.get(x))
+ .read_error("Invalid COFF symbol index")?;
+ Bytes(bytes_of(bytes))
+ .read()
+ .read_error("Invalid COFF symbol data")
+ }
+
+ /// Construct a map from addresses to a user-defined map entry.
+ pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Coff::ImageSymbol) -> Option<Entry>>(
+ &self,
+ f: F,
+ ) -> SymbolMap<Entry> {
+ let mut symbols = Vec::with_capacity(self.symbols.len());
+ for (_, symbol) in self.iter() {
+ if !symbol.is_definition() {
+ continue;
+ }
+ if let Some(entry) = f(symbol) {
+ symbols.push(entry);
+ }
+ }
+ SymbolMap::new(symbols)
+ }
+}
+
+/// An iterator for symbol entries in a COFF or PE file.
+///
+/// Yields the index and symbol structure for each symbol.
+#[derive(Debug)]
+pub struct SymbolIterator<'data, 'table, R = &'data [u8], Coff = pe::ImageFileHeader>
+where
+ R: ReadRef<'data>,
+ Coff: CoffHeader,
+{
+ symbols: &'table SymbolTable<'data, R, Coff>,
+ index: usize,
+}
+
+impl<'data, 'table, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for SymbolIterator<'data, 'table, R, Coff>
+{
+ type Item = (usize, &'data Coff::ImageSymbol);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let index = self.index;
+ let symbol = self.symbols.symbol(index).ok()?;
+ self.index += 1 + symbol.number_of_aux_symbols() as usize;
+ Some((index, symbol))
+ }
+}
+
+/// A symbol table of a `CoffBigFile`.
+pub type CoffBigSymbolTable<'data, 'file, R = &'data [u8]> =
+ CoffSymbolTable<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// A symbol table of a `CoffFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct CoffSymbolTable<'data, 'file, R = &'data [u8], Coff = pe::ImageFileHeader>
+where
+ R: ReadRef<'data>,
+ Coff: CoffHeader,
+{
+ pub(crate) file: &'file CoffCommon<'data, R, Coff>,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
+ for CoffSymbolTable<'data, 'file, R, Coff>
+{
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbolTable<'data>
+ for CoffSymbolTable<'data, 'file, R, Coff>
+{
+ type Symbol = CoffSymbol<'data, 'file, R, Coff>;
+ type SymbolIterator = CoffSymbolIterator<'data, 'file, R, Coff>;
+
+ fn symbols(&self) -> Self::SymbolIterator {
+ CoffSymbolIterator {
+ file: self.file,
+ index: 0,
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> {
+ let symbol = self.file.symbols.symbol(index.0)?;
+ Ok(CoffSymbol {
+ file: self.file,
+ index,
+ symbol,
+ })
+ }
+}
+
+/// An iterator over the symbols of a `CoffBigFile`.
+pub type CoffBigSymbolIterator<'data, 'file, R = &'data [u8]> =
+ CoffSymbolIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// An iterator over the symbols of a `CoffFile`.
+pub struct CoffSymbolIterator<'data, 'file, R = &'data [u8], Coff = pe::ImageFileHeader>
+where
+ R: ReadRef<'data>,
+ Coff: CoffHeader,
+{
+ pub(crate) file: &'file CoffCommon<'data, R, Coff>,
+ pub(crate) index: usize,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> fmt::Debug
+ for CoffSymbolIterator<'data, 'file, R, Coff>
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("CoffSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffSymbolIterator<'data, 'file, R, Coff>
+{
+ type Item = CoffSymbol<'data, 'file, R, Coff>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let index = self.index;
+ let symbol = self.file.symbols.symbol(index).ok()?;
+ self.index += 1 + symbol.number_of_aux_symbols() as usize;
+ Some(CoffSymbol {
+ file: self.file,
+ index: SymbolIndex(index),
+ symbol,
+ })
+ }
+}
+
+/// A symbol of a `CoffBigFile`.
+pub type CoffBigSymbol<'data, 'file, R = &'data [u8]> =
+ CoffSymbol<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// A symbol of a `CoffFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct CoffSymbol<'data, 'file, R = &'data [u8], Coff = pe::ImageFileHeader>
+where
+ R: ReadRef<'data>,
+ Coff: CoffHeader,
+{
+ pub(crate) file: &'file CoffCommon<'data, R, Coff>,
+ pub(crate) index: SymbolIndex,
+ pub(crate) symbol: &'data Coff::ImageSymbol,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffSymbol<'data, 'file, R, Coff> {
+ #[inline]
+ /// Get the raw `ImageSymbol` struct.
+ pub fn raw_symbol(&self) -> &'data Coff::ImageSymbol {
+ self.symbol
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
+ for CoffSymbol<'data, 'file, R, Coff>
+{
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbol<'data>
+ for CoffSymbol<'data, 'file, R, Coff>
+{
+ #[inline]
+ fn index(&self) -> SymbolIndex {
+ self.index
+ }
+
+ fn name_bytes(&self) -> read::Result<&'data [u8]> {
+ if self.symbol.has_aux_file_name() {
+ self.file
+ .symbols
+ .aux_file_name(self.index.0, self.symbol.number_of_aux_symbols())
+ } else {
+ self.symbol.name(self.file.symbols.strings())
+ }
+ }
+
+ fn name(&self) -> read::Result<&'data str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 COFF symbol name")
+ }
+
+ fn address(&self) -> u64 {
+ // Only return an address for storage classes that we know use an address.
+ match self.symbol.storage_class() {
+ pe::IMAGE_SYM_CLASS_STATIC
+ | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ | pe::IMAGE_SYM_CLASS_LABEL => {}
+ pe::IMAGE_SYM_CLASS_EXTERNAL => {
+ if self.symbol.section_number() == pe::IMAGE_SYM_UNDEFINED {
+ // Undefined or common data, neither of which have an address.
+ return 0;
+ }
+ }
+ _ => return 0,
+ }
+ self.symbol
+ .address(self.file.image_base, &self.file.sections)
+ .unwrap_or(0)
+ }
+
+ fn size(&self) -> u64 {
+ match self.symbol.storage_class() {
+ pe::IMAGE_SYM_CLASS_STATIC => {
+ // Section symbols may duplicate the size from the section table.
+ if self.symbol.has_aux_section() {
+ if let Ok(aux) = self.file.symbols.aux_section(self.index.0) {
+ u64::from(aux.length.get(LE))
+ } else {
+ 0
+ }
+ } else {
+ 0
+ }
+ }
+ pe::IMAGE_SYM_CLASS_EXTERNAL => {
+ if self.symbol.section_number() == pe::IMAGE_SYM_UNDEFINED {
+ // For undefined symbols, symbol.value is 0 and the size is 0.
+ // For common data, symbol.value is the size.
+ u64::from(self.symbol.value())
+ } else if self.symbol.has_aux_function() {
+ // Function symbols may have a size.
+ if let Ok(aux) = self.file.symbols.aux_function(self.index.0) {
+ u64::from(aux.total_size.get(LE))
+ } else {
+ 0
+ }
+ } else {
+ 0
+ }
+ }
+ // Most symbols don't have sizes.
+ _ => 0,
+ }
+ }
+
+ fn kind(&self) -> SymbolKind {
+ let derived_kind = if self.symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION {
+ SymbolKind::Text
+ } else {
+ SymbolKind::Data
+ };
+ match self.symbol.storage_class() {
+ pe::IMAGE_SYM_CLASS_STATIC => {
+ if self.symbol.value() == 0 && self.symbol.number_of_aux_symbols() > 0 {
+ SymbolKind::Section
+ } else {
+ derived_kind
+ }
+ }
+ pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => derived_kind,
+ pe::IMAGE_SYM_CLASS_SECTION => SymbolKind::Section,
+ pe::IMAGE_SYM_CLASS_FILE => SymbolKind::File,
+ pe::IMAGE_SYM_CLASS_LABEL => SymbolKind::Label,
+ _ => SymbolKind::Unknown,
+ }
+ }
+
+ fn section(&self) -> SymbolSection {
+ match self.symbol.section_number() {
+ pe::IMAGE_SYM_UNDEFINED => {
+ if self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_EXTERNAL
+ && self.symbol.value() == 0
+ {
+ SymbolSection::Undefined
+ } else {
+ SymbolSection::Common
+ }
+ }
+ pe::IMAGE_SYM_ABSOLUTE => SymbolSection::Absolute,
+ pe::IMAGE_SYM_DEBUG => {
+ if self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_FILE {
+ SymbolSection::None
+ } else {
+ SymbolSection::Unknown
+ }
+ }
+ index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)),
+ _ => SymbolSection::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_EXTERNAL
+ && self.symbol.section_number() == pe::IMAGE_SYM_UNDEFINED
+ && self.symbol.value() == 0
+ }
+
+ #[inline]
+ fn is_definition(&self) -> bool {
+ self.symbol.is_definition()
+ }
+
+ #[inline]
+ fn is_common(&self) -> bool {
+ self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_EXTERNAL
+ && self.symbol.section_number() == pe::IMAGE_SYM_UNDEFINED
+ && self.symbol.value() != 0
+ }
+
+ #[inline]
+ fn is_weak(&self) -> bool {
+ self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ }
+
+ #[inline]
+ fn scope(&self) -> SymbolScope {
+ match self.symbol.storage_class() {
+ pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => {
+ // TODO: determine if symbol is exported
+ SymbolScope::Linkage
+ }
+ _ => SymbolScope::Compilation,
+ }
+ }
+
+ #[inline]
+ fn is_global(&self) -> bool {
+ match self.symbol.storage_class() {
+ pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true,
+ _ => false,
+ }
+ }
+
+ #[inline]
+ fn is_local(&self) -> bool {
+ !self.is_global()
+ }
+
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
+ if self.symbol.has_aux_section() {
+ if let Ok(aux) = self.file.symbols.aux_section(self.index.0) {
+ let number = if Coff::is_type_bigobj() {
+ u32::from(aux.number.get(LE)) | (u32::from(aux.high_number.get(LE)) << 16)
+ } else {
+ u32::from(aux.number.get(LE))
+ };
+ return SymbolFlags::CoffSection {
+ selection: aux.selection,
+ associative_section: if number == 0 {
+ None
+ } else {
+ Some(SectionIndex(number as usize))
+ },
+ };
+ }
+ }
+ SymbolFlags::None
+ }
+}
+
+/// A trait for generic access to `ImageSymbol` and `ImageSymbolEx`.
+#[allow(missing_docs)]
+pub trait ImageSymbol: Debug + Pod {
+ fn raw_name(&self) -> &[u8; 8];
+ fn value(&self) -> u32;
+ fn section_number(&self) -> i32;
+ fn typ(&self) -> u16;
+ fn storage_class(&self) -> u8;
+ fn number_of_aux_symbols(&self) -> u8;
+
+ /// Parse a COFF symbol name.
+ ///
+ /// `strings` must be the string table used for symbol names.
+ fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ let name = self.raw_name();
+ if name[0] == 0 {
+ // If the name starts with 0 then the last 4 bytes are a string table offset.
+ let offset = u32::from_le_bytes(name[4..8].try_into().unwrap());
+ strings
+ .get(offset)
+ .read_error("Invalid COFF symbol name offset")
+ } else {
+ // The name is inline and padded with nulls.
+ Ok(match memchr::memchr(b'\0', name) {
+ Some(end) => &name[..end],
+ None => &name[..],
+ })
+ }
+ }
+
+ /// Return the symbol address.
+ ///
+ /// This takes into account the image base and the section address.
+ fn address(&self, image_base: u64, sections: &SectionTable<'_>) -> Result<u64> {
+ let section_number = self.section_number() as usize;
+ let section = sections.section(section_number)?;
+ let virtual_address = u64::from(section.virtual_address.get(LE));
+ let value = u64::from(self.value());
+ Ok(image_base + virtual_address + value)
+ }
+
+ /// Return true if the symbol is a definition of a function or data object.
+ fn is_definition(&self) -> bool {
+ let section_number = self.section_number();
+ if section_number == pe::IMAGE_SYM_UNDEFINED {
+ return false;
+ }
+ match self.storage_class() {
+ pe::IMAGE_SYM_CLASS_STATIC => {
+ // Exclude section symbols.
+ !(self.value() == 0 && self.number_of_aux_symbols() > 0)
+ }
+ pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true,
+ _ => false,
+ }
+ }
+
+ /// Return true if the symbol has an auxiliary file name.
+ fn has_aux_file_name(&self) -> bool {
+ self.number_of_aux_symbols() > 0 && self.storage_class() == pe::IMAGE_SYM_CLASS_FILE
+ }
+
+ /// Return true if the symbol has an auxiliary function symbol.
+ fn has_aux_function(&self) -> bool {
+ self.number_of_aux_symbols() > 0 && self.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION
+ }
+
+ /// Return true if the symbol has an auxiliary section symbol.
+ fn has_aux_section(&self) -> bool {
+ self.number_of_aux_symbols() > 0
+ && self.storage_class() == pe::IMAGE_SYM_CLASS_STATIC
+ && self.value() == 0
+ }
+
+ fn base_type(&self) -> u16 {
+ self.typ() & pe::N_BTMASK
+ }
+
+ fn derived_type(&self) -> u16 {
+ (self.typ() & pe::N_TMASK) >> pe::N_BTSHFT
+ }
+}
+
+impl ImageSymbol for pe::ImageSymbol {
+ fn raw_name(&self) -> &[u8; 8] {
+ &self.name
+ }
+ fn value(&self) -> u32 {
+ self.value.get(LE)
+ }
+ fn section_number(&self) -> i32 {
+ let section_number = self.section_number.get(LE);
+ if section_number >= pe::IMAGE_SYM_SECTION_MAX {
+ (section_number as i16) as i32
+ } else {
+ section_number as i32
+ }
+ }
+ fn typ(&self) -> u16 {
+ self.typ.get(LE)
+ }
+ fn storage_class(&self) -> u8 {
+ self.storage_class
+ }
+ fn number_of_aux_symbols(&self) -> u8 {
+ self.number_of_aux_symbols
+ }
+}
+
+impl ImageSymbol for pe::ImageSymbolEx {
+ fn raw_name(&self) -> &[u8; 8] {
+ &self.name
+ }
+ fn value(&self) -> u32 {
+ self.value.get(LE)
+ }
+ fn section_number(&self) -> i32 {
+ self.section_number.get(LE)
+ }
+ fn typ(&self) -> u16 {
+ self.typ.get(LE)
+ }
+ fn storage_class(&self) -> u8 {
+ self.storage_class
+ }
+ fn number_of_aux_symbols(&self) -> u8 {
+ self.number_of_aux_symbols
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/attributes.rs b/third_party/rust/object/src/read/elf/attributes.rs
new file mode 100644
index 0000000000..6ec535d724
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/attributes.rs
@@ -0,0 +1,303 @@
+use core::convert::TryInto;
+
+use crate::elf;
+use crate::endian;
+use crate::read::{Bytes, Error, ReadError, Result};
+
+use super::FileHeader;
+
+/// An ELF attributes section.
+///
+/// This may be a GNU attributes section, or an architecture specific attributes section.
+///
+/// An attributes section contains a series of subsections.
+#[derive(Debug, Clone)]
+pub struct AttributesSection<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ version: u8,
+ data: Bytes<'data>,
+}
+
+impl<'data, Elf: FileHeader> AttributesSection<'data, Elf> {
+ /// Parse an ELF attributes section given the section data.
+ pub fn new(endian: Elf::Endian, data: &'data [u8]) -> Result<Self> {
+ let mut data = Bytes(data);
+
+ // Skip the version field that is one byte long.
+ let version = *data
+ .read::<u8>()
+ .read_error("Invalid ELF attributes section offset or size")?;
+
+ Ok(AttributesSection {
+ endian,
+ version,
+ data,
+ })
+ }
+
+ /// Return the version of the attributes section.
+ pub fn version(&self) -> u8 {
+ self.version
+ }
+
+ /// Return an iterator over the subsections.
+ pub fn subsections(&self) -> Result<AttributesSubsectionIterator<'data, Elf>> {
+ // There is currently only one format version.
+ if self.version != b'A' {
+ return Err(Error("Unsupported ELF attributes section version"));
+ }
+
+ Ok(AttributesSubsectionIterator {
+ endian: self.endian,
+ data: self.data,
+ })
+ }
+}
+
+/// An iterator over the subsections in an ELF attributes section.
+#[derive(Debug, Clone)]
+pub struct AttributesSubsectionIterator<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ data: Bytes<'data>,
+}
+
+impl<'data, Elf: FileHeader> AttributesSubsectionIterator<'data, Elf> {
+ /// Return the next subsection.
+ pub fn next(&mut self) -> Result<Option<AttributesSubsection<'data, Elf>>> {
+ if self.data.is_empty() {
+ return Ok(None);
+ }
+
+ let result = self.parse();
+ if result.is_err() {
+ self.data = Bytes(&[]);
+ }
+ result
+ }
+
+ fn parse(&mut self) -> Result<Option<AttributesSubsection<'data, Elf>>> {
+ // First read the subsection length.
+ let mut data = self.data;
+ let length = data
+ .read::<endian::U32Bytes<Elf::Endian>>()
+ .read_error("ELF attributes section is too short")?
+ .get(self.endian);
+
+ // Now read the entire subsection, updating self.data.
+ let mut data = self
+ .data
+ .read_bytes(length as usize)
+ .read_error("Invalid ELF attributes subsection length")?;
+ // Skip the subsection length field.
+ data.skip(4)
+ .read_error("Invalid ELF attributes subsection length")?;
+
+ let vendor = data
+ .read_string()
+ .read_error("Invalid ELF attributes vendor")?;
+
+ Ok(Some(AttributesSubsection {
+ endian: self.endian,
+ length,
+ vendor,
+ data,
+ }))
+ }
+}
+
+/// A subsection in an ELF attributes section.
+///
+/// A subsection is identified by a vendor name. It contains a series of sub-subsections.
+#[derive(Debug, Clone)]
+pub struct AttributesSubsection<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ length: u32,
+ vendor: &'data [u8],
+ data: Bytes<'data>,
+}
+
+impl<'data, Elf: FileHeader> AttributesSubsection<'data, Elf> {
+ /// Return the length of the attributes subsection.
+ pub fn length(&self) -> u32 {
+ self.length
+ }
+
+ /// Return the vendor name of the attributes subsection.
+ pub fn vendor(&self) -> &'data [u8] {
+ self.vendor
+ }
+
+ /// Return an iterator over the sub-subsections.
+ pub fn subsubsections(&self) -> AttributesSubsubsectionIterator<'data, Elf> {
+ AttributesSubsubsectionIterator {
+ endian: self.endian,
+ data: self.data,
+ }
+ }
+}
+
+/// An iterator over the sub-subsections in an ELF attributes section.
+#[derive(Debug, Clone)]
+pub struct AttributesSubsubsectionIterator<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ data: Bytes<'data>,
+}
+
+impl<'data, Elf: FileHeader> AttributesSubsubsectionIterator<'data, Elf> {
+ /// Return the next sub-subsection.
+ pub fn next(&mut self) -> Result<Option<AttributesSubsubsection<'data>>> {
+ if self.data.is_empty() {
+ return Ok(None);
+ }
+
+ let result = self.parse();
+ if result.is_err() {
+ self.data = Bytes(&[]);
+ }
+ result
+ }
+
+ fn parse(&mut self) -> Result<Option<AttributesSubsubsection<'data>>> {
+ // The format of a sub-section looks like this:
+ //
+ // <file-tag> <size> <attribute>*
+ // | <section-tag> <size> <section-number>* 0 <attribute>*
+ // | <symbol-tag> <size> <symbol-number>* 0 <attribute>*
+ let mut data = self.data;
+ let tag = *data
+ .read::<u8>()
+ .read_error("ELF attributes subsection is too short")?;
+ let length = data
+ .read::<endian::U32Bytes<Elf::Endian>>()
+ .read_error("ELF attributes subsection is too short")?
+ .get(self.endian);
+
+ // Now read the entire sub-subsection, updating self.data.
+ let mut data = self
+ .data
+ .read_bytes(length as usize)
+ .read_error("Invalid ELF attributes sub-subsection length")?;
+ // Skip the tag and sub-subsection size field.
+ data.skip(1 + 4)
+ .read_error("Invalid ELF attributes sub-subsection length")?;
+
+ let indices = if tag == elf::Tag_Section || tag == elf::Tag_Symbol {
+ data.read_string()
+ .map(Bytes)
+ .read_error("Missing ELF attributes sub-subsection indices")?
+ } else if tag == elf::Tag_File {
+ Bytes(&[])
+ } else {
+ return Err(Error("Unimplemented ELF attributes sub-subsection tag"));
+ };
+
+ Ok(Some(AttributesSubsubsection {
+ tag,
+ length,
+ indices,
+ data,
+ }))
+ }
+}
+
+/// A sub-subsection in an ELF attributes section.
+///
+/// A sub-subsection is identified by a tag. It contains an optional series of indices,
+/// followed by a series of attributes.
+#[derive(Debug, Clone)]
+pub struct AttributesSubsubsection<'data> {
+ tag: u8,
+ length: u32,
+ indices: Bytes<'data>,
+ data: Bytes<'data>,
+}
+
+impl<'data> AttributesSubsubsection<'data> {
+ /// Return the tag of the attributes sub-subsection.
+ pub fn tag(&self) -> u8 {
+ self.tag
+ }
+
+ /// Return the length of the attributes sub-subsection.
+ pub fn length(&self) -> u32 {
+ self.length
+ }
+
+ /// Return the data containing the indices.
+ pub fn indices_data(&self) -> &'data [u8] {
+ self.indices.0
+ }
+
+ /// Return the indices.
+ ///
+ /// This will be section indices if the tag is `Tag_Section`,
+ /// or symbol indices if the tag is `Tag_Symbol`,
+ /// and otherwise it will be empty.
+ pub fn indices(&self) -> AttributeIndexIterator<'data> {
+ AttributeIndexIterator { data: self.indices }
+ }
+
+ /// Return the data containing the attributes.
+ pub fn attributes_data(&self) -> &'data [u8] {
+ self.data.0
+ }
+
+ /// Return a parser for the data containing the attributes.
+ pub fn attributes(&self) -> AttributeReader<'data> {
+ AttributeReader { data: self.data }
+ }
+}
+
+/// An iterator over the indices in a sub-subsection in an ELF attributes section.
+#[derive(Debug, Clone)]
+pub struct AttributeIndexIterator<'data> {
+ data: Bytes<'data>,
+}
+
+impl<'data> AttributeIndexIterator<'data> {
+ /// Parse the next index.
+ pub fn next(&mut self) -> Result<Option<u32>> {
+ if self.data.is_empty() {
+ return Ok(None);
+ }
+ let err = "Invalid ELF attribute index";
+ self.data
+ .read_uleb128()
+ .read_error(err)?
+ .try_into()
+ .map_err(|_| ())
+ .read_error(err)
+ .map(Some)
+ }
+}
+
+/// A parser for the attributes in a sub-subsection in an ELF attributes section.
+///
+/// The parser relies on the caller to know the format of the data for each attribute tag.
+#[derive(Debug, Clone)]
+pub struct AttributeReader<'data> {
+ data: Bytes<'data>,
+}
+
+impl<'data> AttributeReader<'data> {
+ /// Parse a tag.
+ pub fn read_tag(&mut self) -> Result<Option<u64>> {
+ if self.data.is_empty() {
+ return Ok(None);
+ }
+ let err = "Invalid ELF attribute tag";
+ self.data.read_uleb128().read_error(err).map(Some)
+ }
+
+ /// Parse an integer value.
+ pub fn read_integer(&mut self) -> Result<u64> {
+ let err = "Invalid ELF attribute integer value";
+ self.data.read_uleb128().read_error(err)
+ }
+
+ /// Parse a string value.
+ pub fn read_string(&mut self) -> Result<&'data [u8]> {
+ let err = "Invalid ELF attribute string value";
+ self.data.read_string().read_error(err)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/comdat.rs b/third_party/rust/object/src/read/elf/comdat.rs
new file mode 100644
index 0000000000..1a2f2f44a9
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/comdat.rs
@@ -0,0 +1,160 @@
+use core::fmt::Debug;
+use core::{iter, slice, str};
+
+use crate::elf;
+use crate::endian::{Endianness, U32Bytes};
+use crate::read::{self, ComdatKind, ObjectComdat, ReadError, ReadRef, SectionIndex, SymbolIndex};
+
+use super::{ElfFile, FileHeader, SectionHeader, Sym};
+
+/// An iterator over the COMDAT section groups of an `ElfFile32`.
+pub type ElfComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfComdatIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator over the COMDAT section groups of an `ElfFile64`.
+pub type ElfComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfComdatIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator over the COMDAT section groups of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfComdatIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) iter: iter::Enumerate<slice::Iter<'data, Elf::SectionHeader>>,
+}
+
+impl<'data, 'file, Elf, R> Iterator for ElfComdatIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = ElfComdat<'data, 'file, Elf, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ for (_index, section) in self.iter.by_ref() {
+ if let Some(comdat) = ElfComdat::parse(self.file, section) {
+ return Some(comdat);
+ }
+ }
+ None
+ }
+}
+
+/// A COMDAT section group of an `ElfFile32`.
+pub type ElfComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfComdat<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// A COMDAT section group of an `ElfFile64`.
+pub type ElfComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfComdat<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// A COMDAT section group of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfComdat<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ file: &'file ElfFile<'data, Elf, R>,
+ section: &'data Elf::SectionHeader,
+ sections: &'data [U32Bytes<Elf::Endian>],
+}
+
+impl<'data, 'file, Elf, R> ElfComdat<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn parse(
+ file: &'file ElfFile<'data, Elf, R>,
+ section: &'data Elf::SectionHeader,
+ ) -> Option<ElfComdat<'data, 'file, Elf, R>> {
+ let (flag, sections) = section.group(file.endian, file.data).ok()??;
+ if flag != elf::GRP_COMDAT {
+ return None;
+ }
+ Some(ElfComdat {
+ file,
+ section,
+ sections,
+ })
+ }
+}
+
+impl<'data, 'file, Elf, R> read::private::Sealed for ElfComdat<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Elf, R> ObjectComdat<'data> for ElfComdat<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type SectionIterator = ElfComdatSectionIterator<'data, 'file, Elf, R>;
+
+ #[inline]
+ fn kind(&self) -> ComdatKind {
+ ComdatKind::Any
+ }
+
+ #[inline]
+ fn symbol(&self) -> SymbolIndex {
+ SymbolIndex(self.section.sh_info(self.file.endian) as usize)
+ }
+
+ fn name_bytes(&self) -> read::Result<&[u8]> {
+ // FIXME: check sh_link
+ let index = self.section.sh_info(self.file.endian) as usize;
+ let symbol = self.file.symbols.symbol(index)?;
+ symbol.name(self.file.endian, self.file.symbols.strings())
+ }
+
+ fn name(&self) -> read::Result<&str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 ELF COMDAT name")
+ }
+
+ fn sections(&self) -> Self::SectionIterator {
+ ElfComdatSectionIterator {
+ file: self.file,
+ sections: self.sections.iter(),
+ }
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of an `ElfFile32`.
+pub type ElfComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfComdatSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator over the sections in a COMDAT section group of an `ElfFile64`.
+pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfComdatSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator over the sections in a COMDAT section group of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfComdatSectionIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ file: &'file ElfFile<'data, Elf, R>,
+ sections: slice::Iter<'data, U32Bytes<Elf::Endian>>,
+}
+
+impl<'data, 'file, Elf, R> Iterator for ElfComdatSectionIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let index = self.sections.next()?;
+ Some(SectionIndex(index.get(self.file.endian) as usize))
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/compression.rs b/third_party/rust/object/src/read/elf/compression.rs
new file mode 100644
index 0000000000..7242dd39c8
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/compression.rs
@@ -0,0 +1,56 @@
+use core::fmt::Debug;
+
+use crate::elf;
+use crate::endian;
+use crate::pod::Pod;
+
+/// A trait for generic access to `CompressionHeader32` and `CompressionHeader64`.
+#[allow(missing_docs)]
+pub trait CompressionHeader: Debug + Pod {
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn ch_type(&self, endian: Self::Endian) -> u32;
+ fn ch_size(&self, endian: Self::Endian) -> Self::Word;
+ fn ch_addralign(&self, endian: Self::Endian) -> Self::Word;
+}
+
+impl<Endian: endian::Endian> CompressionHeader for elf::CompressionHeader32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+
+ #[inline]
+ fn ch_type(&self, endian: Self::Endian) -> u32 {
+ self.ch_type.get(endian)
+ }
+
+ #[inline]
+ fn ch_size(&self, endian: Self::Endian) -> Self::Word {
+ self.ch_size.get(endian)
+ }
+
+ #[inline]
+ fn ch_addralign(&self, endian: Self::Endian) -> Self::Word {
+ self.ch_addralign.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> CompressionHeader for elf::CompressionHeader64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+
+ #[inline]
+ fn ch_type(&self, endian: Self::Endian) -> u32 {
+ self.ch_type.get(endian)
+ }
+
+ #[inline]
+ fn ch_size(&self, endian: Self::Endian) -> Self::Word {
+ self.ch_size.get(endian)
+ }
+
+ #[inline]
+ fn ch_addralign(&self, endian: Self::Endian) -> Self::Word {
+ self.ch_addralign.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/dynamic.rs b/third_party/rust/object/src/read/elf/dynamic.rs
new file mode 100644
index 0000000000..5fe15b560d
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/dynamic.rs
@@ -0,0 +1,117 @@
+use core::convert::TryInto;
+use core::fmt::Debug;
+
+use crate::elf;
+use crate::endian;
+use crate::pod::Pod;
+use crate::read::{ReadError, Result, StringTable};
+
+/// A trait for generic access to `Dyn32` and `Dyn64`.
+#[allow(missing_docs)]
+pub trait Dyn: Debug + Pod {
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn d_tag(&self, endian: Self::Endian) -> Self::Word;
+ fn d_val(&self, endian: Self::Endian) -> Self::Word;
+
+ /// Try to convert the tag to a `u32`.
+ fn tag32(&self, endian: Self::Endian) -> Option<u32> {
+ self.d_tag(endian).into().try_into().ok()
+ }
+
+ /// Try to convert the value to a `u32`.
+ fn val32(&self, endian: Self::Endian) -> Option<u32> {
+ self.d_val(endian).into().try_into().ok()
+ }
+
+ /// Return true if the value is an offset in the dynamic string table.
+ fn is_string(&self, endian: Self::Endian) -> bool {
+ if let Some(tag) = self.tag32(endian) {
+ match tag {
+ elf::DT_NEEDED
+ | elf::DT_SONAME
+ | elf::DT_RPATH
+ | elf::DT_RUNPATH
+ | elf::DT_AUXILIARY
+ | elf::DT_FILTER => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ }
+
+ /// Use the value to get a string in a string table.
+ ///
+ /// Does not check for an appropriate tag.
+ fn string<'data>(
+ &self,
+ endian: Self::Endian,
+ strings: StringTable<'data>,
+ ) -> Result<&'data [u8]> {
+ self.val32(endian)
+ .and_then(|val| strings.get(val).ok())
+ .read_error("Invalid ELF dyn string")
+ }
+
+ /// Return true if the value is an address.
+ fn is_address(&self, endian: Self::Endian) -> bool {
+ if let Some(tag) = self.tag32(endian) {
+ match tag {
+ elf::DT_PLTGOT
+ | elf::DT_HASH
+ | elf::DT_STRTAB
+ | elf::DT_SYMTAB
+ | elf::DT_RELA
+ | elf::DT_INIT
+ | elf::DT_FINI
+ | elf::DT_SYMBOLIC
+ | elf::DT_REL
+ | elf::DT_DEBUG
+ | elf::DT_JMPREL
+ | elf::DT_FINI_ARRAY
+ | elf::DT_INIT_ARRAY
+ | elf::DT_PREINIT_ARRAY
+ | elf::DT_SYMTAB_SHNDX
+ | elf::DT_VERDEF
+ | elf::DT_VERNEED
+ | elf::DT_VERSYM
+ | elf::DT_ADDRRNGLO..=elf::DT_ADDRRNGHI => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ }
+}
+
+impl<Endian: endian::Endian> Dyn for elf::Dyn32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+
+ #[inline]
+ fn d_tag(&self, endian: Self::Endian) -> Self::Word {
+ self.d_tag.get(endian)
+ }
+
+ #[inline]
+ fn d_val(&self, endian: Self::Endian) -> Self::Word {
+ self.d_val.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> Dyn for elf::Dyn64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+
+ #[inline]
+ fn d_tag(&self, endian: Self::Endian) -> Self::Word {
+ self.d_tag.get(endian)
+ }
+
+ #[inline]
+ fn d_val(&self, endian: Self::Endian) -> Self::Word {
+ self.d_val.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/file.rs b/third_party/rust/object/src/read/elf/file.rs
new file mode 100644
index 0000000000..67be37e21f
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/file.rs
@@ -0,0 +1,911 @@
+use alloc::vec::Vec;
+use core::convert::TryInto;
+use core::fmt::Debug;
+use core::mem;
+
+use crate::read::{
+ self, util, Architecture, ByteString, Bytes, Error, Export, FileFlags, Import, Object,
+ ObjectKind, ReadError, ReadRef, SectionIndex, StringTable, SymbolIndex,
+};
+use crate::{elf, endian, Endian, Endianness, Pod, U32};
+
+use super::{
+ CompressionHeader, Dyn, ElfComdat, ElfComdatIterator, ElfDynamicRelocationIterator, ElfSection,
+ ElfSectionIterator, ElfSegment, ElfSegmentIterator, ElfSymbol, ElfSymbolIterator,
+ ElfSymbolTable, NoteHeader, ProgramHeader, Rel, Rela, RelocationSections, SectionHeader,
+ SectionTable, Sym, SymbolTable,
+};
+
+/// A 32-bit ELF object file.
+pub type ElfFile32<'data, Endian = Endianness, R = &'data [u8]> =
+ ElfFile<'data, elf::FileHeader32<Endian>, R>;
+/// A 64-bit ELF object file.
+pub type ElfFile64<'data, Endian = Endianness, R = &'data [u8]> =
+ ElfFile<'data, elf::FileHeader64<Endian>, R>;
+
+/// A partially parsed ELF file.
+///
+/// Most of the functionality of this type is provided by the `Object` trait implementation.
+#[derive(Debug)]
+pub struct ElfFile<'data, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) endian: Elf::Endian,
+ pub(super) data: R,
+ pub(super) header: &'data Elf,
+ pub(super) segments: &'data [Elf::ProgramHeader],
+ pub(super) sections: SectionTable<'data, Elf, R>,
+ pub(super) relocations: RelocationSections,
+ pub(super) symbols: SymbolTable<'data, Elf, R>,
+ pub(super) dynamic_symbols: SymbolTable<'data, Elf, R>,
+}
+
+impl<'data, Elf, R> ElfFile<'data, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ /// Parse the raw ELF file data.
+ pub fn parse(data: R) -> read::Result<Self> {
+ let header = Elf::parse(data)?;
+ let endian = header.endian()?;
+ let segments = header.program_headers(endian, data)?;
+ let sections = header.sections(endian, data)?;
+ let symbols = sections.symbols(endian, data, elf::SHT_SYMTAB)?;
+ // TODO: get dynamic symbols from DT_SYMTAB if there are no sections
+ let dynamic_symbols = sections.symbols(endian, data, elf::SHT_DYNSYM)?;
+ // The API we provide requires a mapping from section to relocations, so build it now.
+ let relocations = sections.relocation_sections(endian, symbols.section())?;
+
+ Ok(ElfFile {
+ endian,
+ data,
+ header,
+ segments,
+ sections,
+ relocations,
+ symbols,
+ dynamic_symbols,
+ })
+ }
+
+ /// Returns the endianness.
+ pub fn endian(&self) -> Elf::Endian {
+ self.endian
+ }
+
+ /// Returns the raw data.
+ pub fn data(&self) -> R {
+ self.data
+ }
+
+ /// Returns the raw ELF file header.
+ pub fn raw_header(&self) -> &'data Elf {
+ self.header
+ }
+
+ /// Returns the raw ELF segments.
+ pub fn raw_segments(&self) -> &'data [Elf::ProgramHeader] {
+ self.segments
+ }
+
+ fn raw_section_by_name<'file>(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<ElfSection<'data, 'file, Elf, R>> {
+ self.sections
+ .section_by_name(self.endian, section_name)
+ .map(|(index, section)| ElfSection {
+ file: self,
+ index: SectionIndex(index),
+ section,
+ })
+ }
+
+ #[cfg(feature = "compression")]
+ fn zdebug_section_by_name<'file>(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<ElfSection<'data, 'file, Elf, R>> {
+ if !section_name.starts_with(b".debug_") {
+ return None;
+ }
+ let mut name = Vec::with_capacity(section_name.len() + 1);
+ name.extend_from_slice(b".zdebug_");
+ name.extend_from_slice(&section_name[7..]);
+ self.raw_section_by_name(&name)
+ }
+
+ #[cfg(not(feature = "compression"))]
+ fn zdebug_section_by_name<'file>(
+ &'file self,
+ _section_name: &[u8],
+ ) -> Option<ElfSection<'data, 'file, Elf, R>> {
+ None
+ }
+}
+
+impl<'data, Elf, R> read::private::Sealed for ElfFile<'data, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Elf, R> Object<'data, 'file> for ElfFile<'data, Elf, R>
+where
+ 'data: 'file,
+ Elf: FileHeader,
+ R: 'file + ReadRef<'data>,
+{
+ type Segment = ElfSegment<'data, 'file, Elf, R>;
+ type SegmentIterator = ElfSegmentIterator<'data, 'file, Elf, R>;
+ type Section = ElfSection<'data, 'file, Elf, R>;
+ type SectionIterator = ElfSectionIterator<'data, 'file, Elf, R>;
+ type Comdat = ElfComdat<'data, 'file, Elf, R>;
+ type ComdatIterator = ElfComdatIterator<'data, 'file, Elf, R>;
+ type Symbol = ElfSymbol<'data, 'file, Elf, R>;
+ type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf, R>;
+ type SymbolTable = ElfSymbolTable<'data, 'file, Elf, R>;
+ type DynamicRelocationIterator = ElfDynamicRelocationIterator<'data, 'file, Elf, R>;
+
+ fn architecture(&self) -> Architecture {
+ match (
+ self.header.e_machine(self.endian),
+ self.header.is_class_64(),
+ ) {
+ (elf::EM_AARCH64, true) => Architecture::Aarch64,
+ (elf::EM_AARCH64, false) => Architecture::Aarch64_Ilp32,
+ (elf::EM_ARM, _) => Architecture::Arm,
+ (elf::EM_AVR, _) => Architecture::Avr,
+ (elf::EM_BPF, _) => Architecture::Bpf,
+ (elf::EM_CSKY, _) => Architecture::Csky,
+ (elf::EM_386, _) => Architecture::I386,
+ (elf::EM_X86_64, false) => Architecture::X86_64_X32,
+ (elf::EM_X86_64, true) => Architecture::X86_64,
+ (elf::EM_HEXAGON, _) => Architecture::Hexagon,
+ (elf::EM_LOONGARCH, true) => Architecture::LoongArch64,
+ (elf::EM_MIPS, false) => Architecture::Mips,
+ (elf::EM_MIPS, true) => Architecture::Mips64,
+ (elf::EM_MSP430, _) => Architecture::Msp430,
+ (elf::EM_PPC, _) => Architecture::PowerPc,
+ (elf::EM_PPC64, _) => Architecture::PowerPc64,
+ (elf::EM_RISCV, false) => Architecture::Riscv32,
+ (elf::EM_RISCV, true) => Architecture::Riscv64,
+ // This is either s390 or s390x, depending on the ELF class.
+ // We only support the 64-bit variant s390x here.
+ (elf::EM_S390, true) => Architecture::S390x,
+ (elf::EM_SBF, _) => Architecture::Sbf,
+ (elf::EM_SPARCV9, true) => Architecture::Sparc64,
+ (elf::EM_XTENSA, false) => Architecture::Xtensa,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ self.header.is_little_endian()
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ self.header.is_class_64()
+ }
+
+ fn kind(&self) -> ObjectKind {
+ match self.header.e_type(self.endian) {
+ elf::ET_REL => ObjectKind::Relocatable,
+ elf::ET_EXEC => ObjectKind::Executable,
+ // TODO: check for `DF_1_PIE`?
+ elf::ET_DYN => ObjectKind::Dynamic,
+ elf::ET_CORE => ObjectKind::Core,
+ _ => ObjectKind::Unknown,
+ }
+ }
+
+ fn segments(&'file self) -> ElfSegmentIterator<'data, 'file, Elf, R> {
+ ElfSegmentIterator {
+ file: self,
+ iter: self.segments.iter(),
+ }
+ }
+
+ fn section_by_name_bytes(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<ElfSection<'data, 'file, Elf, R>> {
+ self.raw_section_by_name(section_name)
+ .or_else(|| self.zdebug_section_by_name(section_name))
+ }
+
+ fn section_by_index(
+ &'file self,
+ index: SectionIndex,
+ ) -> read::Result<ElfSection<'data, 'file, Elf, R>> {
+ let section = self.sections.section(index)?;
+ Ok(ElfSection {
+ file: self,
+ index,
+ section,
+ })
+ }
+
+ fn sections(&'file self) -> ElfSectionIterator<'data, 'file, Elf, R> {
+ ElfSectionIterator {
+ file: self,
+ iter: self.sections.iter().enumerate(),
+ }
+ }
+
+ fn comdats(&'file self) -> ElfComdatIterator<'data, 'file, Elf, R> {
+ ElfComdatIterator {
+ file: self,
+ iter: self.sections.iter().enumerate(),
+ }
+ }
+
+ fn symbol_by_index(
+ &'file self,
+ index: SymbolIndex,
+ ) -> read::Result<ElfSymbol<'data, 'file, Elf, R>> {
+ let symbol = self.symbols.symbol(index.0)?;
+ Ok(ElfSymbol {
+ endian: self.endian,
+ symbols: &self.symbols,
+ index,
+ symbol,
+ })
+ }
+
+ fn symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf, R> {
+ ElfSymbolIterator {
+ endian: self.endian,
+ symbols: &self.symbols,
+ index: 0,
+ }
+ }
+
+ fn symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> {
+ if self.symbols.is_empty() {
+ return None;
+ }
+ Some(ElfSymbolTable {
+ endian: self.endian,
+ symbols: &self.symbols,
+ })
+ }
+
+ fn dynamic_symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf, R> {
+ ElfSymbolIterator {
+ endian: self.endian,
+ symbols: &self.dynamic_symbols,
+ index: 0,
+ }
+ }
+
+ fn dynamic_symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> {
+ if self.dynamic_symbols.is_empty() {
+ return None;
+ }
+ Some(ElfSymbolTable {
+ endian: self.endian,
+ symbols: &self.dynamic_symbols,
+ })
+ }
+
+ fn dynamic_relocations(
+ &'file self,
+ ) -> Option<ElfDynamicRelocationIterator<'data, 'file, Elf, R>> {
+ Some(ElfDynamicRelocationIterator {
+ section_index: SectionIndex(1),
+ file: self,
+ relocations: None,
+ })
+ }
+
+ /// Get the imported symbols.
+ fn imports(&self) -> read::Result<Vec<Import<'data>>> {
+ let mut imports = Vec::new();
+ for symbol in self.dynamic_symbols.iter() {
+ if symbol.is_undefined(self.endian) {
+ let name = symbol.name(self.endian, self.dynamic_symbols.strings())?;
+ if !name.is_empty() {
+ // TODO: use symbol versioning to determine library
+ imports.push(Import {
+ name: ByteString(name),
+ library: ByteString(&[]),
+ });
+ }
+ }
+ }
+ Ok(imports)
+ }
+
+ /// Get the exported symbols.
+ fn exports(&self) -> read::Result<Vec<Export<'data>>> {
+ let mut exports = Vec::new();
+ for symbol in self.dynamic_symbols.iter() {
+ if symbol.is_definition(self.endian) {
+ let name = symbol.name(self.endian, self.dynamic_symbols.strings())?;
+ let address = symbol.st_value(self.endian).into();
+ exports.push(Export {
+ name: ByteString(name),
+ address,
+ });
+ }
+ }
+ Ok(exports)
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ for section in self.sections.iter() {
+ if let Ok(name) = self.sections.section_name(self.endian, section) {
+ if name == b".debug_info" || name == b".zdebug_info" {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
+ fn build_id(&self) -> read::Result<Option<&'data [u8]>> {
+ let endian = self.endian;
+ // Use section headers if present, otherwise use program headers.
+ if !self.sections.is_empty() {
+ for section in self.sections.iter() {
+ if let Some(mut notes) = section.notes(endian, self.data)? {
+ while let Some(note) = notes.next()? {
+ if note.name() == elf::ELF_NOTE_GNU
+ && note.n_type(endian) == elf::NT_GNU_BUILD_ID
+ {
+ return Ok(Some(note.desc()));
+ }
+ }
+ }
+ }
+ } else {
+ for segment in self.segments {
+ if let Some(mut notes) = segment.notes(endian, self.data)? {
+ while let Some(note) = notes.next()? {
+ if note.name() == elf::ELF_NOTE_GNU
+ && note.n_type(endian) == elf::NT_GNU_BUILD_ID
+ {
+ return Ok(Some(note.desc()));
+ }
+ }
+ }
+ }
+ }
+ Ok(None)
+ }
+
+ fn gnu_debuglink(&self) -> read::Result<Option<(&'data [u8], u32)>> {
+ let section = match self.raw_section_by_name(b".gnu_debuglink") {
+ Some(section) => section,
+ None => return Ok(None),
+ };
+ let data = section
+ .section
+ .data(self.endian, self.data)
+ .read_error("Invalid ELF .gnu_debuglink section offset or size")
+ .map(Bytes)?;
+ let filename = data
+ .read_string_at(0)
+ .read_error("Missing ELF .gnu_debuglink filename")?;
+ let crc_offset = util::align(filename.len() + 1, 4);
+ let crc = data
+ .read_at::<U32<_>>(crc_offset)
+ .read_error("Missing ELF .gnu_debuglink crc")?
+ .get(self.endian);
+ Ok(Some((filename, crc)))
+ }
+
+ fn gnu_debugaltlink(&self) -> read::Result<Option<(&'data [u8], &'data [u8])>> {
+ let section = match self.raw_section_by_name(b".gnu_debugaltlink") {
+ Some(section) => section,
+ None => return Ok(None),
+ };
+ let mut data = section
+ .section
+ .data(self.endian, self.data)
+ .read_error("Invalid ELF .gnu_debugaltlink section offset or size")
+ .map(Bytes)?;
+ let filename = data
+ .read_string()
+ .read_error("Missing ELF .gnu_debugaltlink filename")?;
+ let build_id = data.0;
+ Ok(Some((filename, build_id)))
+ }
+
+ fn relative_address_base(&self) -> u64 {
+ 0
+ }
+
+ fn entry(&self) -> u64 {
+ self.header.e_entry(self.endian).into()
+ }
+
+ fn flags(&self) -> FileFlags {
+ FileFlags::Elf {
+ os_abi: self.header.e_ident().os_abi,
+ abi_version: self.header.e_ident().abi_version,
+ e_flags: self.header.e_flags(self.endian),
+ }
+ }
+}
+
+/// A trait for generic access to `FileHeader32` and `FileHeader64`.
+#[allow(missing_docs)]
+pub trait FileHeader: Debug + Pod {
+ // Ideally this would be a `u64: From<Word>`, but can't express that.
+ type Word: Into<u64>;
+ type Sword: Into<i64>;
+ type Endian: endian::Endian;
+ type ProgramHeader: ProgramHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>;
+ type SectionHeader: SectionHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>;
+ type CompressionHeader: CompressionHeader<Endian = Self::Endian, Word = Self::Word>;
+ type NoteHeader: NoteHeader<Endian = Self::Endian>;
+ type Dyn: Dyn<Endian = Self::Endian, Word = Self::Word>;
+ type Sym: Sym<Endian = Self::Endian, Word = Self::Word>;
+ type Rel: Rel<Endian = Self::Endian, Word = Self::Word>;
+ type Rela: Rela<Endian = Self::Endian, Word = Self::Word> + From<Self::Rel>;
+
+ /// Return true if this type is a 64-bit header.
+ ///
+ /// This is a property of the type, not a value in the header data.
+ fn is_type_64(&self) -> bool;
+
+ /// Return true if this type is a 64-bit header.
+ ///
+ /// This is a property of the type, not a value in the header data.
+ ///
+ /// This is the same as `is_type_64`, but is non-dispatchable.
+ fn is_type_64_sized() -> bool
+ where
+ Self: Sized;
+
+ fn e_ident(&self) -> &elf::Ident;
+ fn e_type(&self, endian: Self::Endian) -> u16;
+ fn e_machine(&self, endian: Self::Endian) -> u16;
+ fn e_version(&self, endian: Self::Endian) -> u32;
+ fn e_entry(&self, endian: Self::Endian) -> Self::Word;
+ fn e_phoff(&self, endian: Self::Endian) -> Self::Word;
+ fn e_shoff(&self, endian: Self::Endian) -> Self::Word;
+ fn e_flags(&self, endian: Self::Endian) -> u32;
+ fn e_ehsize(&self, endian: Self::Endian) -> u16;
+ fn e_phentsize(&self, endian: Self::Endian) -> u16;
+ fn e_phnum(&self, endian: Self::Endian) -> u16;
+ fn e_shentsize(&self, endian: Self::Endian) -> u16;
+ fn e_shnum(&self, endian: Self::Endian) -> u16;
+ fn e_shstrndx(&self, endian: Self::Endian) -> u16;
+
+ // Provided methods.
+
+ /// Read the file header.
+ ///
+ /// Also checks that the ident field in the file header is a supported format.
+ fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> {
+ let header = data
+ .read_at::<Self>(0)
+ .read_error("Invalid ELF header size or alignment")?;
+ if !header.is_supported() {
+ return Err(Error("Unsupported ELF header"));
+ }
+ // TODO: Check self.e_ehsize?
+ Ok(header)
+ }
+
+ /// Check that the ident field in the file header is a supported format.
+ ///
+ /// This checks the magic number, version, class, and endianness.
+ fn is_supported(&self) -> bool {
+ let ident = self.e_ident();
+ // TODO: Check self.e_version too? Requires endian though.
+ ident.magic == elf::ELFMAG
+ && (self.is_type_64() || self.is_class_32())
+ && (!self.is_type_64() || self.is_class_64())
+ && (self.is_little_endian() || self.is_big_endian())
+ && ident.version == elf::EV_CURRENT
+ }
+
+ fn is_class_32(&self) -> bool {
+ self.e_ident().class == elf::ELFCLASS32
+ }
+
+ fn is_class_64(&self) -> bool {
+ self.e_ident().class == elf::ELFCLASS64
+ }
+
+ fn is_little_endian(&self) -> bool {
+ self.e_ident().data == elf::ELFDATA2LSB
+ }
+
+ fn is_big_endian(&self) -> bool {
+ self.e_ident().data == elf::ELFDATA2MSB
+ }
+
+ fn endian(&self) -> read::Result<Self::Endian> {
+ Self::Endian::from_big_endian(self.is_big_endian()).read_error("Unsupported ELF endian")
+ }
+
+ /// Return the first section header, if present.
+ ///
+ /// Section 0 is a special case because getting the section headers normally
+ /// requires `shnum`, but `shnum` may be in the first section header.
+ fn section_0<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data Self::SectionHeader>> {
+ let shoff: u64 = self.e_shoff(endian).into();
+ if shoff == 0 {
+ // No section headers is ok.
+ return Ok(None);
+ }
+ let shentsize = usize::from(self.e_shentsize(endian));
+ if shentsize != mem::size_of::<Self::SectionHeader>() {
+ // Section header size must match.
+ return Err(Error("Invalid ELF section header entry size"));
+ }
+ data.read_at(shoff)
+ .map(Some)
+ .read_error("Invalid ELF section header offset or size")
+ }
+
+ /// Return the `e_phnum` field of the header. Handles extended values.
+ ///
+ /// Returns `Err` for invalid values.
+ fn phnum<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<usize> {
+ let e_phnum = self.e_phnum(endian);
+ if e_phnum < elf::PN_XNUM {
+ Ok(e_phnum as usize)
+ } else if let Some(section_0) = self.section_0(endian, data)? {
+ Ok(section_0.sh_info(endian) as usize)
+ } else {
+ // Section 0 must exist if e_phnum overflows.
+ Err(Error("Missing ELF section headers for e_phnum overflow"))
+ }
+ }
+
+ /// Return the `e_shnum` field of the header. Handles extended values.
+ ///
+ /// Returns `Err` for invalid values.
+ fn shnum<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<usize> {
+ let e_shnum = self.e_shnum(endian);
+ if e_shnum > 0 {
+ Ok(e_shnum as usize)
+ } else if let Some(section_0) = self.section_0(endian, data)? {
+ section_0
+ .sh_size(endian)
+ .into()
+ .try_into()
+ .ok()
+ .read_error("Invalid ELF extended e_shnum")
+ } else {
+ // No section headers is ok.
+ Ok(0)
+ }
+ }
+
+ /// Return the `e_shstrndx` field of the header. Handles extended values.
+ ///
+ /// Returns `Err` for invalid values (including if the index is 0).
+ fn shstrndx<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<u32> {
+ let e_shstrndx = self.e_shstrndx(endian);
+ let index = if e_shstrndx != elf::SHN_XINDEX {
+ e_shstrndx.into()
+ } else if let Some(section_0) = self.section_0(endian, data)? {
+ section_0.sh_link(endian)
+ } else {
+ // Section 0 must exist if we're trying to read e_shstrndx.
+ return Err(Error("Missing ELF section headers for e_shstrndx overflow"));
+ };
+ if index == 0 {
+ return Err(Error("Missing ELF e_shstrndx"));
+ }
+ Ok(index)
+ }
+
+ /// Return the slice of program headers.
+ ///
+ /// Returns `Ok(&[])` if there are no program headers.
+ /// Returns `Err` for invalid values.
+ fn program_headers<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<&'data [Self::ProgramHeader]> {
+ let phoff: u64 = self.e_phoff(endian).into();
+ if phoff == 0 {
+ // No program headers is ok.
+ return Ok(&[]);
+ }
+ let phnum = self.phnum(endian, data)?;
+ if phnum == 0 {
+ // No program headers is ok.
+ return Ok(&[]);
+ }
+ let phentsize = self.e_phentsize(endian) as usize;
+ if phentsize != mem::size_of::<Self::ProgramHeader>() {
+ // Program header size must match.
+ return Err(Error("Invalid ELF program header entry size"));
+ }
+ data.read_slice_at(phoff, phnum)
+ .read_error("Invalid ELF program header size or alignment")
+ }
+
+ /// Return the slice of section headers.
+ ///
+ /// Returns `Ok(&[])` if there are no section headers.
+ /// Returns `Err` for invalid values.
+ fn section_headers<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<&'data [Self::SectionHeader]> {
+ let shoff: u64 = self.e_shoff(endian).into();
+ if shoff == 0 {
+ // No section headers is ok.
+ return Ok(&[]);
+ }
+ let shnum = self.shnum(endian, data)?;
+ if shnum == 0 {
+ // No section headers is ok.
+ return Ok(&[]);
+ }
+ let shentsize = usize::from(self.e_shentsize(endian));
+ if shentsize != mem::size_of::<Self::SectionHeader>() {
+ // Section header size must match.
+ return Err(Error("Invalid ELF section header entry size"));
+ }
+ data.read_slice_at(shoff, shnum)
+ .read_error("Invalid ELF section header offset/size/alignment")
+ }
+
+ /// Return the string table for the section headers.
+ fn section_strings<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ sections: &[Self::SectionHeader],
+ ) -> read::Result<StringTable<'data, R>> {
+ if sections.is_empty() {
+ return Ok(StringTable::default());
+ }
+ let index = self.shstrndx(endian, data)? as usize;
+ let shstrtab = sections.get(index).read_error("Invalid ELF e_shstrndx")?;
+ let strings = if let Some((shstrtab_offset, shstrtab_size)) = shstrtab.file_range(endian) {
+ let shstrtab_end = shstrtab_offset
+ .checked_add(shstrtab_size)
+ .read_error("Invalid ELF shstrtab size")?;
+ StringTable::new(data, shstrtab_offset, shstrtab_end)
+ } else {
+ StringTable::default()
+ };
+ Ok(strings)
+ }
+
+ /// Return the section table.
+ fn sections<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<SectionTable<'data, Self, R>> {
+ let sections = self.section_headers(endian, data)?;
+ let strings = self.section_strings(endian, data, sections)?;
+ Ok(SectionTable::new(sections, strings))
+ }
+
+ /// Returns whether this is a mips64el elf file.
+ fn is_mips64el(&self, endian: Self::Endian) -> bool {
+ self.is_class_64() && self.is_little_endian() && self.e_machine(endian) == elf::EM_MIPS
+ }
+}
+
+impl<Endian: endian::Endian> FileHeader for elf::FileHeader32<Endian> {
+ type Word = u32;
+ type Sword = i32;
+ type Endian = Endian;
+ type ProgramHeader = elf::ProgramHeader32<Endian>;
+ type SectionHeader = elf::SectionHeader32<Endian>;
+ type CompressionHeader = elf::CompressionHeader32<Endian>;
+ type NoteHeader = elf::NoteHeader32<Endian>;
+ type Dyn = elf::Dyn32<Endian>;
+ type Sym = elf::Sym32<Endian>;
+ type Rel = elf::Rel32<Endian>;
+ type Rela = elf::Rela32<Endian>;
+
+ #[inline]
+ fn is_type_64(&self) -> bool {
+ false
+ }
+
+ #[inline]
+ fn is_type_64_sized() -> bool
+ where
+ Self: Sized,
+ {
+ false
+ }
+
+ #[inline]
+ fn e_ident(&self) -> &elf::Ident {
+ &self.e_ident
+ }
+
+ #[inline]
+ fn e_type(&self, endian: Self::Endian) -> u16 {
+ self.e_type.get(endian)
+ }
+
+ #[inline]
+ fn e_machine(&self, endian: Self::Endian) -> u16 {
+ self.e_machine.get(endian)
+ }
+
+ #[inline]
+ fn e_version(&self, endian: Self::Endian) -> u32 {
+ self.e_version.get(endian)
+ }
+
+ #[inline]
+ fn e_entry(&self, endian: Self::Endian) -> Self::Word {
+ self.e_entry.get(endian)
+ }
+
+ #[inline]
+ fn e_phoff(&self, endian: Self::Endian) -> Self::Word {
+ self.e_phoff.get(endian)
+ }
+
+ #[inline]
+ fn e_shoff(&self, endian: Self::Endian) -> Self::Word {
+ self.e_shoff.get(endian)
+ }
+
+ #[inline]
+ fn e_flags(&self, endian: Self::Endian) -> u32 {
+ self.e_flags.get(endian)
+ }
+
+ #[inline]
+ fn e_ehsize(&self, endian: Self::Endian) -> u16 {
+ self.e_ehsize.get(endian)
+ }
+
+ #[inline]
+ fn e_phentsize(&self, endian: Self::Endian) -> u16 {
+ self.e_phentsize.get(endian)
+ }
+
+ #[inline]
+ fn e_phnum(&self, endian: Self::Endian) -> u16 {
+ self.e_phnum.get(endian)
+ }
+
+ #[inline]
+ fn e_shentsize(&self, endian: Self::Endian) -> u16 {
+ self.e_shentsize.get(endian)
+ }
+
+ #[inline]
+ fn e_shnum(&self, endian: Self::Endian) -> u16 {
+ self.e_shnum.get(endian)
+ }
+
+ #[inline]
+ fn e_shstrndx(&self, endian: Self::Endian) -> u16 {
+ self.e_shstrndx.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> FileHeader for elf::FileHeader64<Endian> {
+ type Word = u64;
+ type Sword = i64;
+ type Endian = Endian;
+ type ProgramHeader = elf::ProgramHeader64<Endian>;
+ type SectionHeader = elf::SectionHeader64<Endian>;
+ type CompressionHeader = elf::CompressionHeader64<Endian>;
+ type NoteHeader = elf::NoteHeader32<Endian>;
+ type Dyn = elf::Dyn64<Endian>;
+ type Sym = elf::Sym64<Endian>;
+ type Rel = elf::Rel64<Endian>;
+ type Rela = elf::Rela64<Endian>;
+
+ #[inline]
+ fn is_type_64(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn is_type_64_sized() -> bool
+ where
+ Self: Sized,
+ {
+ true
+ }
+
+ #[inline]
+ fn e_ident(&self) -> &elf::Ident {
+ &self.e_ident
+ }
+
+ #[inline]
+ fn e_type(&self, endian: Self::Endian) -> u16 {
+ self.e_type.get(endian)
+ }
+
+ #[inline]
+ fn e_machine(&self, endian: Self::Endian) -> u16 {
+ self.e_machine.get(endian)
+ }
+
+ #[inline]
+ fn e_version(&self, endian: Self::Endian) -> u32 {
+ self.e_version.get(endian)
+ }
+
+ #[inline]
+ fn e_entry(&self, endian: Self::Endian) -> Self::Word {
+ self.e_entry.get(endian)
+ }
+
+ #[inline]
+ fn e_phoff(&self, endian: Self::Endian) -> Self::Word {
+ self.e_phoff.get(endian)
+ }
+
+ #[inline]
+ fn e_shoff(&self, endian: Self::Endian) -> Self::Word {
+ self.e_shoff.get(endian)
+ }
+
+ #[inline]
+ fn e_flags(&self, endian: Self::Endian) -> u32 {
+ self.e_flags.get(endian)
+ }
+
+ #[inline]
+ fn e_ehsize(&self, endian: Self::Endian) -> u16 {
+ self.e_ehsize.get(endian)
+ }
+
+ #[inline]
+ fn e_phentsize(&self, endian: Self::Endian) -> u16 {
+ self.e_phentsize.get(endian)
+ }
+
+ #[inline]
+ fn e_phnum(&self, endian: Self::Endian) -> u16 {
+ self.e_phnum.get(endian)
+ }
+
+ #[inline]
+ fn e_shentsize(&self, endian: Self::Endian) -> u16 {
+ self.e_shentsize.get(endian)
+ }
+
+ #[inline]
+ fn e_shnum(&self, endian: Self::Endian) -> u16 {
+ self.e_shnum.get(endian)
+ }
+
+ #[inline]
+ fn e_shstrndx(&self, endian: Self::Endian) -> u16 {
+ self.e_shstrndx.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/hash.rs b/third_party/rust/object/src/read/elf/hash.rs
new file mode 100644
index 0000000000..aadbb9208a
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/hash.rs
@@ -0,0 +1,220 @@
+use core::mem;
+
+use crate::elf;
+use crate::read::{ReadError, ReadRef, Result};
+use crate::{U32, U64};
+
+use super::{FileHeader, Sym, SymbolTable, Version, VersionTable};
+
+/// A SysV symbol hash table in an ELF file.
+#[derive(Debug)]
+pub struct HashTable<'data, Elf: FileHeader> {
+ buckets: &'data [U32<Elf::Endian>],
+ chains: &'data [U32<Elf::Endian>],
+}
+
+impl<'data, Elf: FileHeader> HashTable<'data, Elf> {
+ /// Parse a SysV hash table.
+ ///
+ /// `data` should be from a `SHT_HASH` section, or from a
+ /// segment pointed to via the `DT_HASH` entry.
+ ///
+ /// The header is read at offset 0 in the given `data`.
+ pub fn parse(endian: Elf::Endian, data: &'data [u8]) -> Result<Self> {
+ let mut offset = 0;
+ let header = data
+ .read::<elf::HashHeader<Elf::Endian>>(&mut offset)
+ .read_error("Invalid hash header")?;
+ let buckets = data
+ .read_slice(&mut offset, header.bucket_count.get(endian) as usize)
+ .read_error("Invalid hash buckets")?;
+ let chains = data
+ .read_slice(&mut offset, header.chain_count.get(endian) as usize)
+ .read_error("Invalid hash chains")?;
+ Ok(HashTable { buckets, chains })
+ }
+
+ /// Return the symbol table length.
+ pub fn symbol_table_length(&self) -> u32 {
+ self.chains.len() as u32
+ }
+
+ /// Use the hash table to find the symbol table entry with the given name, hash and version.
+ pub fn find<R: ReadRef<'data>>(
+ &self,
+ endian: Elf::Endian,
+ name: &[u8],
+ hash: u32,
+ version: Option<&Version<'_>>,
+ symbols: &SymbolTable<'data, Elf, R>,
+ versions: &VersionTable<'data, Elf>,
+ ) -> Option<(usize, &'data Elf::Sym)> {
+ // Get the chain start from the bucket for this hash.
+ let mut index = self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize;
+ // Avoid infinite loop.
+ let mut i = 0;
+ let strings = symbols.strings();
+ while index != 0 && i < self.chains.len() {
+ if let Ok(symbol) = symbols.symbol(index) {
+ if symbol.name(endian, strings) == Ok(name)
+ && versions.matches(endian, index, version)
+ {
+ return Some((index, symbol));
+ }
+ }
+ index = self.chains.get(index)?.get(endian) as usize;
+ i += 1;
+ }
+ None
+ }
+}
+
+/// A GNU symbol hash table in an ELF file.
+#[derive(Debug)]
+pub struct GnuHashTable<'data, Elf: FileHeader> {
+ symbol_base: u32,
+ bloom_shift: u32,
+ bloom_filters: &'data [u8],
+ buckets: &'data [U32<Elf::Endian>],
+ values: &'data [U32<Elf::Endian>],
+}
+
+impl<'data, Elf: FileHeader> GnuHashTable<'data, Elf> {
+ /// Parse a GNU hash table.
+ ///
+ /// `data` should be from a `SHT_GNU_HASH` section, or from a
+ /// segment pointed to via the `DT_GNU_HASH` entry.
+ ///
+ /// The header is read at offset 0 in the given `data`.
+ ///
+ /// The header does not contain a length field, and so all of `data`
+ /// will be used as the hash table values. It does not matter if this
+ /// is longer than needed, and this will often the case when accessing
+ /// the hash table via the `DT_GNU_HASH` entry.
+ pub fn parse(endian: Elf::Endian, data: &'data [u8]) -> Result<Self> {
+ let mut offset = 0;
+ let header = data
+ .read::<elf::GnuHashHeader<Elf::Endian>>(&mut offset)
+ .read_error("Invalid GNU hash header")?;
+ let bloom_len =
+ u64::from(header.bloom_count.get(endian)) * mem::size_of::<Elf::Word>() as u64;
+ let bloom_filters = data
+ .read_bytes(&mut offset, bloom_len)
+ .read_error("Invalid GNU hash bloom filters")?;
+ let buckets = data
+ .read_slice(&mut offset, header.bucket_count.get(endian) as usize)
+ .read_error("Invalid GNU hash buckets")?;
+ let chain_count = (data.len() - offset as usize) / 4;
+ let values = data
+ .read_slice(&mut offset, chain_count)
+ .read_error("Invalid GNU hash values")?;
+ Ok(GnuHashTable {
+ symbol_base: header.symbol_base.get(endian),
+ bloom_shift: header.bloom_shift.get(endian),
+ bloom_filters,
+ buckets,
+ values,
+ })
+ }
+
+ /// Return the symbol table index of the first symbol in the hash table.
+ pub fn symbol_base(&self) -> u32 {
+ self.symbol_base
+ }
+
+ /// Determine the symbol table length by finding the last entry in the hash table.
+ ///
+ /// Returns `None` if the hash table is empty or invalid.
+ pub fn symbol_table_length(&self, endian: Elf::Endian) -> Option<u32> {
+ // Ensure we find a non-empty bucket.
+ if self.symbol_base == 0 {
+ return None;
+ }
+
+ // Find the highest chain index in a bucket.
+ let mut max_symbol = 0;
+ for bucket in self.buckets {
+ let bucket = bucket.get(endian);
+ if max_symbol < bucket {
+ max_symbol = bucket;
+ }
+ }
+
+ // Find the end of the chain.
+ for value in self
+ .values
+ .get(max_symbol.checked_sub(self.symbol_base)? as usize..)?
+ {
+ max_symbol += 1;
+ if value.get(endian) & 1 != 0 {
+ return Some(max_symbol);
+ }
+ }
+
+ None
+ }
+
+ /// Use the hash table to find the symbol table entry with the given name, hash, and version.
+ pub fn find<R: ReadRef<'data>>(
+ &self,
+ endian: Elf::Endian,
+ name: &[u8],
+ hash: u32,
+ version: Option<&Version<'_>>,
+ symbols: &SymbolTable<'data, Elf, R>,
+ versions: &VersionTable<'data, Elf>,
+ ) -> Option<(usize, &'data Elf::Sym)> {
+ let word_bits = mem::size_of::<Elf::Word>() as u32 * 8;
+
+ // Test against bloom filter.
+ let bloom_count = self.bloom_filters.len() / mem::size_of::<Elf::Word>();
+ let offset =
+ ((hash / word_bits) & (bloom_count as u32 - 1)) * mem::size_of::<Elf::Word>() as u32;
+ let filter = if word_bits == 64 {
+ self.bloom_filters
+ .read_at::<U64<Elf::Endian>>(offset.into())
+ .ok()?
+ .get(endian)
+ } else {
+ self.bloom_filters
+ .read_at::<U32<Elf::Endian>>(offset.into())
+ .ok()?
+ .get(endian)
+ .into()
+ };
+ if filter & (1 << (hash % word_bits)) == 0 {
+ return None;
+ }
+ if filter & (1 << ((hash >> self.bloom_shift) % word_bits)) == 0 {
+ return None;
+ }
+
+ // Get the chain start from the bucket for this hash.
+ let mut index = self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize;
+ if index == 0 {
+ return None;
+ }
+
+ // Test symbols in the chain.
+ let strings = symbols.strings();
+ let symbols = symbols.symbols().get(index..)?;
+ let values = self
+ .values
+ .get(index.checked_sub(self.symbol_base as usize)?..)?;
+ for (symbol, value) in symbols.iter().zip(values.iter()) {
+ let value = value.get(endian);
+ if value | 1 == hash | 1 {
+ if symbol.name(endian, strings) == Ok(name)
+ && versions.matches(endian, index, version)
+ {
+ return Some((index, symbol));
+ }
+ }
+ if value & 1 != 0 {
+ break;
+ }
+ index += 1;
+ }
+ None
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/mod.rs b/third_party/rust/object/src/read/elf/mod.rs
new file mode 100644
index 0000000000..07db6cd660
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/mod.rs
@@ -0,0 +1,42 @@
+//! Support for reading ELF files.
+//!
+//! Defines traits to abstract over the difference between ELF32/ELF64,
+//! and implements read functionality in terms of these traits.
+//!
+//! Also provides `ElfFile` and related types which implement the `Object` trait.
+
+mod file;
+pub use file::*;
+
+mod segment;
+pub use segment::*;
+
+mod section;
+pub use section::*;
+
+mod symbol;
+pub use symbol::*;
+
+mod relocation;
+pub use relocation::*;
+
+mod comdat;
+pub use comdat::*;
+
+mod dynamic;
+pub use dynamic::*;
+
+mod compression;
+pub use compression::*;
+
+mod note;
+pub use note::*;
+
+mod hash;
+pub use hash::*;
+
+mod version;
+pub use version::*;
+
+mod attributes;
+pub use attributes::*;
diff --git a/third_party/rust/object/src/read/elf/note.rs b/third_party/rust/object/src/read/elf/note.rs
new file mode 100644
index 0000000000..84d4179de2
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/note.rs
@@ -0,0 +1,266 @@
+use core::fmt::Debug;
+use core::mem;
+
+use crate::elf;
+use crate::endian::{self, U32};
+use crate::pod::Pod;
+use crate::read::util;
+use crate::read::{self, Bytes, Error, ReadError};
+
+use super::FileHeader;
+
+/// An iterator over the notes in an ELF section or segment.
+#[derive(Debug)]
+pub struct NoteIterator<'data, Elf>
+where
+ Elf: FileHeader,
+{
+ endian: Elf::Endian,
+ align: usize,
+ data: Bytes<'data>,
+}
+
+impl<'data, Elf> NoteIterator<'data, Elf>
+where
+ Elf: FileHeader,
+{
+ /// An iterator over the notes in an ELF section or segment.
+ ///
+ /// `align` should be from the `p_align` field of the segment,
+ /// or the `sh_addralign` field of the section. Supported values are
+ /// either 4 or 8, but values less than 4 are treated as 4.
+ /// This matches the behaviour of binutils.
+ ///
+ /// Returns `Err` if `align` is invalid.
+ pub fn new(endian: Elf::Endian, align: Elf::Word, data: &'data [u8]) -> read::Result<Self> {
+ let align = match align.into() {
+ 0u64..=4 => 4,
+ 8 => 8,
+ _ => return Err(Error("Invalid ELF note alignment")),
+ };
+ // TODO: check data alignment?
+ Ok(NoteIterator {
+ endian,
+ align,
+ data: Bytes(data),
+ })
+ }
+
+ /// Returns the next note.
+ pub fn next(&mut self) -> read::Result<Option<Note<'data, Elf>>> {
+ let mut data = self.data;
+ if data.is_empty() {
+ return Ok(None);
+ }
+
+ let header = data
+ .read_at::<Elf::NoteHeader>(0)
+ .read_error("ELF note is too short")?;
+
+ // The name has no alignment requirement.
+ let offset = mem::size_of::<Elf::NoteHeader>();
+ let namesz = header.n_namesz(self.endian) as usize;
+ let name = data
+ .read_bytes_at(offset, namesz)
+ .read_error("Invalid ELF note namesz")?
+ .0;
+
+ // The descriptor must be aligned.
+ let offset = util::align(offset + namesz, self.align);
+ let descsz = header.n_descsz(self.endian) as usize;
+ let desc = data
+ .read_bytes_at(offset, descsz)
+ .read_error("Invalid ELF note descsz")?
+ .0;
+
+ // The next note (if any) must be aligned.
+ let offset = util::align(offset + descsz, self.align);
+ if data.skip(offset).is_err() {
+ data = Bytes(&[]);
+ }
+ self.data = data;
+
+ Ok(Some(Note { header, name, desc }))
+ }
+}
+
+/// A parsed `NoteHeader`.
+#[derive(Debug)]
+pub struct Note<'data, Elf>
+where
+ Elf: FileHeader,
+{
+ header: &'data Elf::NoteHeader,
+ name: &'data [u8],
+ desc: &'data [u8],
+}
+
+impl<'data, Elf: FileHeader> Note<'data, Elf> {
+ /// Return the `n_type` field of the `NoteHeader`.
+ ///
+ /// The meaning of this field is determined by `name`.
+ pub fn n_type(&self, endian: Elf::Endian) -> u32 {
+ self.header.n_type(endian)
+ }
+
+ /// Return the `n_namesz` field of the `NoteHeader`.
+ pub fn n_namesz(&self, endian: Elf::Endian) -> u32 {
+ self.header.n_namesz(endian)
+ }
+
+ /// Return the `n_descsz` field of the `NoteHeader`.
+ pub fn n_descsz(&self, endian: Elf::Endian) -> u32 {
+ self.header.n_descsz(endian)
+ }
+
+ /// Return the bytes for the name field following the `NoteHeader`.
+ ///
+ /// This field is usually a string including one or more trailing null bytes
+ /// (but it is not required to be).
+ ///
+ /// The length of this field is given by `n_namesz`.
+ pub fn name_bytes(&self) -> &'data [u8] {
+ self.name
+ }
+
+ /// Return the bytes for the name field following the `NoteHeader`,
+ /// excluding all trailing null bytes.
+ pub fn name(&self) -> &'data [u8] {
+ let mut name = self.name;
+ while let [rest @ .., 0] = name {
+ name = rest;
+ }
+ name
+ }
+
+ /// Return the bytes for the desc field following the `NoteHeader`.
+ ///
+ /// The length of this field is given by `n_descsz`. The meaning
+ /// of this field is determined by `name` and `n_type`.
+ pub fn desc(&self) -> &'data [u8] {
+ self.desc
+ }
+
+ /// Return an iterator for properties if this note's type is `NT_GNU_PROPERTY_TYPE_0`.
+ pub fn gnu_properties(
+ &self,
+ endian: Elf::Endian,
+ ) -> Option<GnuPropertyIterator<'data, Elf::Endian>> {
+ if self.name() != elf::ELF_NOTE_GNU || self.n_type(endian) != elf::NT_GNU_PROPERTY_TYPE_0 {
+ return None;
+ }
+ // Use the ELF class instead of the section alignment.
+ // This matches what other parsers do.
+ let align = if Elf::is_type_64_sized() { 8 } else { 4 };
+ Some(GnuPropertyIterator {
+ endian,
+ align,
+ data: Bytes(self.desc),
+ })
+ }
+}
+
+/// A trait for generic access to `NoteHeader32` and `NoteHeader64`.
+#[allow(missing_docs)]
+pub trait NoteHeader: Debug + Pod {
+ type Endian: endian::Endian;
+
+ fn n_namesz(&self, endian: Self::Endian) -> u32;
+ fn n_descsz(&self, endian: Self::Endian) -> u32;
+ fn n_type(&self, endian: Self::Endian) -> u32;
+}
+
+impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader32<Endian> {
+ type Endian = Endian;
+
+ #[inline]
+ fn n_namesz(&self, endian: Self::Endian) -> u32 {
+ self.n_namesz.get(endian)
+ }
+
+ #[inline]
+ fn n_descsz(&self, endian: Self::Endian) -> u32 {
+ self.n_descsz.get(endian)
+ }
+
+ #[inline]
+ fn n_type(&self, endian: Self::Endian) -> u32 {
+ self.n_type.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader64<Endian> {
+ type Endian = Endian;
+
+ #[inline]
+ fn n_namesz(&self, endian: Self::Endian) -> u32 {
+ self.n_namesz.get(endian)
+ }
+
+ #[inline]
+ fn n_descsz(&self, endian: Self::Endian) -> u32 {
+ self.n_descsz.get(endian)
+ }
+
+ #[inline]
+ fn n_type(&self, endian: Self::Endian) -> u32 {
+ self.n_type.get(endian)
+ }
+}
+
+/// An iterator over the properties in a `NT_GNU_PROPERTY_TYPE_0` note.
+#[derive(Debug)]
+pub struct GnuPropertyIterator<'data, Endian: endian::Endian> {
+ endian: Endian,
+ align: usize,
+ data: Bytes<'data>,
+}
+
+impl<'data, Endian: endian::Endian> GnuPropertyIterator<'data, Endian> {
+ /// Returns the next property.
+ pub fn next(&mut self) -> read::Result<Option<GnuProperty<'data>>> {
+ let mut data = self.data;
+ if data.is_empty() {
+ return Ok(None);
+ }
+
+ (|| -> Result<_, ()> {
+ let pr_type = data.read_at::<U32<Endian>>(0)?.get(self.endian);
+ let pr_datasz = data.read_at::<U32<Endian>>(4)?.get(self.endian) as usize;
+ let pr_data = data.read_bytes_at(8, pr_datasz)?.0;
+ data.skip(util::align(8 + pr_datasz, self.align))?;
+ self.data = data;
+ Ok(Some(GnuProperty { pr_type, pr_data }))
+ })()
+ .read_error("Invalid ELF GNU property")
+ }
+}
+
+/// A property in a `NT_GNU_PROPERTY_TYPE_0` note.
+#[derive(Debug)]
+pub struct GnuProperty<'data> {
+ pr_type: u32,
+ pr_data: &'data [u8],
+}
+
+impl<'data> GnuProperty<'data> {
+ /// Return the property type.
+ ///
+ /// This is one of the `GNU_PROPERTY_*` constants.
+ pub fn pr_type(&self) -> u32 {
+ self.pr_type
+ }
+
+ /// Return the property data.
+ pub fn pr_data(&self) -> &'data [u8] {
+ self.pr_data
+ }
+
+ /// Parse the property data as an unsigned 32-bit integer.
+ pub fn data_u32<E: endian::Endian>(&self, endian: E) -> read::Result<u32> {
+ Bytes(self.pr_data)
+ .read_at::<U32<E>>(0)
+ .read_error("Invalid ELF GNU property data")
+ .map(|val| val.get(endian))
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/relocation.rs b/third_party/rust/object/src/read/elf/relocation.rs
new file mode 100644
index 0000000000..78032dfdbc
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/relocation.rs
@@ -0,0 +1,576 @@
+use alloc::fmt;
+use alloc::vec::Vec;
+use core::fmt::Debug;
+use core::slice;
+
+use crate::elf;
+use crate::endian::{self, Endianness};
+use crate::pod::Pod;
+use crate::read::{
+ self, Error, ReadRef, Relocation, RelocationEncoding, RelocationKind, RelocationTarget,
+ SectionIndex, SymbolIndex,
+};
+
+use super::{ElfFile, FileHeader, SectionHeader, SectionTable};
+
+/// A mapping from section index to associated relocation sections.
+#[derive(Debug)]
+pub struct RelocationSections {
+ relocations: Vec<usize>,
+}
+
+impl RelocationSections {
+ /// Create a new mapping using the section table.
+ ///
+ /// Skips relocation sections that do not use the given symbol table section.
+ pub fn parse<'data, Elf: FileHeader, R: ReadRef<'data>>(
+ endian: Elf::Endian,
+ sections: &SectionTable<'data, Elf, R>,
+ symbol_section: SectionIndex,
+ ) -> read::Result<Self> {
+ let mut relocations = vec![0; sections.len()];
+ for (index, section) in sections.iter().enumerate().rev() {
+ let sh_type = section.sh_type(endian);
+ if sh_type == elf::SHT_REL || sh_type == elf::SHT_RELA {
+ // The symbol indices used in relocations must be for the symbol table
+ // we are expecting to use.
+ let sh_link = SectionIndex(section.sh_link(endian) as usize);
+ if sh_link != symbol_section {
+ continue;
+ }
+
+ let sh_info = section.sh_info(endian) as usize;
+ if sh_info == 0 {
+ // Skip dynamic relocations.
+ continue;
+ }
+ if sh_info >= relocations.len() {
+ return Err(Error("Invalid ELF sh_info for relocation section"));
+ }
+
+ // Handle multiple relocation sections by chaining them.
+ let next = relocations[sh_info];
+ relocations[sh_info] = index;
+ relocations[index] = next;
+ }
+ }
+ Ok(Self { relocations })
+ }
+
+ /// Given a section index, return the section index of the associated relocation section.
+ ///
+ /// This may also be called with a relocation section index, and it will return the
+ /// next associated relocation section.
+ pub fn get(&self, index: usize) -> Option<usize> {
+ self.relocations.get(index).cloned().filter(|x| *x != 0)
+ }
+}
+
+pub(super) enum ElfRelaIterator<'data, Elf: FileHeader> {
+ Rel(slice::Iter<'data, Elf::Rel>),
+ Rela(slice::Iter<'data, Elf::Rela>),
+}
+
+impl<'data, Elf: FileHeader> ElfRelaIterator<'data, Elf> {
+ fn is_rel(&self) -> bool {
+ match self {
+ ElfRelaIterator::Rel(_) => true,
+ ElfRelaIterator::Rela(_) => false,
+ }
+ }
+}
+
+impl<'data, Elf: FileHeader> Iterator for ElfRelaIterator<'data, Elf> {
+ type Item = Elf::Rela;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self {
+ ElfRelaIterator::Rel(ref mut i) => i.next().cloned().map(Self::Item::from),
+ ElfRelaIterator::Rela(ref mut i) => i.next().cloned(),
+ }
+ }
+}
+
+/// An iterator over the dynamic relocations for an `ElfFile32`.
+pub type ElfDynamicRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator over the dynamic relocations for an `ElfFile64`.
+pub type ElfDynamicRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator over the dynamic relocations for an `ElfFile`.
+pub struct ElfDynamicRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ /// The current relocation section index.
+ pub(super) section_index: SectionIndex,
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>,
+}
+
+impl<'data, 'file, Elf, R> Iterator for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let endian = self.file.endian;
+ loop {
+ if let Some(ref mut relocations) = self.relocations {
+ if let Some(reloc) = relocations.next() {
+ let relocation =
+ parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
+ return Some((reloc.r_offset(endian).into(), relocation));
+ }
+ self.relocations = None;
+ }
+
+ let section = self.file.sections.section(self.section_index).ok()?;
+ self.section_index.0 += 1;
+
+ let sh_link = SectionIndex(section.sh_link(endian) as usize);
+ if sh_link != self.file.dynamic_symbols.section() {
+ continue;
+ }
+
+ match section.sh_type(endian) {
+ elf::SHT_REL => {
+ if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
+ self.relocations = Some(ElfRelaIterator::Rel(relocations.iter()));
+ }
+ }
+ elf::SHT_RELA => {
+ if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
+ self.relocations = Some(ElfRelaIterator::Rela(relocations.iter()));
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+}
+
+impl<'data, 'file, Elf, R> fmt::Debug for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ElfDynamicRelocationIterator").finish()
+ }
+}
+
+/// An iterator over the relocations for an `ElfSection32`.
+pub type ElfSectionRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSectionRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator over the relocations for an `ElfSection64`.
+pub type ElfSectionRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSectionRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator over the relocations for an `ElfSection`.
+pub struct ElfSectionRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ /// The current pointer in the chain of relocation sections.
+ pub(super) section_index: SectionIndex,
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>,
+}
+
+impl<'data, 'file, Elf, R> Iterator for ElfSectionRelocationIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let endian = self.file.endian;
+ loop {
+ if let Some(ref mut relocations) = self.relocations {
+ if let Some(reloc) = relocations.next() {
+ let relocation =
+ parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
+ return Some((reloc.r_offset(endian).into(), relocation));
+ }
+ self.relocations = None;
+ }
+ self.section_index = SectionIndex(self.file.relocations.get(self.section_index.0)?);
+ // The construction of RelocationSections ensures section_index is valid.
+ let section = self.file.sections.section(self.section_index).unwrap();
+ match section.sh_type(endian) {
+ elf::SHT_REL => {
+ if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
+ self.relocations = Some(ElfRelaIterator::Rel(relocations.iter()));
+ }
+ }
+ elf::SHT_RELA => {
+ if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
+ self.relocations = Some(ElfRelaIterator::Rela(relocations.iter()));
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+}
+
+impl<'data, 'file, Elf, R> fmt::Debug for ElfSectionRelocationIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ElfSectionRelocationIterator").finish()
+ }
+}
+
+fn parse_relocation<Elf: FileHeader>(
+ header: &Elf,
+ endian: Elf::Endian,
+ reloc: Elf::Rela,
+ implicit_addend: bool,
+) -> Relocation {
+ let mut encoding = RelocationEncoding::Generic;
+ let is_mips64el = header.is_mips64el(endian);
+ let (kind, size) = match header.e_machine(endian) {
+ elf::EM_AARCH64 => {
+ if header.is_type_64() {
+ match reloc.r_type(endian, false) {
+ elf::R_AARCH64_ABS64 => (RelocationKind::Absolute, 64),
+ elf::R_AARCH64_ABS32 => (RelocationKind::Absolute, 32),
+ elf::R_AARCH64_ABS16 => (RelocationKind::Absolute, 16),
+ elf::R_AARCH64_PREL64 => (RelocationKind::Relative, 64),
+ elf::R_AARCH64_PREL32 => (RelocationKind::Relative, 32),
+ elf::R_AARCH64_PREL16 => (RelocationKind::Relative, 16),
+ elf::R_AARCH64_CALL26 => {
+ encoding = RelocationEncoding::AArch64Call;
+ (RelocationKind::PltRelative, 26)
+ }
+ r_type => (RelocationKind::Elf(r_type), 0),
+ }
+ } else {
+ match reloc.r_type(endian, false) {
+ elf::R_AARCH64_P32_ABS32 => (RelocationKind::Absolute, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ }
+ }
+ }
+ elf::EM_ARM => match reloc.r_type(endian, false) {
+ elf::R_ARM_ABS32 => (RelocationKind::Absolute, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_AVR => match reloc.r_type(endian, false) {
+ elf::R_AVR_32 => (RelocationKind::Absolute, 32),
+ elf::R_AVR_16 => (RelocationKind::Absolute, 16),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_BPF => match reloc.r_type(endian, false) {
+ elf::R_BPF_64_64 => (RelocationKind::Absolute, 64),
+ elf::R_BPF_64_32 => (RelocationKind::Absolute, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_CSKY => match reloc.r_type(endian, false) {
+ elf::R_CKCORE_ADDR32 => (RelocationKind::Absolute, 32),
+ elf::R_CKCORE_PCREL32 => (RelocationKind::Relative, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_386 => match reloc.r_type(endian, false) {
+ elf::R_386_32 => (RelocationKind::Absolute, 32),
+ elf::R_386_PC32 => (RelocationKind::Relative, 32),
+ elf::R_386_GOT32 => (RelocationKind::Got, 32),
+ elf::R_386_PLT32 => (RelocationKind::PltRelative, 32),
+ elf::R_386_GOTOFF => (RelocationKind::GotBaseOffset, 32),
+ elf::R_386_GOTPC => (RelocationKind::GotBaseRelative, 32),
+ elf::R_386_16 => (RelocationKind::Absolute, 16),
+ elf::R_386_PC16 => (RelocationKind::Relative, 16),
+ elf::R_386_8 => (RelocationKind::Absolute, 8),
+ elf::R_386_PC8 => (RelocationKind::Relative, 8),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_X86_64 => match reloc.r_type(endian, false) {
+ elf::R_X86_64_64 => (RelocationKind::Absolute, 64),
+ elf::R_X86_64_PC32 => (RelocationKind::Relative, 32),
+ elf::R_X86_64_GOT32 => (RelocationKind::Got, 32),
+ elf::R_X86_64_PLT32 => (RelocationKind::PltRelative, 32),
+ elf::R_X86_64_GOTPCREL => (RelocationKind::GotRelative, 32),
+ elf::R_X86_64_32 => (RelocationKind::Absolute, 32),
+ elf::R_X86_64_32S => {
+ encoding = RelocationEncoding::X86Signed;
+ (RelocationKind::Absolute, 32)
+ }
+ elf::R_X86_64_16 => (RelocationKind::Absolute, 16),
+ elf::R_X86_64_PC16 => (RelocationKind::Relative, 16),
+ elf::R_X86_64_8 => (RelocationKind::Absolute, 8),
+ elf::R_X86_64_PC8 => (RelocationKind::Relative, 8),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_HEXAGON => match reloc.r_type(endian, false) {
+ elf::R_HEX_32 => (RelocationKind::Absolute, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_LOONGARCH => match reloc.r_type(endian, false) {
+ elf::R_LARCH_32 => (RelocationKind::Absolute, 32),
+ elf::R_LARCH_64 => (RelocationKind::Absolute, 64),
+ elf::R_LARCH_32_PCREL => (RelocationKind::Relative, 32),
+ elf::R_LARCH_B16 => {
+ encoding = RelocationEncoding::LoongArchBranch;
+ (RelocationKind::Relative, 16)
+ }
+ elf::R_LARCH_B21 => {
+ encoding = RelocationEncoding::LoongArchBranch;
+ (RelocationKind::Relative, 21)
+ }
+ elf::R_LARCH_B26 => {
+ encoding = RelocationEncoding::LoongArchBranch;
+ (RelocationKind::Relative, 26)
+ }
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_MIPS => match reloc.r_type(endian, is_mips64el) {
+ elf::R_MIPS_16 => (RelocationKind::Absolute, 16),
+ elf::R_MIPS_32 => (RelocationKind::Absolute, 32),
+ elf::R_MIPS_64 => (RelocationKind::Absolute, 64),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_MSP430 => match reloc.r_type(endian, false) {
+ elf::R_MSP430_32 => (RelocationKind::Absolute, 32),
+ elf::R_MSP430_16_BYTE => (RelocationKind::Absolute, 16),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_PPC => match reloc.r_type(endian, false) {
+ elf::R_PPC_ADDR32 => (RelocationKind::Absolute, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_PPC64 => match reloc.r_type(endian, false) {
+ elf::R_PPC64_ADDR32 => (RelocationKind::Absolute, 32),
+ elf::R_PPC64_ADDR64 => (RelocationKind::Absolute, 64),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_RISCV => match reloc.r_type(endian, false) {
+ elf::R_RISCV_32 => (RelocationKind::Absolute, 32),
+ elf::R_RISCV_64 => (RelocationKind::Absolute, 64),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_S390 => match reloc.r_type(endian, false) {
+ elf::R_390_8 => (RelocationKind::Absolute, 8),
+ elf::R_390_16 => (RelocationKind::Absolute, 16),
+ elf::R_390_32 => (RelocationKind::Absolute, 32),
+ elf::R_390_64 => (RelocationKind::Absolute, 64),
+ elf::R_390_PC16 => (RelocationKind::Relative, 16),
+ elf::R_390_PC32 => (RelocationKind::Relative, 32),
+ elf::R_390_PC64 => (RelocationKind::Relative, 64),
+ elf::R_390_PC16DBL => {
+ encoding = RelocationEncoding::S390xDbl;
+ (RelocationKind::Relative, 16)
+ }
+ elf::R_390_PC32DBL => {
+ encoding = RelocationEncoding::S390xDbl;
+ (RelocationKind::Relative, 32)
+ }
+ elf::R_390_PLT16DBL => {
+ encoding = RelocationEncoding::S390xDbl;
+ (RelocationKind::PltRelative, 16)
+ }
+ elf::R_390_PLT32DBL => {
+ encoding = RelocationEncoding::S390xDbl;
+ (RelocationKind::PltRelative, 32)
+ }
+ elf::R_390_GOT16 => (RelocationKind::Got, 16),
+ elf::R_390_GOT32 => (RelocationKind::Got, 32),
+ elf::R_390_GOT64 => (RelocationKind::Got, 64),
+ elf::R_390_GOTENT => {
+ encoding = RelocationEncoding::S390xDbl;
+ (RelocationKind::GotRelative, 32)
+ }
+ elf::R_390_GOTOFF16 => (RelocationKind::GotBaseOffset, 16),
+ elf::R_390_GOTOFF32 => (RelocationKind::GotBaseOffset, 32),
+ elf::R_390_GOTOFF64 => (RelocationKind::GotBaseOffset, 64),
+ elf::R_390_GOTPC => (RelocationKind::GotBaseRelative, 64),
+ elf::R_390_GOTPCDBL => {
+ encoding = RelocationEncoding::S390xDbl;
+ (RelocationKind::GotBaseRelative, 32)
+ }
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_SBF => match reloc.r_type(endian, false) {
+ elf::R_SBF_64_64 => (RelocationKind::Absolute, 64),
+ elf::R_SBF_64_32 => (RelocationKind::Absolute, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ elf::EM_SPARC | elf::EM_SPARC32PLUS | elf::EM_SPARCV9 => {
+ match reloc.r_type(endian, false) {
+ elf::R_SPARC_32 | elf::R_SPARC_UA32 => (RelocationKind::Absolute, 32),
+ elf::R_SPARC_64 | elf::R_SPARC_UA64 => (RelocationKind::Absolute, 64),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ }
+ }
+ elf::EM_XTENSA => match reloc.r_type(endian, false) {
+ elf::R_XTENSA_32 => (RelocationKind::Absolute, 32),
+ elf::R_XTENSA_32_PCREL => (RelocationKind::Relative, 32),
+ r_type => (RelocationKind::Elf(r_type), 0),
+ },
+ _ => (RelocationKind::Elf(reloc.r_type(endian, false)), 0),
+ };
+ let sym = reloc.r_sym(endian, is_mips64el) as usize;
+ let target = if sym == 0 {
+ RelocationTarget::Absolute
+ } else {
+ RelocationTarget::Symbol(SymbolIndex(sym))
+ };
+ Relocation {
+ kind,
+ encoding,
+ size,
+ target,
+ addend: reloc.r_addend(endian).into(),
+ implicit_addend,
+ }
+}
+
+/// A trait for generic access to `Rel32` and `Rel64`.
+#[allow(missing_docs)]
+pub trait Rel: Debug + Pod + Clone {
+ type Word: Into<u64>;
+ type Sword: Into<i64>;
+ type Endian: endian::Endian;
+
+ fn r_offset(&self, endian: Self::Endian) -> Self::Word;
+ fn r_info(&self, endian: Self::Endian) -> Self::Word;
+ fn r_sym(&self, endian: Self::Endian) -> u32;
+ fn r_type(&self, endian: Self::Endian) -> u32;
+}
+
+impl<Endian: endian::Endian> Rel for elf::Rel32<Endian> {
+ type Word = u32;
+ type Sword = i32;
+ type Endian = Endian;
+
+ #[inline]
+ fn r_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.r_offset.get(endian)
+ }
+
+ #[inline]
+ fn r_info(&self, endian: Self::Endian) -> Self::Word {
+ self.r_info.get(endian)
+ }
+
+ #[inline]
+ fn r_sym(&self, endian: Self::Endian) -> u32 {
+ self.r_sym(endian)
+ }
+
+ #[inline]
+ fn r_type(&self, endian: Self::Endian) -> u32 {
+ self.r_type(endian)
+ }
+}
+
+impl<Endian: endian::Endian> Rel for elf::Rel64<Endian> {
+ type Word = u64;
+ type Sword = i64;
+ type Endian = Endian;
+
+ #[inline]
+ fn r_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.r_offset.get(endian)
+ }
+
+ #[inline]
+ fn r_info(&self, endian: Self::Endian) -> Self::Word {
+ self.r_info.get(endian)
+ }
+
+ #[inline]
+ fn r_sym(&self, endian: Self::Endian) -> u32 {
+ self.r_sym(endian)
+ }
+
+ #[inline]
+ fn r_type(&self, endian: Self::Endian) -> u32 {
+ self.r_type(endian)
+ }
+}
+
+/// A trait for generic access to `Rela32` and `Rela64`.
+#[allow(missing_docs)]
+pub trait Rela: Debug + Pod + Clone {
+ type Word: Into<u64>;
+ type Sword: Into<i64>;
+ type Endian: endian::Endian;
+
+ fn r_offset(&self, endian: Self::Endian) -> Self::Word;
+ fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word;
+ fn r_addend(&self, endian: Self::Endian) -> Self::Sword;
+ fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
+ fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
+}
+
+impl<Endian: endian::Endian> Rela for elf::Rela32<Endian> {
+ type Word = u32;
+ type Sword = i32;
+ type Endian = Endian;
+
+ #[inline]
+ fn r_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.r_offset.get(endian)
+ }
+
+ #[inline]
+ fn r_info(&self, endian: Self::Endian, _is_mips64el: bool) -> Self::Word {
+ self.r_info.get(endian)
+ }
+
+ #[inline]
+ fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
+ self.r_addend.get(endian)
+ }
+
+ #[inline]
+ fn r_sym(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
+ self.r_sym(endian)
+ }
+
+ #[inline]
+ fn r_type(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
+ self.r_type(endian)
+ }
+}
+
+impl<Endian: endian::Endian> Rela for elf::Rela64<Endian> {
+ type Word = u64;
+ type Sword = i64;
+ type Endian = Endian;
+
+ #[inline]
+ fn r_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.r_offset.get(endian)
+ }
+
+ #[inline]
+ fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word {
+ self.get_r_info(endian, is_mips64el)
+ }
+
+ #[inline]
+ fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
+ self.r_addend.get(endian)
+ }
+
+ #[inline]
+ fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
+ self.r_sym(endian, is_mips64el)
+ }
+
+ #[inline]
+ fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
+ self.r_type(endian, is_mips64el)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/section.rs b/third_party/rust/object/src/read/elf/section.rs
new file mode 100644
index 0000000000..df08f9e3e2
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/section.rs
@@ -0,0 +1,1146 @@
+use core::fmt::Debug;
+use core::{iter, mem, slice, str};
+
+use crate::elf;
+use crate::endian::{self, Endianness, U32Bytes};
+use crate::pod::Pod;
+use crate::read::{
+ self, Bytes, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection,
+ ReadError, ReadRef, SectionFlags, SectionIndex, SectionKind, StringTable,
+};
+
+use super::{
+ AttributesSection, CompressionHeader, ElfFile, ElfSectionRelocationIterator, FileHeader,
+ GnuHashTable, HashTable, NoteIterator, RelocationSections, SymbolTable, VerdefIterator,
+ VerneedIterator, VersionTable,
+};
+
+/// The table of section headers in an ELF file.
+///
+/// Also includes the string table used for the section names.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct SectionTable<'data, Elf: FileHeader, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ sections: &'data [Elf::SectionHeader],
+ strings: StringTable<'data, R>,
+}
+
+impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> {
+ /// Create a new section table.
+ #[inline]
+ pub fn new(sections: &'data [Elf::SectionHeader], strings: StringTable<'data, R>) -> Self {
+ SectionTable { sections, strings }
+ }
+
+ /// Iterate over the section headers.
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'data, Elf::SectionHeader> {
+ self.sections.iter()
+ }
+
+ /// Return true if the section table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.sections.is_empty()
+ }
+
+ /// The number of section headers.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.sections.len()
+ }
+
+ /// Return the section header at the given index.
+ pub fn section(&self, index: SectionIndex) -> read::Result<&'data Elf::SectionHeader> {
+ self.sections
+ .get(index.0)
+ .read_error("Invalid ELF section index")
+ }
+
+ /// Return the section header with the given name.
+ ///
+ /// Ignores sections with invalid names.
+ pub fn section_by_name(
+ &self,
+ endian: Elf::Endian,
+ name: &[u8],
+ ) -> Option<(usize, &'data Elf::SectionHeader)> {
+ self.sections
+ .iter()
+ .enumerate()
+ .find(|(_, section)| self.section_name(endian, section) == Ok(name))
+ }
+
+ /// Return the section name for the given section header.
+ pub fn section_name(
+ &self,
+ endian: Elf::Endian,
+ section: &'data Elf::SectionHeader,
+ ) -> read::Result<&'data [u8]> {
+ section.name(endian, self.strings)
+ }
+
+ /// Return the string table at the given section index.
+ ///
+ /// Returns an error if the section is not a string table.
+ #[inline]
+ pub fn strings(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ index: SectionIndex,
+ ) -> read::Result<StringTable<'data, R>> {
+ self.section(index)?
+ .strings(endian, data)?
+ .read_error("Invalid ELF string section type")
+ }
+
+ /// Return the symbol table of the given section type.
+ ///
+ /// Returns an empty symbol table if the symbol table does not exist.
+ #[inline]
+ pub fn symbols(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ sh_type: u32,
+ ) -> read::Result<SymbolTable<'data, Elf, R>> {
+ debug_assert!(sh_type == elf::SHT_DYNSYM || sh_type == elf::SHT_SYMTAB);
+
+ let (index, section) = match self
+ .iter()
+ .enumerate()
+ .find(|s| s.1.sh_type(endian) == sh_type)
+ {
+ Some(s) => s,
+ None => return Ok(SymbolTable::default()),
+ };
+
+ SymbolTable::parse(endian, data, self, SectionIndex(index), section)
+ }
+
+ /// Return the symbol table at the given section index.
+ ///
+ /// Returns an error if the section is not a symbol table.
+ #[inline]
+ pub fn symbol_table_by_index(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ index: SectionIndex,
+ ) -> read::Result<SymbolTable<'data, Elf, R>> {
+ let section = self.section(index)?;
+ match section.sh_type(endian) {
+ elf::SHT_DYNSYM | elf::SHT_SYMTAB => {}
+ _ => return Err(Error("Invalid ELF symbol table section type")),
+ }
+ SymbolTable::parse(endian, data, self, index, section)
+ }
+
+ /// Create a mapping from section index to associated relocation sections.
+ #[inline]
+ pub fn relocation_sections(
+ &self,
+ endian: Elf::Endian,
+ symbol_section: SectionIndex,
+ ) -> read::Result<RelocationSections> {
+ RelocationSections::parse(endian, self, symbol_section)
+ }
+
+ /// Return the contents of a dynamic section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_DYNAMIC` section.
+ /// Returns `Err` for invalid values.
+ pub fn dynamic(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [Elf::Dyn], SectionIndex)>> {
+ for section in self.sections {
+ if let Some(dynamic) = section.dynamic(endian, data)? {
+ return Ok(Some(dynamic));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the header of a SysV hash section.
+ ///
+ /// Returns `Ok(None)` if there is no SysV GNU hash section.
+ /// Returns `Err` for invalid values.
+ pub fn hash_header(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::HashHeader<Elf::Endian>>> {
+ for section in self.sections {
+ if let Some(hash) = section.hash_header(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a SysV hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if there is no SysV hash section.
+ /// Returns `Err` for invalid values.
+ pub fn hash(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(HashTable<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(hash) = section.hash(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the header of a GNU hash section.
+ ///
+ /// Returns `Ok(None)` if there is no GNU hash section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_hash_header(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::GnuHashHeader<Elf::Endian>>> {
+ for section in self.sections {
+ if let Some(hash) = section.gnu_hash_header(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a GNU hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if there is no GNU hash section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_hash(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(GnuHashTable<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(hash) = section.gnu_hash(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a `SHT_GNU_VERSYM` section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERSYM` section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_versym(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [elf::Versym<Elf::Endian>], SectionIndex)>> {
+ for section in self.sections {
+ if let Some(syms) = section.gnu_versym(endian, data)? {
+ return Ok(Some(syms));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a `SHT_GNU_VERDEF` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERDEF` section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_verdef(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerdefIterator<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(defs) = section.gnu_verdef(endian, data)? {
+ return Ok(Some(defs));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a `SHT_GNU_VERNEED` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERNEED` section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_verneed(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerneedIterator<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(needs) = section.gnu_verneed(endian, data)? {
+ return Ok(Some(needs));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Returns the symbol version table.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERSYM` section.
+ /// Returns `Err` for invalid values.
+ pub fn versions(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<VersionTable<'data, Elf>>> {
+ let (versyms, link) = match self.gnu_versym(endian, data)? {
+ Some(val) => val,
+ None => return Ok(None),
+ };
+ let strings = self.symbol_table_by_index(endian, data, link)?.strings();
+ // TODO: check links?
+ let verdefs = self.gnu_verdef(endian, data)?.map(|x| x.0);
+ let verneeds = self.gnu_verneed(endian, data)?.map(|x| x.0);
+ VersionTable::parse(endian, versyms, verdefs, verneeds, strings).map(Some)
+ }
+}
+
+/// An iterator over the sections of an `ElfFile32`.
+pub type ElfSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator over the sections of an `ElfFile64`.
+pub type ElfSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator over the sections of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSectionIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) iter: iter::Enumerate<slice::Iter<'data, Elf::SectionHeader>>,
+}
+
+impl<'data, 'file, Elf, R> Iterator for ElfSectionIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = ElfSection<'data, 'file, Elf, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| ElfSection {
+ index: SectionIndex(index),
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A section of an `ElfFile32`.
+pub type ElfSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSection<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// A section of an `ElfFile64`.
+pub type ElfSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSection<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// A section of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSection<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) index: SectionIndex,
+ pub(super) section: &'data Elf::SectionHeader,
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSection<'data, 'file, Elf, R> {
+ fn bytes(&self) -> read::Result<&'data [u8]> {
+ self.section
+ .data(self.file.endian, self.file.data)
+ .read_error("Invalid ELF section size or offset")
+ }
+
+ fn maybe_compressed(&self) -> read::Result<Option<CompressedFileRange>> {
+ let endian = self.file.endian;
+ if let Some((header, offset, compressed_size)) =
+ self.section.compression(endian, self.file.data)?
+ {
+ let format = match header.ch_type(endian) {
+ elf::ELFCOMPRESS_ZLIB => CompressionFormat::Zlib,
+ elf::ELFCOMPRESS_ZSTD => CompressionFormat::Zstandard,
+ _ => return Err(Error("Unsupported ELF compression type")),
+ };
+ let uncompressed_size = header.ch_size(endian).into();
+ Ok(Some(CompressedFileRange {
+ format,
+ offset,
+ compressed_size,
+ uncompressed_size,
+ }))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try GNU-style "ZLIB" header decompression.
+ fn maybe_compressed_gnu(&self) -> read::Result<Option<CompressedFileRange>> {
+ let name = match self.name() {
+ Ok(name) => name,
+ // I think it's ok to ignore this error?
+ Err(_) => return Ok(None),
+ };
+ if !name.starts_with(".zdebug_") {
+ return Ok(None);
+ }
+ let (section_offset, section_size) = self
+ .section
+ .file_range(self.file.endian)
+ .read_error("Invalid ELF GNU compressed section type")?;
+ let mut offset = section_offset;
+ let data = self.file.data;
+ // Assume ZLIB-style uncompressed data is no more than 4GB to avoid accidentally
+ // huge allocations. This also reduces the chance of accidentally matching on a
+ // .debug_str that happens to start with "ZLIB".
+ if data
+ .read_bytes(&mut offset, 8)
+ .read_error("ELF GNU compressed section is too short")?
+ != b"ZLIB\0\0\0\0"
+ {
+ return Err(Error("Invalid ELF GNU compressed section header"));
+ }
+ let uncompressed_size = data
+ .read::<U32Bytes<_>>(&mut offset)
+ .read_error("ELF GNU compressed section is too short")?
+ .get(endian::BigEndian)
+ .into();
+ let compressed_size = section_size
+ .checked_sub(offset - section_offset)
+ .read_error("ELF GNU compressed section is too short")?;
+ Ok(Some(CompressedFileRange {
+ format: CompressionFormat::Zlib,
+ offset,
+ compressed_size,
+ uncompressed_size,
+ }))
+ }
+}
+
+impl<'data, 'file, Elf, R> read::private::Sealed for ElfSection<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Elf, R> ObjectSection<'data> for ElfSection<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type RelocationIterator = ElfSectionRelocationIterator<'data, 'file, Elf, R>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.section.sh_addr(self.file.endian).into()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.section.sh_size(self.file.endian).into()
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.section.sh_addralign(self.file.endian).into()
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ self.section.file_range(self.file.endian)
+ }
+
+ #[inline]
+ fn data(&self) -> read::Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ fn compressed_file_range(&self) -> read::Result<CompressedFileRange> {
+ Ok(if let Some(data) = self.maybe_compressed()? {
+ data
+ } else if let Some(data) = self.maybe_compressed_gnu()? {
+ data
+ } else {
+ CompressedFileRange::none(self.file_range())
+ })
+ }
+
+ fn compressed_data(&self) -> read::Result<CompressedData<'data>> {
+ self.compressed_file_range()?.data(self.file.data)
+ }
+
+ fn name_bytes(&self) -> read::Result<&[u8]> {
+ self.file
+ .sections
+ .section_name(self.file.endian, self.section)
+ }
+
+ fn name(&self) -> read::Result<&str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 ELF section name")
+ }
+
+ #[inline]
+ fn segment_name_bytes(&self) -> read::Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn segment_name(&self) -> read::Result<Option<&str>> {
+ Ok(None)
+ }
+
+ fn kind(&self) -> SectionKind {
+ let flags = self.section.sh_flags(self.file.endian).into();
+ let sh_type = self.section.sh_type(self.file.endian);
+ match sh_type {
+ elf::SHT_PROGBITS => {
+ if flags & u64::from(elf::SHF_ALLOC) != 0 {
+ if flags & u64::from(elf::SHF_EXECINSTR) != 0 {
+ SectionKind::Text
+ } else if flags & u64::from(elf::SHF_TLS) != 0 {
+ SectionKind::Tls
+ } else if flags & u64::from(elf::SHF_WRITE) != 0 {
+ SectionKind::Data
+ } else if flags & u64::from(elf::SHF_STRINGS) != 0 {
+ SectionKind::ReadOnlyString
+ } else {
+ SectionKind::ReadOnlyData
+ }
+ } else if flags & u64::from(elf::SHF_STRINGS) != 0 {
+ SectionKind::OtherString
+ } else {
+ SectionKind::Other
+ }
+ }
+ elf::SHT_NOBITS => {
+ if flags & u64::from(elf::SHF_TLS) != 0 {
+ SectionKind::UninitializedTls
+ } else {
+ SectionKind::UninitializedData
+ }
+ }
+ elf::SHT_NOTE => SectionKind::Note,
+ elf::SHT_NULL
+ | elf::SHT_SYMTAB
+ | elf::SHT_STRTAB
+ | elf::SHT_RELA
+ | elf::SHT_HASH
+ | elf::SHT_DYNAMIC
+ | elf::SHT_REL
+ | elf::SHT_DYNSYM
+ | elf::SHT_GROUP => SectionKind::Metadata,
+ _ => SectionKind::Elf(sh_type),
+ }
+ }
+
+ fn relocations(&self) -> ElfSectionRelocationIterator<'data, 'file, Elf, R> {
+ ElfSectionRelocationIterator {
+ section_index: self.index,
+ file: self.file,
+ relocations: None,
+ }
+ }
+
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::Elf {
+ sh_flags: self.section.sh_flags(self.file.endian).into(),
+ }
+ }
+}
+
+/// A trait for generic access to `SectionHeader32` and `SectionHeader64`.
+#[allow(missing_docs)]
+pub trait SectionHeader: Debug + Pod {
+ type Elf: FileHeader<SectionHeader = Self, Endian = Self::Endian, Word = Self::Word>;
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn sh_name(&self, endian: Self::Endian) -> u32;
+ fn sh_type(&self, endian: Self::Endian) -> u32;
+ fn sh_flags(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_addr(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_offset(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_size(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_link(&self, endian: Self::Endian) -> u32;
+ fn sh_info(&self, endian: Self::Endian) -> u32;
+ fn sh_addralign(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_entsize(&self, endian: Self::Endian) -> Self::Word;
+
+ /// Parse the section name from the string table.
+ fn name<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ strings: StringTable<'data, R>,
+ ) -> read::Result<&'data [u8]> {
+ strings
+ .get(self.sh_name(endian))
+ .read_error("Invalid ELF section name offset")
+ }
+
+ /// Return the offset and size of the section in the file.
+ ///
+ /// Returns `None` for sections that have no data in the file.
+ fn file_range(&self, endian: Self::Endian) -> Option<(u64, u64)> {
+ if self.sh_type(endian) == elf::SHT_NOBITS {
+ None
+ } else {
+ Some((self.sh_offset(endian).into(), self.sh_size(endian).into()))
+ }
+ }
+
+ /// Return the section data.
+ ///
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values.
+ fn data<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<&'data [u8]> {
+ if let Some((offset, size)) = self.file_range(endian) {
+ data.read_bytes_at(offset, size)
+ .read_error("Invalid ELF section size or offset")
+ } else {
+ Ok(&[])
+ }
+ }
+
+ /// Return the section data as a slice of the given type.
+ ///
+ /// Allows padding at the end of the data.
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values, including bad alignment.
+ fn data_as_array<'data, T: Pod, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<&'data [T]> {
+ let mut data = self.data(endian, data).map(Bytes)?;
+ data.read_slice(data.len() / mem::size_of::<T>())
+ .read_error("Invalid ELF section size or offset")
+ }
+
+ /// Return the strings in the section.
+ ///
+ /// Returns `Ok(None)` if the section does not contain strings.
+ /// Returns `Err` for invalid values.
+ fn strings<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<StringTable<'data, R>>> {
+ if self.sh_type(endian) != elf::SHT_STRTAB {
+ return Ok(None);
+ }
+ let str_offset = self.sh_offset(endian).into();
+ let str_size = self.sh_size(endian).into();
+ let str_end = str_offset
+ .checked_add(str_size)
+ .read_error("Invalid ELF string section offset or size")?;
+ Ok(Some(StringTable::new(data, str_offset, str_end)))
+ }
+
+ /// Return the symbols in the section.
+ ///
+ /// Also finds the linked string table in `sections`.
+ ///
+ /// `section_index` must be the 0-based index of this section, and is used
+ /// to find the corresponding extended section index table in `sections`.
+ ///
+ /// Returns `Ok(None)` if the section does not contain symbols.
+ /// Returns `Err` for invalid values.
+ fn symbols<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ sections: &SectionTable<'data, Self::Elf, R>,
+ section_index: SectionIndex,
+ ) -> read::Result<Option<SymbolTable<'data, Self::Elf, R>>> {
+ let sh_type = self.sh_type(endian);
+ if sh_type != elf::SHT_SYMTAB && sh_type != elf::SHT_DYNSYM {
+ return Ok(None);
+ }
+ SymbolTable::parse(endian, data, sections, section_index, self).map(Some)
+ }
+
+ /// Return the `Elf::Rel` entries in the section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain relocations.
+ /// Returns `Err` for invalid values.
+ fn rel<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Rel], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_REL {
+ return Ok(None);
+ }
+ let rel = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF relocation section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((rel, link)))
+ }
+
+ /// Return the `Elf::Rela` entries in the section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain relocations.
+ /// Returns `Err` for invalid values.
+ fn rela<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Rela], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_RELA {
+ return Ok(None);
+ }
+ let rela = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF relocation section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((rela, link)))
+ }
+
+ /// Return entries in a dynamic section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_DYNAMIC`.
+ /// Returns `Err` for invalid values.
+ fn dynamic<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Dyn], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_DYNAMIC {
+ return Ok(None);
+ }
+ let dynamic = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF dynamic section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((dynamic, link)))
+ }
+
+ /// Return a note iterator for the section data.
+ ///
+ /// Returns `Ok(None)` if the section does not contain notes.
+ /// Returns `Err` for invalid values.
+ fn notes<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> {
+ if self.sh_type(endian) != elf::SHT_NOTE {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF note section offset or size")?;
+ let notes = NoteIterator::new(endian, self.sh_addralign(endian), data)?;
+ Ok(Some(notes))
+ }
+
+ /// Return the contents of a group section.
+ ///
+ /// The first value is a `GRP_*` value, and the remaining values
+ /// are section indices.
+ ///
+ /// Returns `Ok(None)` if the section does not define a group.
+ /// Returns `Err` for invalid values.
+ fn group<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(u32, &'data [U32Bytes<Self::Endian>])>> {
+ if self.sh_type(endian) != elf::SHT_GROUP {
+ return Ok(None);
+ }
+ let mut data = self
+ .data(endian, data)
+ .read_error("Invalid ELF group section offset or size")
+ .map(Bytes)?;
+ let flag = data
+ .read::<U32Bytes<_>>()
+ .read_error("Invalid ELF group section offset or size")?
+ .get(endian);
+ let count = data.len() / mem::size_of::<U32Bytes<Self::Endian>>();
+ let sections = data
+ .read_slice(count)
+ .read_error("Invalid ELF group section offset or size")?;
+ Ok(Some((flag, sections)))
+ }
+
+ /// Return the header of a SysV hash section.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a SysV hash.
+ /// Returns `Err` for invalid values.
+ fn hash_header<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::HashHeader<Self::Endian>>> {
+ if self.sh_type(endian) != elf::SHT_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF hash section offset or size")?;
+ let header = data
+ .read_at::<elf::HashHeader<Self::Endian>>(0)
+ .read_error("Invalid hash header")?;
+ Ok(Some(header))
+ }
+
+ /// Return the contents of a SysV hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a SysV hash.
+ /// Returns `Err` for invalid values.
+ fn hash<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(HashTable<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF hash section offset or size")?;
+ let hash = HashTable::parse(endian, data)?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((hash, link)))
+ }
+
+ /// Return the header of a GNU hash section.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a GNU hash.
+ /// Returns `Err` for invalid values.
+ fn gnu_hash_header<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::GnuHashHeader<Self::Endian>>> {
+ if self.sh_type(endian) != elf::SHT_GNU_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU hash section offset or size")?;
+ let header = data
+ .read_at::<elf::GnuHashHeader<Self::Endian>>(0)
+ .read_error("Invalid GNU hash header")?;
+ Ok(Some(header))
+ }
+
+ /// Return the contents of a GNU hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a GNU hash.
+ /// Returns `Err` for invalid values.
+ fn gnu_hash<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(GnuHashTable<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU hash section offset or size")?;
+ let hash = GnuHashTable::parse(endian, data)?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((hash, link)))
+ }
+
+ /// Return the contents of a `SHT_GNU_VERSYM` section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERSYM`.
+ /// Returns `Err` for invalid values.
+ fn gnu_versym<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [elf::Versym<Self::Endian>], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_VERSYM {
+ return Ok(None);
+ }
+ let versym = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF GNU versym section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((versym, link)))
+ }
+
+ /// Return an iterator for the entries of a `SHT_GNU_VERDEF` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERDEF`.
+ /// Returns `Err` for invalid values.
+ fn gnu_verdef<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerdefIterator<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_VERDEF {
+ return Ok(None);
+ }
+ let verdef = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU verdef section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((VerdefIterator::new(endian, verdef), link)))
+ }
+
+ /// Return an iterator for the entries of a `SHT_GNU_VERNEED` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERNEED`.
+ /// Returns `Err` for invalid values.
+ fn gnu_verneed<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerneedIterator<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_VERNEED {
+ return Ok(None);
+ }
+ let verneed = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU verneed section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((VerneedIterator::new(endian, verneed), link)))
+ }
+
+ /// Return the contents of a `SHT_GNU_ATTRIBUTES` section.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_ATTRIBUTES`.
+ /// Returns `Err` for invalid values.
+ fn gnu_attributes<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<AttributesSection<'data, Self::Elf>>> {
+ if self.sh_type(endian) != elf::SHT_GNU_ATTRIBUTES {
+ return Ok(None);
+ }
+ self.attributes(endian, data).map(Some)
+ }
+
+ /// Parse the contents of the section as attributes.
+ ///
+ /// This function does not check whether section type corresponds
+ /// to a section that contains attributes.
+ ///
+ /// Returns `Err` for invalid values.
+ fn attributes<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<AttributesSection<'data, Self::Elf>> {
+ let data = self.data(endian, data)?;
+ AttributesSection::new(endian, data)
+ }
+
+ /// Parse the compression header if present.
+ ///
+ /// Returns the header, and the offset and size of the compressed section data
+ /// in the file.
+ ///
+ /// Returns `Ok(None)` if the section flags do not have `SHF_COMPRESSED`.
+ /// Returns `Err` for invalid values.
+ fn compression<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<
+ Option<(
+ &'data <Self::Elf as FileHeader>::CompressionHeader,
+ u64,
+ u64,
+ )>,
+ > {
+ if (self.sh_flags(endian).into() & u64::from(elf::SHF_COMPRESSED)) == 0 {
+ return Ok(None);
+ }
+ let (section_offset, section_size) = self
+ .file_range(endian)
+ .read_error("Invalid ELF compressed section type")?;
+ let mut offset = section_offset;
+ let header = data
+ .read::<<Self::Elf as FileHeader>::CompressionHeader>(&mut offset)
+ .read_error("Invalid ELF compressed section offset")?;
+ let compressed_size = section_size
+ .checked_sub(offset - section_offset)
+ .read_error("Invalid ELF compressed section size")?;
+ Ok(Some((header, offset, compressed_size)))
+ }
+}
+
+impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader32<Endian> {
+ type Elf = elf::FileHeader32<Endian>;
+ type Word = u32;
+ type Endian = Endian;
+
+ #[inline]
+ fn sh_name(&self, endian: Self::Endian) -> u32 {
+ self.sh_name.get(endian)
+ }
+
+ #[inline]
+ fn sh_type(&self, endian: Self::Endian) -> u32 {
+ self.sh_type.get(endian)
+ }
+
+ #[inline]
+ fn sh_flags(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_flags.get(endian)
+ }
+
+ #[inline]
+ fn sh_addr(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addr.get(endian)
+ }
+
+ #[inline]
+ fn sh_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_offset.get(endian)
+ }
+
+ #[inline]
+ fn sh_size(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_size.get(endian)
+ }
+
+ #[inline]
+ fn sh_link(&self, endian: Self::Endian) -> u32 {
+ self.sh_link.get(endian)
+ }
+
+ #[inline]
+ fn sh_info(&self, endian: Self::Endian) -> u32 {
+ self.sh_info.get(endian)
+ }
+
+ #[inline]
+ fn sh_addralign(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addralign.get(endian)
+ }
+
+ #[inline]
+ fn sh_entsize(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_entsize.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+ type Elf = elf::FileHeader64<Endian>;
+
+ #[inline]
+ fn sh_name(&self, endian: Self::Endian) -> u32 {
+ self.sh_name.get(endian)
+ }
+
+ #[inline]
+ fn sh_type(&self, endian: Self::Endian) -> u32 {
+ self.sh_type.get(endian)
+ }
+
+ #[inline]
+ fn sh_flags(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_flags.get(endian)
+ }
+
+ #[inline]
+ fn sh_addr(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addr.get(endian)
+ }
+
+ #[inline]
+ fn sh_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_offset.get(endian)
+ }
+
+ #[inline]
+ fn sh_size(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_size.get(endian)
+ }
+
+ #[inline]
+ fn sh_link(&self, endian: Self::Endian) -> u32 {
+ self.sh_link.get(endian)
+ }
+
+ #[inline]
+ fn sh_info(&self, endian: Self::Endian) -> u32 {
+ self.sh_info.get(endian)
+ }
+
+ #[inline]
+ fn sh_addralign(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addralign.get(endian)
+ }
+
+ #[inline]
+ fn sh_entsize(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_entsize.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/segment.rs b/third_party/rust/object/src/read/elf/segment.rs
new file mode 100644
index 0000000000..3972731ecf
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/segment.rs
@@ -0,0 +1,332 @@
+use core::fmt::Debug;
+use core::{mem, slice, str};
+
+use crate::elf;
+use crate::endian::{self, Endianness};
+use crate::pod::Pod;
+use crate::read::{self, Bytes, ObjectSegment, ReadError, ReadRef, SegmentFlags};
+
+use super::{ElfFile, FileHeader, NoteIterator};
+
+/// An iterator over the segments of an `ElfFile32`.
+pub type ElfSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSegmentIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator over the segments of an `ElfFile64`.
+pub type ElfSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSegmentIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator over the segments of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSegmentIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) iter: slice::Iter<'data, Elf::ProgramHeader>,
+}
+
+impl<'data, 'file, Elf, R> Iterator for ElfSegmentIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = ElfSegment<'data, 'file, Elf, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ for segment in self.iter.by_ref() {
+ if segment.p_type(self.file.endian) == elf::PT_LOAD {
+ return Some(ElfSegment {
+ file: self.file,
+ segment,
+ });
+ }
+ }
+ None
+ }
+}
+
+/// A segment of an `ElfFile32`.
+pub type ElfSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSegment<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// A segment of an `ElfFile64`.
+pub type ElfSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSegment<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// A segment of an `ElfFile`.
+#[derive(Debug)]
+pub struct ElfSegment<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) segment: &'data Elf::ProgramHeader,
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSegment<'data, 'file, Elf, R> {
+ fn bytes(&self) -> read::Result<&'data [u8]> {
+ self.segment
+ .data(self.file.endian, self.file.data)
+ .read_error("Invalid ELF segment size or offset")
+ }
+}
+
+impl<'data, 'file, Elf, R> read::private::Sealed for ElfSegment<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Elf, R> ObjectSegment<'data> for ElfSegment<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[inline]
+ fn address(&self) -> u64 {
+ self.segment.p_vaddr(self.file.endian).into()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.segment.p_memsz(self.file.endian).into()
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.segment.p_align(self.file.endian).into()
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ self.segment.file_range(self.file.endian)
+ }
+
+ #[inline]
+ fn data(&self) -> read::Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> read::Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn name(&self) -> read::Result<Option<&str>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn flags(&self) -> SegmentFlags {
+ let p_flags = self.segment.p_flags(self.file.endian);
+ SegmentFlags::Elf { p_flags }
+ }
+}
+
+/// A trait for generic access to `ProgramHeader32` and `ProgramHeader64`.
+#[allow(missing_docs)]
+pub trait ProgramHeader: Debug + Pod {
+ type Elf: FileHeader<ProgramHeader = Self, Endian = Self::Endian, Word = Self::Word>;
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn p_type(&self, endian: Self::Endian) -> u32;
+ fn p_flags(&self, endian: Self::Endian) -> u32;
+ fn p_offset(&self, endian: Self::Endian) -> Self::Word;
+ fn p_vaddr(&self, endian: Self::Endian) -> Self::Word;
+ fn p_paddr(&self, endian: Self::Endian) -> Self::Word;
+ fn p_filesz(&self, endian: Self::Endian) -> Self::Word;
+ fn p_memsz(&self, endian: Self::Endian) -> Self::Word;
+ fn p_align(&self, endian: Self::Endian) -> Self::Word;
+
+ /// Return the offset and size of the segment in the file.
+ fn file_range(&self, endian: Self::Endian) -> (u64, u64) {
+ (self.p_offset(endian).into(), self.p_filesz(endian).into())
+ }
+
+ /// Return the segment data.
+ ///
+ /// Returns `Err` for invalid values.
+ fn data<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> Result<&'data [u8], ()> {
+ let (offset, size) = self.file_range(endian);
+ data.read_bytes_at(offset, size)
+ }
+
+ /// Return the segment data as a slice of the given type.
+ ///
+ /// Allows padding at the end of the data.
+ /// Returns `Ok(&[])` if the segment has no data.
+ /// Returns `Err` for invalid values, including bad alignment.
+ fn data_as_array<'data, T: Pod, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> Result<&'data [T], ()> {
+ let mut data = self.data(endian, data).map(Bytes)?;
+ data.read_slice(data.len() / mem::size_of::<T>())
+ }
+
+ /// Return the segment data in the given virtual address range
+ ///
+ /// Returns `Ok(None)` if the segment does not contain the address.
+ /// Returns `Err` for invalid values.
+ fn data_range<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ address: u64,
+ size: u64,
+ ) -> Result<Option<&'data [u8]>, ()> {
+ Ok(read::util::data_range(
+ self.data(endian, data)?,
+ self.p_vaddr(endian).into(),
+ address,
+ size,
+ ))
+ }
+
+ /// Return entries in a dynamic segment.
+ ///
+ /// Returns `Ok(None)` if the segment is not `PT_DYNAMIC`.
+ /// Returns `Err` for invalid values.
+ fn dynamic<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Dyn]>> {
+ if self.p_type(endian) != elf::PT_DYNAMIC {
+ return Ok(None);
+ }
+ let dynamic = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF dynamic segment offset or size")?;
+ Ok(Some(dynamic))
+ }
+
+ /// Return a note iterator for the segment data.
+ ///
+ /// Returns `Ok(None)` if the segment does not contain notes.
+ /// Returns `Err` for invalid values.
+ fn notes<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> {
+ if self.p_type(endian) != elf::PT_NOTE {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF note segment offset or size")?;
+ let notes = NoteIterator::new(endian, self.p_align(endian), data)?;
+ Ok(Some(notes))
+ }
+}
+
+impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+ type Elf = elf::FileHeader32<Endian>;
+
+ #[inline]
+ fn p_type(&self, endian: Self::Endian) -> u32 {
+ self.p_type.get(endian)
+ }
+
+ #[inline]
+ fn p_flags(&self, endian: Self::Endian) -> u32 {
+ self.p_flags.get(endian)
+ }
+
+ #[inline]
+ fn p_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.p_offset.get(endian)
+ }
+
+ #[inline]
+ fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
+ self.p_vaddr.get(endian)
+ }
+
+ #[inline]
+ fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
+ self.p_paddr.get(endian)
+ }
+
+ #[inline]
+ fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
+ self.p_filesz.get(endian)
+ }
+
+ #[inline]
+ fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
+ self.p_memsz.get(endian)
+ }
+
+ #[inline]
+ fn p_align(&self, endian: Self::Endian) -> Self::Word {
+ self.p_align.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+ type Elf = elf::FileHeader64<Endian>;
+
+ #[inline]
+ fn p_type(&self, endian: Self::Endian) -> u32 {
+ self.p_type.get(endian)
+ }
+
+ #[inline]
+ fn p_flags(&self, endian: Self::Endian) -> u32 {
+ self.p_flags.get(endian)
+ }
+
+ #[inline]
+ fn p_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.p_offset.get(endian)
+ }
+
+ #[inline]
+ fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
+ self.p_vaddr.get(endian)
+ }
+
+ #[inline]
+ fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
+ self.p_paddr.get(endian)
+ }
+
+ #[inline]
+ fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
+ self.p_filesz.get(endian)
+ }
+
+ #[inline]
+ fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
+ self.p_memsz.get(endian)
+ }
+
+ #[inline]
+ fn p_align(&self, endian: Self::Endian) -> Self::Word {
+ self.p_align.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/symbol.rs b/third_party/rust/object/src/read/elf/symbol.rs
new file mode 100644
index 0000000000..ee5aa37f19
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/symbol.rs
@@ -0,0 +1,585 @@
+use alloc::fmt;
+use alloc::vec::Vec;
+use core::fmt::Debug;
+use core::slice;
+use core::str;
+
+use crate::endian::{self, Endianness};
+use crate::pod::Pod;
+use crate::read::util::StringTable;
+use crate::read::{
+ self, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, SectionIndex, SymbolFlags,
+ SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection,
+};
+use crate::{elf, U32};
+
+use super::{FileHeader, SectionHeader, SectionTable};
+
+/// A table of symbol entries in an ELF file.
+///
+/// Also includes the string table used for the symbol names.
+#[derive(Debug, Clone, Copy)]
+pub struct SymbolTable<'data, Elf: FileHeader, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ section: SectionIndex,
+ string_section: SectionIndex,
+ shndx_section: SectionIndex,
+ symbols: &'data [Elf::Sym],
+ strings: StringTable<'data, R>,
+ shndx: &'data [U32<Elf::Endian>],
+}
+
+impl<'data, Elf: FileHeader, R: ReadRef<'data>> Default for SymbolTable<'data, Elf, R> {
+ fn default() -> Self {
+ SymbolTable {
+ section: SectionIndex(0),
+ string_section: SectionIndex(0),
+ shndx_section: SectionIndex(0),
+ symbols: &[],
+ strings: Default::default(),
+ shndx: &[],
+ }
+ }
+}
+
+impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> {
+ /// Parse the given symbol table section.
+ pub fn parse(
+ endian: Elf::Endian,
+ data: R,
+ sections: &SectionTable<'data, Elf, R>,
+ section_index: SectionIndex,
+ section: &Elf::SectionHeader,
+ ) -> read::Result<SymbolTable<'data, Elf, R>> {
+ debug_assert!(
+ section.sh_type(endian) == elf::SHT_DYNSYM
+ || section.sh_type(endian) == elf::SHT_SYMTAB
+ );
+
+ let symbols = section
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF symbol table data")?;
+
+ let link = SectionIndex(section.sh_link(endian) as usize);
+ let strings = sections.strings(endian, data, link)?;
+
+ let mut shndx_section = SectionIndex(0);
+ let mut shndx = &[][..];
+ for (i, s) in sections.iter().enumerate() {
+ if s.sh_type(endian) == elf::SHT_SYMTAB_SHNDX
+ && s.sh_link(endian) as usize == section_index.0
+ {
+ shndx_section = SectionIndex(i);
+ shndx = s
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF symtab_shndx data")?;
+ }
+ }
+
+ Ok(SymbolTable {
+ section: section_index,
+ string_section: link,
+ symbols,
+ strings,
+ shndx,
+ shndx_section,
+ })
+ }
+
+ /// Return the section index of this symbol table.
+ #[inline]
+ pub fn section(&self) -> SectionIndex {
+ self.section
+ }
+
+ /// Return the section index of the shndx table.
+ #[inline]
+ pub fn shndx_section(&self) -> SectionIndex {
+ self.shndx_section
+ }
+
+ /// Return the section index of the linked string table.
+ #[inline]
+ pub fn string_section(&self) -> SectionIndex {
+ self.string_section
+ }
+
+ /// Return the string table used for the symbol names.
+ #[inline]
+ pub fn strings(&self) -> StringTable<'data, R> {
+ self.strings
+ }
+
+ /// Return the symbol table.
+ #[inline]
+ pub fn symbols(&self) -> &'data [Elf::Sym] {
+ self.symbols
+ }
+
+ /// Iterate over the symbols.
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'data, Elf::Sym> {
+ self.symbols.iter()
+ }
+
+ /// Return true if the symbol table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.symbols.is_empty()
+ }
+
+ /// The number of symbols.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.symbols.len()
+ }
+
+ /// Return the symbol at the given index.
+ pub fn symbol(&self, index: usize) -> read::Result<&'data Elf::Sym> {
+ self.symbols
+ .get(index)
+ .read_error("Invalid ELF symbol index")
+ }
+
+ /// Return the extended section index for the given symbol if present.
+ #[inline]
+ pub fn shndx(&self, endian: Elf::Endian, index: usize) -> Option<u32> {
+ self.shndx.get(index).map(|x| x.get(endian))
+ }
+
+ /// Return the section index for the given symbol.
+ ///
+ /// This uses the extended section index if present.
+ pub fn symbol_section(
+ &self,
+ endian: Elf::Endian,
+ symbol: &'data Elf::Sym,
+ index: usize,
+ ) -> read::Result<Option<SectionIndex>> {
+ match symbol.st_shndx(endian) {
+ elf::SHN_UNDEF => Ok(None),
+ elf::SHN_XINDEX => self
+ .shndx(endian, index)
+ .read_error("Missing ELF symbol extended index")
+ .map(|index| Some(SectionIndex(index as usize))),
+ shndx if shndx < elf::SHN_LORESERVE => Ok(Some(SectionIndex(shndx.into()))),
+ _ => Ok(None),
+ }
+ }
+
+ /// Return the symbol name for the given symbol.
+ pub fn symbol_name(
+ &self,
+ endian: Elf::Endian,
+ symbol: &'data Elf::Sym,
+ ) -> read::Result<&'data [u8]> {
+ symbol.name(endian, self.strings)
+ }
+
+ /// Construct a map from addresses to a user-defined map entry.
+ pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Elf::Sym) -> Option<Entry>>(
+ &self,
+ endian: Elf::Endian,
+ f: F,
+ ) -> SymbolMap<Entry> {
+ let mut symbols = Vec::with_capacity(self.symbols.len());
+ for symbol in self.symbols {
+ if !symbol.is_definition(endian) {
+ continue;
+ }
+ if let Some(entry) = f(symbol) {
+ symbols.push(entry);
+ }
+ }
+ SymbolMap::new(symbols)
+ }
+}
+
+/// A symbol table of an `ElfFile32`.
+pub type ElfSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSymbolTable<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// A symbol table of an `ElfFile32`.
+pub type ElfSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSymbolTable<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// A symbol table of an `ElfFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct ElfSymbolTable<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) endian: Elf::Endian,
+ pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed
+ for ElfSymbolTable<'data, 'file, Elf, R>
+{
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data>
+ for ElfSymbolTable<'data, 'file, Elf, R>
+{
+ type Symbol = ElfSymbol<'data, 'file, Elf, R>;
+ type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf, R>;
+
+ fn symbols(&self) -> Self::SymbolIterator {
+ ElfSymbolIterator {
+ endian: self.endian,
+ symbols: self.symbols,
+ index: 0,
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> {
+ let symbol = self.symbols.symbol(index.0)?;
+ Ok(ElfSymbol {
+ endian: self.endian,
+ symbols: self.symbols,
+ index,
+ symbol,
+ })
+ }
+}
+
+/// An iterator over the symbols of an `ElfFile32`.
+pub type ElfSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSymbolIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator over the symbols of an `ElfFile64`.
+pub type ElfSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSymbolIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator over the symbols of an `ElfFile`.
+pub struct ElfSymbolIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) endian: Elf::Endian,
+ pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
+ pub(super) index: usize,
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> fmt::Debug
+ for ElfSymbolIterator<'data, 'file, Elf, R>
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ElfSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> Iterator
+ for ElfSymbolIterator<'data, 'file, Elf, R>
+{
+ type Item = ElfSymbol<'data, 'file, Elf, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let index = self.index;
+ let symbol = self.symbols.symbols.get(index)?;
+ self.index += 1;
+ Some(ElfSymbol {
+ endian: self.endian,
+ symbols: self.symbols,
+ index: SymbolIndex(index),
+ symbol,
+ })
+ }
+}
+
+/// A symbol of an `ElfFile32`.
+pub type ElfSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSymbol<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// A symbol of an `ElfFile64`.
+pub type ElfSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSymbol<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// A symbol of an `ElfFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct ElfSymbol<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) endian: Elf::Endian,
+ pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
+ pub(super) index: SymbolIndex,
+ pub(super) symbol: &'data Elf::Sym,
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSymbol<'data, 'file, Elf, R> {
+ /// Return a reference to the raw symbol structure.
+ #[inline]
+ pub fn raw_symbol(&self) -> &'data Elf::Sym {
+ self.symbol
+ }
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed
+ for ElfSymbol<'data, 'file, Elf, R>
+{
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data>
+ for ElfSymbol<'data, 'file, Elf, R>
+{
+ #[inline]
+ fn index(&self) -> SymbolIndex {
+ self.index
+ }
+
+ fn name_bytes(&self) -> read::Result<&'data [u8]> {
+ self.symbol.name(self.endian, self.symbols.strings())
+ }
+
+ fn name(&self) -> read::Result<&'data str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 ELF symbol name")
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.symbol.st_value(self.endian).into()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.symbol.st_size(self.endian).into()
+ }
+
+ fn kind(&self) -> SymbolKind {
+ match self.symbol.st_type() {
+ elf::STT_NOTYPE if self.index.0 == 0 => SymbolKind::Null,
+ elf::STT_NOTYPE => SymbolKind::Label,
+ elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data,
+ elf::STT_FUNC | elf::STT_GNU_IFUNC => SymbolKind::Text,
+ elf::STT_SECTION => SymbolKind::Section,
+ elf::STT_FILE => SymbolKind::File,
+ elf::STT_TLS => SymbolKind::Tls,
+ _ => SymbolKind::Unknown,
+ }
+ }
+
+ fn section(&self) -> SymbolSection {
+ match self.symbol.st_shndx(self.endian) {
+ elf::SHN_UNDEF => SymbolSection::Undefined,
+ elf::SHN_ABS => {
+ if self.symbol.st_type() == elf::STT_FILE {
+ SymbolSection::None
+ } else {
+ SymbolSection::Absolute
+ }
+ }
+ elf::SHN_COMMON => SymbolSection::Common,
+ elf::SHN_XINDEX => match self.symbols.shndx(self.endian, self.index.0) {
+ Some(index) => SymbolSection::Section(SectionIndex(index as usize)),
+ None => SymbolSection::Unknown,
+ },
+ index if index < elf::SHN_LORESERVE => {
+ SymbolSection::Section(SectionIndex(index as usize))
+ }
+ _ => SymbolSection::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF
+ }
+
+ #[inline]
+ fn is_definition(&self) -> bool {
+ self.symbol.is_definition(self.endian)
+ }
+
+ #[inline]
+ fn is_common(&self) -> bool {
+ self.symbol.st_shndx(self.endian) == elf::SHN_COMMON
+ }
+
+ #[inline]
+ fn is_weak(&self) -> bool {
+ self.symbol.st_bind() == elf::STB_WEAK
+ }
+
+ fn scope(&self) -> SymbolScope {
+ if self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF {
+ SymbolScope::Unknown
+ } else {
+ match self.symbol.st_bind() {
+ elf::STB_LOCAL => SymbolScope::Compilation,
+ elf::STB_GLOBAL | elf::STB_WEAK => {
+ if self.symbol.st_visibility() == elf::STV_HIDDEN {
+ SymbolScope::Linkage
+ } else {
+ SymbolScope::Dynamic
+ }
+ }
+ _ => SymbolScope::Unknown,
+ }
+ }
+ }
+
+ #[inline]
+ fn is_global(&self) -> bool {
+ self.symbol.st_bind() != elf::STB_LOCAL
+ }
+
+ #[inline]
+ fn is_local(&self) -> bool {
+ self.symbol.st_bind() == elf::STB_LOCAL
+ }
+
+ #[inline]
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
+ SymbolFlags::Elf {
+ st_info: self.symbol.st_info(),
+ st_other: self.symbol.st_other(),
+ }
+ }
+}
+
+/// A trait for generic access to `Sym32` and `Sym64`.
+#[allow(missing_docs)]
+pub trait Sym: Debug + Pod {
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn st_name(&self, endian: Self::Endian) -> u32;
+ fn st_info(&self) -> u8;
+ fn st_bind(&self) -> u8;
+ fn st_type(&self) -> u8;
+ fn st_other(&self) -> u8;
+ fn st_visibility(&self) -> u8;
+ fn st_shndx(&self, endian: Self::Endian) -> u16;
+ fn st_value(&self, endian: Self::Endian) -> Self::Word;
+ fn st_size(&self, endian: Self::Endian) -> Self::Word;
+
+ /// Parse the symbol name from the string table.
+ fn name<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ strings: StringTable<'data, R>,
+ ) -> read::Result<&'data [u8]> {
+ strings
+ .get(self.st_name(endian))
+ .read_error("Invalid ELF symbol name offset")
+ }
+
+ /// Return true if the symbol is undefined.
+ #[inline]
+ fn is_undefined(&self, endian: Self::Endian) -> bool {
+ self.st_shndx(endian) == elf::SHN_UNDEF
+ }
+
+ /// Return true if the symbol is a definition of a function or data object.
+ fn is_definition(&self, endian: Self::Endian) -> bool {
+ let st_type = self.st_type();
+ (st_type == elf::STT_NOTYPE || st_type == elf::STT_FUNC || st_type == elf::STT_OBJECT)
+ && self.st_shndx(endian) != elf::SHN_UNDEF
+ }
+}
+
+impl<Endian: endian::Endian> Sym for elf::Sym32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+
+ #[inline]
+ fn st_name(&self, endian: Self::Endian) -> u32 {
+ self.st_name.get(endian)
+ }
+
+ #[inline]
+ fn st_info(&self) -> u8 {
+ self.st_info
+ }
+
+ #[inline]
+ fn st_bind(&self) -> u8 {
+ self.st_bind()
+ }
+
+ #[inline]
+ fn st_type(&self) -> u8 {
+ self.st_type()
+ }
+
+ #[inline]
+ fn st_other(&self) -> u8 {
+ self.st_other
+ }
+
+ #[inline]
+ fn st_visibility(&self) -> u8 {
+ self.st_visibility()
+ }
+
+ #[inline]
+ fn st_shndx(&self, endian: Self::Endian) -> u16 {
+ self.st_shndx.get(endian)
+ }
+
+ #[inline]
+ fn st_value(&self, endian: Self::Endian) -> Self::Word {
+ self.st_value.get(endian)
+ }
+
+ #[inline]
+ fn st_size(&self, endian: Self::Endian) -> Self::Word {
+ self.st_size.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> Sym for elf::Sym64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+
+ #[inline]
+ fn st_name(&self, endian: Self::Endian) -> u32 {
+ self.st_name.get(endian)
+ }
+
+ #[inline]
+ fn st_info(&self) -> u8 {
+ self.st_info
+ }
+
+ #[inline]
+ fn st_bind(&self) -> u8 {
+ self.st_bind()
+ }
+
+ #[inline]
+ fn st_type(&self) -> u8 {
+ self.st_type()
+ }
+
+ #[inline]
+ fn st_other(&self) -> u8 {
+ self.st_other
+ }
+
+ #[inline]
+ fn st_visibility(&self) -> u8 {
+ self.st_visibility()
+ }
+
+ #[inline]
+ fn st_shndx(&self, endian: Self::Endian) -> u16 {
+ self.st_shndx.get(endian)
+ }
+
+ #[inline]
+ fn st_value(&self, endian: Self::Endian) -> Self::Word {
+ self.st_value.get(endian)
+ }
+
+ #[inline]
+ fn st_size(&self, endian: Self::Endian) -> Self::Word {
+ self.st_size.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/elf/version.rs b/third_party/rust/object/src/read/elf/version.rs
new file mode 100644
index 0000000000..cc87bbef1c
--- /dev/null
+++ b/third_party/rust/object/src/read/elf/version.rs
@@ -0,0 +1,421 @@
+use alloc::vec::Vec;
+
+use crate::read::{Bytes, ReadError, ReadRef, Result, StringTable};
+use crate::{elf, endian};
+
+use super::FileHeader;
+
+/// A version index.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct VersionIndex(pub u16);
+
+impl VersionIndex {
+ /// Return the version index.
+ pub fn index(&self) -> u16 {
+ self.0 & elf::VERSYM_VERSION
+ }
+
+ /// Return true if it is the local index.
+ pub fn is_local(&self) -> bool {
+ self.index() == elf::VER_NDX_LOCAL
+ }
+
+ /// Return true if it is the global index.
+ pub fn is_global(&self) -> bool {
+ self.index() == elf::VER_NDX_GLOBAL
+ }
+
+ /// Return the hidden flag.
+ pub fn is_hidden(&self) -> bool {
+ self.0 & elf::VERSYM_HIDDEN != 0
+ }
+}
+
+/// A version definition or requirement.
+///
+/// This is derived from entries in the `SHT_GNU_verdef` and `SHT_GNU_verneed` sections.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct Version<'data> {
+ name: &'data [u8],
+ hash: u32,
+ // Used to keep track of valid indices in `VersionTable`.
+ valid: bool,
+}
+
+impl<'data> Version<'data> {
+ /// Return the version name.
+ pub fn name(&self) -> &'data [u8] {
+ self.name
+ }
+
+ /// Return hash of the version name.
+ pub fn hash(&self) -> u32 {
+ self.hash
+ }
+}
+
+/// A table of version definitions and requirements.
+///
+/// It allows looking up the version information for a given symbol index.
+///
+/// This is derived from entries in the `SHT_GNU_versym`, `SHT_GNU_verdef` and `SHT_GNU_verneed` sections.
+#[derive(Debug, Clone)]
+pub struct VersionTable<'data, Elf: FileHeader> {
+ symbols: &'data [elf::Versym<Elf::Endian>],
+ versions: Vec<Version<'data>>,
+}
+
+impl<'data, Elf: FileHeader> Default for VersionTable<'data, Elf> {
+ fn default() -> Self {
+ VersionTable {
+ symbols: &[],
+ versions: Vec::new(),
+ }
+ }
+}
+
+impl<'data, Elf: FileHeader> VersionTable<'data, Elf> {
+ /// Parse the version sections.
+ pub fn parse<R: ReadRef<'data>>(
+ endian: Elf::Endian,
+ versyms: &'data [elf::Versym<Elf::Endian>],
+ verdefs: Option<VerdefIterator<'data, Elf>>,
+ verneeds: Option<VerneedIterator<'data, Elf>>,
+ strings: StringTable<'data, R>,
+ ) -> Result<Self> {
+ let mut max_index = 0;
+ if let Some(mut verdefs) = verdefs.clone() {
+ while let Some((verdef, _)) = verdefs.next()? {
+ if verdef.vd_flags.get(endian) & elf::VER_FLG_BASE != 0 {
+ continue;
+ }
+ let index = verdef.vd_ndx.get(endian) & elf::VERSYM_VERSION;
+ if max_index < index {
+ max_index = index;
+ }
+ }
+ }
+ if let Some(mut verneeds) = verneeds.clone() {
+ while let Some((_, mut vernauxs)) = verneeds.next()? {
+ while let Some(vernaux) = vernauxs.next()? {
+ let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION;
+ if max_index < index {
+ max_index = index;
+ }
+ }
+ }
+ }
+
+ // Indices should be sequential, but this could be up to
+ // 32k * size_of::<Version>() if max_index is bad.
+ let mut versions = vec![Version::default(); max_index as usize + 1];
+
+ if let Some(mut verdefs) = verdefs {
+ while let Some((verdef, mut verdauxs)) = verdefs.next()? {
+ if verdef.vd_flags.get(endian) & elf::VER_FLG_BASE != 0 {
+ continue;
+ }
+ let index = verdef.vd_ndx.get(endian) & elf::VERSYM_VERSION;
+ if index <= elf::VER_NDX_GLOBAL {
+ // TODO: return error?
+ continue;
+ }
+ if let Some(verdaux) = verdauxs.next()? {
+ versions[usize::from(index)] = Version {
+ name: verdaux.name(endian, strings)?,
+ hash: verdef.vd_hash.get(endian),
+ valid: true,
+ };
+ }
+ }
+ }
+ if let Some(mut verneeds) = verneeds {
+ while let Some((_, mut vernauxs)) = verneeds.next()? {
+ while let Some(vernaux) = vernauxs.next()? {
+ let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION;
+ if index <= elf::VER_NDX_GLOBAL {
+ // TODO: return error?
+ continue;
+ }
+ versions[usize::from(index)] = Version {
+ name: vernaux.name(endian, strings)?,
+ hash: vernaux.vna_hash.get(endian),
+ valid: true,
+ };
+ }
+ }
+ }
+
+ Ok(VersionTable {
+ symbols: versyms,
+ versions,
+ })
+ }
+
+ /// Return true if the version table is empty.
+ pub fn is_empty(&self) -> bool {
+ self.symbols.is_empty()
+ }
+
+ /// Return version index for a given symbol index.
+ pub fn version_index(&self, endian: Elf::Endian, index: usize) -> VersionIndex {
+ let version_index = match self.symbols.get(index) {
+ Some(x) => x.0.get(endian),
+ // Ideally this would be VER_NDX_LOCAL for undefined symbols,
+ // but currently there are no checks that need this distinction.
+ None => elf::VER_NDX_GLOBAL,
+ };
+ VersionIndex(version_index)
+ }
+
+ /// Return version information for a given symbol version index.
+ ///
+ /// Returns `Ok(None)` for local and global versions.
+ /// Returns `Err(_)` if index is invalid.
+ pub fn version(&self, index: VersionIndex) -> Result<Option<&Version<'data>>> {
+ if index.index() <= elf::VER_NDX_GLOBAL {
+ return Ok(None);
+ }
+ self.versions
+ .get(usize::from(index.index()))
+ .filter(|version| version.valid)
+ .read_error("Invalid ELF symbol version index")
+ .map(Some)
+ }
+
+ /// Return true if the given symbol index satisfies the requirements of `need`.
+ ///
+ /// Returns false for any error.
+ ///
+ /// Note: this function hasn't been fully tested and is likely to be incomplete.
+ pub fn matches(&self, endian: Elf::Endian, index: usize, need: Option<&Version<'_>>) -> bool {
+ let version_index = self.version_index(endian, index);
+ let def = match self.version(version_index) {
+ Ok(def) => def,
+ Err(_) => return false,
+ };
+ match (def, need) {
+ (Some(def), Some(need)) => need.hash == def.hash && need.name == def.name,
+ (None, Some(_need)) => {
+ // Version must be present if needed.
+ false
+ }
+ (Some(_def), None) => {
+ // For a dlsym call, use the newest version.
+ // TODO: if not a dlsym call, then use the oldest version.
+ !version_index.is_hidden()
+ }
+ (None, None) => true,
+ }
+ }
+}
+
+/// An iterator over the entries in an ELF `SHT_GNU_verdef` section.
+#[derive(Debug, Clone)]
+pub struct VerdefIterator<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ data: Bytes<'data>,
+}
+
+impl<'data, Elf: FileHeader> VerdefIterator<'data, Elf> {
+ pub(super) fn new(endian: Elf::Endian, data: &'data [u8]) -> Self {
+ VerdefIterator {
+ endian,
+ data: Bytes(data),
+ }
+ }
+
+ /// Return the next `Verdef` entry.
+ pub fn next(
+ &mut self,
+ ) -> Result<Option<(&'data elf::Verdef<Elf::Endian>, VerdauxIterator<'data, Elf>)>> {
+ if self.data.is_empty() {
+ return Ok(None);
+ }
+
+ let verdef = self
+ .data
+ .read_at::<elf::Verdef<_>>(0)
+ .read_error("ELF verdef is too short")?;
+
+ let mut verdaux_data = self.data;
+ verdaux_data
+ .skip(verdef.vd_aux.get(self.endian) as usize)
+ .read_error("Invalid ELF vd_aux")?;
+ let verdaux =
+ VerdauxIterator::new(self.endian, verdaux_data.0, verdef.vd_cnt.get(self.endian));
+
+ let next = verdef.vd_next.get(self.endian);
+ if next != 0 {
+ self.data
+ .skip(next as usize)
+ .read_error("Invalid ELF vd_next")?;
+ } else {
+ self.data = Bytes(&[]);
+ }
+ Ok(Some((verdef, verdaux)))
+ }
+}
+
+/// An iterator over the auxiliary records for an entry in an ELF `SHT_GNU_verdef` section.
+#[derive(Debug, Clone)]
+pub struct VerdauxIterator<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ data: Bytes<'data>,
+ count: u16,
+}
+
+impl<'data, Elf: FileHeader> VerdauxIterator<'data, Elf> {
+ pub(super) fn new(endian: Elf::Endian, data: &'data [u8], count: u16) -> Self {
+ VerdauxIterator {
+ endian,
+ data: Bytes(data),
+ count,
+ }
+ }
+
+ /// Return the next `Verdaux` entry.
+ pub fn next(&mut self) -> Result<Option<&'data elf::Verdaux<Elf::Endian>>> {
+ if self.count == 0 {
+ return Ok(None);
+ }
+
+ let verdaux = self
+ .data
+ .read_at::<elf::Verdaux<_>>(0)
+ .read_error("ELF verdaux is too short")?;
+
+ self.data
+ .skip(verdaux.vda_next.get(self.endian) as usize)
+ .read_error("Invalid ELF vda_next")?;
+ self.count -= 1;
+ Ok(Some(verdaux))
+ }
+}
+
+/// An iterator over the entries in an ELF `SHT_GNU_verneed` section.
+#[derive(Debug, Clone)]
+pub struct VerneedIterator<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ data: Bytes<'data>,
+}
+
+impl<'data, Elf: FileHeader> VerneedIterator<'data, Elf> {
+ pub(super) fn new(endian: Elf::Endian, data: &'data [u8]) -> Self {
+ VerneedIterator {
+ endian,
+ data: Bytes(data),
+ }
+ }
+
+ /// Return the next `Verneed` entry.
+ pub fn next(
+ &mut self,
+ ) -> Result<
+ Option<(
+ &'data elf::Verneed<Elf::Endian>,
+ VernauxIterator<'data, Elf>,
+ )>,
+ > {
+ if self.data.is_empty() {
+ return Ok(None);
+ }
+
+ let verneed = self
+ .data
+ .read_at::<elf::Verneed<_>>(0)
+ .read_error("ELF verneed is too short")?;
+
+ let mut vernaux_data = self.data;
+ vernaux_data
+ .skip(verneed.vn_aux.get(self.endian) as usize)
+ .read_error("Invalid ELF vn_aux")?;
+ let vernaux =
+ VernauxIterator::new(self.endian, vernaux_data.0, verneed.vn_cnt.get(self.endian));
+
+ let next = verneed.vn_next.get(self.endian);
+ if next != 0 {
+ self.data
+ .skip(next as usize)
+ .read_error("Invalid ELF vn_next")?;
+ } else {
+ self.data = Bytes(&[]);
+ }
+ Ok(Some((verneed, vernaux)))
+ }
+}
+
+/// An iterator over the auxiliary records for an entry in an ELF `SHT_GNU_verneed` section.
+#[derive(Debug, Clone)]
+pub struct VernauxIterator<'data, Elf: FileHeader> {
+ endian: Elf::Endian,
+ data: Bytes<'data>,
+ count: u16,
+}
+
+impl<'data, Elf: FileHeader> VernauxIterator<'data, Elf> {
+ pub(super) fn new(endian: Elf::Endian, data: &'data [u8], count: u16) -> Self {
+ VernauxIterator {
+ endian,
+ data: Bytes(data),
+ count,
+ }
+ }
+
+ /// Return the next `Vernaux` entry.
+ pub fn next(&mut self) -> Result<Option<&'data elf::Vernaux<Elf::Endian>>> {
+ if self.count == 0 {
+ return Ok(None);
+ }
+
+ let vernaux = self
+ .data
+ .read_at::<elf::Vernaux<_>>(0)
+ .read_error("ELF vernaux is too short")?;
+
+ self.data
+ .skip(vernaux.vna_next.get(self.endian) as usize)
+ .read_error("Invalid ELF vna_next")?;
+ self.count -= 1;
+ Ok(Some(vernaux))
+ }
+}
+
+impl<Endian: endian::Endian> elf::Verdaux<Endian> {
+ /// Parse the version name from the string table.
+ pub fn name<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Endian,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ strings
+ .get(self.vda_name.get(endian))
+ .read_error("Invalid ELF vda_name")
+ }
+}
+
+impl<Endian: endian::Endian> elf::Verneed<Endian> {
+ /// Parse the file from the string table.
+ pub fn file<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Endian,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ strings
+ .get(self.vn_file.get(endian))
+ .read_error("Invalid ELF vn_file")
+ }
+}
+
+impl<Endian: endian::Endian> elf::Vernaux<Endian> {
+ /// Parse the version name from the string table.
+ pub fn name<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Endian,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ strings
+ .get(self.vna_name.get(endian))
+ .read_error("Invalid ELF vna_name")
+ }
+}
diff --git a/third_party/rust/object/src/read/macho/dyld_cache.rs b/third_party/rust/object/src/read/macho/dyld_cache.rs
new file mode 100644
index 0000000000..68f27f5491
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/dyld_cache.rs
@@ -0,0 +1,343 @@
+use alloc::vec::Vec;
+use core::slice;
+
+use crate::read::{Error, File, ReadError, ReadRef, Result};
+use crate::{macho, Architecture, Endian, Endianness};
+
+/// A parsed representation of the dyld shared cache.
+#[derive(Debug)]
+pub struct DyldCache<'data, E = Endianness, R = &'data [u8]>
+where
+ E: Endian,
+ R: ReadRef<'data>,
+{
+ endian: E,
+ data: R,
+ subcaches: Vec<DyldSubCache<'data, E, R>>,
+ mappings: &'data [macho::DyldCacheMappingInfo<E>],
+ images: &'data [macho::DyldCacheImageInfo<E>],
+ arch: Architecture,
+}
+
+/// Information about a subcache.
+#[derive(Debug)]
+pub struct DyldSubCache<'data, E = Endianness, R = &'data [u8]>
+where
+ E: Endian,
+ R: ReadRef<'data>,
+{
+ data: R,
+ mappings: &'data [macho::DyldCacheMappingInfo<E>],
+}
+
+// This is the offset of the images_across_all_subcaches_count field.
+const MIN_HEADER_SIZE_SUBCACHES: u32 = 0x1c4;
+
+impl<'data, E, R> DyldCache<'data, E, R>
+where
+ E: Endian,
+ R: ReadRef<'data>,
+{
+ /// Parse the raw dyld shared cache data.
+ /// For shared caches from macOS 12 / iOS 15 and above, the subcache files need to be
+ /// supplied as well, in the correct order, with the .symbols subcache last (if present).
+ /// For example, data would be the data for dyld_shared_cache_x86_64,
+ /// and subcache_data would be the data for [dyld_shared_cache_x86_64.1, dyld_shared_cache_x86_64.2, ...]
+ pub fn parse(data: R, subcache_data: &[R]) -> Result<Self> {
+ let header = macho::DyldCacheHeader::parse(data)?;
+ let (arch, endian) = header.parse_magic()?;
+ let mappings = header.mappings(endian, data)?;
+
+ let symbols_subcache_uuid = header.symbols_subcache_uuid(endian);
+ let subcaches_info = header.subcaches(endian, data)?.unwrap_or(&[]);
+
+ if subcache_data.len() != subcaches_info.len() + symbols_subcache_uuid.is_some() as usize {
+ return Err(Error("Incorrect number of SubCaches"));
+ }
+
+ // Split out the .symbols subcache data from the other subcaches.
+ let (symbols_subcache_data_and_uuid, subcache_data) =
+ if let Some(symbols_uuid) = symbols_subcache_uuid {
+ let (sym_data, rest_data) = subcache_data.split_last().unwrap();
+ (Some((*sym_data, symbols_uuid)), rest_data)
+ } else {
+ (None, subcache_data)
+ };
+
+ // Read the regular SubCaches (.1, .2, ...), if present.
+ let mut subcaches = Vec::new();
+ for (&data, info) in subcache_data.iter().zip(subcaches_info.iter()) {
+ let sc_header = macho::DyldCacheHeader::<E>::parse(data)?;
+ if sc_header.uuid != info.uuid {
+ return Err(Error("Unexpected SubCache UUID"));
+ }
+ let mappings = sc_header.mappings(endian, data)?;
+ subcaches.push(DyldSubCache { data, mappings });
+ }
+
+ // Read the .symbols SubCache, if present.
+ // Other than the UUID verification, the symbols SubCache is currently unused.
+ let _symbols_subcache = match symbols_subcache_data_and_uuid {
+ Some((data, uuid)) => {
+ let sc_header = macho::DyldCacheHeader::<E>::parse(data)?;
+ if sc_header.uuid != uuid {
+ return Err(Error("Unexpected .symbols SubCache UUID"));
+ }
+ let mappings = sc_header.mappings(endian, data)?;
+ Some(DyldSubCache { data, mappings })
+ }
+ None => None,
+ };
+
+ let images = header.images(endian, data)?;
+ Ok(DyldCache {
+ endian,
+ data,
+ subcaches,
+ mappings,
+ images,
+ arch,
+ })
+ }
+
+ /// Get the architecture type of the file.
+ pub fn architecture(&self) -> Architecture {
+ self.arch
+ }
+
+ /// Get the endianness of the file.
+ #[inline]
+ pub fn endianness(&self) -> Endianness {
+ if self.is_little_endian() {
+ Endianness::Little
+ } else {
+ Endianness::Big
+ }
+ }
+
+ /// Return true if the file is little endian, false if it is big endian.
+ pub fn is_little_endian(&self) -> bool {
+ self.endian.is_little_endian()
+ }
+
+ /// Iterate over the images in this cache.
+ pub fn images<'cache>(&'cache self) -> DyldCacheImageIterator<'data, 'cache, E, R> {
+ DyldCacheImageIterator {
+ cache: self,
+ iter: self.images.iter(),
+ }
+ }
+
+ /// Find the address in a mapping and return the cache or subcache data it was found in,
+ /// together with the translated file offset.
+ pub fn data_and_offset_for_address(&self, address: u64) -> Option<(R, u64)> {
+ if let Some(file_offset) = address_to_file_offset(address, self.endian, self.mappings) {
+ return Some((self.data, file_offset));
+ }
+ for subcache in &self.subcaches {
+ if let Some(file_offset) =
+ address_to_file_offset(address, self.endian, subcache.mappings)
+ {
+ return Some((subcache.data, file_offset));
+ }
+ }
+ None
+ }
+}
+
+/// An iterator over all the images (dylibs) in the dyld shared cache.
+#[derive(Debug)]
+pub struct DyldCacheImageIterator<'data, 'cache, E = Endianness, R = &'data [u8]>
+where
+ E: Endian,
+ R: ReadRef<'data>,
+{
+ cache: &'cache DyldCache<'data, E, R>,
+ iter: slice::Iter<'data, macho::DyldCacheImageInfo<E>>,
+}
+
+impl<'data, 'cache, E, R> Iterator for DyldCacheImageIterator<'data, 'cache, E, R>
+where
+ E: Endian,
+ R: ReadRef<'data>,
+{
+ type Item = DyldCacheImage<'data, 'cache, E, R>;
+
+ fn next(&mut self) -> Option<DyldCacheImage<'data, 'cache, E, R>> {
+ let image_info = self.iter.next()?;
+ Some(DyldCacheImage {
+ cache: self.cache,
+ image_info,
+ })
+ }
+}
+
+/// One image (dylib) from inside the dyld shared cache.
+#[derive(Debug)]
+pub struct DyldCacheImage<'data, 'cache, E = Endianness, R = &'data [u8]>
+where
+ E: Endian,
+ R: ReadRef<'data>,
+{
+ pub(crate) cache: &'cache DyldCache<'data, E, R>,
+ image_info: &'data macho::DyldCacheImageInfo<E>,
+}
+
+impl<'data, 'cache, E, R> DyldCacheImage<'data, 'cache, E, R>
+where
+ E: Endian,
+ R: ReadRef<'data>,
+{
+ /// The file system path of this image.
+ pub fn path(&self) -> Result<&'data str> {
+ let path = self.image_info.path(self.cache.endian, self.cache.data)?;
+ // The path should always be ascii, so from_utf8 should always succeed.
+ let path = core::str::from_utf8(path).map_err(|_| Error("Path string not valid utf-8"))?;
+ Ok(path)
+ }
+
+ /// The subcache data which contains the Mach-O header for this image,
+ /// together with the file offset at which this image starts.
+ pub fn image_data_and_offset(&self) -> Result<(R, u64)> {
+ let address = self.image_info.address.get(self.cache.endian);
+ self.cache
+ .data_and_offset_for_address(address)
+ .ok_or(Error("Address not found in any mapping"))
+ }
+
+ /// Parse this image into an Object.
+ pub fn parse_object(&self) -> Result<File<'data, R>> {
+ File::parse_dyld_cache_image(self)
+ }
+}
+
+impl<E: Endian> macho::DyldCacheHeader<E> {
+ /// Read the dyld cache header.
+ pub fn parse<'data, R: ReadRef<'data>>(data: R) -> Result<&'data Self> {
+ data.read_at::<macho::DyldCacheHeader<E>>(0)
+ .read_error("Invalid dyld cache header size or alignment")
+ }
+
+ /// Returns (arch, endian) based on the magic string.
+ pub fn parse_magic(&self) -> Result<(Architecture, E)> {
+ let (arch, is_big_endian) = match &self.magic {
+ b"dyld_v1 i386\0" => (Architecture::I386, false),
+ b"dyld_v1 x86_64\0" => (Architecture::X86_64, false),
+ b"dyld_v1 x86_64h\0" => (Architecture::X86_64, false),
+ b"dyld_v1 ppc\0" => (Architecture::PowerPc, true),
+ b"dyld_v1 armv6\0" => (Architecture::Arm, false),
+ b"dyld_v1 armv7\0" => (Architecture::Arm, false),
+ b"dyld_v1 armv7f\0" => (Architecture::Arm, false),
+ b"dyld_v1 armv7s\0" => (Architecture::Arm, false),
+ b"dyld_v1 armv7k\0" => (Architecture::Arm, false),
+ b"dyld_v1 arm64\0" => (Architecture::Aarch64, false),
+ b"dyld_v1 arm64e\0" => (Architecture::Aarch64, false),
+ _ => return Err(Error("Unrecognized dyld cache magic")),
+ };
+ let endian =
+ E::from_big_endian(is_big_endian).read_error("Unsupported dyld cache endian")?;
+ Ok((arch, endian))
+ }
+
+ /// Return the mapping information table.
+ pub fn mappings<'data, R: ReadRef<'data>>(
+ &self,
+ endian: E,
+ data: R,
+ ) -> Result<&'data [macho::DyldCacheMappingInfo<E>]> {
+ data.read_slice_at::<macho::DyldCacheMappingInfo<E>>(
+ self.mapping_offset.get(endian).into(),
+ self.mapping_count.get(endian) as usize,
+ )
+ .read_error("Invalid dyld cache mapping size or alignment")
+ }
+
+ /// Return the information about subcaches, if present.
+ pub fn subcaches<'data, R: ReadRef<'data>>(
+ &self,
+ endian: E,
+ data: R,
+ ) -> Result<Option<&'data [macho::DyldSubCacheInfo<E>]>> {
+ if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES {
+ let subcaches = data
+ .read_slice_at::<macho::DyldSubCacheInfo<E>>(
+ self.subcaches_offset.get(endian).into(),
+ self.subcaches_count.get(endian) as usize,
+ )
+ .read_error("Invalid dyld subcaches size or alignment")?;
+ Ok(Some(subcaches))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Return the UUID for the .symbols subcache, if present.
+ pub fn symbols_subcache_uuid(&self, endian: E) -> Option<[u8; 16]> {
+ if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES {
+ let uuid = self.symbols_subcache_uuid;
+ if uuid != [0; 16] {
+ return Some(uuid);
+ }
+ }
+ None
+ }
+
+ /// Return the image information table.
+ pub fn images<'data, R: ReadRef<'data>>(
+ &self,
+ endian: E,
+ data: R,
+ ) -> Result<&'data [macho::DyldCacheImageInfo<E>]> {
+ if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES {
+ data.read_slice_at::<macho::DyldCacheImageInfo<E>>(
+ self.images_across_all_subcaches_offset.get(endian).into(),
+ self.images_across_all_subcaches_count.get(endian) as usize,
+ )
+ .read_error("Invalid dyld cache image size or alignment")
+ } else {
+ data.read_slice_at::<macho::DyldCacheImageInfo<E>>(
+ self.images_offset.get(endian).into(),
+ self.images_count.get(endian) as usize,
+ )
+ .read_error("Invalid dyld cache image size or alignment")
+ }
+ }
+}
+
+impl<E: Endian> macho::DyldCacheImageInfo<E> {
+ /// The file system path of this image.
+ pub fn path<'data, R: ReadRef<'data>>(&self, endian: E, data: R) -> Result<&'data [u8]> {
+ let r_start = self.path_file_offset.get(endian).into();
+ let r_end = data.len().read_error("Couldn't get data len()")?;
+ data.read_bytes_at_until(r_start..r_end, 0)
+ .read_error("Couldn't read dyld cache image path")
+ }
+
+ /// Find the file offset of the image by looking up its address in the mappings.
+ pub fn file_offset(
+ &self,
+ endian: E,
+ mappings: &[macho::DyldCacheMappingInfo<E>],
+ ) -> Result<u64> {
+ let address = self.address.get(endian);
+ address_to_file_offset(address, endian, mappings)
+ .read_error("Invalid dyld cache image address")
+ }
+}
+
+/// Find the file offset of the image by looking up its address in the mappings.
+pub fn address_to_file_offset<E: Endian>(
+ address: u64,
+ endian: E,
+ mappings: &[macho::DyldCacheMappingInfo<E>],
+) -> Option<u64> {
+ for mapping in mappings {
+ let mapping_address = mapping.address.get(endian);
+ if address >= mapping_address
+ && address < mapping_address.wrapping_add(mapping.size.get(endian))
+ {
+ return Some(address - mapping_address + mapping.file_offset.get(endian));
+ }
+ }
+ None
+}
diff --git a/third_party/rust/object/src/read/macho/fat.rs b/third_party/rust/object/src/read/macho/fat.rs
new file mode 100644
index 0000000000..d4301b7e11
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/fat.rs
@@ -0,0 +1,122 @@
+use crate::read::{Architecture, Error, ReadError, ReadRef, Result};
+use crate::{macho, BigEndian, Pod};
+
+pub use macho::{FatArch32, FatArch64, FatHeader};
+
+impl FatHeader {
+ /// Attempt to parse a fat header.
+ ///
+ /// Does not validate the magic value.
+ pub fn parse<'data, R: ReadRef<'data>>(file: R) -> Result<&'data FatHeader> {
+ file.read_at::<FatHeader>(0)
+ .read_error("Invalid fat header size or alignment")
+ }
+
+ /// Attempt to parse a fat header and 32-bit fat arches.
+ pub fn parse_arch32<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch32]> {
+ let mut offset = 0;
+ let header = file
+ .read::<FatHeader>(&mut offset)
+ .read_error("Invalid fat header size or alignment")?;
+ if header.magic.get(BigEndian) != macho::FAT_MAGIC {
+ return Err(Error("Invalid 32-bit fat magic"));
+ }
+ file.read_slice::<FatArch32>(&mut offset, header.nfat_arch.get(BigEndian) as usize)
+ .read_error("Invalid nfat_arch")
+ }
+
+ /// Attempt to parse a fat header and 64-bit fat arches.
+ pub fn parse_arch64<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch64]> {
+ let mut offset = 0;
+ let header = file
+ .read::<FatHeader>(&mut offset)
+ .read_error("Invalid fat header size or alignment")?;
+ if header.magic.get(BigEndian) != macho::FAT_MAGIC_64 {
+ return Err(Error("Invalid 64-bit fat magic"));
+ }
+ file.read_slice::<FatArch64>(&mut offset, header.nfat_arch.get(BigEndian) as usize)
+ .read_error("Invalid nfat_arch")
+ }
+}
+
+/// A trait for generic access to `FatArch32` and `FatArch64`.
+#[allow(missing_docs)]
+pub trait FatArch: Pod {
+ type Word: Into<u64>;
+
+ fn cputype(&self) -> u32;
+ fn cpusubtype(&self) -> u32;
+ fn offset(&self) -> Self::Word;
+ fn size(&self) -> Self::Word;
+ fn align(&self) -> u32;
+
+ fn architecture(&self) -> Architecture {
+ match self.cputype() {
+ macho::CPU_TYPE_ARM => Architecture::Arm,
+ macho::CPU_TYPE_ARM64 => Architecture::Aarch64,
+ macho::CPU_TYPE_X86 => Architecture::I386,
+ macho::CPU_TYPE_X86_64 => Architecture::X86_64,
+ macho::CPU_TYPE_MIPS => Architecture::Mips,
+ macho::CPU_TYPE_POWERPC => Architecture::PowerPc,
+ macho::CPU_TYPE_POWERPC64 => Architecture::PowerPc64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ fn file_range(&self) -> (u64, u64) {
+ (self.offset().into(), self.size().into())
+ }
+
+ fn data<'data, R: ReadRef<'data>>(&self, file: R) -> Result<&'data [u8]> {
+ file.read_bytes_at(self.offset().into(), self.size().into())
+ .read_error("Invalid fat arch offset or size")
+ }
+}
+
+impl FatArch for FatArch32 {
+ type Word = u32;
+
+ fn cputype(&self) -> u32 {
+ self.cputype.get(BigEndian)
+ }
+
+ fn cpusubtype(&self) -> u32 {
+ self.cpusubtype.get(BigEndian)
+ }
+
+ fn offset(&self) -> Self::Word {
+ self.offset.get(BigEndian)
+ }
+
+ fn size(&self) -> Self::Word {
+ self.size.get(BigEndian)
+ }
+
+ fn align(&self) -> u32 {
+ self.align.get(BigEndian)
+ }
+}
+
+impl FatArch for FatArch64 {
+ type Word = u64;
+
+ fn cputype(&self) -> u32 {
+ self.cputype.get(BigEndian)
+ }
+
+ fn cpusubtype(&self) -> u32 {
+ self.cpusubtype.get(BigEndian)
+ }
+
+ fn offset(&self) -> Self::Word {
+ self.offset.get(BigEndian)
+ }
+
+ fn size(&self) -> Self::Word {
+ self.size.get(BigEndian)
+ }
+
+ fn align(&self) -> u32 {
+ self.align.get(BigEndian)
+ }
+}
diff --git a/third_party/rust/object/src/read/macho/file.rs b/third_party/rust/object/src/read/macho/file.rs
new file mode 100644
index 0000000000..368c28bbd2
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/file.rs
@@ -0,0 +1,731 @@
+use alloc::vec::Vec;
+use core::fmt::Debug;
+use core::{mem, str};
+
+use crate::read::{
+ self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator,
+ Object, ObjectComdat, ObjectKind, ObjectMap, ObjectSection, ReadError, ReadRef, Result,
+ SectionIndex, SymbolIndex,
+};
+use crate::{endian, macho, BigEndian, ByteString, Endian, Endianness, Pod};
+
+use super::{
+ DyldCacheImage, LoadCommandIterator, MachOSection, MachOSectionInternal, MachOSectionIterator,
+ MachOSegment, MachOSegmentInternal, MachOSegmentIterator, MachOSymbol, MachOSymbolIterator,
+ MachOSymbolTable, Nlist, Section, Segment, SymbolTable,
+};
+
+/// A 32-bit Mach-O object file.
+pub type MachOFile32<'data, Endian = Endianness, R = &'data [u8]> =
+ MachOFile<'data, macho::MachHeader32<Endian>, R>;
+/// A 64-bit Mach-O object file.
+pub type MachOFile64<'data, Endian = Endianness, R = &'data [u8]> =
+ MachOFile<'data, macho::MachHeader64<Endian>, R>;
+
+/// A partially parsed Mach-O file.
+///
+/// Most of the functionality of this type is provided by the `Object` trait implementation.
+#[derive(Debug)]
+pub struct MachOFile<'data, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) endian: Mach::Endian,
+ pub(super) data: R,
+ pub(super) header_offset: u64,
+ pub(super) header: &'data Mach,
+ pub(super) segments: Vec<MachOSegmentInternal<'data, Mach, R>>,
+ pub(super) sections: Vec<MachOSectionInternal<'data, Mach>>,
+ pub(super) symbols: SymbolTable<'data, Mach, R>,
+}
+
+impl<'data, Mach, R> MachOFile<'data, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ /// Parse the raw Mach-O file data.
+ pub fn parse(data: R) -> Result<Self> {
+ let header = Mach::parse(data, 0)?;
+ let endian = header.endian()?;
+
+ // Build a list of segments and sections to make some operations more efficient.
+ let mut segments = Vec::new();
+ let mut sections = Vec::new();
+ let mut symbols = SymbolTable::default();
+ if let Ok(mut commands) = header.load_commands(endian, data, 0) {
+ while let Ok(Some(command)) = commands.next() {
+ if let Some((segment, section_data)) = Mach::Segment::from_command(command)? {
+ let segment_index = segments.len();
+ segments.push(MachOSegmentInternal { segment, data });
+ for section in segment.sections(endian, section_data)? {
+ let index = SectionIndex(sections.len() + 1);
+ sections.push(MachOSectionInternal::parse(index, segment_index, section));
+ }
+ } else if let Some(symtab) = command.symtab()? {
+ symbols = symtab.symbols(endian, data)?;
+ }
+ }
+ }
+
+ Ok(MachOFile {
+ endian,
+ data,
+ header_offset: 0,
+ header,
+ segments,
+ sections,
+ symbols,
+ })
+ }
+
+ /// Parse the Mach-O file for the given image from the dyld shared cache.
+ /// This will read different sections from different subcaches, if necessary.
+ pub fn parse_dyld_cache_image<'cache, E: Endian>(
+ image: &DyldCacheImage<'data, 'cache, E, R>,
+ ) -> Result<Self> {
+ let (data, header_offset) = image.image_data_and_offset()?;
+ let header = Mach::parse(data, header_offset)?;
+ let endian = header.endian()?;
+
+ // Build a list of sections to make some operations more efficient.
+ // Also build a list of segments, because we need to remember which ReadRef
+ // to read each section's data from. Only the DyldCache knows this information,
+ // and we won't have access to it once we've exited this function.
+ let mut segments = Vec::new();
+ let mut sections = Vec::new();
+ let mut linkedit_data: Option<R> = None;
+ let mut symtab = None;
+ if let Ok(mut commands) = header.load_commands(endian, data, header_offset) {
+ while let Ok(Some(command)) = commands.next() {
+ if let Some((segment, section_data)) = Mach::Segment::from_command(command)? {
+ // Each segment can be stored in a different subcache. Get the segment's
+ // address and look it up in the cache mappings, to find the correct cache data.
+ let addr = segment.vmaddr(endian).into();
+ let (data, _offset) = image
+ .cache
+ .data_and_offset_for_address(addr)
+ .read_error("Could not find segment data in dyld shared cache")?;
+ if segment.name() == macho::SEG_LINKEDIT.as_bytes() {
+ linkedit_data = Some(data);
+ }
+ let segment_index = segments.len();
+ segments.push(MachOSegmentInternal { segment, data });
+
+ for section in segment.sections(endian, section_data)? {
+ let index = SectionIndex(sections.len() + 1);
+ sections.push(MachOSectionInternal::parse(index, segment_index, section));
+ }
+ } else if let Some(st) = command.symtab()? {
+ symtab = Some(st);
+ }
+ }
+ }
+
+ // The symbols are found in the __LINKEDIT segment, so make sure to read them from the
+ // correct subcache.
+ let symbols = match (symtab, linkedit_data) {
+ (Some(symtab), Some(linkedit_data)) => symtab.symbols(endian, linkedit_data)?,
+ _ => SymbolTable::default(),
+ };
+
+ Ok(MachOFile {
+ endian,
+ data,
+ header_offset,
+ header,
+ segments,
+ sections,
+ symbols,
+ })
+ }
+
+ /// Return the section at the given index.
+ #[inline]
+ pub(super) fn section_internal(
+ &self,
+ index: SectionIndex,
+ ) -> Result<&MachOSectionInternal<'data, Mach>> {
+ index
+ .0
+ .checked_sub(1)
+ .and_then(|index| self.sections.get(index))
+ .read_error("Invalid Mach-O section index")
+ }
+
+ pub(super) fn segment_internal(
+ &self,
+ index: usize,
+ ) -> Result<&MachOSegmentInternal<'data, Mach, R>> {
+ self.segments
+ .get(index)
+ .read_error("Invalid Mach-O segment index")
+ }
+}
+
+impl<'data, Mach, R> read::private::Sealed for MachOFile<'data, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Mach, R> Object<'data, 'file> for MachOFile<'data, Mach, R>
+where
+ 'data: 'file,
+ Mach: MachHeader,
+ R: 'file + ReadRef<'data>,
+{
+ type Segment = MachOSegment<'data, 'file, Mach, R>;
+ type SegmentIterator = MachOSegmentIterator<'data, 'file, Mach, R>;
+ type Section = MachOSection<'data, 'file, Mach, R>;
+ type SectionIterator = MachOSectionIterator<'data, 'file, Mach, R>;
+ type Comdat = MachOComdat<'data, 'file, Mach, R>;
+ type ComdatIterator = MachOComdatIterator<'data, 'file, Mach, R>;
+ type Symbol = MachOSymbol<'data, 'file, Mach, R>;
+ type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach, R>;
+ type SymbolTable = MachOSymbolTable<'data, 'file, Mach, R>;
+ type DynamicRelocationIterator = NoDynamicRelocationIterator;
+
+ fn architecture(&self) -> Architecture {
+ match self.header.cputype(self.endian) {
+ macho::CPU_TYPE_ARM => Architecture::Arm,
+ macho::CPU_TYPE_ARM64 => Architecture::Aarch64,
+ macho::CPU_TYPE_ARM64_32 => Architecture::Aarch64_Ilp32,
+ macho::CPU_TYPE_X86 => Architecture::I386,
+ macho::CPU_TYPE_X86_64 => Architecture::X86_64,
+ macho::CPU_TYPE_MIPS => Architecture::Mips,
+ macho::CPU_TYPE_POWERPC => Architecture::PowerPc,
+ macho::CPU_TYPE_POWERPC64 => Architecture::PowerPc64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ self.header.is_little_endian()
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ self.header.is_type_64()
+ }
+
+ fn kind(&self) -> ObjectKind {
+ match self.header.filetype(self.endian) {
+ macho::MH_OBJECT => ObjectKind::Relocatable,
+ macho::MH_EXECUTE => ObjectKind::Executable,
+ macho::MH_CORE => ObjectKind::Core,
+ macho::MH_DYLIB => ObjectKind::Dynamic,
+ _ => ObjectKind::Unknown,
+ }
+ }
+
+ fn segments(&'file self) -> MachOSegmentIterator<'data, 'file, Mach, R> {
+ MachOSegmentIterator {
+ file: self,
+ iter: self.segments.iter(),
+ }
+ }
+
+ fn section_by_name_bytes(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<MachOSection<'data, 'file, Mach, R>> {
+ // Translate the "." prefix to the "__" prefix used by OSX/Mach-O, eg
+ // ".debug_info" to "__debug_info", and limit to 16 bytes total.
+ let system_name = if section_name.starts_with(b".") {
+ if section_name.len() > 15 {
+ Some(&section_name[1..15])
+ } else {
+ Some(&section_name[1..])
+ }
+ } else {
+ None
+ };
+ let cmp_section_name = |section: &MachOSection<'data, 'file, Mach, R>| {
+ section
+ .name_bytes()
+ .map(|name| {
+ section_name == name
+ || system_name
+ .filter(|system_name| {
+ name.starts_with(b"__") && name[2..] == **system_name
+ })
+ .is_some()
+ })
+ .unwrap_or(false)
+ };
+
+ self.sections().find(cmp_section_name)
+ }
+
+ fn section_by_index(
+ &'file self,
+ index: SectionIndex,
+ ) -> Result<MachOSection<'data, 'file, Mach, R>> {
+ let internal = *self.section_internal(index)?;
+ Ok(MachOSection {
+ file: self,
+ internal,
+ })
+ }
+
+ fn sections(&'file self) -> MachOSectionIterator<'data, 'file, Mach, R> {
+ MachOSectionIterator {
+ file: self,
+ iter: self.sections.iter(),
+ }
+ }
+
+ fn comdats(&'file self) -> MachOComdatIterator<'data, 'file, Mach, R> {
+ MachOComdatIterator { file: self }
+ }
+
+ fn symbol_by_index(
+ &'file self,
+ index: SymbolIndex,
+ ) -> Result<MachOSymbol<'data, 'file, Mach, R>> {
+ let nlist = self.symbols.symbol(index.0)?;
+ MachOSymbol::new(self, index, nlist).read_error("Unsupported Mach-O symbol index")
+ }
+
+ fn symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach, R> {
+ MachOSymbolIterator {
+ file: self,
+ index: 0,
+ }
+ }
+
+ #[inline]
+ fn symbol_table(&'file self) -> Option<MachOSymbolTable<'data, 'file, Mach, R>> {
+ Some(MachOSymbolTable { file: self })
+ }
+
+ fn dynamic_symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach, R> {
+ MachOSymbolIterator {
+ file: self,
+ index: self.symbols.len(),
+ }
+ }
+
+ #[inline]
+ fn dynamic_symbol_table(&'file self) -> Option<MachOSymbolTable<'data, 'file, Mach, R>> {
+ None
+ }
+
+ fn object_map(&'file self) -> ObjectMap<'data> {
+ self.symbols.object_map(self.endian)
+ }
+
+ fn imports(&self) -> Result<Vec<Import<'data>>> {
+ let mut dysymtab = None;
+ let mut libraries = Vec::new();
+ let twolevel = self.header.flags(self.endian) & macho::MH_TWOLEVEL != 0;
+ if twolevel {
+ libraries.push(&[][..]);
+ }
+ let mut commands = self
+ .header
+ .load_commands(self.endian, self.data, self.header_offset)?;
+ while let Some(command) = commands.next()? {
+ if let Some(command) = command.dysymtab()? {
+ dysymtab = Some(command);
+ }
+ if twolevel {
+ if let Some(dylib) = command.dylib()? {
+ libraries.push(command.string(self.endian, dylib.dylib.name)?);
+ }
+ }
+ }
+
+ let mut imports = Vec::new();
+ if let Some(dysymtab) = dysymtab {
+ let index = dysymtab.iundefsym.get(self.endian) as usize;
+ let number = dysymtab.nundefsym.get(self.endian) as usize;
+ for i in index..(index.wrapping_add(number)) {
+ let symbol = self.symbols.symbol(i)?;
+ let name = symbol.name(self.endian, self.symbols.strings())?;
+ let library = if twolevel {
+ libraries
+ .get(symbol.library_ordinal(self.endian) as usize)
+ .copied()
+ .read_error("Invalid Mach-O symbol library ordinal")?
+ } else {
+ &[]
+ };
+ imports.push(Import {
+ name: ByteString(name),
+ library: ByteString(library),
+ });
+ }
+ }
+ Ok(imports)
+ }
+
+ fn exports(&self) -> Result<Vec<Export<'data>>> {
+ let mut dysymtab = None;
+ let mut commands = self
+ .header
+ .load_commands(self.endian, self.data, self.header_offset)?;
+ while let Some(command) = commands.next()? {
+ if let Some(command) = command.dysymtab()? {
+ dysymtab = Some(command);
+ break;
+ }
+ }
+
+ let mut exports = Vec::new();
+ if let Some(dysymtab) = dysymtab {
+ let index = dysymtab.iextdefsym.get(self.endian) as usize;
+ let number = dysymtab.nextdefsym.get(self.endian) as usize;
+ for i in index..(index.wrapping_add(number)) {
+ let symbol = self.symbols.symbol(i)?;
+ let name = symbol.name(self.endian, self.symbols.strings())?;
+ let address = symbol.n_value(self.endian).into();
+ exports.push(Export {
+ name: ByteString(name),
+ address,
+ });
+ }
+ }
+ Ok(exports)
+ }
+
+ #[inline]
+ fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> {
+ None
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ self.section_by_name(".debug_info").is_some()
+ }
+
+ fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
+ self.header.uuid(self.endian, self.data, self.header_offset)
+ }
+
+ fn relative_address_base(&self) -> u64 {
+ 0
+ }
+
+ fn entry(&self) -> u64 {
+ if let Ok(mut commands) =
+ self.header
+ .load_commands(self.endian, self.data, self.header_offset)
+ {
+ while let Ok(Some(command)) = commands.next() {
+ if let Ok(Some(command)) = command.entry_point() {
+ return command.entryoff.get(self.endian);
+ }
+ }
+ }
+ 0
+ }
+
+ fn flags(&self) -> FileFlags {
+ FileFlags::MachO {
+ flags: self.header.flags(self.endian),
+ }
+ }
+}
+
+/// An iterator over the COMDAT section groups of a `MachOFile64`.
+pub type MachOComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOComdatIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// An iterator over the COMDAT section groups of a `MachOFile64`.
+pub type MachOComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOComdatIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// An iterator over the COMDAT section groups of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOComdatIterator<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file MachOFile<'data, Mach, R>,
+}
+
+impl<'data, 'file, Mach, R> Iterator for MachOComdatIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type Item = MachOComdat<'data, 'file, Mach, R>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A COMDAT section group of a `MachOFile32`.
+pub type MachOComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOComdat<'data, 'file, macho::MachHeader32<Endian>, R>;
+
+/// A COMDAT section group of a `MachOFile64`.
+pub type MachOComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOComdat<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// A COMDAT section group of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOComdat<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file MachOFile<'data, Mach, R>,
+}
+
+impl<'data, 'file, Mach, R> read::private::Sealed for MachOComdat<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Mach, R> ObjectComdat<'data> for MachOComdat<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type SectionIterator = MachOComdatSectionIterator<'data, 'file, Mach, R>;
+
+ #[inline]
+ fn kind(&self) -> ComdatKind {
+ unreachable!();
+ }
+
+ #[inline]
+ fn symbol(&self) -> SymbolIndex {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn sections(&self) -> Self::SectionIterator {
+ unreachable!();
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of a `MachOFile32`.
+pub type MachOComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOComdatSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// An iterator over the sections in a COMDAT section group of a `MachOFile64`.
+pub type MachOComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOComdatSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// An iterator over the sections in a COMDAT section group of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOComdatSectionIterator<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file MachOFile<'data, Mach, R>,
+}
+
+impl<'data, 'file, Mach, R> Iterator for MachOComdatSectionIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A trait for generic access to `MachHeader32` and `MachHeader64`.
+#[allow(missing_docs)]
+pub trait MachHeader: Debug + Pod {
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+ type Segment: Segment<Endian = Self::Endian, Section = Self::Section>;
+ type Section: Section<Endian = Self::Endian>;
+ type Nlist: Nlist<Endian = Self::Endian>;
+
+ /// Return true if this type is a 64-bit header.
+ ///
+ /// This is a property of the type, not a value in the header data.
+ fn is_type_64(&self) -> bool;
+
+ /// Return true if the `magic` field signifies big-endian.
+ fn is_big_endian(&self) -> bool;
+
+ /// Return true if the `magic` field signifies little-endian.
+ fn is_little_endian(&self) -> bool;
+
+ fn magic(&self) -> u32;
+ fn cputype(&self, endian: Self::Endian) -> u32;
+ fn cpusubtype(&self, endian: Self::Endian) -> u32;
+ fn filetype(&self, endian: Self::Endian) -> u32;
+ fn ncmds(&self, endian: Self::Endian) -> u32;
+ fn sizeofcmds(&self, endian: Self::Endian) -> u32;
+ fn flags(&self, endian: Self::Endian) -> u32;
+
+ // Provided methods.
+
+ /// Read the file header.
+ ///
+ /// Also checks that the magic field in the file header is a supported format.
+ fn parse<'data, R: ReadRef<'data>>(data: R, offset: u64) -> read::Result<&'data Self> {
+ let header = data
+ .read_at::<Self>(offset)
+ .read_error("Invalid Mach-O header size or alignment")?;
+ if !header.is_supported() {
+ return Err(Error("Unsupported Mach-O header"));
+ }
+ Ok(header)
+ }
+
+ fn is_supported(&self) -> bool {
+ self.is_little_endian() || self.is_big_endian()
+ }
+
+ fn endian(&self) -> Result<Self::Endian> {
+ Self::Endian::from_big_endian(self.is_big_endian()).read_error("Unsupported Mach-O endian")
+ }
+
+ fn load_commands<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ header_offset: u64,
+ ) -> Result<LoadCommandIterator<'data, Self::Endian>> {
+ let data = data
+ .read_bytes_at(
+ header_offset + mem::size_of::<Self>() as u64,
+ self.sizeofcmds(endian).into(),
+ )
+ .read_error("Invalid Mach-O load command table size")?;
+ Ok(LoadCommandIterator::new(endian, data, self.ncmds(endian)))
+ }
+
+ /// Return the UUID from the `LC_UUID` load command, if one is present.
+ fn uuid<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ header_offset: u64,
+ ) -> Result<Option<[u8; 16]>> {
+ let mut commands = self.load_commands(endian, data, header_offset)?;
+ while let Some(command) = commands.next()? {
+ if let Ok(Some(uuid)) = command.uuid() {
+ return Ok(Some(uuid.uuid));
+ }
+ }
+ Ok(None)
+ }
+}
+
+impl<Endian: endian::Endian> MachHeader for macho::MachHeader32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+ type Segment = macho::SegmentCommand32<Endian>;
+ type Section = macho::Section32<Endian>;
+ type Nlist = macho::Nlist32<Endian>;
+
+ fn is_type_64(&self) -> bool {
+ false
+ }
+
+ fn is_big_endian(&self) -> bool {
+ self.magic() == macho::MH_MAGIC
+ }
+
+ fn is_little_endian(&self) -> bool {
+ self.magic() == macho::MH_CIGAM
+ }
+
+ fn magic(&self) -> u32 {
+ self.magic.get(BigEndian)
+ }
+
+ fn cputype(&self, endian: Self::Endian) -> u32 {
+ self.cputype.get(endian)
+ }
+
+ fn cpusubtype(&self, endian: Self::Endian) -> u32 {
+ self.cpusubtype.get(endian)
+ }
+
+ fn filetype(&self, endian: Self::Endian) -> u32 {
+ self.filetype.get(endian)
+ }
+
+ fn ncmds(&self, endian: Self::Endian) -> u32 {
+ self.ncmds.get(endian)
+ }
+
+ fn sizeofcmds(&self, endian: Self::Endian) -> u32 {
+ self.sizeofcmds.get(endian)
+ }
+
+ fn flags(&self, endian: Self::Endian) -> u32 {
+ self.flags.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> MachHeader for macho::MachHeader64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+ type Segment = macho::SegmentCommand64<Endian>;
+ type Section = macho::Section64<Endian>;
+ type Nlist = macho::Nlist64<Endian>;
+
+ fn is_type_64(&self) -> bool {
+ true
+ }
+
+ fn is_big_endian(&self) -> bool {
+ self.magic() == macho::MH_MAGIC_64
+ }
+
+ fn is_little_endian(&self) -> bool {
+ self.magic() == macho::MH_CIGAM_64
+ }
+
+ fn magic(&self) -> u32 {
+ self.magic.get(BigEndian)
+ }
+
+ fn cputype(&self, endian: Self::Endian) -> u32 {
+ self.cputype.get(endian)
+ }
+
+ fn cpusubtype(&self, endian: Self::Endian) -> u32 {
+ self.cpusubtype.get(endian)
+ }
+
+ fn filetype(&self, endian: Self::Endian) -> u32 {
+ self.filetype.get(endian)
+ }
+
+ fn ncmds(&self, endian: Self::Endian) -> u32 {
+ self.ncmds.get(endian)
+ }
+
+ fn sizeofcmds(&self, endian: Self::Endian) -> u32 {
+ self.sizeofcmds.get(endian)
+ }
+
+ fn flags(&self, endian: Self::Endian) -> u32 {
+ self.flags.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/macho/load_command.rs b/third_party/rust/object/src/read/macho/load_command.rs
new file mode 100644
index 0000000000..e9af89d8bf
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/load_command.rs
@@ -0,0 +1,373 @@
+use core::marker::PhantomData;
+use core::mem;
+
+use crate::endian::Endian;
+use crate::macho;
+use crate::pod::Pod;
+use crate::read::macho::{MachHeader, SymbolTable};
+use crate::read::{Bytes, Error, ReadError, ReadRef, Result, StringTable};
+
+/// An iterator over the load commands of a `MachHeader`.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct LoadCommandIterator<'data, E: Endian> {
+ endian: E,
+ data: Bytes<'data>,
+ ncmds: u32,
+}
+
+impl<'data, E: Endian> LoadCommandIterator<'data, E> {
+ pub(super) fn new(endian: E, data: &'data [u8], ncmds: u32) -> Self {
+ LoadCommandIterator {
+ endian,
+ data: Bytes(data),
+ ncmds,
+ }
+ }
+
+ /// Return the next load command.
+ pub fn next(&mut self) -> Result<Option<LoadCommandData<'data, E>>> {
+ if self.ncmds == 0 {
+ return Ok(None);
+ }
+ let header = self
+ .data
+ .read_at::<macho::LoadCommand<E>>(0)
+ .read_error("Invalid Mach-O load command header")?;
+ let cmd = header.cmd.get(self.endian);
+ let cmdsize = header.cmdsize.get(self.endian) as usize;
+ if cmdsize < mem::size_of::<macho::LoadCommand<E>>() {
+ return Err(Error("Invalid Mach-O load command size"));
+ }
+ let data = self
+ .data
+ .read_bytes(cmdsize)
+ .read_error("Invalid Mach-O load command size")?;
+ self.ncmds -= 1;
+ Ok(Some(LoadCommandData {
+ cmd,
+ data,
+ marker: Default::default(),
+ }))
+ }
+}
+
+/// The data for a `LoadCommand`.
+#[derive(Debug, Clone, Copy)]
+pub struct LoadCommandData<'data, E: Endian> {
+ cmd: u32,
+ // Includes the header.
+ data: Bytes<'data>,
+ marker: PhantomData<E>,
+}
+
+impl<'data, E: Endian> LoadCommandData<'data, E> {
+ /// Return the `cmd` field of the `LoadCommand`.
+ ///
+ /// This is one of the `LC_` constants.
+ pub fn cmd(&self) -> u32 {
+ self.cmd
+ }
+
+ /// Return the `cmdsize` field of the `LoadCommand`.
+ pub fn cmdsize(&self) -> u32 {
+ self.data.len() as u32
+ }
+
+ /// Parse the data as the given type.
+ #[inline]
+ pub fn data<T: Pod>(&self) -> Result<&'data T> {
+ self.data
+ .read_at(0)
+ .read_error("Invalid Mach-O command size")
+ }
+
+ /// Raw bytes of this LoadCommand structure.
+ pub fn raw_data(&self) -> &'data [u8] {
+ self.data.0
+ }
+
+ /// Parse a load command string value.
+ ///
+ /// Strings used by load commands are specified by offsets that are
+ /// relative to the load command header.
+ pub fn string(&self, endian: E, s: macho::LcStr<E>) -> Result<&'data [u8]> {
+ self.data
+ .read_string_at(s.offset.get(endian) as usize)
+ .read_error("Invalid load command string offset")
+ }
+
+ /// Parse the command data according to the `cmd` field.
+ pub fn variant(&self) -> Result<LoadCommandVariant<'data, E>> {
+ Ok(match self.cmd {
+ macho::LC_SEGMENT => {
+ let mut data = self.data;
+ let segment = data.read().read_error("Invalid Mach-O command size")?;
+ LoadCommandVariant::Segment32(segment, data.0)
+ }
+ macho::LC_SYMTAB => LoadCommandVariant::Symtab(self.data()?),
+ macho::LC_THREAD | macho::LC_UNIXTHREAD => {
+ let mut data = self.data;
+ let thread = data.read().read_error("Invalid Mach-O command size")?;
+ LoadCommandVariant::Thread(thread, data.0)
+ }
+ macho::LC_DYSYMTAB => LoadCommandVariant::Dysymtab(self.data()?),
+ macho::LC_LOAD_DYLIB
+ | macho::LC_LOAD_WEAK_DYLIB
+ | macho::LC_REEXPORT_DYLIB
+ | macho::LC_LAZY_LOAD_DYLIB
+ | macho::LC_LOAD_UPWARD_DYLIB => LoadCommandVariant::Dylib(self.data()?),
+ macho::LC_ID_DYLIB => LoadCommandVariant::IdDylib(self.data()?),
+ macho::LC_LOAD_DYLINKER => LoadCommandVariant::LoadDylinker(self.data()?),
+ macho::LC_ID_DYLINKER => LoadCommandVariant::IdDylinker(self.data()?),
+ macho::LC_PREBOUND_DYLIB => LoadCommandVariant::PreboundDylib(self.data()?),
+ macho::LC_ROUTINES => LoadCommandVariant::Routines32(self.data()?),
+ macho::LC_SUB_FRAMEWORK => LoadCommandVariant::SubFramework(self.data()?),
+ macho::LC_SUB_UMBRELLA => LoadCommandVariant::SubUmbrella(self.data()?),
+ macho::LC_SUB_CLIENT => LoadCommandVariant::SubClient(self.data()?),
+ macho::LC_SUB_LIBRARY => LoadCommandVariant::SubLibrary(self.data()?),
+ macho::LC_TWOLEVEL_HINTS => LoadCommandVariant::TwolevelHints(self.data()?),
+ macho::LC_PREBIND_CKSUM => LoadCommandVariant::PrebindCksum(self.data()?),
+ macho::LC_SEGMENT_64 => {
+ let mut data = self.data;
+ let segment = data.read().read_error("Invalid Mach-O command size")?;
+ LoadCommandVariant::Segment64(segment, data.0)
+ }
+ macho::LC_ROUTINES_64 => LoadCommandVariant::Routines64(self.data()?),
+ macho::LC_UUID => LoadCommandVariant::Uuid(self.data()?),
+ macho::LC_RPATH => LoadCommandVariant::Rpath(self.data()?),
+ macho::LC_CODE_SIGNATURE
+ | macho::LC_SEGMENT_SPLIT_INFO
+ | macho::LC_FUNCTION_STARTS
+ | macho::LC_DATA_IN_CODE
+ | macho::LC_DYLIB_CODE_SIGN_DRS
+ | macho::LC_LINKER_OPTIMIZATION_HINT
+ | macho::LC_DYLD_EXPORTS_TRIE
+ | macho::LC_DYLD_CHAINED_FIXUPS => LoadCommandVariant::LinkeditData(self.data()?),
+ macho::LC_ENCRYPTION_INFO => LoadCommandVariant::EncryptionInfo32(self.data()?),
+ macho::LC_DYLD_INFO | macho::LC_DYLD_INFO_ONLY => {
+ LoadCommandVariant::DyldInfo(self.data()?)
+ }
+ macho::LC_VERSION_MIN_MACOSX
+ | macho::LC_VERSION_MIN_IPHONEOS
+ | macho::LC_VERSION_MIN_TVOS
+ | macho::LC_VERSION_MIN_WATCHOS => LoadCommandVariant::VersionMin(self.data()?),
+ macho::LC_DYLD_ENVIRONMENT => LoadCommandVariant::DyldEnvironment(self.data()?),
+ macho::LC_MAIN => LoadCommandVariant::EntryPoint(self.data()?),
+ macho::LC_SOURCE_VERSION => LoadCommandVariant::SourceVersion(self.data()?),
+ macho::LC_ENCRYPTION_INFO_64 => LoadCommandVariant::EncryptionInfo64(self.data()?),
+ macho::LC_LINKER_OPTION => LoadCommandVariant::LinkerOption(self.data()?),
+ macho::LC_NOTE => LoadCommandVariant::Note(self.data()?),
+ macho::LC_BUILD_VERSION => LoadCommandVariant::BuildVersion(self.data()?),
+ macho::LC_FILESET_ENTRY => LoadCommandVariant::FilesetEntry(self.data()?),
+ _ => LoadCommandVariant::Other,
+ })
+ }
+
+ /// Try to parse this command as a `SegmentCommand32`.
+ ///
+ /// Returns the segment command and the data containing the sections.
+ pub fn segment_32(self) -> Result<Option<(&'data macho::SegmentCommand32<E>, &'data [u8])>> {
+ if self.cmd == macho::LC_SEGMENT {
+ let mut data = self.data;
+ let segment = data.read().read_error("Invalid Mach-O command size")?;
+ Ok(Some((segment, data.0)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try to parse this command as a `SymtabCommand`.
+ ///
+ /// Returns the segment command and the data containing the sections.
+ pub fn symtab(self) -> Result<Option<&'data macho::SymtabCommand<E>>> {
+ if self.cmd == macho::LC_SYMTAB {
+ Some(self.data()).transpose()
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try to parse this command as a `DysymtabCommand`.
+ pub fn dysymtab(self) -> Result<Option<&'data macho::DysymtabCommand<E>>> {
+ if self.cmd == macho::LC_DYSYMTAB {
+ Some(self.data()).transpose()
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try to parse this command as a `DylibCommand`.
+ pub fn dylib(self) -> Result<Option<&'data macho::DylibCommand<E>>> {
+ if self.cmd == macho::LC_LOAD_DYLIB
+ || self.cmd == macho::LC_LOAD_WEAK_DYLIB
+ || self.cmd == macho::LC_REEXPORT_DYLIB
+ || self.cmd == macho::LC_LAZY_LOAD_DYLIB
+ || self.cmd == macho::LC_LOAD_UPWARD_DYLIB
+ {
+ Some(self.data()).transpose()
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try to parse this command as a `UuidCommand`.
+ pub fn uuid(self) -> Result<Option<&'data macho::UuidCommand<E>>> {
+ if self.cmd == macho::LC_UUID {
+ Some(self.data()).transpose()
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try to parse this command as a `SegmentCommand64`.
+ pub fn segment_64(self) -> Result<Option<(&'data macho::SegmentCommand64<E>, &'data [u8])>> {
+ if self.cmd == macho::LC_SEGMENT_64 {
+ let mut data = self.data;
+ let command = data.read().read_error("Invalid Mach-O command size")?;
+ Ok(Some((command, data.0)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try to parse this command as a `DyldInfoCommand`.
+ pub fn dyld_info(self) -> Result<Option<&'data macho::DyldInfoCommand<E>>> {
+ if self.cmd == macho::LC_DYLD_INFO || self.cmd == macho::LC_DYLD_INFO_ONLY {
+ Some(self.data()).transpose()
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try to parse this command as an `EntryPointCommand`.
+ pub fn entry_point(self) -> Result<Option<&'data macho::EntryPointCommand<E>>> {
+ if self.cmd == macho::LC_MAIN {
+ Some(self.data()).transpose()
+ } else {
+ Ok(None)
+ }
+ }
+}
+
+/// A `LoadCommand` that has been interpreted according to its `cmd` field.
+#[derive(Debug, Clone, Copy)]
+#[non_exhaustive]
+pub enum LoadCommandVariant<'data, E: Endian> {
+ /// `LC_SEGMENT`
+ Segment32(&'data macho::SegmentCommand32<E>, &'data [u8]),
+ /// `LC_SYMTAB`
+ Symtab(&'data macho::SymtabCommand<E>),
+ // obsolete: `LC_SYMSEG`
+ //Symseg(&'data macho::SymsegCommand<E>),
+ /// `LC_THREAD` or `LC_UNIXTHREAD`
+ Thread(&'data macho::ThreadCommand<E>, &'data [u8]),
+ // obsolete: `LC_IDFVMLIB` or `LC_LOADFVMLIB`
+ //Fvmlib(&'data macho::FvmlibCommand<E>),
+ // obsolete: `LC_IDENT`
+ //Ident(&'data macho::IdentCommand<E>),
+ // internal: `LC_FVMFILE`
+ //Fvmfile(&'data macho::FvmfileCommand<E>),
+ // internal: `LC_PREPAGE`
+ /// `LC_DYSYMTAB`
+ Dysymtab(&'data macho::DysymtabCommand<E>),
+ /// `LC_LOAD_DYLIB`, `LC_LOAD_WEAK_DYLIB`, `LC_REEXPORT_DYLIB`,
+ /// `LC_LAZY_LOAD_DYLIB`, or `LC_LOAD_UPWARD_DYLIB`
+ Dylib(&'data macho::DylibCommand<E>),
+ /// `LC_ID_DYLIB`
+ IdDylib(&'data macho::DylibCommand<E>),
+ /// `LC_LOAD_DYLINKER`
+ LoadDylinker(&'data macho::DylinkerCommand<E>),
+ /// `LC_ID_DYLINKER`
+ IdDylinker(&'data macho::DylinkerCommand<E>),
+ /// `LC_PREBOUND_DYLIB`
+ PreboundDylib(&'data macho::PreboundDylibCommand<E>),
+ /// `LC_ROUTINES`
+ Routines32(&'data macho::RoutinesCommand32<E>),
+ /// `LC_SUB_FRAMEWORK`
+ SubFramework(&'data macho::SubFrameworkCommand<E>),
+ /// `LC_SUB_UMBRELLA`
+ SubUmbrella(&'data macho::SubUmbrellaCommand<E>),
+ /// `LC_SUB_CLIENT`
+ SubClient(&'data macho::SubClientCommand<E>),
+ /// `LC_SUB_LIBRARY`
+ SubLibrary(&'data macho::SubLibraryCommand<E>),
+ /// `LC_TWOLEVEL_HINTS`
+ TwolevelHints(&'data macho::TwolevelHintsCommand<E>),
+ /// `LC_PREBIND_CKSUM`
+ PrebindCksum(&'data macho::PrebindCksumCommand<E>),
+ /// `LC_SEGMENT_64`
+ Segment64(&'data macho::SegmentCommand64<E>, &'data [u8]),
+ /// `LC_ROUTINES_64`
+ Routines64(&'data macho::RoutinesCommand64<E>),
+ /// `LC_UUID`
+ Uuid(&'data macho::UuidCommand<E>),
+ /// `LC_RPATH`
+ Rpath(&'data macho::RpathCommand<E>),
+ /// `LC_CODE_SIGNATURE`, `LC_SEGMENT_SPLIT_INFO`, `LC_FUNCTION_STARTS`,
+ /// `LC_DATA_IN_CODE`, `LC_DYLIB_CODE_SIGN_DRS`, `LC_LINKER_OPTIMIZATION_HINT`,
+ /// `LC_DYLD_EXPORTS_TRIE`, or `LC_DYLD_CHAINED_FIXUPS`.
+ LinkeditData(&'data macho::LinkeditDataCommand<E>),
+ /// `LC_ENCRYPTION_INFO`
+ EncryptionInfo32(&'data macho::EncryptionInfoCommand32<E>),
+ /// `LC_DYLD_INFO` or `LC_DYLD_INFO_ONLY`
+ DyldInfo(&'data macho::DyldInfoCommand<E>),
+ /// `LC_VERSION_MIN_MACOSX`, `LC_VERSION_MIN_IPHONEOS`, `LC_VERSION_MIN_WATCHOS`,
+ /// or `LC_VERSION_MIN_TVOS`
+ VersionMin(&'data macho::VersionMinCommand<E>),
+ /// `LC_DYLD_ENVIRONMENT`
+ DyldEnvironment(&'data macho::DylinkerCommand<E>),
+ /// `LC_MAIN`
+ EntryPoint(&'data macho::EntryPointCommand<E>),
+ /// `LC_SOURCE_VERSION`
+ SourceVersion(&'data macho::SourceVersionCommand<E>),
+ /// `LC_ENCRYPTION_INFO_64`
+ EncryptionInfo64(&'data macho::EncryptionInfoCommand64<E>),
+ /// `LC_LINKER_OPTION`
+ LinkerOption(&'data macho::LinkerOptionCommand<E>),
+ /// `LC_NOTE`
+ Note(&'data macho::NoteCommand<E>),
+ /// `LC_BUILD_VERSION`
+ BuildVersion(&'data macho::BuildVersionCommand<E>),
+ /// `LC_FILESET_ENTRY`
+ FilesetEntry(&'data macho::FilesetEntryCommand<E>),
+ /// An unrecognized or obsolete load command.
+ Other,
+}
+
+impl<E: Endian> macho::SymtabCommand<E> {
+ /// Return the symbol table that this command references.
+ pub fn symbols<'data, Mach: MachHeader<Endian = E>, R: ReadRef<'data>>(
+ &self,
+ endian: E,
+ data: R,
+ ) -> Result<SymbolTable<'data, Mach, R>> {
+ let symbols = data
+ .read_slice_at(
+ self.symoff.get(endian).into(),
+ self.nsyms.get(endian) as usize,
+ )
+ .read_error("Invalid Mach-O symbol table offset or size")?;
+ let str_start: u64 = self.stroff.get(endian).into();
+ let str_end = str_start
+ .checked_add(self.strsize.get(endian).into())
+ .read_error("Invalid Mach-O string table length")?;
+ let strings = StringTable::new(data, str_start, str_end);
+ Ok(SymbolTable::new(symbols, strings))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::LittleEndian;
+
+ #[test]
+ fn cmd_size_invalid() {
+ let mut commands = LoadCommandIterator::new(LittleEndian, &[0; 8], 10);
+ assert!(commands.next().is_err());
+ let mut commands = LoadCommandIterator::new(LittleEndian, &[0, 0, 0, 0, 7, 0, 0, 0, 0], 10);
+ assert!(commands.next().is_err());
+ let mut commands = LoadCommandIterator::new(LittleEndian, &[0, 0, 0, 0, 8, 0, 0, 0, 0], 10);
+ assert!(commands.next().is_ok());
+ }
+}
diff --git a/third_party/rust/object/src/read/macho/mod.rs b/third_party/rust/object/src/read/macho/mod.rs
new file mode 100644
index 0000000000..f07ed581b6
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/mod.rs
@@ -0,0 +1,30 @@
+//! Support for reading Mach-O files.
+//!
+//! Defines traits to abstract over the difference between 32-bit and 64-bit
+//! Mach-O files, and implements read functionality in terms of these traits.
+//!
+//! Also provides `MachOFile` and related types which implement the `Object` trait.
+
+mod dyld_cache;
+pub use dyld_cache::*;
+
+mod fat;
+pub use fat::*;
+
+mod file;
+pub use file::*;
+
+mod load_command;
+pub use load_command::*;
+
+mod segment;
+pub use segment::*;
+
+mod section;
+pub use section::*;
+
+mod symbol;
+pub use symbol::*;
+
+mod relocation;
+pub use relocation::*;
diff --git a/third_party/rust/object/src/read/macho/relocation.rs b/third_party/rust/object/src/read/macho/relocation.rs
new file mode 100644
index 0000000000..18e22ef706
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/relocation.rs
@@ -0,0 +1,127 @@
+use core::{fmt, slice};
+
+use crate::endian::Endianness;
+use crate::macho;
+use crate::read::{
+ ReadRef, Relocation, RelocationEncoding, RelocationKind, RelocationTarget, SectionIndex,
+ SymbolIndex,
+};
+
+use super::{MachHeader, MachOFile};
+
+/// An iterator over the relocations in a `MachOSection32`.
+pub type MachORelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachORelocationIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// An iterator over the relocations in a `MachOSection64`.
+pub type MachORelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachORelocationIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// An iterator over the relocations in a `MachOSection`.
+pub struct MachORelocationIterator<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file MachOFile<'data, Mach, R>,
+ pub(super) relocations: slice::Iter<'data, macho::Relocation<Mach::Endian>>,
+}
+
+impl<'data, 'file, Mach, R> Iterator for MachORelocationIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ let reloc = self.relocations.next()?;
+ let endian = self.file.endian;
+ let cputype = self.file.header.cputype(endian);
+ if reloc.r_scattered(endian, cputype) {
+ // FIXME: handle scattered relocations
+ // We need to add `RelocationTarget::Address` for this.
+ continue;
+ }
+ let reloc = reloc.info(self.file.endian);
+ let mut encoding = RelocationEncoding::Generic;
+ let kind = match cputype {
+ macho::CPU_TYPE_ARM => match (reloc.r_type, reloc.r_pcrel) {
+ (macho::ARM_RELOC_VANILLA, false) => RelocationKind::Absolute,
+ _ => RelocationKind::MachO {
+ value: reloc.r_type,
+ relative: reloc.r_pcrel,
+ },
+ },
+ macho::CPU_TYPE_ARM64 | macho::CPU_TYPE_ARM64_32 => {
+ match (reloc.r_type, reloc.r_pcrel) {
+ (macho::ARM64_RELOC_UNSIGNED, false) => RelocationKind::Absolute,
+ _ => RelocationKind::MachO {
+ value: reloc.r_type,
+ relative: reloc.r_pcrel,
+ },
+ }
+ }
+ macho::CPU_TYPE_X86 => match (reloc.r_type, reloc.r_pcrel) {
+ (macho::GENERIC_RELOC_VANILLA, false) => RelocationKind::Absolute,
+ _ => RelocationKind::MachO {
+ value: reloc.r_type,
+ relative: reloc.r_pcrel,
+ },
+ },
+ macho::CPU_TYPE_X86_64 => match (reloc.r_type, reloc.r_pcrel) {
+ (macho::X86_64_RELOC_UNSIGNED, false) => RelocationKind::Absolute,
+ (macho::X86_64_RELOC_SIGNED, true) => {
+ encoding = RelocationEncoding::X86RipRelative;
+ RelocationKind::Relative
+ }
+ (macho::X86_64_RELOC_BRANCH, true) => {
+ encoding = RelocationEncoding::X86Branch;
+ RelocationKind::Relative
+ }
+ (macho::X86_64_RELOC_GOT, true) => RelocationKind::GotRelative,
+ (macho::X86_64_RELOC_GOT_LOAD, true) => {
+ encoding = RelocationEncoding::X86RipRelativeMovq;
+ RelocationKind::GotRelative
+ }
+ _ => RelocationKind::MachO {
+ value: reloc.r_type,
+ relative: reloc.r_pcrel,
+ },
+ },
+ _ => RelocationKind::MachO {
+ value: reloc.r_type,
+ relative: reloc.r_pcrel,
+ },
+ };
+ let size = 8 << reloc.r_length;
+ let target = if reloc.r_extern {
+ RelocationTarget::Symbol(SymbolIndex(reloc.r_symbolnum as usize))
+ } else {
+ RelocationTarget::Section(SectionIndex(reloc.r_symbolnum as usize))
+ };
+ let addend = if reloc.r_pcrel { -4 } else { 0 };
+ return Some((
+ reloc.r_address as u64,
+ Relocation {
+ kind,
+ encoding,
+ size,
+ target,
+ addend,
+ implicit_addend: true,
+ },
+ ));
+ }
+ }
+}
+
+impl<'data, 'file, Mach, R> fmt::Debug for MachORelocationIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MachORelocationIterator").finish()
+ }
+}
diff --git a/third_party/rust/object/src/read/macho/section.rs b/third_party/rust/object/src/read/macho/section.rs
new file mode 100644
index 0000000000..f43a5b83d4
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/section.rs
@@ -0,0 +1,387 @@
+use core::fmt::Debug;
+use core::{fmt, result, slice, str};
+
+use crate::endian::{self, Endianness};
+use crate::macho;
+use crate::pod::Pod;
+use crate::read::{
+ self, CompressedData, CompressedFileRange, ObjectSection, ReadError, ReadRef, Result,
+ SectionFlags, SectionIndex, SectionKind,
+};
+
+use super::{MachHeader, MachOFile, MachORelocationIterator};
+
+/// An iterator over the sections of a `MachOFile32`.
+pub type MachOSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// An iterator over the sections of a `MachOFile64`.
+pub type MachOSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// An iterator over the sections of a `MachOFile`.
+pub struct MachOSectionIterator<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file MachOFile<'data, Mach, R>,
+ pub(super) iter: slice::Iter<'file, MachOSectionInternal<'data, Mach>>,
+}
+
+impl<'data, 'file, Mach, R> fmt::Debug for MachOSectionIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // It's painful to do much better than this
+ f.debug_struct("MachOSectionIterator").finish()
+ }
+}
+
+impl<'data, 'file, Mach, R> Iterator for MachOSectionIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type Item = MachOSection<'data, 'file, Mach, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|&internal| MachOSection {
+ file: self.file,
+ internal,
+ })
+ }
+}
+
+/// A section of a `MachOFile32`.
+pub type MachOSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSection<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// A section of a `MachOFile64`.
+pub type MachOSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSection<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// A section of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOSection<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file MachOFile<'data, Mach, R>,
+ pub(super) internal: MachOSectionInternal<'data, Mach>,
+}
+
+impl<'data, 'file, Mach, R> MachOSection<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ fn bytes(&self) -> Result<&'data [u8]> {
+ let segment_index = self.internal.segment_index;
+ let segment = self.file.segment_internal(segment_index)?;
+ self.internal
+ .section
+ .data(self.file.endian, segment.data)
+ .read_error("Invalid Mach-O section size or offset")
+ }
+}
+
+impl<'data, 'file, Mach, R> read::private::Sealed for MachOSection<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Mach, R> ObjectSection<'data> for MachOSection<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type RelocationIterator = MachORelocationIterator<'data, 'file, Mach, R>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.internal.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.internal.section.addr(self.file.endian).into()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.internal.section.size(self.file.endian).into()
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ let align = self.internal.section.align(self.file.endian);
+ if align < 64 {
+ 1 << align
+ } else {
+ 0
+ }
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ self.internal.section.file_range(self.file.endian)
+ }
+
+ #[inline]
+ fn data(&self) -> Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ #[inline]
+ fn compressed_file_range(&self) -> Result<CompressedFileRange> {
+ Ok(CompressedFileRange::none(self.file_range()))
+ }
+
+ #[inline]
+ fn compressed_data(&self) -> Result<CompressedData<'data>> {
+ self.data().map(CompressedData::none)
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ Ok(self.internal.section.name())
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ str::from_utf8(self.internal.section.name())
+ .ok()
+ .read_error("Non UTF-8 Mach-O section name")
+ }
+
+ #[inline]
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
+ Ok(Some(self.internal.section.segment_name()))
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Result<Option<&str>> {
+ Ok(Some(
+ str::from_utf8(self.internal.section.segment_name())
+ .ok()
+ .read_error("Non UTF-8 Mach-O segment name")?,
+ ))
+ }
+
+ fn kind(&self) -> SectionKind {
+ self.internal.kind
+ }
+
+ fn relocations(&self) -> MachORelocationIterator<'data, 'file, Mach, R> {
+ MachORelocationIterator {
+ file: self.file,
+ relocations: self
+ .internal
+ .section
+ .relocations(self.file.endian, self.file.data)
+ .unwrap_or(&[])
+ .iter(),
+ }
+ }
+
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::MachO {
+ flags: self.internal.section.flags(self.file.endian),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(super) struct MachOSectionInternal<'data, Mach: MachHeader> {
+ pub index: SectionIndex,
+ pub segment_index: usize,
+ pub kind: SectionKind,
+ pub section: &'data Mach::Section,
+}
+
+impl<'data, Mach: MachHeader> MachOSectionInternal<'data, Mach> {
+ pub(super) fn parse(
+ index: SectionIndex,
+ segment_index: usize,
+ section: &'data Mach::Section,
+ ) -> Self {
+ // TODO: we don't validate flags, should we?
+ let kind = match (section.segment_name(), section.name()) {
+ (b"__TEXT", b"__text") => SectionKind::Text,
+ (b"__TEXT", b"__const") => SectionKind::ReadOnlyData,
+ (b"__TEXT", b"__cstring") => SectionKind::ReadOnlyString,
+ (b"__TEXT", b"__literal4") => SectionKind::ReadOnlyData,
+ (b"__TEXT", b"__literal8") => SectionKind::ReadOnlyData,
+ (b"__TEXT", b"__literal16") => SectionKind::ReadOnlyData,
+ (b"__TEXT", b"__eh_frame") => SectionKind::ReadOnlyData,
+ (b"__TEXT", b"__gcc_except_tab") => SectionKind::ReadOnlyData,
+ (b"__DATA", b"__data") => SectionKind::Data,
+ (b"__DATA", b"__const") => SectionKind::ReadOnlyData,
+ (b"__DATA", b"__bss") => SectionKind::UninitializedData,
+ (b"__DATA", b"__common") => SectionKind::Common,
+ (b"__DATA", b"__thread_data") => SectionKind::Tls,
+ (b"__DATA", b"__thread_bss") => SectionKind::UninitializedTls,
+ (b"__DATA", b"__thread_vars") => SectionKind::TlsVariables,
+ (b"__DWARF", _) => SectionKind::Debug,
+ _ => SectionKind::Unknown,
+ };
+ MachOSectionInternal {
+ index,
+ segment_index,
+ kind,
+ section,
+ }
+ }
+}
+
+/// A trait for generic access to `Section32` and `Section64`.
+#[allow(missing_docs)]
+pub trait Section: Debug + Pod {
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn sectname(&self) -> &[u8; 16];
+ fn segname(&self) -> &[u8; 16];
+ fn addr(&self, endian: Self::Endian) -> Self::Word;
+ fn size(&self, endian: Self::Endian) -> Self::Word;
+ fn offset(&self, endian: Self::Endian) -> u32;
+ fn align(&self, endian: Self::Endian) -> u32;
+ fn reloff(&self, endian: Self::Endian) -> u32;
+ fn nreloc(&self, endian: Self::Endian) -> u32;
+ fn flags(&self, endian: Self::Endian) -> u32;
+
+ /// Return the `sectname` bytes up until the null terminator.
+ fn name(&self) -> &[u8] {
+ let sectname = &self.sectname()[..];
+ match memchr::memchr(b'\0', sectname) {
+ Some(end) => &sectname[..end],
+ None => sectname,
+ }
+ }
+
+ /// Return the `segname` bytes up until the null terminator.
+ fn segment_name(&self) -> &[u8] {
+ let segname = &self.segname()[..];
+ match memchr::memchr(b'\0', segname) {
+ Some(end) => &segname[..end],
+ None => segname,
+ }
+ }
+
+ /// Return the offset and size of the section in the file.
+ ///
+ /// Returns `None` for sections that have no data in the file.
+ fn file_range(&self, endian: Self::Endian) -> Option<(u64, u64)> {
+ match self.flags(endian) & macho::SECTION_TYPE {
+ macho::S_ZEROFILL | macho::S_GB_ZEROFILL | macho::S_THREAD_LOCAL_ZEROFILL => None,
+ _ => Some((self.offset(endian).into(), self.size(endian).into())),
+ }
+ }
+
+ /// Return the section data.
+ ///
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values.
+ fn data<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> result::Result<&'data [u8], ()> {
+ if let Some((offset, size)) = self.file_range(endian) {
+ data.read_bytes_at(offset, size)
+ } else {
+ Ok(&[])
+ }
+ }
+
+ /// Return the relocation array.
+ ///
+ /// Returns `Err` for invalid values.
+ fn relocations<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> Result<&'data [macho::Relocation<Self::Endian>]> {
+ data.read_slice_at(self.reloff(endian).into(), self.nreloc(endian) as usize)
+ .read_error("Invalid Mach-O relocations offset or number")
+ }
+}
+
+impl<Endian: endian::Endian> Section for macho::Section32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+
+ fn sectname(&self) -> &[u8; 16] {
+ &self.sectname
+ }
+ fn segname(&self) -> &[u8; 16] {
+ &self.segname
+ }
+ fn addr(&self, endian: Self::Endian) -> Self::Word {
+ self.addr.get(endian)
+ }
+ fn size(&self, endian: Self::Endian) -> Self::Word {
+ self.size.get(endian)
+ }
+ fn offset(&self, endian: Self::Endian) -> u32 {
+ self.offset.get(endian)
+ }
+ fn align(&self, endian: Self::Endian) -> u32 {
+ self.align.get(endian)
+ }
+ fn reloff(&self, endian: Self::Endian) -> u32 {
+ self.reloff.get(endian)
+ }
+ fn nreloc(&self, endian: Self::Endian) -> u32 {
+ self.nreloc.get(endian)
+ }
+ fn flags(&self, endian: Self::Endian) -> u32 {
+ self.flags.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> Section for macho::Section64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+
+ fn sectname(&self) -> &[u8; 16] {
+ &self.sectname
+ }
+ fn segname(&self) -> &[u8; 16] {
+ &self.segname
+ }
+ fn addr(&self, endian: Self::Endian) -> Self::Word {
+ self.addr.get(endian)
+ }
+ fn size(&self, endian: Self::Endian) -> Self::Word {
+ self.size.get(endian)
+ }
+ fn offset(&self, endian: Self::Endian) -> u32 {
+ self.offset.get(endian)
+ }
+ fn align(&self, endian: Self::Endian) -> u32 {
+ self.align.get(endian)
+ }
+ fn reloff(&self, endian: Self::Endian) -> u32 {
+ self.reloff.get(endian)
+ }
+ fn nreloc(&self, endian: Self::Endian) -> u32 {
+ self.nreloc.get(endian)
+ }
+ fn flags(&self, endian: Self::Endian) -> u32 {
+ self.flags.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/macho/segment.rs b/third_party/rust/object/src/read/macho/segment.rs
new file mode 100644
index 0000000000..01037e1dd4
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/segment.rs
@@ -0,0 +1,301 @@
+use core::fmt::Debug;
+use core::{result, slice, str};
+
+use crate::endian::{self, Endianness};
+use crate::macho;
+use crate::pod::Pod;
+use crate::read::{self, ObjectSegment, ReadError, ReadRef, Result, SegmentFlags};
+
+use super::{LoadCommandData, MachHeader, MachOFile, Section};
+
+/// An iterator over the segments of a `MachOFile32`.
+pub type MachOSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSegmentIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// An iterator over the segments of a `MachOFile64`.
+pub type MachOSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSegmentIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// An iterator over the segments of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOSegmentIterator<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file MachOFile<'data, Mach, R>,
+ pub(super) iter: slice::Iter<'file, MachOSegmentInternal<'data, Mach, R>>,
+}
+
+impl<'data, 'file, Mach, R> Iterator for MachOSegmentIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type Item = MachOSegment<'data, 'file, Mach, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|internal| MachOSegment {
+ file: self.file,
+ internal,
+ })
+ }
+}
+
+/// A segment of a `MachOFile32`.
+pub type MachOSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSegment<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// A segment of a `MachOFile64`.
+pub type MachOSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSegment<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// A segment of a `MachOFile`.
+#[derive(Debug)]
+pub struct MachOSegment<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ file: &'file MachOFile<'data, Mach, R>,
+ internal: &'file MachOSegmentInternal<'data, Mach, R>,
+}
+
+impl<'data, 'file, Mach, R> MachOSegment<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ fn bytes(&self) -> Result<&'data [u8]> {
+ self.internal
+ .segment
+ .data(self.file.endian, self.file.data)
+ .read_error("Invalid Mach-O segment size or offset")
+ }
+}
+
+impl<'data, 'file, Mach, R> read::private::Sealed for MachOSegment<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Mach, R> ObjectSegment<'data> for MachOSegment<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ #[inline]
+ fn address(&self) -> u64 {
+ self.internal.segment.vmaddr(self.file.endian).into()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.internal.segment.vmsize(self.file.endian).into()
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ // Page size.
+ 0x1000
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ self.internal.segment.file_range(self.file.endian)
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<Option<&[u8]>> {
+ Ok(Some(self.internal.segment.name()))
+ }
+
+ #[inline]
+ fn name(&self) -> Result<Option<&str>> {
+ Ok(Some(
+ str::from_utf8(self.internal.segment.name())
+ .ok()
+ .read_error("Non UTF-8 Mach-O segment name")?,
+ ))
+ }
+
+ #[inline]
+ fn flags(&self) -> SegmentFlags {
+ let flags = self.internal.segment.flags(self.file.endian);
+ let maxprot = self.internal.segment.maxprot(self.file.endian);
+ let initprot = self.internal.segment.initprot(self.file.endian);
+ SegmentFlags::MachO {
+ flags,
+ maxprot,
+ initprot,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(super) struct MachOSegmentInternal<'data, Mach: MachHeader, R: ReadRef<'data>> {
+ pub data: R,
+ pub segment: &'data Mach::Segment,
+}
+
+/// A trait for generic access to `SegmentCommand32` and `SegmentCommand64`.
+#[allow(missing_docs)]
+pub trait Segment: Debug + Pod {
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+ type Section: Section<Endian = Self::Endian>;
+
+ fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>>;
+
+ fn cmd(&self, endian: Self::Endian) -> u32;
+ fn cmdsize(&self, endian: Self::Endian) -> u32;
+ fn segname(&self) -> &[u8; 16];
+ fn vmaddr(&self, endian: Self::Endian) -> Self::Word;
+ fn vmsize(&self, endian: Self::Endian) -> Self::Word;
+ fn fileoff(&self, endian: Self::Endian) -> Self::Word;
+ fn filesize(&self, endian: Self::Endian) -> Self::Word;
+ fn maxprot(&self, endian: Self::Endian) -> u32;
+ fn initprot(&self, endian: Self::Endian) -> u32;
+ fn nsects(&self, endian: Self::Endian) -> u32;
+ fn flags(&self, endian: Self::Endian) -> u32;
+
+ /// Return the `segname` bytes up until the null terminator.
+ fn name(&self) -> &[u8] {
+ let segname = &self.segname()[..];
+ match memchr::memchr(b'\0', segname) {
+ Some(end) => &segname[..end],
+ None => segname,
+ }
+ }
+
+ /// Return the offset and size of the segment in the file.
+ fn file_range(&self, endian: Self::Endian) -> (u64, u64) {
+ (self.fileoff(endian).into(), self.filesize(endian).into())
+ }
+
+ /// Get the segment data from the file data.
+ ///
+ /// Returns `Err` for invalid values.
+ fn data<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> result::Result<&'data [u8], ()> {
+ let (offset, size) = self.file_range(endian);
+ data.read_bytes_at(offset, size)
+ }
+
+ /// Get the array of sections from the data following the segment command.
+ ///
+ /// Returns `Err` for invalid values.
+ fn sections<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ section_data: R,
+ ) -> Result<&'data [Self::Section]> {
+ section_data
+ .read_slice_at(0, self.nsects(endian) as usize)
+ .read_error("Invalid Mach-O number of sections")
+ }
+}
+
+impl<Endian: endian::Endian> Segment for macho::SegmentCommand32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+ type Section = macho::Section32<Self::Endian>;
+
+ fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> {
+ command.segment_32()
+ }
+
+ fn cmd(&self, endian: Self::Endian) -> u32 {
+ self.cmd.get(endian)
+ }
+ fn cmdsize(&self, endian: Self::Endian) -> u32 {
+ self.cmdsize.get(endian)
+ }
+ fn segname(&self) -> &[u8; 16] {
+ &self.segname
+ }
+ fn vmaddr(&self, endian: Self::Endian) -> Self::Word {
+ self.vmaddr.get(endian)
+ }
+ fn vmsize(&self, endian: Self::Endian) -> Self::Word {
+ self.vmsize.get(endian)
+ }
+ fn fileoff(&self, endian: Self::Endian) -> Self::Word {
+ self.fileoff.get(endian)
+ }
+ fn filesize(&self, endian: Self::Endian) -> Self::Word {
+ self.filesize.get(endian)
+ }
+ fn maxprot(&self, endian: Self::Endian) -> u32 {
+ self.maxprot.get(endian)
+ }
+ fn initprot(&self, endian: Self::Endian) -> u32 {
+ self.initprot.get(endian)
+ }
+ fn nsects(&self, endian: Self::Endian) -> u32 {
+ self.nsects.get(endian)
+ }
+ fn flags(&self, endian: Self::Endian) -> u32 {
+ self.flags.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> Segment for macho::SegmentCommand64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+ type Section = macho::Section64<Self::Endian>;
+
+ fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> {
+ command.segment_64()
+ }
+
+ fn cmd(&self, endian: Self::Endian) -> u32 {
+ self.cmd.get(endian)
+ }
+ fn cmdsize(&self, endian: Self::Endian) -> u32 {
+ self.cmdsize.get(endian)
+ }
+ fn segname(&self) -> &[u8; 16] {
+ &self.segname
+ }
+ fn vmaddr(&self, endian: Self::Endian) -> Self::Word {
+ self.vmaddr.get(endian)
+ }
+ fn vmsize(&self, endian: Self::Endian) -> Self::Word {
+ self.vmsize.get(endian)
+ }
+ fn fileoff(&self, endian: Self::Endian) -> Self::Word {
+ self.fileoff.get(endian)
+ }
+ fn filesize(&self, endian: Self::Endian) -> Self::Word {
+ self.filesize.get(endian)
+ }
+ fn maxprot(&self, endian: Self::Endian) -> u32 {
+ self.maxprot.get(endian)
+ }
+ fn initprot(&self, endian: Self::Endian) -> u32 {
+ self.initprot.get(endian)
+ }
+ fn nsects(&self, endian: Self::Endian) -> u32 {
+ self.nsects.get(endian)
+ }
+ fn flags(&self, endian: Self::Endian) -> u32 {
+ self.flags.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/macho/symbol.rs b/third_party/rust/object/src/read/macho/symbol.rs
new file mode 100644
index 0000000000..ef88521451
--- /dev/null
+++ b/third_party/rust/object/src/read/macho/symbol.rs
@@ -0,0 +1,488 @@
+use alloc::vec::Vec;
+use core::fmt::Debug;
+use core::{fmt, slice, str};
+
+use crate::endian::{self, Endianness};
+use crate::macho;
+use crate::pod::Pod;
+use crate::read::util::StringTable;
+use crate::read::{
+ self, ObjectMap, ObjectMapEntry, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result,
+ SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry,
+ SymbolScope, SymbolSection,
+};
+
+use super::{MachHeader, MachOFile};
+
+/// A table of symbol entries in a Mach-O file.
+///
+/// Also includes the string table used for the symbol names.
+#[derive(Debug, Clone, Copy)]
+pub struct SymbolTable<'data, Mach: MachHeader, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ symbols: &'data [Mach::Nlist],
+ strings: StringTable<'data, R>,
+}
+
+impl<'data, Mach: MachHeader, R: ReadRef<'data>> Default for SymbolTable<'data, Mach, R> {
+ fn default() -> Self {
+ SymbolTable {
+ symbols: &[],
+ strings: Default::default(),
+ }
+ }
+}
+
+impl<'data, Mach: MachHeader, R: ReadRef<'data>> SymbolTable<'data, Mach, R> {
+ #[inline]
+ pub(super) fn new(symbols: &'data [Mach::Nlist], strings: StringTable<'data, R>) -> Self {
+ SymbolTable { symbols, strings }
+ }
+
+ /// Return the string table used for the symbol names.
+ #[inline]
+ pub fn strings(&self) -> StringTable<'data, R> {
+ self.strings
+ }
+
+ /// Iterate over the symbols.
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'data, Mach::Nlist> {
+ self.symbols.iter()
+ }
+
+ /// Return true if the symbol table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.symbols.is_empty()
+ }
+
+ /// The number of symbols.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.symbols.len()
+ }
+
+ /// Return the symbol at the given index.
+ pub fn symbol(&self, index: usize) -> Result<&'data Mach::Nlist> {
+ self.symbols
+ .get(index)
+ .read_error("Invalid Mach-O symbol index")
+ }
+
+ /// Construct a map from addresses to a user-defined map entry.
+ pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Mach::Nlist) -> Option<Entry>>(
+ &self,
+ f: F,
+ ) -> SymbolMap<Entry> {
+ let mut symbols = Vec::new();
+ for nlist in self.symbols {
+ if !nlist.is_definition() {
+ continue;
+ }
+ if let Some(entry) = f(nlist) {
+ symbols.push(entry);
+ }
+ }
+ SymbolMap::new(symbols)
+ }
+
+ /// Construct a map from addresses to symbol names and object file names.
+ pub fn object_map(&self, endian: Mach::Endian) -> ObjectMap<'data> {
+ let mut symbols = Vec::new();
+ let mut objects = Vec::new();
+ let mut object = None;
+ let mut current_function = None;
+ // Each module starts with one or two N_SO symbols (path, or directory + filename)
+ // and one N_OSO symbol. The module is terminated by an empty N_SO symbol.
+ for nlist in self.symbols {
+ let n_type = nlist.n_type();
+ if n_type & macho::N_STAB == 0 {
+ continue;
+ }
+ // TODO: includes variables too (N_GSYM, N_STSYM). These may need to get their
+ // address from regular symbols though.
+ match n_type {
+ macho::N_SO => {
+ object = None;
+ }
+ macho::N_OSO => {
+ object = None;
+ if let Ok(name) = nlist.name(endian, self.strings) {
+ if !name.is_empty() {
+ object = Some(objects.len());
+ objects.push(name);
+ }
+ }
+ }
+ macho::N_FUN => {
+ if let Ok(name) = nlist.name(endian, self.strings) {
+ if !name.is_empty() {
+ current_function = Some((name, nlist.n_value(endian).into()))
+ } else if let Some((name, address)) = current_function.take() {
+ if let Some(object) = object {
+ symbols.push(ObjectMapEntry {
+ address,
+ size: nlist.n_value(endian).into(),
+ name,
+ object,
+ });
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ ObjectMap {
+ symbols: SymbolMap::new(symbols),
+ objects,
+ }
+ }
+}
+
+/// An iterator over the symbols of a `MachOFile32`.
+pub type MachOSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSymbolTable<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// An iterator over the symbols of a `MachOFile64`.
+pub type MachOSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSymbolTable<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// A symbol table of a `MachOFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct MachOSymbolTable<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file MachOFile<'data, Mach, R>,
+}
+
+impl<'data, 'file, Mach, R> read::private::Sealed for MachOSymbolTable<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Mach, R> ObjectSymbolTable<'data> for MachOSymbolTable<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type Symbol = MachOSymbol<'data, 'file, Mach, R>;
+ type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach, R>;
+
+ fn symbols(&self) -> Self::SymbolIterator {
+ MachOSymbolIterator {
+ file: self.file,
+ index: 0,
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> {
+ let nlist = self.file.symbols.symbol(index.0)?;
+ MachOSymbol::new(self.file, index, nlist).read_error("Unsupported Mach-O symbol index")
+ }
+}
+
+/// An iterator over the symbols of a `MachOFile32`.
+pub type MachOSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSymbolIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// An iterator over the symbols of a `MachOFile64`.
+pub type MachOSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSymbolIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// An iterator over the symbols of a `MachOFile`.
+pub struct MachOSymbolIterator<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file MachOFile<'data, Mach, R>,
+ pub(super) index: usize,
+}
+
+impl<'data, 'file, Mach, R> fmt::Debug for MachOSymbolIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MachOSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file, Mach, R> Iterator for MachOSymbolIterator<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ type Item = MachOSymbol<'data, 'file, Mach, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ let index = self.index;
+ let nlist = self.file.symbols.symbols.get(index)?;
+ self.index += 1;
+ if let Some(symbol) = MachOSymbol::new(self.file, SymbolIndex(index), nlist) {
+ return Some(symbol);
+ }
+ }
+ }
+}
+
+/// A symbol of a `MachOFile32`.
+pub type MachOSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSymbol<'data, 'file, macho::MachHeader32<Endian>, R>;
+/// A symbol of a `MachOFile64`.
+pub type MachOSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ MachOSymbol<'data, 'file, macho::MachHeader64<Endian>, R>;
+
+/// A symbol of a `MachOFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct MachOSymbol<'data, 'file, Mach, R = &'data [u8]>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ file: &'file MachOFile<'data, Mach, R>,
+ index: SymbolIndex,
+ nlist: &'data Mach::Nlist,
+}
+
+impl<'data, 'file, Mach, R> MachOSymbol<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) fn new(
+ file: &'file MachOFile<'data, Mach, R>,
+ index: SymbolIndex,
+ nlist: &'data Mach::Nlist,
+ ) -> Option<Self> {
+ if nlist.n_type() & macho::N_STAB != 0 {
+ return None;
+ }
+ Some(MachOSymbol { file, index, nlist })
+ }
+}
+
+impl<'data, 'file, Mach, R> read::private::Sealed for MachOSymbol<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Mach, R> ObjectSymbol<'data> for MachOSymbol<'data, 'file, Mach, R>
+where
+ Mach: MachHeader,
+ R: ReadRef<'data>,
+{
+ #[inline]
+ fn index(&self) -> SymbolIndex {
+ self.index
+ }
+
+ fn name_bytes(&self) -> Result<&'data [u8]> {
+ self.nlist.name(self.file.endian, self.file.symbols.strings)
+ }
+
+ fn name(&self) -> Result<&'data str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 Mach-O symbol name")
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.nlist.n_value(self.file.endian).into()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ 0
+ }
+
+ fn kind(&self) -> SymbolKind {
+ self.section()
+ .index()
+ .and_then(|index| self.file.section_internal(index).ok())
+ .map(|section| match section.kind {
+ SectionKind::Text => SymbolKind::Text,
+ SectionKind::Data
+ | SectionKind::ReadOnlyData
+ | SectionKind::ReadOnlyString
+ | SectionKind::UninitializedData
+ | SectionKind::Common => SymbolKind::Data,
+ SectionKind::Tls | SectionKind::UninitializedTls | SectionKind::TlsVariables => {
+ SymbolKind::Tls
+ }
+ _ => SymbolKind::Unknown,
+ })
+ .unwrap_or(SymbolKind::Unknown)
+ }
+
+ fn section(&self) -> SymbolSection {
+ match self.nlist.n_type() & macho::N_TYPE {
+ macho::N_UNDF => SymbolSection::Undefined,
+ macho::N_ABS => SymbolSection::Absolute,
+ macho::N_SECT => {
+ let n_sect = self.nlist.n_sect();
+ if n_sect != 0 {
+ SymbolSection::Section(SectionIndex(n_sect as usize))
+ } else {
+ SymbolSection::Unknown
+ }
+ }
+ _ => SymbolSection::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ self.nlist.n_type() & macho::N_TYPE == macho::N_UNDF
+ }
+
+ #[inline]
+ fn is_definition(&self) -> bool {
+ self.nlist.is_definition()
+ }
+
+ #[inline]
+ fn is_common(&self) -> bool {
+ // Mach-O common symbols are based on section, not symbol
+ false
+ }
+
+ #[inline]
+ fn is_weak(&self) -> bool {
+ self.nlist.n_desc(self.file.endian) & (macho::N_WEAK_REF | macho::N_WEAK_DEF) != 0
+ }
+
+ fn scope(&self) -> SymbolScope {
+ let n_type = self.nlist.n_type();
+ if n_type & macho::N_TYPE == macho::N_UNDF {
+ SymbolScope::Unknown
+ } else if n_type & macho::N_EXT == 0 {
+ SymbolScope::Compilation
+ } else if n_type & macho::N_PEXT != 0 {
+ SymbolScope::Linkage
+ } else {
+ SymbolScope::Dynamic
+ }
+ }
+
+ #[inline]
+ fn is_global(&self) -> bool {
+ self.scope() != SymbolScope::Compilation
+ }
+
+ #[inline]
+ fn is_local(&self) -> bool {
+ self.scope() == SymbolScope::Compilation
+ }
+
+ #[inline]
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
+ let n_desc = self.nlist.n_desc(self.file.endian);
+ SymbolFlags::MachO { n_desc }
+ }
+}
+
+/// A trait for generic access to `Nlist32` and `Nlist64`.
+#[allow(missing_docs)]
+pub trait Nlist: Debug + Pod {
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn n_strx(&self, endian: Self::Endian) -> u32;
+ fn n_type(&self) -> u8;
+ fn n_sect(&self) -> u8;
+ fn n_desc(&self, endian: Self::Endian) -> u16;
+ fn n_value(&self, endian: Self::Endian) -> Self::Word;
+
+ fn name<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ strings
+ .get(self.n_strx(endian))
+ .read_error("Invalid Mach-O symbol name offset")
+ }
+
+ /// Return true if this is a STAB symbol.
+ ///
+ /// This determines the meaning of the `n_type` field.
+ fn is_stab(&self) -> bool {
+ self.n_type() & macho::N_STAB != 0
+ }
+
+ /// Return true if this is an undefined symbol.
+ fn is_undefined(&self) -> bool {
+ let n_type = self.n_type();
+ n_type & macho::N_STAB == 0 && n_type & macho::N_TYPE == macho::N_UNDF
+ }
+
+ /// Return true if the symbol is a definition of a function or data object.
+ fn is_definition(&self) -> bool {
+ let n_type = self.n_type();
+ n_type & macho::N_STAB == 0 && n_type & macho::N_TYPE != macho::N_UNDF
+ }
+
+ /// Return the library ordinal.
+ ///
+ /// This is either a 1-based index into the dylib load commands,
+ /// or a special ordinal.
+ #[inline]
+ fn library_ordinal(&self, endian: Self::Endian) -> u8 {
+ (self.n_desc(endian) >> 8) as u8
+ }
+}
+
+impl<Endian: endian::Endian> Nlist for macho::Nlist32<Endian> {
+ type Word = u32;
+ type Endian = Endian;
+
+ fn n_strx(&self, endian: Self::Endian) -> u32 {
+ self.n_strx.get(endian)
+ }
+ fn n_type(&self) -> u8 {
+ self.n_type
+ }
+ fn n_sect(&self) -> u8 {
+ self.n_sect
+ }
+ fn n_desc(&self, endian: Self::Endian) -> u16 {
+ self.n_desc.get(endian)
+ }
+ fn n_value(&self, endian: Self::Endian) -> Self::Word {
+ self.n_value.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> Nlist for macho::Nlist64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+
+ fn n_strx(&self, endian: Self::Endian) -> u32 {
+ self.n_strx.get(endian)
+ }
+ fn n_type(&self) -> u8 {
+ self.n_type
+ }
+ fn n_sect(&self) -> u8 {
+ self.n_sect
+ }
+ fn n_desc(&self, endian: Self::Endian) -> u16 {
+ self.n_desc.get(endian)
+ }
+ fn n_value(&self, endian: Self::Endian) -> Self::Word {
+ self.n_value.get(endian)
+ }
+}
diff --git a/third_party/rust/object/src/read/mod.rs b/third_party/rust/object/src/read/mod.rs
new file mode 100644
index 0000000000..8230d43ba5
--- /dev/null
+++ b/third_party/rust/object/src/read/mod.rs
@@ -0,0 +1,767 @@
+//! Interface for reading object files.
+
+use alloc::borrow::Cow;
+use alloc::vec::Vec;
+use core::{fmt, result};
+
+use crate::common::*;
+
+mod read_ref;
+pub use read_ref::*;
+
+#[cfg(feature = "std")]
+mod read_cache;
+#[cfg(feature = "std")]
+pub use read_cache::*;
+
+mod util;
+pub use util::*;
+
+#[cfg(any(
+ feature = "coff",
+ feature = "elf",
+ feature = "macho",
+ feature = "pe",
+ feature = "wasm",
+ feature = "xcoff"
+))]
+mod any;
+#[cfg(any(
+ feature = "coff",
+ feature = "elf",
+ feature = "macho",
+ feature = "pe",
+ feature = "wasm",
+ feature = "xcoff"
+))]
+pub use any::*;
+
+#[cfg(feature = "archive")]
+pub mod archive;
+
+#[cfg(feature = "coff")]
+pub mod coff;
+
+#[cfg(feature = "elf")]
+pub mod elf;
+
+#[cfg(feature = "macho")]
+pub mod macho;
+
+#[cfg(feature = "pe")]
+pub mod pe;
+
+#[cfg(feature = "wasm")]
+pub mod wasm;
+
+#[cfg(feature = "xcoff")]
+pub mod xcoff;
+
+mod traits;
+pub use traits::*;
+
+mod private {
+ pub trait Sealed {}
+}
+
+/// The error type used within the read module.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Error(&'static str);
+
+impl fmt::Display for Error {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Error {}
+
+/// The result type used within the read module.
+pub type Result<T> = result::Result<T, Error>;
+
+trait ReadError<T> {
+ fn read_error(self, error: &'static str) -> Result<T>;
+}
+
+impl<T> ReadError<T> for result::Result<T, ()> {
+ fn read_error(self, error: &'static str) -> Result<T> {
+ self.map_err(|()| Error(error))
+ }
+}
+
+impl<T> ReadError<T> for result::Result<T, Error> {
+ fn read_error(self, error: &'static str) -> Result<T> {
+ self.map_err(|_| Error(error))
+ }
+}
+
+impl<T> ReadError<T> for Option<T> {
+ fn read_error(self, error: &'static str) -> Result<T> {
+ self.ok_or(Error(error))
+ }
+}
+
+/// The native executable file for the target platform.
+#[cfg(all(
+ unix,
+ not(target_os = "macos"),
+ target_pointer_width = "32",
+ feature = "elf"
+))]
+pub type NativeFile<'data, R = &'data [u8]> = elf::ElfFile32<'data, crate::Endianness, R>;
+
+/// The native executable file for the target platform.
+#[cfg(all(
+ unix,
+ not(target_os = "macos"),
+ target_pointer_width = "64",
+ feature = "elf"
+))]
+pub type NativeFile<'data, R = &'data [u8]> = elf::ElfFile64<'data, crate::Endianness, R>;
+
+/// The native executable file for the target platform.
+#[cfg(all(target_os = "macos", target_pointer_width = "32", feature = "macho"))]
+pub type NativeFile<'data, R = &'data [u8]> = macho::MachOFile32<'data, crate::Endianness, R>;
+
+/// The native executable file for the target platform.
+#[cfg(all(target_os = "macos", target_pointer_width = "64", feature = "macho"))]
+pub type NativeFile<'data, R = &'data [u8]> = macho::MachOFile64<'data, crate::Endianness, R>;
+
+/// The native executable file for the target platform.
+#[cfg(all(target_os = "windows", target_pointer_width = "32", feature = "pe"))]
+pub type NativeFile<'data, R = &'data [u8]> = pe::PeFile32<'data, R>;
+
+/// The native executable file for the target platform.
+#[cfg(all(target_os = "windows", target_pointer_width = "64", feature = "pe"))]
+pub type NativeFile<'data, R = &'data [u8]> = pe::PeFile64<'data, R>;
+
+/// The native executable file for the target platform.
+#[cfg(all(feature = "wasm", target_arch = "wasm32", feature = "wasm"))]
+pub type NativeFile<'data, R = &'data [u8]> = wasm::WasmFile<'data, R>;
+
+/// A file format kind.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum FileKind {
+ /// A Unix archive.
+ #[cfg(feature = "archive")]
+ Archive,
+ /// A COFF object file.
+ #[cfg(feature = "coff")]
+ Coff,
+ /// A COFF bigobj object file.
+ ///
+ /// This supports a larger number of sections.
+ #[cfg(feature = "coff")]
+ CoffBig,
+ /// A Windows short import file.
+ #[cfg(feature = "coff")]
+ CoffImport,
+ /// A dyld cache file containing Mach-O images.
+ #[cfg(feature = "macho")]
+ DyldCache,
+ /// A 32-bit ELF file.
+ #[cfg(feature = "elf")]
+ Elf32,
+ /// A 64-bit ELF file.
+ #[cfg(feature = "elf")]
+ Elf64,
+ /// A 32-bit Mach-O file.
+ #[cfg(feature = "macho")]
+ MachO32,
+ /// A 64-bit Mach-O file.
+ #[cfg(feature = "macho")]
+ MachO64,
+ /// A 32-bit Mach-O fat binary.
+ #[cfg(feature = "macho")]
+ MachOFat32,
+ /// A 64-bit Mach-O fat binary.
+ #[cfg(feature = "macho")]
+ MachOFat64,
+ /// A 32-bit PE file.
+ #[cfg(feature = "pe")]
+ Pe32,
+ /// A 64-bit PE file.
+ #[cfg(feature = "pe")]
+ Pe64,
+ /// A Wasm file.
+ #[cfg(feature = "wasm")]
+ Wasm,
+ /// A 32-bit XCOFF file.
+ #[cfg(feature = "xcoff")]
+ Xcoff32,
+ /// A 64-bit XCOFF file.
+ #[cfg(feature = "xcoff")]
+ Xcoff64,
+}
+
+impl FileKind {
+ /// Determine a file kind by parsing the start of the file.
+ pub fn parse<'data, R: ReadRef<'data>>(data: R) -> Result<FileKind> {
+ Self::parse_at(data, 0)
+ }
+
+ /// Determine a file kind by parsing at the given offset.
+ pub fn parse_at<'data, R: ReadRef<'data>>(data: R, offset: u64) -> Result<FileKind> {
+ let magic = data
+ .read_bytes_at(offset, 16)
+ .read_error("Could not read file magic")?;
+ if magic.len() < 16 {
+ return Err(Error("File too short"));
+ }
+
+ let kind = match [magic[0], magic[1], magic[2], magic[3], magic[4], magic[5], magic[6], magic[7]] {
+ #[cfg(feature = "archive")]
+ [b'!', b'<', b'a', b'r', b'c', b'h', b'>', b'\n'] => FileKind::Archive,
+ #[cfg(feature = "macho")]
+ [b'd', b'y', b'l', b'd', b'_', b'v', b'1', b' '] => FileKind::DyldCache,
+ #[cfg(feature = "elf")]
+ [0x7f, b'E', b'L', b'F', 1, ..] => FileKind::Elf32,
+ #[cfg(feature = "elf")]
+ [0x7f, b'E', b'L', b'F', 2, ..] => FileKind::Elf64,
+ #[cfg(feature = "macho")]
+ [0xfe, 0xed, 0xfa, 0xce, ..]
+ | [0xce, 0xfa, 0xed, 0xfe, ..] => FileKind::MachO32,
+ #[cfg(feature = "macho")]
+ | [0xfe, 0xed, 0xfa, 0xcf, ..]
+ | [0xcf, 0xfa, 0xed, 0xfe, ..] => FileKind::MachO64,
+ #[cfg(feature = "macho")]
+ [0xca, 0xfe, 0xba, 0xbe, ..] => FileKind::MachOFat32,
+ #[cfg(feature = "macho")]
+ [0xca, 0xfe, 0xba, 0xbf, ..] => FileKind::MachOFat64,
+ #[cfg(feature = "wasm")]
+ [0x00, b'a', b's', b'm', ..] => FileKind::Wasm,
+ #[cfg(feature = "pe")]
+ [b'M', b'Z', ..] if offset == 0 => {
+ // offset == 0 restriction is because optional_header_magic only looks at offset 0
+ match pe::optional_header_magic(data) {
+ Ok(crate::pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC) => {
+ FileKind::Pe32
+ }
+ Ok(crate::pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC) => {
+ FileKind::Pe64
+ }
+ _ => return Err(Error("Unknown MS-DOS file")),
+ }
+ }
+ // TODO: more COFF machines
+ #[cfg(feature = "coff")]
+ // COFF arm
+ [0xc4, 0x01, ..]
+ // COFF arm64
+ | [0x64, 0xaa, ..]
+ // COFF x86
+ | [0x4c, 0x01, ..]
+ // COFF x86-64
+ | [0x64, 0x86, ..] => FileKind::Coff,
+ #[cfg(feature = "coff")]
+ [0x00, 0x00, 0xff, 0xff, 0x00, 0x00, ..] => FileKind::CoffImport,
+ #[cfg(feature = "coff")]
+ [0x00, 0x00, 0xff, 0xff, 0x02, 0x00, ..] if offset == 0 => {
+ // offset == 0 restriction is because anon_object_class_id only looks at offset 0
+ match coff::anon_object_class_id(data) {
+ Ok(crate::pe::ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID) => FileKind::CoffBig,
+ _ => return Err(Error("Unknown anon object file")),
+ }
+ }
+ #[cfg(feature = "xcoff")]
+ [0x01, 0xdf, ..] => FileKind::Xcoff32,
+ #[cfg(feature = "xcoff")]
+ [0x01, 0xf7, ..] => FileKind::Xcoff64,
+ _ => return Err(Error("Unknown file magic")),
+ };
+ Ok(kind)
+ }
+}
+
+/// An object kind.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum ObjectKind {
+ /// The object kind is unknown.
+ Unknown,
+ /// Relocatable object.
+ Relocatable,
+ /// Executable.
+ Executable,
+ /// Dynamic shared object.
+ Dynamic,
+ /// Core.
+ Core,
+}
+
+/// The index used to identify a section of a file.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SectionIndex(pub usize);
+
+/// The index used to identify a symbol of a file.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SymbolIndex(pub usize);
+
+/// The section where a symbol is defined.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SymbolSection {
+ /// The section is unknown.
+ Unknown,
+ /// The section is not applicable for this symbol (such as file symbols).
+ None,
+ /// The symbol is undefined.
+ Undefined,
+ /// The symbol has an absolute value.
+ Absolute,
+ /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
+ Common,
+ /// The symbol is defined in the given section.
+ Section(SectionIndex),
+}
+
+impl SymbolSection {
+ /// Returns the section index for the section where the symbol is defined.
+ ///
+ /// May return `None` if the symbol is not defined in a section.
+ #[inline]
+ pub fn index(self) -> Option<SectionIndex> {
+ if let SymbolSection::Section(index) = self {
+ Some(index)
+ } else {
+ None
+ }
+ }
+}
+
+/// An entry in a `SymbolMap`.
+pub trait SymbolMapEntry {
+ /// The symbol address.
+ fn address(&self) -> u64;
+}
+
+/// A map from addresses to symbols.
+#[derive(Debug, Default, Clone)]
+pub struct SymbolMap<T: SymbolMapEntry> {
+ symbols: Vec<T>,
+}
+
+impl<T: SymbolMapEntry> SymbolMap<T> {
+ /// Construct a new symbol map.
+ ///
+ /// This function will sort the symbols by address.
+ pub fn new(mut symbols: Vec<T>) -> Self {
+ symbols.sort_unstable_by_key(|s| s.address());
+ SymbolMap { symbols }
+ }
+
+ /// Get the symbol before the given address.
+ pub fn get(&self, address: u64) -> Option<&T> {
+ let index = match self
+ .symbols
+ .binary_search_by_key(&address, |symbol| symbol.address())
+ {
+ Ok(index) => index,
+ Err(index) => index.checked_sub(1)?,
+ };
+ self.symbols.get(index)
+ }
+
+ /// Get all symbols in the map.
+ #[inline]
+ pub fn symbols(&self) -> &[T] {
+ &self.symbols
+ }
+}
+
+/// A `SymbolMap` entry for symbol names.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SymbolMapName<'data> {
+ address: u64,
+ name: &'data str,
+}
+
+impl<'data> SymbolMapName<'data> {
+ /// Construct a `SymbolMapName`.
+ pub fn new(address: u64, name: &'data str) -> Self {
+ SymbolMapName { address, name }
+ }
+
+ /// The symbol address.
+ #[inline]
+ pub fn address(&self) -> u64 {
+ self.address
+ }
+
+ /// The symbol name.
+ #[inline]
+ pub fn name(&self) -> &'data str {
+ self.name
+ }
+}
+
+impl<'data> SymbolMapEntry for SymbolMapName<'data> {
+ #[inline]
+ fn address(&self) -> u64 {
+ self.address
+ }
+}
+
+/// A map from addresses to symbol names and object files.
+///
+/// This is derived from STAB entries in Mach-O files.
+#[derive(Debug, Default, Clone)]
+pub struct ObjectMap<'data> {
+ symbols: SymbolMap<ObjectMapEntry<'data>>,
+ objects: Vec<&'data [u8]>,
+}
+
+impl<'data> ObjectMap<'data> {
+ /// Get the entry containing the given address.
+ pub fn get(&self, address: u64) -> Option<&ObjectMapEntry<'data>> {
+ self.symbols
+ .get(address)
+ .filter(|entry| entry.size == 0 || address.wrapping_sub(entry.address) < entry.size)
+ }
+
+ /// Get all symbols in the map.
+ #[inline]
+ pub fn symbols(&self) -> &[ObjectMapEntry<'data>] {
+ self.symbols.symbols()
+ }
+
+ /// Get all objects in the map.
+ #[inline]
+ pub fn objects(&self) -> &[&'data [u8]] {
+ &self.objects
+ }
+}
+
+/// A `ObjectMap` entry.
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ObjectMapEntry<'data> {
+ address: u64,
+ size: u64,
+ name: &'data [u8],
+ object: usize,
+}
+
+impl<'data> ObjectMapEntry<'data> {
+ /// Get the symbol address.
+ #[inline]
+ pub fn address(&self) -> u64 {
+ self.address
+ }
+
+ /// Get the symbol size.
+ ///
+ /// This may be 0 if the size is unknown.
+ #[inline]
+ pub fn size(&self) -> u64 {
+ self.size
+ }
+
+ /// Get the symbol name.
+ #[inline]
+ pub fn name(&self) -> &'data [u8] {
+ self.name
+ }
+
+ /// Get the index of the object file name.
+ #[inline]
+ pub fn object_index(&self) -> usize {
+ self.object
+ }
+
+ /// Get the object file name.
+ #[inline]
+ pub fn object(&self, map: &ObjectMap<'data>) -> &'data [u8] {
+ map.objects[self.object]
+ }
+}
+
+impl<'data> SymbolMapEntry for ObjectMapEntry<'data> {
+ #[inline]
+ fn address(&self) -> u64 {
+ self.address
+ }
+}
+
+/// An imported symbol.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Import<'data> {
+ library: ByteString<'data>,
+ // TODO: or ordinal
+ name: ByteString<'data>,
+}
+
+impl<'data> Import<'data> {
+ /// The symbol name.
+ #[inline]
+ pub fn name(&self) -> &'data [u8] {
+ self.name.0
+ }
+
+ /// The name of the library to import the symbol from.
+ #[inline]
+ pub fn library(&self) -> &'data [u8] {
+ self.library.0
+ }
+}
+
+/// An exported symbol.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Export<'data> {
+ // TODO: and ordinal?
+ name: ByteString<'data>,
+ address: u64,
+}
+
+impl<'data> Export<'data> {
+ /// The symbol name.
+ #[inline]
+ pub fn name(&self) -> &'data [u8] {
+ self.name.0
+ }
+
+ /// The virtual address of the symbol.
+ #[inline]
+ pub fn address(&self) -> u64 {
+ self.address
+ }
+}
+
+/// PDB Information
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct CodeView<'data> {
+ guid: [u8; 16],
+ path: ByteString<'data>,
+ age: u32,
+}
+
+impl<'data> CodeView<'data> {
+ /// The path to the PDB as stored in CodeView
+ #[inline]
+ pub fn path(&self) -> &'data [u8] {
+ self.path.0
+ }
+
+ /// The age of the PDB
+ #[inline]
+ pub fn age(&self) -> u32 {
+ self.age
+ }
+
+ /// The GUID of the PDB.
+ #[inline]
+ pub fn guid(&self) -> [u8; 16] {
+ self.guid
+ }
+}
+
+/// The target referenced by a relocation.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum RelocationTarget {
+ /// The target is a symbol.
+ Symbol(SymbolIndex),
+ /// The target is a section.
+ Section(SectionIndex),
+ /// The offset is an absolute address.
+ Absolute,
+}
+
+/// A relocation entry.
+#[derive(Debug)]
+pub struct Relocation {
+ kind: RelocationKind,
+ encoding: RelocationEncoding,
+ size: u8,
+ target: RelocationTarget,
+ addend: i64,
+ implicit_addend: bool,
+}
+
+impl Relocation {
+ /// The operation used to calculate the result of the relocation.
+ #[inline]
+ pub fn kind(&self) -> RelocationKind {
+ self.kind
+ }
+
+ /// Information about how the result of the relocation operation is encoded in the place.
+ #[inline]
+ pub fn encoding(&self) -> RelocationEncoding {
+ self.encoding
+ }
+
+ /// The size in bits of the place of the relocation.
+ ///
+ /// If 0, then the size is determined by the relocation kind.
+ #[inline]
+ pub fn size(&self) -> u8 {
+ self.size
+ }
+
+ /// The target of the relocation.
+ #[inline]
+ pub fn target(&self) -> RelocationTarget {
+ self.target
+ }
+
+ /// The addend to use in the relocation calculation.
+ #[inline]
+ pub fn addend(&self) -> i64 {
+ self.addend
+ }
+
+ /// Set the addend to use in the relocation calculation.
+ #[inline]
+ pub fn set_addend(&mut self, addend: i64) {
+ self.addend = addend
+ }
+
+ /// Returns true if there is an implicit addend stored in the data at the offset
+ /// to be relocated.
+ #[inline]
+ pub fn has_implicit_addend(&self) -> bool {
+ self.implicit_addend
+ }
+}
+
+/// A data compression format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum CompressionFormat {
+ /// The data is uncompressed.
+ None,
+ /// The data is compressed, but the compression format is unknown.
+ Unknown,
+ /// ZLIB/DEFLATE.
+ ///
+ /// Used for ELF compression and GNU compressed debug information.
+ Zlib,
+ /// Zstandard.
+ ///
+ /// Used for ELF compression.
+ Zstandard,
+}
+
+/// A range in a file that may be compressed.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CompressedFileRange {
+ /// The data compression format.
+ pub format: CompressionFormat,
+ /// The file offset of the compressed data.
+ pub offset: u64,
+ /// The compressed data size.
+ pub compressed_size: u64,
+ /// The uncompressed data size.
+ pub uncompressed_size: u64,
+}
+
+impl CompressedFileRange {
+ /// Data that is uncompressed.
+ #[inline]
+ pub fn none(range: Option<(u64, u64)>) -> Self {
+ if let Some((offset, size)) = range {
+ CompressedFileRange {
+ format: CompressionFormat::None,
+ offset,
+ compressed_size: size,
+ uncompressed_size: size,
+ }
+ } else {
+ CompressedFileRange {
+ format: CompressionFormat::None,
+ offset: 0,
+ compressed_size: 0,
+ uncompressed_size: 0,
+ }
+ }
+ }
+
+ /// Convert to `CompressedData` by reading from the file.
+ pub fn data<'data, R: ReadRef<'data>>(self, file: R) -> Result<CompressedData<'data>> {
+ let data = file
+ .read_bytes_at(self.offset, self.compressed_size)
+ .read_error("Invalid compressed data size or offset")?;
+ Ok(CompressedData {
+ format: self.format,
+ data,
+ uncompressed_size: self.uncompressed_size,
+ })
+ }
+}
+
+/// Data that may be compressed.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CompressedData<'data> {
+ /// The data compression format.
+ pub format: CompressionFormat,
+ /// The compressed data.
+ pub data: &'data [u8],
+ /// The uncompressed data size.
+ pub uncompressed_size: u64,
+}
+
+impl<'data> CompressedData<'data> {
+ /// Data that is uncompressed.
+ #[inline]
+ pub fn none(data: &'data [u8]) -> Self {
+ CompressedData {
+ format: CompressionFormat::None,
+ data,
+ uncompressed_size: data.len() as u64,
+ }
+ }
+
+ /// Return the uncompressed data.
+ ///
+ /// Returns an error for invalid data or unsupported compression.
+ /// This includes if the data is compressed but the `compression` feature
+ /// for this crate is disabled.
+ pub fn decompress(self) -> Result<Cow<'data, [u8]>> {
+ match self.format {
+ CompressionFormat::None => Ok(Cow::Borrowed(self.data)),
+ #[cfg(feature = "compression")]
+ CompressionFormat::Zlib => {
+ use core::convert::TryInto;
+ let size = self
+ .uncompressed_size
+ .try_into()
+ .ok()
+ .read_error("Uncompressed data size is too large.")?;
+ let mut decompressed = Vec::with_capacity(size);
+ let mut decompress = flate2::Decompress::new(true);
+ decompress
+ .decompress_vec(
+ self.data,
+ &mut decompressed,
+ flate2::FlushDecompress::Finish,
+ )
+ .ok()
+ .read_error("Invalid zlib compressed data")?;
+ Ok(Cow::Owned(decompressed))
+ }
+ #[cfg(feature = "compression")]
+ CompressionFormat::Zstandard => {
+ use core::convert::TryInto;
+ use std::io::Read;
+ let size = self
+ .uncompressed_size
+ .try_into()
+ .ok()
+ .read_error("Uncompressed data size is too large.")?;
+ let mut decompressed = Vec::with_capacity(size);
+ let mut decoder = ruzstd::StreamingDecoder::new(self.data)
+ .ok()
+ .read_error("Invalid zstd compressed data")?;
+ decoder
+ .read_to_end(&mut decompressed)
+ .ok()
+ .read_error("Invalid zstd compressed data")?;
+ Ok(Cow::Owned(decompressed))
+ }
+ _ => Err(Error("Unsupported compressed data.")),
+ }
+ }
+}
diff --git a/third_party/rust/object/src/read/pe/data_directory.rs b/third_party/rust/object/src/read/pe/data_directory.rs
new file mode 100644
index 0000000000..0e10244bf3
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/data_directory.rs
@@ -0,0 +1,211 @@
+use core::slice;
+
+use crate::read::{Error, ReadError, ReadRef, Result};
+use crate::{pe, LittleEndian as LE};
+
+use super::{
+ DelayLoadImportTable, ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectory,
+ SectionTable,
+};
+
+/// The table of data directories in a PE file.
+#[derive(Debug, Clone, Copy)]
+pub struct DataDirectories<'data> {
+ entries: &'data [pe::ImageDataDirectory],
+}
+
+impl<'data> DataDirectories<'data> {
+ /// Parse the data directory table.
+ ///
+ /// `data` must be the remaining optional data following the
+ /// [optional header](pe::ImageOptionalHeader64). `number` must be from the
+ /// [`number_of_rva_and_sizes`](pe::ImageOptionalHeader64::number_of_rva_and_sizes)
+ /// field of the optional header.
+ pub fn parse(data: &'data [u8], number: u32) -> Result<Self> {
+ let entries = data
+ .read_slice_at(0, number as usize)
+ .read_error("Invalid PE number of RVA and sizes")?;
+ Ok(DataDirectories { entries })
+ }
+
+ /// The number of data directories.
+ #[allow(clippy::len_without_is_empty)]
+ pub fn len(&self) -> usize {
+ self.entries.len()
+ }
+
+ /// Iterator over the data directories.
+ pub fn iter(&self) -> slice::Iter<'data, pe::ImageDataDirectory> {
+ self.entries.iter()
+ }
+
+ /// Iterator which gives the directories as well as their index (one of the IMAGE_DIRECTORY_ENTRY_* constants).
+ pub fn enumerate(&self) -> core::iter::Enumerate<slice::Iter<'data, pe::ImageDataDirectory>> {
+ self.entries.iter().enumerate()
+ }
+
+ /// Returns the data directory at the given index.
+ ///
+ /// Index should be one of the `IMAGE_DIRECTORY_ENTRY_*` constants.
+ ///
+ /// Returns `None` if the index is larger than the table size,
+ /// or if the entry at the index has a zero virtual address.
+ pub fn get(&self, index: usize) -> Option<&'data pe::ImageDataDirectory> {
+ self.entries
+ .get(index)
+ .filter(|d| d.virtual_address.get(LE) != 0)
+ }
+
+ /// Returns the unparsed export directory.
+ ///
+ /// `data` must be the entire file data.
+ pub fn export_directory<R: ReadRef<'data>>(
+ &self,
+ data: R,
+ sections: &SectionTable<'data>,
+ ) -> Result<Option<&'data pe::ImageExportDirectory>> {
+ let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_EXPORT) {
+ Some(data_dir) => data_dir,
+ None => return Ok(None),
+ };
+ let export_data = data_dir.data(data, sections)?;
+ ExportTable::parse_directory(export_data).map(Some)
+ }
+
+ /// Returns the partially parsed export directory.
+ ///
+ /// `data` must be the entire file data.
+ pub fn export_table<R: ReadRef<'data>>(
+ &self,
+ data: R,
+ sections: &SectionTable<'data>,
+ ) -> Result<Option<ExportTable<'data>>> {
+ let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_EXPORT) {
+ Some(data_dir) => data_dir,
+ None => return Ok(None),
+ };
+ let export_va = data_dir.virtual_address.get(LE);
+ let export_data = data_dir.data(data, sections)?;
+ ExportTable::parse(export_data, export_va).map(Some)
+ }
+
+ /// Returns the partially parsed import directory.
+ ///
+ /// `data` must be the entire file data.
+ pub fn import_table<R: ReadRef<'data>>(
+ &self,
+ data: R,
+ sections: &SectionTable<'data>,
+ ) -> Result<Option<ImportTable<'data>>> {
+ let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_IMPORT) {
+ Some(data_dir) => data_dir,
+ None => return Ok(None),
+ };
+ let import_va = data_dir.virtual_address.get(LE);
+ let (section_data, section_va) = sections
+ .pe_data_containing(data, import_va)
+ .read_error("Invalid import data dir virtual address")?;
+ Ok(Some(ImportTable::new(section_data, section_va, import_va)))
+ }
+
+ /// Returns the partially parsed delay-load import directory.
+ ///
+ /// `data` must be the entire file data.
+ pub fn delay_load_import_table<R: ReadRef<'data>>(
+ &self,
+ data: R,
+ sections: &SectionTable<'data>,
+ ) -> Result<Option<DelayLoadImportTable<'data>>> {
+ let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT) {
+ Some(data_dir) => data_dir,
+ None => return Ok(None),
+ };
+ let import_va = data_dir.virtual_address.get(LE);
+ let (section_data, section_va) = sections
+ .pe_data_containing(data, import_va)
+ .read_error("Invalid import data dir virtual address")?;
+ Ok(Some(DelayLoadImportTable::new(
+ section_data,
+ section_va,
+ import_va,
+ )))
+ }
+
+ /// Returns the blocks in the base relocation directory.
+ ///
+ /// `data` must be the entire file data.
+ pub fn relocation_blocks<R: ReadRef<'data>>(
+ &self,
+ data: R,
+ sections: &SectionTable<'data>,
+ ) -> Result<Option<RelocationBlockIterator<'data>>> {
+ let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_BASERELOC) {
+ Some(data_dir) => data_dir,
+ None => return Ok(None),
+ };
+ let reloc_data = data_dir.data(data, sections)?;
+ Ok(Some(RelocationBlockIterator::new(reloc_data)))
+ }
+
+ /// Returns the resource directory.
+ ///
+ /// `data` must be the entire file data.
+ pub fn resource_directory<R: ReadRef<'data>>(
+ &self,
+ data: R,
+ sections: &SectionTable<'data>,
+ ) -> Result<Option<ResourceDirectory<'data>>> {
+ let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_RESOURCE) {
+ Some(data_dir) => data_dir,
+ None => return Ok(None),
+ };
+ let rsrc_data = data_dir.data(data, sections)?;
+ Ok(Some(ResourceDirectory::new(rsrc_data)))
+ }
+}
+
+impl pe::ImageDataDirectory {
+ /// Return the virtual address range of this directory entry.
+ pub fn address_range(&self) -> (u32, u32) {
+ (self.virtual_address.get(LE), self.size.get(LE))
+ }
+
+ /// Return the file offset and size of this directory entry.
+ ///
+ /// This function has some limitations:
+ /// - It requires that the data is contained in a single section.
+ /// - It uses the size field of the directory entry, which is
+ /// not desirable for all data directories.
+ /// - It uses the `virtual_address` of the directory entry as an address,
+ /// which is not valid for `IMAGE_DIRECTORY_ENTRY_SECURITY`.
+ pub fn file_range(&self, sections: &SectionTable<'_>) -> Result<(u32, u32)> {
+ let (offset, section_size) = sections
+ .pe_file_range_at(self.virtual_address.get(LE))
+ .read_error("Invalid data dir virtual address")?;
+ let size = self.size.get(LE);
+ if size > section_size {
+ return Err(Error("Invalid data dir size"));
+ }
+ Ok((offset, size))
+ }
+
+ /// Get the data referenced by this directory entry.
+ ///
+ /// This function has some limitations:
+ /// - It requires that the data is contained in a single section.
+ /// - It uses the size field of the directory entry, which is
+ /// not desirable for all data directories.
+ /// - It uses the `virtual_address` of the directory entry as an address,
+ /// which is not valid for `IMAGE_DIRECTORY_ENTRY_SECURITY`.
+ pub fn data<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ sections: &SectionTable<'data>,
+ ) -> Result<&'data [u8]> {
+ sections
+ .pe_data_at(data, self.virtual_address.get(LE))
+ .read_error("Invalid data dir virtual address")?
+ .get(..self.size.get(LE) as usize)
+ .read_error("Invalid data dir size")
+ }
+}
diff --git a/third_party/rust/object/src/read/pe/export.rs b/third_party/rust/object/src/read/pe/export.rs
new file mode 100644
index 0000000000..88dc78d50b
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/export.rs
@@ -0,0 +1,331 @@
+use alloc::vec::Vec;
+use core::fmt::Debug;
+
+use crate::read::{ByteString, Bytes, Error, ReadError, ReadRef, Result};
+use crate::{pe, LittleEndian as LE, U16Bytes, U32Bytes};
+
+/// Where an export is pointing to.
+#[derive(Clone, Copy)]
+pub enum ExportTarget<'data> {
+ /// The address of the export, relative to the image base.
+ Address(u32),
+ /// Forwarded to an export ordinal in another DLL.
+ ///
+ /// This gives the name of the DLL, and the ordinal.
+ ForwardByOrdinal(&'data [u8], u32),
+ /// Forwarded to an export name in another DLL.
+ ///
+ /// This gives the name of the DLL, and the export name.
+ ForwardByName(&'data [u8], &'data [u8]),
+}
+
+impl<'data> ExportTarget<'data> {
+ /// Returns true if the target is an address.
+ pub fn is_address(&self) -> bool {
+ match self {
+ ExportTarget::Address(_) => true,
+ _ => false,
+ }
+ }
+
+ /// Returns true if the export is forwarded to another DLL.
+ pub fn is_forward(&self) -> bool {
+ !self.is_address()
+ }
+}
+
+/// An export from a PE file.
+///
+/// There are multiple kinds of PE exports (with or without a name, and local or forwarded).
+#[derive(Clone, Copy)]
+pub struct Export<'data> {
+ /// The ordinal of the export.
+ ///
+ /// These are sequential, starting at a base specified in the DLL.
+ pub ordinal: u32,
+ /// The name of the export, if known.
+ pub name: Option<&'data [u8]>,
+ /// The target of this export.
+ pub target: ExportTarget<'data>,
+}
+
+impl<'a> Debug for Export<'a> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
+ f.debug_struct("Export")
+ .field("ordinal", &self.ordinal)
+ .field("name", &self.name.map(ByteString))
+ .field("target", &self.target)
+ .finish()
+ }
+}
+
+impl<'a> Debug for ExportTarget<'a> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
+ match self {
+ ExportTarget::Address(address) => write!(f, "Address({:#x})", address),
+ ExportTarget::ForwardByOrdinal(library, ordinal) => write!(
+ f,
+ "ForwardByOrdinal({:?}.#{})",
+ ByteString(library),
+ ordinal
+ ),
+ ExportTarget::ForwardByName(library, name) => write!(
+ f,
+ "ForwardByName({:?}.{:?})",
+ ByteString(library),
+ ByteString(name)
+ ),
+ }
+ }
+}
+
+/// A partially parsed PE export table.
+#[derive(Debug, Clone)]
+pub struct ExportTable<'data> {
+ data: Bytes<'data>,
+ virtual_address: u32,
+ directory: &'data pe::ImageExportDirectory,
+ addresses: &'data [U32Bytes<LE>],
+ names: &'data [U32Bytes<LE>],
+ name_ordinals: &'data [U16Bytes<LE>],
+}
+
+impl<'data> ExportTable<'data> {
+ /// Parse the export table given its section data and address.
+ pub fn parse(data: &'data [u8], virtual_address: u32) -> Result<Self> {
+ let directory = Self::parse_directory(data)?;
+ let data = Bytes(data);
+
+ let mut addresses = &[][..];
+ let address_of_functions = directory.address_of_functions.get(LE);
+ if address_of_functions != 0 {
+ addresses = data
+ .read_slice_at::<U32Bytes<_>>(
+ address_of_functions.wrapping_sub(virtual_address) as usize,
+ directory.number_of_functions.get(LE) as usize,
+ )
+ .read_error("Invalid PE export address table")?;
+ }
+
+ let mut names = &[][..];
+ let mut name_ordinals = &[][..];
+ let address_of_names = directory.address_of_names.get(LE);
+ let address_of_name_ordinals = directory.address_of_name_ordinals.get(LE);
+ if address_of_names != 0 {
+ if address_of_name_ordinals == 0 {
+ return Err(Error("Missing PE export ordinal table"));
+ }
+
+ let number = directory.number_of_names.get(LE) as usize;
+ names = data
+ .read_slice_at::<U32Bytes<_>>(
+ address_of_names.wrapping_sub(virtual_address) as usize,
+ number,
+ )
+ .read_error("Invalid PE export name pointer table")?;
+ name_ordinals = data
+ .read_slice_at::<U16Bytes<_>>(
+ address_of_name_ordinals.wrapping_sub(virtual_address) as usize,
+ number,
+ )
+ .read_error("Invalid PE export ordinal table")?;
+ }
+
+ Ok(ExportTable {
+ data,
+ virtual_address,
+ directory,
+ addresses,
+ names,
+ name_ordinals,
+ })
+ }
+
+ /// Parse the export directory given its section data.
+ pub fn parse_directory(data: &'data [u8]) -> Result<&'data pe::ImageExportDirectory> {
+ data.read_at::<pe::ImageExportDirectory>(0)
+ .read_error("Invalid PE export dir size")
+ }
+
+ /// Returns the header of the export table.
+ pub fn directory(&self) -> &'data pe::ImageExportDirectory {
+ self.directory
+ }
+
+ /// Returns the base value of ordinals.
+ ///
+ /// Adding this to an address index will give an ordinal.
+ pub fn ordinal_base(&self) -> u32 {
+ self.directory.base.get(LE)
+ }
+
+ /// Returns the unparsed address table.
+ ///
+ /// An address table entry may be a local address, or the address of a forwarded export entry.
+ /// See [`Self::is_forward`] and [`Self::target_from_address`].
+ pub fn addresses(&self) -> &'data [U32Bytes<LE>] {
+ self.addresses
+ }
+
+ /// Returns the unparsed name pointer table.
+ ///
+ /// A name pointer table entry can be used with [`Self::name_from_pointer`].
+ pub fn name_pointers(&self) -> &'data [U32Bytes<LE>] {
+ self.names
+ }
+
+ /// Returns the unparsed ordinal table.
+ ///
+ /// An ordinal table entry is a 0-based index into the address table.
+ /// See [`Self::address_by_index`] and [`Self::target_by_index`].
+ pub fn name_ordinals(&self) -> &'data [U16Bytes<LE>] {
+ self.name_ordinals
+ }
+
+ /// Returns an iterator for the entries in the name pointer table and ordinal table.
+ ///
+ /// A name pointer table entry can be used with [`Self::name_from_pointer`].
+ ///
+ /// An ordinal table entry is a 0-based index into the address table.
+ /// See [`Self::address_by_index`] and [`Self::target_by_index`].
+ pub fn name_iter(&self) -> impl Iterator<Item = (u32, u16)> + 'data {
+ self.names
+ .iter()
+ .map(|x| x.get(LE))
+ .zip(self.name_ordinals.iter().map(|x| x.get(LE)))
+ }
+
+ /// Returns the export address table entry at the given address index.
+ ///
+ /// This may be a local address, or the address of a forwarded export entry.
+ /// See [`Self::is_forward`] and [`Self::target_from_address`].
+ ///
+ /// `index` is a 0-based index into the export address table.
+ pub fn address_by_index(&self, index: u32) -> Result<u32> {
+ Ok(self
+ .addresses
+ .get(index as usize)
+ .read_error("Invalid PE export address index")?
+ .get(LE))
+ }
+
+ /// Returns the export address table entry at the given ordinal.
+ ///
+ /// This may be a local address, or the address of a forwarded export entry.
+ /// See [`Self::is_forward`] and [`Self::target_from_address`].
+ pub fn address_by_ordinal(&self, ordinal: u32) -> Result<u32> {
+ self.address_by_index(ordinal.wrapping_sub(self.ordinal_base()))
+ }
+
+ /// Returns the target of the export at the given address index.
+ ///
+ /// `index` is a 0-based index into the export address table.
+ pub fn target_by_index(&self, index: u32) -> Result<ExportTarget<'data>> {
+ self.target_from_address(self.address_by_index(index)?)
+ }
+
+ /// Returns the target of the export at the given ordinal.
+ pub fn target_by_ordinal(&self, ordinal: u32) -> Result<ExportTarget<'data>> {
+ self.target_from_address(self.address_by_ordinal(ordinal)?)
+ }
+
+ /// Convert an export address table entry into a target.
+ pub fn target_from_address(&self, address: u32) -> Result<ExportTarget<'data>> {
+ Ok(if let Some(forward) = self.forward_string(address)? {
+ let i = forward
+ .iter()
+ .position(|x| *x == b'.')
+ .read_error("Missing PE forwarded export separator")?;
+ let library = &forward[..i];
+ match &forward[i + 1..] {
+ [b'#', digits @ ..] => {
+ let ordinal =
+ parse_ordinal(digits).read_error("Invalid PE forwarded export ordinal")?;
+ ExportTarget::ForwardByOrdinal(library, ordinal)
+ }
+ [] => {
+ return Err(Error("Missing PE forwarded export name"));
+ }
+ name => ExportTarget::ForwardByName(library, name),
+ }
+ } else {
+ ExportTarget::Address(address)
+ })
+ }
+
+ fn forward_offset(&self, address: u32) -> Option<usize> {
+ let offset = address.wrapping_sub(self.virtual_address) as usize;
+ if offset < self.data.len() {
+ Some(offset)
+ } else {
+ None
+ }
+ }
+
+ /// Return true if the export address table entry is a forward.
+ pub fn is_forward(&self, address: u32) -> bool {
+ self.forward_offset(address).is_some()
+ }
+
+ /// Return the forward string if the export address table entry is a forward.
+ pub fn forward_string(&self, address: u32) -> Result<Option<&'data [u8]>> {
+ if let Some(offset) = self.forward_offset(address) {
+ self.data
+ .read_string_at(offset)
+ .read_error("Invalid PE forwarded export address")
+ .map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Convert an export name pointer table entry into a name.
+ pub fn name_from_pointer(&self, name_pointer: u32) -> Result<&'data [u8]> {
+ let offset = name_pointer.wrapping_sub(self.virtual_address);
+ self.data
+ .read_string_at(offset as usize)
+ .read_error("Invalid PE export name pointer")
+ }
+
+ /// Returns the parsed exports in this table.
+ pub fn exports(&self) -> Result<Vec<Export<'data>>> {
+ // First, let's list all exports.
+ let mut exports = Vec::new();
+ let ordinal_base = self.ordinal_base();
+ for (i, address) in self.addresses.iter().enumerate() {
+ // Convert from an array index to an ordinal.
+ let ordinal = ordinal_base.wrapping_add(i as u32);
+ let target = self.target_from_address(address.get(LE))?;
+ exports.push(Export {
+ ordinal,
+ target,
+ // Might be populated later.
+ name: None,
+ });
+ }
+
+ // Now, check whether some (or all) of them have an associated name.
+ // `ordinal_index` is a 0-based index into `addresses`.
+ for (name_pointer, ordinal_index) in self.name_iter() {
+ let name = self.name_from_pointer(name_pointer)?;
+ exports
+ .get_mut(ordinal_index as usize)
+ .read_error("Invalid PE export ordinal")?
+ .name = Some(name);
+ }
+
+ Ok(exports)
+ }
+}
+
+fn parse_ordinal(digits: &[u8]) -> Option<u32> {
+ if digits.is_empty() {
+ return None;
+ }
+ let mut result: u32 = 0;
+ for &c in digits {
+ let x = (c as char).to_digit(10)?;
+ result = result.checked_mul(10)?.checked_add(x)?;
+ }
+ Some(result)
+}
diff --git a/third_party/rust/object/src/read/pe/file.rs b/third_party/rust/object/src/read/pe/file.rs
new file mode 100644
index 0000000000..0f8ce9f259
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/file.rs
@@ -0,0 +1,1029 @@
+use alloc::vec::Vec;
+use core::fmt::Debug;
+use core::{mem, str};
+
+use core::convert::TryInto;
+
+use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable};
+use crate::read::{
+ self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator,
+ Object, ObjectComdat, ObjectKind, ReadError, ReadRef, Result, SectionIndex, SymbolIndex,
+};
+use crate::{pe, ByteString, Bytes, CodeView, LittleEndian as LE, Pod, U32};
+
+use super::{
+ DataDirectories, ExportTable, ImageThunkData, ImportTable, PeSection, PeSectionIterator,
+ PeSegment, PeSegmentIterator, RichHeaderInfo, SectionTable,
+};
+
+/// A PE32 (32-bit) image file.
+pub type PeFile32<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders32, R>;
+/// A PE32+ (64-bit) image file.
+pub type PeFile64<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders64, R>;
+
+/// A PE object file.
+#[derive(Debug)]
+pub struct PeFile<'data, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ pub(super) dos_header: &'data pe::ImageDosHeader,
+ pub(super) nt_headers: &'data Pe,
+ pub(super) data_directories: DataDirectories<'data>,
+ pub(super) common: CoffCommon<'data, R>,
+ pub(super) data: R,
+}
+
+impl<'data, Pe, R> PeFile<'data, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ /// Parse the raw PE file data.
+ pub fn parse(data: R) -> Result<Self> {
+ let dos_header = pe::ImageDosHeader::parse(data)?;
+ let mut offset = dos_header.nt_headers_offset().into();
+ let (nt_headers, data_directories) = Pe::parse(data, &mut offset)?;
+ let sections = nt_headers.sections(data, offset)?;
+ let coff_symbols = nt_headers.symbols(data);
+ let image_base = nt_headers.optional_header().image_base();
+
+ Ok(PeFile {
+ dos_header,
+ nt_headers,
+ data_directories,
+ common: CoffCommon {
+ sections,
+ // The PE file format deprecates the COFF symbol table (https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image)
+ // We do not want to prevent parsing the rest of the PE file for a corrupt COFF header, but rather return an empty symbol table
+ symbols: coff_symbols.unwrap_or_default(),
+ image_base,
+ },
+ data,
+ })
+ }
+
+ /// Returns this binary data.
+ pub fn data(&self) -> R {
+ self.data
+ }
+
+ /// Return the DOS header of this file.
+ pub fn dos_header(&self) -> &'data pe::ImageDosHeader {
+ self.dos_header
+ }
+
+ /// Return the NT Headers of this file.
+ pub fn nt_headers(&self) -> &'data Pe {
+ self.nt_headers
+ }
+
+ /// Returns information about the rich header of this file (if any).
+ pub fn rich_header_info(&self) -> Option<RichHeaderInfo<'_>> {
+ RichHeaderInfo::parse(self.data, self.dos_header.nt_headers_offset().into())
+ }
+
+ /// Returns the section table of this binary.
+ pub fn section_table(&self) -> SectionTable<'data> {
+ self.common.sections
+ }
+
+ /// Returns the data directories of this file.
+ pub fn data_directories(&self) -> DataDirectories<'data> {
+ self.data_directories
+ }
+
+ /// Returns the data directory at the given index.
+ pub fn data_directory(&self, id: usize) -> Option<&'data pe::ImageDataDirectory> {
+ self.data_directories.get(id)
+ }
+
+ /// Returns the export table of this file.
+ ///
+ /// The export table is located using the data directory.
+ pub fn export_table(&self) -> Result<Option<ExportTable<'data>>> {
+ self.data_directories
+ .export_table(self.data, &self.common.sections)
+ }
+
+ /// Returns the import table of this file.
+ ///
+ /// The import table is located using the data directory.
+ pub fn import_table(&self) -> Result<Option<ImportTable<'data>>> {
+ self.data_directories
+ .import_table(self.data, &self.common.sections)
+ }
+
+ pub(super) fn section_alignment(&self) -> u64 {
+ u64::from(self.nt_headers.optional_header().section_alignment())
+ }
+}
+
+impl<'data, Pe, R> read::private::Sealed for PeFile<'data, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Pe, R> Object<'data, 'file> for PeFile<'data, Pe, R>
+where
+ 'data: 'file,
+ Pe: ImageNtHeaders,
+ R: 'file + ReadRef<'data>,
+{
+ type Segment = PeSegment<'data, 'file, Pe, R>;
+ type SegmentIterator = PeSegmentIterator<'data, 'file, Pe, R>;
+ type Section = PeSection<'data, 'file, Pe, R>;
+ type SectionIterator = PeSectionIterator<'data, 'file, Pe, R>;
+ type Comdat = PeComdat<'data, 'file, Pe, R>;
+ type ComdatIterator = PeComdatIterator<'data, 'file, Pe, R>;
+ type Symbol = CoffSymbol<'data, 'file, R>;
+ type SymbolIterator = CoffSymbolIterator<'data, 'file, R>;
+ type SymbolTable = CoffSymbolTable<'data, 'file, R>;
+ type DynamicRelocationIterator = NoDynamicRelocationIterator;
+
+ fn architecture(&self) -> Architecture {
+ match self.nt_headers.file_header().machine.get(LE) {
+ pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm,
+ pe::IMAGE_FILE_MACHINE_ARM64 => Architecture::Aarch64,
+ pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
+ pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
+ _ => Architecture::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ // Only little endian is supported.
+ true
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ self.nt_headers.is_type_64()
+ }
+
+ fn kind(&self) -> ObjectKind {
+ let characteristics = self.nt_headers.file_header().characteristics.get(LE);
+ if characteristics & pe::IMAGE_FILE_DLL != 0 {
+ ObjectKind::Dynamic
+ } else if characteristics & pe::IMAGE_FILE_SYSTEM != 0 {
+ ObjectKind::Unknown
+ } else {
+ ObjectKind::Executable
+ }
+ }
+
+ fn segments(&'file self) -> PeSegmentIterator<'data, 'file, Pe, R> {
+ PeSegmentIterator {
+ file: self,
+ iter: self.common.sections.iter(),
+ }
+ }
+
+ fn section_by_name_bytes(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<PeSection<'data, 'file, Pe, R>> {
+ self.common
+ .sections
+ .section_by_name(self.common.symbols.strings(), section_name)
+ .map(|(index, section)| PeSection {
+ file: self,
+ index: SectionIndex(index),
+ section,
+ })
+ }
+
+ fn section_by_index(
+ &'file self,
+ index: SectionIndex,
+ ) -> Result<PeSection<'data, 'file, Pe, R>> {
+ let section = self.common.sections.section(index.0)?;
+ Ok(PeSection {
+ file: self,
+ index,
+ section,
+ })
+ }
+
+ fn sections(&'file self) -> PeSectionIterator<'data, 'file, Pe, R> {
+ PeSectionIterator {
+ file: self,
+ iter: self.common.sections.iter().enumerate(),
+ }
+ }
+
+ fn comdats(&'file self) -> PeComdatIterator<'data, 'file, Pe, R> {
+ PeComdatIterator { file: self }
+ }
+
+ fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<CoffSymbol<'data, 'file, R>> {
+ let symbol = self.common.symbols.symbol(index.0)?;
+ Ok(CoffSymbol {
+ file: &self.common,
+ index,
+ symbol,
+ })
+ }
+
+ fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> {
+ CoffSymbolIterator {
+ file: &self.common,
+ index: 0,
+ }
+ }
+
+ fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> {
+ Some(CoffSymbolTable { file: &self.common })
+ }
+
+ fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> {
+ CoffSymbolIterator {
+ file: &self.common,
+ // Hack: don't return any.
+ index: self.common.symbols.len(),
+ }
+ }
+
+ fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> {
+ None
+ }
+
+ fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> {
+ None
+ }
+
+ fn imports(&self) -> Result<Vec<Import<'data>>> {
+ let mut imports = Vec::new();
+ if let Some(import_table) = self.import_table()? {
+ let mut import_descs = import_table.descriptors()?;
+ while let Some(import_desc) = import_descs.next()? {
+ let library = import_table.name(import_desc.name.get(LE))?;
+ let mut first_thunk = import_desc.original_first_thunk.get(LE);
+ if first_thunk == 0 {
+ first_thunk = import_desc.first_thunk.get(LE);
+ }
+ let mut thunks = import_table.thunks(first_thunk)?;
+ while let Some(thunk) = thunks.next::<Pe>()? {
+ if !thunk.is_ordinal() {
+ let (_hint, name) = import_table.hint_name(thunk.address())?;
+ imports.push(Import {
+ library: ByteString(library),
+ name: ByteString(name),
+ });
+ }
+ }
+ }
+ }
+ Ok(imports)
+ }
+
+ fn exports(&self) -> Result<Vec<Export<'data>>> {
+ let mut exports = Vec::new();
+ if let Some(export_table) = self.export_table()? {
+ for (name_pointer, address_index) in export_table.name_iter() {
+ let name = export_table.name_from_pointer(name_pointer)?;
+ let address = export_table.address_by_index(address_index.into())?;
+ if !export_table.is_forward(address) {
+ exports.push(Export {
+ name: ByteString(name),
+ address: self.common.image_base.wrapping_add(address.into()),
+ })
+ }
+ }
+ }
+ Ok(exports)
+ }
+
+ fn pdb_info(&self) -> Result<Option<CodeView<'_>>> {
+ let data_dir = match self.data_directory(pe::IMAGE_DIRECTORY_ENTRY_DEBUG) {
+ Some(data_dir) => data_dir,
+ None => return Ok(None),
+ };
+ let debug_data = data_dir.data(self.data, &self.common.sections).map(Bytes)?;
+ let debug_data_size = data_dir.size.get(LE) as usize;
+
+ let count = debug_data_size / mem::size_of::<pe::ImageDebugDirectory>();
+ let rem = debug_data_size % mem::size_of::<pe::ImageDebugDirectory>();
+ if rem != 0 || count < 1 {
+ return Err(Error("Invalid PE debug dir size"));
+ }
+
+ let debug_dirs = debug_data
+ .read_slice_at::<pe::ImageDebugDirectory>(0, count)
+ .read_error("Invalid PE debug dir size")?;
+
+ for debug_dir in debug_dirs {
+ if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW {
+ continue;
+ }
+
+ let info = self
+ .data
+ .read_slice_at::<u8>(
+ debug_dir.pointer_to_raw_data.get(LE) as u64,
+ debug_dir.size_of_data.get(LE) as usize,
+ )
+ .read_error("Invalid CodeView Info address")?;
+
+ let mut info = Bytes(info);
+
+ let sig = info
+ .read_bytes(4)
+ .read_error("Invalid CodeView signature")?;
+ if sig.0 != b"RSDS" {
+ continue;
+ }
+
+ let guid: [u8; 16] = info
+ .read_bytes(16)
+ .read_error("Invalid CodeView GUID")?
+ .0
+ .try_into()
+ .unwrap();
+
+ let age = info.read::<U32<LE>>().read_error("Invalid CodeView Age")?;
+
+ let path = info
+ .read_string()
+ .read_error("Invalid CodeView file path")?;
+
+ return Ok(Some(CodeView {
+ path: ByteString(path),
+ guid,
+ age: age.get(LE),
+ }));
+ }
+ Ok(None)
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ self.section_by_name(".debug_info").is_some()
+ }
+
+ fn relative_address_base(&self) -> u64 {
+ self.common.image_base
+ }
+
+ fn entry(&self) -> u64 {
+ u64::from(self.nt_headers.optional_header().address_of_entry_point())
+ .wrapping_add(self.common.image_base)
+ }
+
+ fn flags(&self) -> FileFlags {
+ FileFlags::Coff {
+ characteristics: self.nt_headers.file_header().characteristics.get(LE),
+ }
+ }
+}
+
+/// An iterator over the COMDAT section groups of a `PeFile32`.
+pub type PeComdatIterator32<'data, 'file, R = &'data [u8]> =
+ PeComdatIterator<'data, 'file, pe::ImageNtHeaders32, R>;
+/// An iterator over the COMDAT section groups of a `PeFile64`.
+pub type PeComdatIterator64<'data, 'file, R = &'data [u8]> =
+ PeComdatIterator<'data, 'file, pe::ImageNtHeaders64, R>;
+
+/// An iterator over the COMDAT section groups of a `PeFile`.
+#[derive(Debug)]
+pub struct PeComdatIterator<'data, 'file, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file PeFile<'data, Pe, R>,
+}
+
+impl<'data, 'file, Pe, R> Iterator for PeComdatIterator<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ type Item = PeComdat<'data, 'file, Pe, R>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A COMDAT section group of a `PeFile32`.
+pub type PeComdat32<'data, 'file, R = &'data [u8]> =
+ PeComdat<'data, 'file, pe::ImageNtHeaders32, R>;
+/// A COMDAT section group of a `PeFile64`.
+pub type PeComdat64<'data, 'file, R = &'data [u8]> =
+ PeComdat<'data, 'file, pe::ImageNtHeaders64, R>;
+
+/// A COMDAT section group of a `PeFile`.
+#[derive(Debug)]
+pub struct PeComdat<'data, 'file, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file PeFile<'data, Pe, R>,
+}
+
+impl<'data, 'file, Pe, R> read::private::Sealed for PeComdat<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Pe, R> ObjectComdat<'data> for PeComdat<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ type SectionIterator = PeComdatSectionIterator<'data, 'file, Pe, R>;
+
+ #[inline]
+ fn kind(&self) -> ComdatKind {
+ unreachable!();
+ }
+
+ #[inline]
+ fn symbol(&self) -> SymbolIndex {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn sections(&self) -> Self::SectionIterator {
+ unreachable!();
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of a `PeFile32`.
+pub type PeComdatSectionIterator32<'data, 'file, R = &'data [u8]> =
+ PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>;
+/// An iterator over the sections in a COMDAT section group of a `PeFile64`.
+pub type PeComdatSectionIterator64<'data, 'file, R = &'data [u8]> =
+ PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;
+
+/// An iterator over the sections in a COMDAT section group of a `PeFile`.
+#[derive(Debug)]
+pub struct PeComdatSectionIterator<'data, 'file, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file PeFile<'data, Pe, R>,
+}
+
+impl<'data, 'file, Pe, R> Iterator for PeComdatSectionIterator<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+impl pe::ImageDosHeader {
+ /// Read the DOS header.
+ ///
+ /// Also checks that the `e_magic` field in the header is valid.
+ pub fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> {
+ // DOS header comes first.
+ let dos_header = data
+ .read_at::<pe::ImageDosHeader>(0)
+ .read_error("Invalid DOS header size or alignment")?;
+ if dos_header.e_magic.get(LE) != pe::IMAGE_DOS_SIGNATURE {
+ return Err(Error("Invalid DOS magic"));
+ }
+ Ok(dos_header)
+ }
+
+ /// Return the file offset of the nt_headers.
+ #[inline]
+ pub fn nt_headers_offset(&self) -> u32 {
+ self.e_lfanew.get(LE)
+ }
+}
+
+/// Find the optional header and read the `optional_header.magic`.
+///
+/// It can be useful to know this magic value before trying to
+/// fully parse the NT headers.
+pub fn optional_header_magic<'data, R: ReadRef<'data>>(data: R) -> Result<u16> {
+ let dos_header = pe::ImageDosHeader::parse(data)?;
+ // NT headers are at an offset specified in the DOS header.
+ let offset = dos_header.nt_headers_offset().into();
+ // It doesn't matter which NT header type is used for the purpose
+ // of reading the optional header magic.
+ let nt_headers = data
+ .read_at::<pe::ImageNtHeaders32>(offset)
+ .read_error("Invalid NT headers offset, size, or alignment")?;
+ if nt_headers.signature() != pe::IMAGE_NT_SIGNATURE {
+ return Err(Error("Invalid PE magic"));
+ }
+ Ok(nt_headers.optional_header().magic())
+}
+
+/// A trait for generic access to `ImageNtHeaders32` and `ImageNtHeaders64`.
+#[allow(missing_docs)]
+pub trait ImageNtHeaders: Debug + Pod {
+ type ImageOptionalHeader: ImageOptionalHeader;
+ type ImageThunkData: ImageThunkData;
+
+ /// Return true if this type is a 64-bit header.
+ ///
+ /// This is a property of the type, not a value in the header data.
+ fn is_type_64(&self) -> bool;
+
+ /// Return true if the magic field in the optional header is valid.
+ fn is_valid_optional_magic(&self) -> bool;
+
+ /// Return the signature
+ fn signature(&self) -> u32;
+
+ /// Return the file header.
+ fn file_header(&self) -> &pe::ImageFileHeader;
+
+ /// Return the optional header.
+ fn optional_header(&self) -> &Self::ImageOptionalHeader;
+
+ // Provided methods.
+
+ /// Read the NT headers, including the data directories.
+ ///
+ /// `data` must be for the entire file.
+ ///
+ /// `offset` must be headers offset, which can be obtained from `ImageDosHeader::nt_headers_offset`.
+ /// It is updated to point after the optional header, which is where the section headers are located.
+ ///
+ /// Also checks that the `signature` and `magic` fields in the headers are valid.
+ fn parse<'data, R: ReadRef<'data>>(
+ data: R,
+ offset: &mut u64,
+ ) -> read::Result<(&'data Self, DataDirectories<'data>)> {
+ // Note that this does not include the data directories in the optional header.
+ let nt_headers = data
+ .read::<Self>(offset)
+ .read_error("Invalid PE headers offset or size")?;
+ if nt_headers.signature() != pe::IMAGE_NT_SIGNATURE {
+ return Err(Error("Invalid PE magic"));
+ }
+ if !nt_headers.is_valid_optional_magic() {
+ return Err(Error("Invalid PE optional header magic"));
+ }
+
+ // Read the rest of the optional header, and then read the data directories from that.
+ let optional_data_size =
+ u64::from(nt_headers.file_header().size_of_optional_header.get(LE))
+ .checked_sub(mem::size_of::<Self::ImageOptionalHeader>() as u64)
+ .read_error("PE optional header size is too small")?;
+ let optional_data = data
+ .read_bytes(offset, optional_data_size)
+ .read_error("Invalid PE optional header size")?;
+ let data_directories = DataDirectories::parse(
+ optional_data,
+ nt_headers.optional_header().number_of_rva_and_sizes(),
+ )?;
+
+ Ok((nt_headers, data_directories))
+ }
+
+ /// Read the section table.
+ ///
+ /// `data` must be for the entire file.
+ /// `offset` must be after the optional file header.
+ #[inline]
+ fn sections<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: u64,
+ ) -> read::Result<SectionTable<'data>> {
+ SectionTable::parse(self.file_header(), data, offset)
+ }
+
+ /// Read the COFF symbol table and string table.
+ ///
+ /// `data` must be the entire file data.
+ #[inline]
+ fn symbols<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<SymbolTable<'data, R>> {
+ SymbolTable::parse(self.file_header(), data)
+ }
+}
+
+/// A trait for generic access to `ImageOptionalHeader32` and `ImageOptionalHeader64`.
+#[allow(missing_docs)]
+pub trait ImageOptionalHeader: Debug + Pod {
+ // Standard fields.
+ fn magic(&self) -> u16;
+ fn major_linker_version(&self) -> u8;
+ fn minor_linker_version(&self) -> u8;
+ fn size_of_code(&self) -> u32;
+ fn size_of_initialized_data(&self) -> u32;
+ fn size_of_uninitialized_data(&self) -> u32;
+ fn address_of_entry_point(&self) -> u32;
+ fn base_of_code(&self) -> u32;
+ fn base_of_data(&self) -> Option<u32>;
+
+ // NT additional fields.
+ fn image_base(&self) -> u64;
+ fn section_alignment(&self) -> u32;
+ fn file_alignment(&self) -> u32;
+ fn major_operating_system_version(&self) -> u16;
+ fn minor_operating_system_version(&self) -> u16;
+ fn major_image_version(&self) -> u16;
+ fn minor_image_version(&self) -> u16;
+ fn major_subsystem_version(&self) -> u16;
+ fn minor_subsystem_version(&self) -> u16;
+ fn win32_version_value(&self) -> u32;
+ fn size_of_image(&self) -> u32;
+ fn size_of_headers(&self) -> u32;
+ fn check_sum(&self) -> u32;
+ fn subsystem(&self) -> u16;
+ fn dll_characteristics(&self) -> u16;
+ fn size_of_stack_reserve(&self) -> u64;
+ fn size_of_stack_commit(&self) -> u64;
+ fn size_of_heap_reserve(&self) -> u64;
+ fn size_of_heap_commit(&self) -> u64;
+ fn loader_flags(&self) -> u32;
+ fn number_of_rva_and_sizes(&self) -> u32;
+}
+
+impl ImageNtHeaders for pe::ImageNtHeaders32 {
+ type ImageOptionalHeader = pe::ImageOptionalHeader32;
+ type ImageThunkData = pe::ImageThunkData32;
+
+ #[inline]
+ fn is_type_64(&self) -> bool {
+ false
+ }
+
+ #[inline]
+ fn is_valid_optional_magic(&self) -> bool {
+ self.optional_header.magic.get(LE) == pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ }
+
+ #[inline]
+ fn signature(&self) -> u32 {
+ self.signature.get(LE)
+ }
+
+ #[inline]
+ fn file_header(&self) -> &pe::ImageFileHeader {
+ &self.file_header
+ }
+
+ #[inline]
+ fn optional_header(&self) -> &Self::ImageOptionalHeader {
+ &self.optional_header
+ }
+}
+
+impl ImageOptionalHeader for pe::ImageOptionalHeader32 {
+ #[inline]
+ fn magic(&self) -> u16 {
+ self.magic.get(LE)
+ }
+
+ #[inline]
+ fn major_linker_version(&self) -> u8 {
+ self.major_linker_version
+ }
+
+ #[inline]
+ fn minor_linker_version(&self) -> u8 {
+ self.minor_linker_version
+ }
+
+ #[inline]
+ fn size_of_code(&self) -> u32 {
+ self.size_of_code.get(LE)
+ }
+
+ #[inline]
+ fn size_of_initialized_data(&self) -> u32 {
+ self.size_of_initialized_data.get(LE)
+ }
+
+ #[inline]
+ fn size_of_uninitialized_data(&self) -> u32 {
+ self.size_of_uninitialized_data.get(LE)
+ }
+
+ #[inline]
+ fn address_of_entry_point(&self) -> u32 {
+ self.address_of_entry_point.get(LE)
+ }
+
+ #[inline]
+ fn base_of_code(&self) -> u32 {
+ self.base_of_code.get(LE)
+ }
+
+ #[inline]
+ fn base_of_data(&self) -> Option<u32> {
+ Some(self.base_of_data.get(LE))
+ }
+
+ #[inline]
+ fn image_base(&self) -> u64 {
+ self.image_base.get(LE).into()
+ }
+
+ #[inline]
+ fn section_alignment(&self) -> u32 {
+ self.section_alignment.get(LE)
+ }
+
+ #[inline]
+ fn file_alignment(&self) -> u32 {
+ self.file_alignment.get(LE)
+ }
+
+ #[inline]
+ fn major_operating_system_version(&self) -> u16 {
+ self.major_operating_system_version.get(LE)
+ }
+
+ #[inline]
+ fn minor_operating_system_version(&self) -> u16 {
+ self.minor_operating_system_version.get(LE)
+ }
+
+ #[inline]
+ fn major_image_version(&self) -> u16 {
+ self.major_image_version.get(LE)
+ }
+
+ #[inline]
+ fn minor_image_version(&self) -> u16 {
+ self.minor_image_version.get(LE)
+ }
+
+ #[inline]
+ fn major_subsystem_version(&self) -> u16 {
+ self.major_subsystem_version.get(LE)
+ }
+
+ #[inline]
+ fn minor_subsystem_version(&self) -> u16 {
+ self.minor_subsystem_version.get(LE)
+ }
+
+ #[inline]
+ fn win32_version_value(&self) -> u32 {
+ self.win32_version_value.get(LE)
+ }
+
+ #[inline]
+ fn size_of_image(&self) -> u32 {
+ self.size_of_image.get(LE)
+ }
+
+ #[inline]
+ fn size_of_headers(&self) -> u32 {
+ self.size_of_headers.get(LE)
+ }
+
+ #[inline]
+ fn check_sum(&self) -> u32 {
+ self.check_sum.get(LE)
+ }
+
+ #[inline]
+ fn subsystem(&self) -> u16 {
+ self.subsystem.get(LE)
+ }
+
+ #[inline]
+ fn dll_characteristics(&self) -> u16 {
+ self.dll_characteristics.get(LE)
+ }
+
+ #[inline]
+ fn size_of_stack_reserve(&self) -> u64 {
+ self.size_of_stack_reserve.get(LE).into()
+ }
+
+ #[inline]
+ fn size_of_stack_commit(&self) -> u64 {
+ self.size_of_stack_commit.get(LE).into()
+ }
+
+ #[inline]
+ fn size_of_heap_reserve(&self) -> u64 {
+ self.size_of_heap_reserve.get(LE).into()
+ }
+
+ #[inline]
+ fn size_of_heap_commit(&self) -> u64 {
+ self.size_of_heap_commit.get(LE).into()
+ }
+
+ #[inline]
+ fn loader_flags(&self) -> u32 {
+ self.loader_flags.get(LE)
+ }
+
+ #[inline]
+ fn number_of_rva_and_sizes(&self) -> u32 {
+ self.number_of_rva_and_sizes.get(LE)
+ }
+}
+
+impl ImageNtHeaders for pe::ImageNtHeaders64 {
+ type ImageOptionalHeader = pe::ImageOptionalHeader64;
+ type ImageThunkData = pe::ImageThunkData64;
+
+ #[inline]
+ fn is_type_64(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn is_valid_optional_magic(&self) -> bool {
+ self.optional_header.magic.get(LE) == pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ }
+
+ #[inline]
+ fn signature(&self) -> u32 {
+ self.signature.get(LE)
+ }
+
+ #[inline]
+ fn file_header(&self) -> &pe::ImageFileHeader {
+ &self.file_header
+ }
+
+ #[inline]
+ fn optional_header(&self) -> &Self::ImageOptionalHeader {
+ &self.optional_header
+ }
+}
+
+impl ImageOptionalHeader for pe::ImageOptionalHeader64 {
+ #[inline]
+ fn magic(&self) -> u16 {
+ self.magic.get(LE)
+ }
+
+ #[inline]
+ fn major_linker_version(&self) -> u8 {
+ self.major_linker_version
+ }
+
+ #[inline]
+ fn minor_linker_version(&self) -> u8 {
+ self.minor_linker_version
+ }
+
+ #[inline]
+ fn size_of_code(&self) -> u32 {
+ self.size_of_code.get(LE)
+ }
+
+ #[inline]
+ fn size_of_initialized_data(&self) -> u32 {
+ self.size_of_initialized_data.get(LE)
+ }
+
+ #[inline]
+ fn size_of_uninitialized_data(&self) -> u32 {
+ self.size_of_uninitialized_data.get(LE)
+ }
+
+ #[inline]
+ fn address_of_entry_point(&self) -> u32 {
+ self.address_of_entry_point.get(LE)
+ }
+
+ #[inline]
+ fn base_of_code(&self) -> u32 {
+ self.base_of_code.get(LE)
+ }
+
+ #[inline]
+ fn base_of_data(&self) -> Option<u32> {
+ None
+ }
+
+ #[inline]
+ fn image_base(&self) -> u64 {
+ self.image_base.get(LE)
+ }
+
+ #[inline]
+ fn section_alignment(&self) -> u32 {
+ self.section_alignment.get(LE)
+ }
+
+ #[inline]
+ fn file_alignment(&self) -> u32 {
+ self.file_alignment.get(LE)
+ }
+
+ #[inline]
+ fn major_operating_system_version(&self) -> u16 {
+ self.major_operating_system_version.get(LE)
+ }
+
+ #[inline]
+ fn minor_operating_system_version(&self) -> u16 {
+ self.minor_operating_system_version.get(LE)
+ }
+
+ #[inline]
+ fn major_image_version(&self) -> u16 {
+ self.major_image_version.get(LE)
+ }
+
+ #[inline]
+ fn minor_image_version(&self) -> u16 {
+ self.minor_image_version.get(LE)
+ }
+
+ #[inline]
+ fn major_subsystem_version(&self) -> u16 {
+ self.major_subsystem_version.get(LE)
+ }
+
+ #[inline]
+ fn minor_subsystem_version(&self) -> u16 {
+ self.minor_subsystem_version.get(LE)
+ }
+
+ #[inline]
+ fn win32_version_value(&self) -> u32 {
+ self.win32_version_value.get(LE)
+ }
+
+ #[inline]
+ fn size_of_image(&self) -> u32 {
+ self.size_of_image.get(LE)
+ }
+
+ #[inline]
+ fn size_of_headers(&self) -> u32 {
+ self.size_of_headers.get(LE)
+ }
+
+ #[inline]
+ fn check_sum(&self) -> u32 {
+ self.check_sum.get(LE)
+ }
+
+ #[inline]
+ fn subsystem(&self) -> u16 {
+ self.subsystem.get(LE)
+ }
+
+ #[inline]
+ fn dll_characteristics(&self) -> u16 {
+ self.dll_characteristics.get(LE)
+ }
+
+ #[inline]
+ fn size_of_stack_reserve(&self) -> u64 {
+ self.size_of_stack_reserve.get(LE)
+ }
+
+ #[inline]
+ fn size_of_stack_commit(&self) -> u64 {
+ self.size_of_stack_commit.get(LE)
+ }
+
+ #[inline]
+ fn size_of_heap_reserve(&self) -> u64 {
+ self.size_of_heap_reserve.get(LE)
+ }
+
+ #[inline]
+ fn size_of_heap_commit(&self) -> u64 {
+ self.size_of_heap_commit.get(LE)
+ }
+
+ #[inline]
+ fn loader_flags(&self) -> u32 {
+ self.loader_flags.get(LE)
+ }
+
+ #[inline]
+ fn number_of_rva_and_sizes(&self) -> u32 {
+ self.number_of_rva_and_sizes.get(LE)
+ }
+}
diff --git a/third_party/rust/object/src/read/pe/import.rs b/third_party/rust/object/src/read/pe/import.rs
new file mode 100644
index 0000000000..a5535dc367
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/import.rs
@@ -0,0 +1,332 @@
+use core::fmt::Debug;
+use core::mem;
+
+use crate::read::{Bytes, ReadError, Result};
+use crate::{pe, LittleEndian as LE, Pod, U16Bytes};
+
+use super::ImageNtHeaders;
+
+/// Information for parsing a PE import table.
+#[derive(Debug, Clone)]
+pub struct ImportTable<'data> {
+ section_data: Bytes<'data>,
+ section_address: u32,
+ import_address: u32,
+}
+
+impl<'data> ImportTable<'data> {
+ /// Create a new import table parser.
+ ///
+ /// The import descriptors start at `import_address`.
+ /// The size declared in the `IMAGE_DIRECTORY_ENTRY_IMPORT` data directory is
+ /// ignored by the Windows loader, and so descriptors will be parsed until a null entry.
+ ///
+ /// `section_data` should be from the section containing `import_address`, and
+ /// `section_address` should be the address of that section. Pointers within the
+ /// descriptors and thunks may point to anywhere within the section data.
+ pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self {
+ ImportTable {
+ section_data: Bytes(section_data),
+ section_address,
+ import_address,
+ }
+ }
+
+ /// Return an iterator for the import descriptors.
+ pub fn descriptors(&self) -> Result<ImportDescriptorIterator<'data>> {
+ let offset = self.import_address.wrapping_sub(self.section_address);
+ let mut data = self.section_data;
+ data.skip(offset as usize)
+ .read_error("Invalid PE import descriptor address")?;
+ Ok(ImportDescriptorIterator { data })
+ }
+
+ /// Return a library name given its address.
+ ///
+ /// This address may be from [`pe::ImageImportDescriptor::name`].
+ pub fn name(&self, address: u32) -> Result<&'data [u8]> {
+ self.section_data
+ .read_string_at(address.wrapping_sub(self.section_address) as usize)
+ .read_error("Invalid PE import descriptor name")
+ }
+
+ /// Return a list of thunks given its address.
+ ///
+ /// This address may be from [`pe::ImageImportDescriptor::original_first_thunk`]
+ /// or [`pe::ImageImportDescriptor::first_thunk`].
+ pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> {
+ let offset = address.wrapping_sub(self.section_address);
+ let mut data = self.section_data;
+ data.skip(offset as usize)
+ .read_error("Invalid PE import thunk table address")?;
+ Ok(ImportThunkList { data })
+ }
+
+ /// Parse a thunk.
+ pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> {
+ if thunk.is_ordinal() {
+ Ok(Import::Ordinal(thunk.ordinal()))
+ } else {
+ let (hint, name) = self.hint_name(thunk.address())?;
+ Ok(Import::Name(hint, name))
+ }
+ }
+
+ /// Return the hint and name at the given address.
+ ///
+ /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
+ ///
+ /// The hint is an index into the export name pointer table in the target library.
+ pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> {
+ let offset = address.wrapping_sub(self.section_address);
+ let mut data = self.section_data;
+ data.skip(offset as usize)
+ .read_error("Invalid PE import thunk address")?;
+ let hint = data
+ .read::<U16Bytes<LE>>()
+ .read_error("Missing PE import thunk hint")?
+ .get(LE);
+ let name = data
+ .read_string()
+ .read_error("Missing PE import thunk name")?;
+ Ok((hint, name))
+ }
+}
+
+/// A fallible iterator for the descriptors in the import data directory.
+#[derive(Debug, Clone)]
+pub struct ImportDescriptorIterator<'data> {
+ data: Bytes<'data>,
+}
+
+impl<'data> ImportDescriptorIterator<'data> {
+ /// Return the next descriptor.
+ ///
+ /// Returns `Ok(None)` when a null descriptor is found.
+ pub fn next(&mut self) -> Result<Option<&'data pe::ImageImportDescriptor>> {
+ let import_desc = self
+ .data
+ .read::<pe::ImageImportDescriptor>()
+ .read_error("Missing PE null import descriptor")?;
+ if import_desc.is_null() {
+ Ok(None)
+ } else {
+ Ok(Some(import_desc))
+ }
+ }
+}
+
+/// A list of import thunks.
+///
+/// These may be in the import lookup table, or the import address table.
+#[derive(Debug, Clone)]
+pub struct ImportThunkList<'data> {
+ data: Bytes<'data>,
+}
+
+impl<'data> ImportThunkList<'data> {
+ /// Get the thunk at the given index.
+ pub fn get<Pe: ImageNtHeaders>(&self, index: usize) -> Result<Pe::ImageThunkData> {
+ let thunk = self
+ .data
+ .read_at(index * mem::size_of::<Pe::ImageThunkData>())
+ .read_error("Invalid PE import thunk index")?;
+ Ok(*thunk)
+ }
+
+ /// Return the first thunk in the list, and update `self` to point after it.
+ ///
+ /// Returns `Ok(None)` when a null thunk is found.
+ pub fn next<Pe: ImageNtHeaders>(&mut self) -> Result<Option<Pe::ImageThunkData>> {
+ let thunk = self
+ .data
+ .read::<Pe::ImageThunkData>()
+ .read_error("Missing PE null import thunk")?;
+ if thunk.address() == 0 {
+ Ok(None)
+ } else {
+ Ok(Some(*thunk))
+ }
+ }
+}
+
+/// A parsed import thunk.
+#[derive(Debug, Clone, Copy)]
+pub enum Import<'data> {
+ /// Import by ordinal.
+ Ordinal(u16),
+ /// Import by name.
+ ///
+ /// Includes a hint for the index into the export name pointer table in the target library.
+ Name(u16, &'data [u8]),
+}
+
+/// A trait for generic access to [`pe::ImageThunkData32`] and [`pe::ImageThunkData64`].
+#[allow(missing_docs)]
+pub trait ImageThunkData: Debug + Pod {
+ /// Return the raw thunk value.
+ fn raw(self) -> u64;
+
+ /// Returns true if the ordinal flag is set.
+ fn is_ordinal(self) -> bool;
+
+ /// Return the ordinal portion of the thunk.
+ ///
+ /// Does not check the ordinal flag.
+ fn ordinal(self) -> u16;
+
+ /// Return the RVA portion of the thunk.
+ ///
+ /// Does not check the ordinal flag.
+ fn address(self) -> u32;
+}
+
+impl ImageThunkData for pe::ImageThunkData64 {
+ fn raw(self) -> u64 {
+ self.0.get(LE)
+ }
+
+ fn is_ordinal(self) -> bool {
+ self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG64 != 0
+ }
+
+ fn ordinal(self) -> u16 {
+ self.0.get(LE) as u16
+ }
+
+ fn address(self) -> u32 {
+ self.0.get(LE) as u32 & 0x7fff_ffff
+ }
+}
+
+impl ImageThunkData for pe::ImageThunkData32 {
+ fn raw(self) -> u64 {
+ self.0.get(LE).into()
+ }
+
+ fn is_ordinal(self) -> bool {
+ self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG32 != 0
+ }
+
+ fn ordinal(self) -> u16 {
+ self.0.get(LE) as u16
+ }
+
+ fn address(self) -> u32 {
+ self.0.get(LE) & 0x7fff_ffff
+ }
+}
+
+/// Information for parsing a PE delay-load import table.
+#[derive(Debug, Clone)]
+pub struct DelayLoadImportTable<'data> {
+ section_data: Bytes<'data>,
+ section_address: u32,
+ import_address: u32,
+}
+
+impl<'data> DelayLoadImportTable<'data> {
+ /// Create a new delay load import table parser.
+ ///
+ /// The import descriptors start at `import_address`.
+ /// This table works in the same way the import table does: descriptors will be
+ /// parsed until a null entry.
+ ///
+ /// `section_data` should be from the section containing `import_address`, and
+ /// `section_address` should be the address of that section. Pointers within the
+ /// descriptors and thunks may point to anywhere within the section data.
+ pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self {
+ DelayLoadImportTable {
+ section_data: Bytes(section_data),
+ section_address,
+ import_address,
+ }
+ }
+
+ /// Return an iterator for the import descriptors.
+ pub fn descriptors(&self) -> Result<DelayLoadDescriptorIterator<'data>> {
+ let offset = self.import_address.wrapping_sub(self.section_address);
+ let mut data = self.section_data;
+ data.skip(offset as usize)
+ .read_error("Invalid PE delay-load import descriptor address")?;
+ Ok(DelayLoadDescriptorIterator { data })
+ }
+
+ /// Return a library name given its address.
+ ///
+ /// This address may be from [`pe::ImageDelayloadDescriptor::dll_name_rva`].
+ pub fn name(&self, address: u32) -> Result<&'data [u8]> {
+ self.section_data
+ .read_string_at(address.wrapping_sub(self.section_address) as usize)
+ .read_error("Invalid PE import descriptor name")
+ }
+
+ /// Return a list of thunks given its address.
+ ///
+ /// This address may be from the INT, i.e. from
+ /// [`pe::ImageDelayloadDescriptor::import_name_table_rva`].
+ ///
+ /// Please note that others RVA values from [`pe::ImageDelayloadDescriptor`] are used
+ /// by the delay loader at runtime to store values, and thus do not point inside the same
+ /// section as the INT. Calling this function on those addresses will fail.
+ pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> {
+ let offset = address.wrapping_sub(self.section_address);
+ let mut data = self.section_data;
+ data.skip(offset as usize)
+ .read_error("Invalid PE delay load import thunk table address")?;
+ Ok(ImportThunkList { data })
+ }
+
+ /// Parse a thunk.
+ pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> {
+ if thunk.is_ordinal() {
+ Ok(Import::Ordinal(thunk.ordinal()))
+ } else {
+ let (hint, name) = self.hint_name(thunk.address())?;
+ Ok(Import::Name(hint, name))
+ }
+ }
+
+ /// Return the hint and name at the given address.
+ ///
+ /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
+ ///
+ /// The hint is an index into the export name pointer table in the target library.
+ pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> {
+ let offset = address.wrapping_sub(self.section_address);
+ let mut data = self.section_data;
+ data.skip(offset as usize)
+ .read_error("Invalid PE delay load import thunk address")?;
+ let hint = data
+ .read::<U16Bytes<LE>>()
+ .read_error("Missing PE delay load import thunk hint")?
+ .get(LE);
+ let name = data
+ .read_string()
+ .read_error("Missing PE delay load import thunk name")?;
+ Ok((hint, name))
+ }
+}
+
+/// A fallible iterator for the descriptors in the delay-load data directory.
+#[derive(Debug, Clone)]
+pub struct DelayLoadDescriptorIterator<'data> {
+ data: Bytes<'data>,
+}
+
+impl<'data> DelayLoadDescriptorIterator<'data> {
+ /// Return the next descriptor.
+ ///
+ /// Returns `Ok(None)` when a null descriptor is found.
+ pub fn next(&mut self) -> Result<Option<&'data pe::ImageDelayloadDescriptor>> {
+ let import_desc = self
+ .data
+ .read::<pe::ImageDelayloadDescriptor>()
+ .read_error("Missing PE null delay-load import descriptor")?;
+ if import_desc.is_null() {
+ Ok(None)
+ } else {
+ Ok(Some(import_desc))
+ }
+ }
+}
diff --git a/third_party/rust/object/src/read/pe/mod.rs b/third_party/rust/object/src/read/pe/mod.rs
new file mode 100644
index 0000000000..2b7cc5d7a0
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/mod.rs
@@ -0,0 +1,34 @@
+//! Support for reading PE files.
+//!
+//! Defines traits to abstract over the difference between PE32/PE32+,
+//! and implements read functionality in terms of these traits.
+//!
+//! This module reuses some of the COFF functionality.
+//!
+//! Also provides `PeFile` and related types which implement the `Object` trait.
+
+mod file;
+pub use file::*;
+
+mod section;
+pub use section::*;
+
+mod data_directory;
+pub use data_directory::*;
+
+mod export;
+pub use export::*;
+
+mod import;
+pub use import::*;
+
+mod relocation;
+pub use relocation::*;
+
+mod resource;
+pub use resource::*;
+
+mod rich;
+pub use rich::*;
+
+pub use super::coff::{SectionTable, SymbolTable};
diff --git a/third_party/rust/object/src/read/pe/relocation.rs b/third_party/rust/object/src/read/pe/relocation.rs
new file mode 100644
index 0000000000..06215bd1a7
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/relocation.rs
@@ -0,0 +1,90 @@
+use core::slice;
+
+use crate::endian::{LittleEndian as LE, U16};
+use crate::pe;
+use crate::read::{Bytes, Error, ReadError, Result};
+
+/// An iterator over the relocation blocks in the `.reloc` section of a PE file.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct RelocationBlockIterator<'data> {
+ data: Bytes<'data>,
+}
+
+impl<'data> RelocationBlockIterator<'data> {
+ /// Construct a new iterator from the data of the `.reloc` section.
+ pub fn new(data: &'data [u8]) -> Self {
+ RelocationBlockIterator { data: Bytes(data) }
+ }
+
+ /// Read the next relocation page.
+ pub fn next(&mut self) -> Result<Option<RelocationIterator<'data>>> {
+ if self.data.is_empty() {
+ return Ok(None);
+ }
+ let header = self
+ .data
+ .read::<pe::ImageBaseRelocation>()
+ .read_error("Invalid PE reloc section size")?;
+ let virtual_address = header.virtual_address.get(LE);
+ let size = header.size_of_block.get(LE);
+ if size <= 8 || size & 3 != 0 {
+ return Err(Error("Invalid PE reloc block size"));
+ }
+ let count = (size - 8) / 2;
+ let relocs = self
+ .data
+ .read_slice::<U16<LE>>(count as usize)
+ .read_error("Invalid PE reloc block size")?
+ .iter();
+ Ok(Some(RelocationIterator {
+ virtual_address,
+ size,
+ relocs,
+ }))
+ }
+}
+
+/// An iterator of the relocations in a block in the `.reloc` section of a PE file.
+#[derive(Debug, Clone)]
+pub struct RelocationIterator<'data> {
+ virtual_address: u32,
+ size: u32,
+ relocs: slice::Iter<'data, U16<LE>>,
+}
+
+impl<'data> RelocationIterator<'data> {
+ /// Return the virtual address of the page that this block of relocations applies to.
+ pub fn virtual_address(&self) -> u32 {
+ self.virtual_address
+ }
+
+ /// Return the size in bytes of this block of relocations.
+ pub fn size(&self) -> u32 {
+ self.size
+ }
+}
+
+impl<'data> Iterator for RelocationIterator<'data> {
+ type Item = Relocation;
+
+ fn next(&mut self) -> Option<Relocation> {
+ loop {
+ let reloc = self.relocs.next()?.get(LE);
+ if reloc != 0 {
+ return Some(Relocation {
+ virtual_address: self.virtual_address.wrapping_add((reloc & 0xfff) as u32),
+ typ: reloc >> 12,
+ });
+ }
+ }
+ }
+}
+
+/// A relocation in the `.reloc` section of a PE file.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct Relocation {
+ /// The virtual address of the relocation.
+ pub virtual_address: u32,
+ /// One of the `pe::IMAGE_REL_BASED_*` constants.
+ pub typ: u16,
+}
diff --git a/third_party/rust/object/src/read/pe/resource.rs b/third_party/rust/object/src/read/pe/resource.rs
new file mode 100644
index 0000000000..646eaefaaa
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/resource.rs
@@ -0,0 +1,207 @@
+use alloc::string::String;
+use core::char;
+
+use crate::read::{ReadError, ReadRef, Result};
+use crate::{pe, LittleEndian as LE, U16Bytes};
+
+/// The `.rsrc` section of a PE file.
+#[derive(Debug, Clone, Copy)]
+pub struct ResourceDirectory<'data> {
+ data: &'data [u8],
+}
+
+impl<'data> ResourceDirectory<'data> {
+ /// Construct from the data of the `.rsrc` section.
+ pub fn new(data: &'data [u8]) -> Self {
+ ResourceDirectory { data }
+ }
+
+ /// Parses the root resource directory.
+ pub fn root(&self) -> Result<ResourceDirectoryTable<'data>> {
+ ResourceDirectoryTable::parse(self.data, 0)
+ }
+}
+
+/// A table of resource entries.
+#[derive(Debug, Clone)]
+pub struct ResourceDirectoryTable<'data> {
+ /// The table header.
+ pub header: &'data pe::ImageResourceDirectory,
+ /// The table entries.
+ pub entries: &'data [pe::ImageResourceDirectoryEntry],
+}
+
+impl<'data> ResourceDirectoryTable<'data> {
+ fn parse(data: &'data [u8], offset: u32) -> Result<Self> {
+ let mut offset = u64::from(offset);
+ let header = data
+ .read::<pe::ImageResourceDirectory>(&mut offset)
+ .read_error("Invalid resource table header")?;
+ let entries_count = header.number_of_id_entries.get(LE) as usize
+ + header.number_of_named_entries.get(LE) as usize;
+ let entries = data
+ .read_slice::<pe::ImageResourceDirectoryEntry>(&mut offset, entries_count)
+ .read_error("Invalid resource table entries")?;
+ Ok(Self { header, entries })
+ }
+}
+
+impl pe::ImageResourceDirectoryEntry {
+ /// Returns true if the entry has a name, rather than an ID.
+ pub fn has_name(&self) -> bool {
+ self.name_or_id.get(LE) & pe::IMAGE_RESOURCE_NAME_IS_STRING != 0
+ }
+
+ /// Returns the section offset of the name.
+ ///
+ /// Valid if `has_name()` returns true.
+ fn name(&self) -> ResourceName {
+ let offset = self.name_or_id.get(LE) & !pe::IMAGE_RESOURCE_NAME_IS_STRING;
+ ResourceName { offset }
+ }
+
+ /// Returns the ID.
+ ///
+ /// Valid if `has_string_name()` returns false.
+ fn id(&self) -> u16 {
+ (self.name_or_id.get(LE) & 0x0000_FFFF) as u16
+ }
+
+ /// Returns the entry name
+ pub fn name_or_id(&self) -> ResourceNameOrId {
+ if self.has_name() {
+ ResourceNameOrId::Name(self.name())
+ } else {
+ ResourceNameOrId::Id(self.id())
+ }
+ }
+
+ /// Returns true if the entry is a subtable.
+ pub fn is_table(&self) -> bool {
+ self.offset_to_data_or_directory.get(LE) & pe::IMAGE_RESOURCE_DATA_IS_DIRECTORY != 0
+ }
+
+ /// Returns the section offset of the associated table or data.
+ pub fn data_offset(&self) -> u32 {
+ self.offset_to_data_or_directory.get(LE) & !pe::IMAGE_RESOURCE_DATA_IS_DIRECTORY
+ }
+
+ /// Returns the data associated to this directory entry.
+ pub fn data<'data>(
+ &self,
+ section: ResourceDirectory<'data>,
+ ) -> Result<ResourceDirectoryEntryData<'data>> {
+ if self.is_table() {
+ ResourceDirectoryTable::parse(section.data, self.data_offset())
+ .map(ResourceDirectoryEntryData::Table)
+ } else {
+ section
+ .data
+ .read_at::<pe::ImageResourceDataEntry>(self.data_offset().into())
+ .read_error("Invalid resource entry")
+ .map(ResourceDirectoryEntryData::Data)
+ }
+ }
+}
+
+/// Data associated with a resource directory entry.
+#[derive(Debug, Clone)]
+pub enum ResourceDirectoryEntryData<'data> {
+ /// A subtable entry.
+ Table(ResourceDirectoryTable<'data>),
+ /// A resource data entry.
+ Data(&'data pe::ImageResourceDataEntry),
+}
+
+impl<'data> ResourceDirectoryEntryData<'data> {
+ /// Converts to an option of table.
+ ///
+ /// Helper for iterator filtering.
+ pub fn table(self) -> Option<ResourceDirectoryTable<'data>> {
+ match self {
+ Self::Table(dir) => Some(dir),
+ _ => None,
+ }
+ }
+
+ /// Converts to an option of data entry.
+ ///
+ /// Helper for iterator filtering.
+ pub fn data(self) -> Option<&'data pe::ImageResourceDataEntry> {
+ match self {
+ Self::Data(rsc) => Some(rsc),
+ _ => None,
+ }
+ }
+}
+
+/// A resource name.
+#[derive(Debug, Clone, Copy)]
+pub struct ResourceName {
+ offset: u32,
+}
+
+impl ResourceName {
+ /// Converts to a `String`.
+ pub fn to_string_lossy(&self, directory: ResourceDirectory<'_>) -> Result<String> {
+ let d = self.data(directory)?.iter().map(|c| c.get(LE));
+
+ Ok(char::decode_utf16(d)
+ .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
+ .collect::<String>())
+ }
+
+ /// Returns the string unicode buffer.
+ pub fn data<'data>(
+ &self,
+ directory: ResourceDirectory<'data>,
+ ) -> Result<&'data [U16Bytes<LE>]> {
+ let mut offset = u64::from(self.offset);
+ let len = directory
+ .data
+ .read::<U16Bytes<LE>>(&mut offset)
+ .read_error("Invalid resource name offset")?;
+ directory
+ .data
+ .read_slice::<U16Bytes<LE>>(&mut offset, len.get(LE).into())
+ .read_error("Invalid resource name length")
+ }
+
+ /// Returns the string buffer as raw bytes.
+ pub fn raw_data<'data>(&self, directory: ResourceDirectory<'data>) -> Result<&'data [u8]> {
+ self.data(directory).map(crate::pod::bytes_of_slice)
+ }
+}
+
+/// A resource name or ID.
+///
+/// Can be either a string or a numeric ID.
+#[derive(Debug)]
+pub enum ResourceNameOrId {
+ /// A resource name.
+ Name(ResourceName),
+ /// A resource ID.
+ Id(u16),
+}
+
+impl ResourceNameOrId {
+ /// Converts to an option of name.
+ ///
+ /// Helper for iterator filtering.
+ pub fn name(self) -> Option<ResourceName> {
+ match self {
+ Self::Name(name) => Some(name),
+ _ => None,
+ }
+ }
+
+ /// Converts to an option of ID.
+ ///
+ /// Helper for iterator filtering.
+ pub fn id(self) -> Option<u16> {
+ match self {
+ Self::Id(id) => Some(id),
+ _ => None,
+ }
+ }
+}
diff --git a/third_party/rust/object/src/read/pe/rich.rs b/third_party/rust/object/src/read/pe/rich.rs
new file mode 100644
index 0000000000..33dd039c99
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/rich.rs
@@ -0,0 +1,91 @@
+//! PE rich header handling
+
+use core::mem;
+
+use crate::pod::bytes_of_slice;
+use crate::read::Bytes;
+use crate::{pe, LittleEndian as LE, ReadRef, U32};
+
+/// Parsed information about a Rich Header.
+#[derive(Debug, Clone, Copy)]
+pub struct RichHeaderInfo<'data> {
+ /// The offset at which the rich header starts.
+ pub offset: usize,
+ /// The length (in bytes) of the rich header.
+ ///
+ /// This includes the payload, but also the 16-byte start sequence and the
+ /// 8-byte final "Rich" and XOR key.
+ pub length: usize,
+ /// The XOR key used to mask the rich header.
+ ///
+ /// Unless the file has been tampered with, it should be equal to a checksum
+ /// of the file header.
+ pub xor_key: u32,
+ masked_entries: &'data [pe::MaskedRichHeaderEntry],
+}
+
+/// A PE rich header entry after it has been unmasked.
+///
+/// See [`pe::MaskedRichHeaderEntry`].
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct RichHeaderEntry {
+ /// ID of the component.
+ pub comp_id: u32,
+ /// Number of times this component has been used when building this PE.
+ pub count: u32,
+}
+
+impl<'data> RichHeaderInfo<'data> {
+ /// Try to locate a rich header and its entries in the current PE file.
+ pub fn parse<R: ReadRef<'data>>(data: R, nt_header_offset: u64) -> Option<Self> {
+ // Locate the rich header, if any.
+ // It ends with the "Rich" string and an XOR key, before the NT header.
+ let data = data.read_bytes_at(0, nt_header_offset).map(Bytes).ok()?;
+ let end_marker_offset = memmem(data.0, b"Rich", 4)?;
+ let xor_key = *data.read_at::<U32<LE>>(end_marker_offset + 4).ok()?;
+
+ // It starts at the masked "DanS" string and 3 masked zeroes.
+ let masked_start_marker = U32::new(LE, 0x536e_6144 ^ xor_key.get(LE));
+ let start_header = [masked_start_marker, xor_key, xor_key, xor_key];
+ let start_sequence = bytes_of_slice(&start_header);
+ let start_marker_offset = memmem(&data.0[..end_marker_offset], start_sequence, 4)?;
+
+ // Extract the items between the markers.
+ let items_offset = start_marker_offset + start_sequence.len();
+ let items_len = end_marker_offset - items_offset;
+ let item_count = items_len / mem::size_of::<pe::MaskedRichHeaderEntry>();
+ let items = data.read_slice_at(items_offset, item_count).ok()?;
+ Some(RichHeaderInfo {
+ offset: start_marker_offset,
+ // Includes "Rich" marker and the XOR key.
+ length: end_marker_offset - start_marker_offset + 8,
+ xor_key: xor_key.get(LE),
+ masked_entries: items,
+ })
+ }
+
+ /// Returns an iterator over the unmasked entries.
+ pub fn unmasked_entries(&self) -> impl Iterator<Item = RichHeaderEntry> + 'data {
+ let xor_key = self.xor_key;
+ self.masked_entries
+ .iter()
+ .map(move |entry| RichHeaderEntry {
+ comp_id: entry.masked_comp_id.get(LE) ^ xor_key,
+ count: entry.masked_count.get(LE) ^ xor_key,
+ })
+ }
+}
+
+/// Find the offset of the first occurrence of needle in the data.
+///
+/// The offset must have the given alignment.
+fn memmem(data: &[u8], needle: &[u8], align: usize) -> Option<usize> {
+ let mut offset = 0;
+ loop {
+ if data.get(offset..)?.get(..needle.len())? == needle {
+ return Some(offset);
+ }
+ offset += align;
+ }
+}
diff --git a/third_party/rust/object/src/read/pe/section.rs b/third_party/rust/object/src/read/pe/section.rs
new file mode 100644
index 0000000000..2880e401fe
--- /dev/null
+++ b/third_party/rust/object/src/read/pe/section.rs
@@ -0,0 +1,434 @@
+use core::marker::PhantomData;
+use core::{cmp, iter, slice, str};
+
+use crate::endian::LittleEndian as LE;
+use crate::pe;
+use crate::pe::ImageSectionHeader;
+use crate::read::{
+ self, CompressedData, CompressedFileRange, ObjectSection, ObjectSegment, ReadError, ReadRef,
+ Relocation, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
+};
+
+use super::{ImageNtHeaders, PeFile, SectionTable};
+
+/// An iterator over the loadable sections of a `PeFile32`.
+pub type PeSegmentIterator32<'data, 'file, R = &'data [u8]> =
+ PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32, R>;
+/// An iterator over the loadable sections of a `PeFile64`.
+pub type PeSegmentIterator64<'data, 'file, R = &'data [u8]> =
+ PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64, R>;
+
+/// An iterator over the loadable sections of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSegmentIterator<'data, 'file, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file PeFile<'data, Pe, R>,
+ pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>,
+}
+
+impl<'data, 'file, Pe, R> Iterator for PeSegmentIterator<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ type Item = PeSegment<'data, 'file, Pe, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|section| PeSegment {
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A loadable section of a `PeFile32`.
+pub type PeSegment32<'data, 'file, R = &'data [u8]> =
+ PeSegment<'data, 'file, pe::ImageNtHeaders32, R>;
+/// A loadable section of a `PeFile64`.
+pub type PeSegment64<'data, 'file, R = &'data [u8]> =
+ PeSegment<'data, 'file, pe::ImageNtHeaders64, R>;
+
+/// A loadable section of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSegment<'data, 'file, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ file: &'file PeFile<'data, Pe, R>,
+ section: &'data pe::ImageSectionHeader,
+}
+
+impl<'data, 'file, Pe, R> read::private::Sealed for PeSegment<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ u64::from(self.section.virtual_size.get(LE))
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.file.section_alignment()
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ let (offset, size) = self.section.pe_file_range();
+ (u64::from(offset), u64::from(size))
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ self.section.pe_data(self.file.data)
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.data()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<Option<&[u8]>> {
+ self.section
+ .name(self.file.common.symbols.strings())
+ .map(Some)
+ }
+
+ #[inline]
+ fn name(&self) -> Result<Option<&str>> {
+ let name = self.section.name(self.file.common.symbols.strings())?;
+ Ok(Some(
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 PE section name")?,
+ ))
+ }
+
+ #[inline]
+ fn flags(&self) -> SegmentFlags {
+ let characteristics = self.section.characteristics.get(LE);
+ SegmentFlags::Coff { characteristics }
+ }
+}
+
+/// An iterator over the sections of a `PeFile32`.
+pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> =
+ PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>;
+/// An iterator over the sections of a `PeFile64`.
+pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> =
+ PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;
+
+/// An iterator over the sections of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file PeFile<'data, Pe, R>,
+ pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
+}
+
+impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ type Item = PeSection<'data, 'file, Pe, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| PeSection {
+ file: self.file,
+ index: SectionIndex(index + 1),
+ section,
+ })
+ }
+}
+
+/// A section of a `PeFile32`.
+pub type PeSection32<'data, 'file, R = &'data [u8]> =
+ PeSection<'data, 'file, pe::ImageNtHeaders32, R>;
+/// A section of a `PeFile64`.
+pub type PeSection64<'data, 'file, R = &'data [u8]> =
+ PeSection<'data, 'file, pe::ImageNtHeaders64, R>;
+
+/// A section of a `PeFile`.
+#[derive(Debug)]
+pub struct PeSection<'data, 'file, Pe, R = &'data [u8]>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file PeFile<'data, Pe, R>,
+ pub(super) index: SectionIndex,
+ pub(super) section: &'data pe::ImageSectionHeader,
+}
+
+impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R>
+where
+ Pe: ImageNtHeaders,
+ R: ReadRef<'data>,
+{
+ type RelocationIterator = PeRelocationIterator<'data, 'file, R>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base)
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ u64::from(self.section.virtual_size.get(LE))
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.file.section_alignment()
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ let (offset, size) = self.section.pe_file_range();
+ if size == 0 {
+ None
+ } else {
+ Some((u64::from(offset), u64::from(size)))
+ }
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ self.section.pe_data(self.file.data)
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.data()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ #[inline]
+ fn compressed_file_range(&self) -> Result<CompressedFileRange> {
+ Ok(CompressedFileRange::none(self.file_range()))
+ }
+
+ #[inline]
+ fn compressed_data(&self) -> Result<CompressedData<'data>> {
+ self.data().map(CompressedData::none)
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ self.section.name(self.file.common.symbols.strings())
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 PE section name")
+ }
+
+ #[inline]
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Result<Option<&str>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn kind(&self) -> SectionKind {
+ self.section.kind()
+ }
+
+ fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> {
+ PeRelocationIterator(PhantomData)
+ }
+
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::Coff {
+ characteristics: self.section.characteristics.get(LE),
+ }
+ }
+}
+
+impl<'data> SectionTable<'data> {
+ /// Return the file offset of the given virtual address, and the size up
+ /// to the end of the section containing it.
+ ///
+ /// Returns `None` if no section contains the address.
+ pub fn pe_file_range_at(&self, va: u32) -> Option<(u32, u32)> {
+ self.iter().find_map(|section| section.pe_file_range_at(va))
+ }
+
+ /// Return the data starting at the given virtual address, up to the end of the
+ /// section containing it.
+ ///
+ /// Ignores sections with invalid data.
+ ///
+ /// Returns `None` if no section contains the address.
+ pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
+ self.iter().find_map(|section| section.pe_data_at(data, va))
+ }
+
+ /// Return the data of the section that contains the given virtual address in a PE file.
+ ///
+ /// Also returns the virtual address of that section.
+ ///
+ /// Ignores sections with invalid data.
+ pub fn pe_data_containing<R: ReadRef<'data>>(
+ &self,
+ data: R,
+ va: u32,
+ ) -> Option<(&'data [u8], u32)> {
+ self.iter()
+ .find_map(|section| section.pe_data_containing(data, va))
+ }
+
+ /// Return the section that contains a given virtual address.
+ pub fn section_containing(&self, va: u32) -> Option<&'data ImageSectionHeader> {
+ self.iter().find(|section| section.contains_rva(va))
+ }
+}
+
+impl pe::ImageSectionHeader {
+ /// Return the offset and size of the section in a PE file.
+ ///
+ /// The size of the range will be the minimum of the file size and virtual size.
+ pub fn pe_file_range(&self) -> (u32, u32) {
+ // Pointer and size will be zero for uninitialized data; we don't need to validate this.
+ let offset = self.pointer_to_raw_data.get(LE);
+ let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE));
+ (offset, size)
+ }
+
+ /// Return the file offset of the given virtual address, and the remaining size up
+ /// to the end of the section.
+ ///
+ /// Returns `None` if the section does not contain the address.
+ pub fn pe_file_range_at(&self, va: u32) -> Option<(u32, u32)> {
+ let section_va = self.virtual_address.get(LE);
+ let offset = va.checked_sub(section_va)?;
+ let (section_offset, section_size) = self.pe_file_range();
+ // Address must be within section (and not at its end).
+ if offset < section_size {
+ Some((section_offset.checked_add(offset)?, section_size - offset))
+ } else {
+ None
+ }
+ }
+
+ /// Return the virtual address and size of the section.
+ pub fn pe_address_range(&self) -> (u32, u32) {
+ (self.virtual_address.get(LE), self.virtual_size.get(LE))
+ }
+
+ /// Return the section data in a PE file.
+ ///
+ /// The length of the data will be the minimum of the file size and virtual size.
+ pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> Result<&'data [u8]> {
+ let (offset, size) = self.pe_file_range();
+ data.read_bytes_at(offset.into(), size.into())
+ .read_error("Invalid PE section offset or size")
+ }
+
+ /// Return the data starting at the given virtual address, up to the end of the
+ /// section.
+ ///
+ /// Ignores sections with invalid data.
+ ///
+ /// Returns `None` if the section does not contain the address.
+ pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> {
+ let (offset, size) = self.pe_file_range_at(va)?;
+ data.read_bytes_at(offset.into(), size.into()).ok()
+ }
+
+ /// Tests whether a given RVA is part of this section
+ pub fn contains_rva(&self, va: u32) -> bool {
+ let section_va = self.virtual_address.get(LE);
+ match va.checked_sub(section_va) {
+ None => false,
+ Some(offset) => {
+ // Address must be within section (and not at its end).
+ offset < self.virtual_size.get(LE)
+ }
+ }
+ }
+
+ /// Return the section data if it contains the given virtual address.
+ ///
+ /// Also returns the virtual address of that section.
+ ///
+ /// Ignores sections with invalid data.
+ pub fn pe_data_containing<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ va: u32,
+ ) -> Option<(&'data [u8], u32)> {
+ let section_va = self.virtual_address.get(LE);
+ let offset = va.checked_sub(section_va)?;
+ let (section_offset, section_size) = self.pe_file_range();
+ // Address must be within section (and not at its end).
+ if offset < section_size {
+ let section_data = data
+ .read_bytes_at(section_offset.into(), section_size.into())
+ .ok()?;
+ Some((section_data, section_va))
+ } else {
+ None
+ }
+ }
+}
+
+/// An iterator over the relocations in an `PeSection`.
+#[derive(Debug)]
+pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>(
+ PhantomData<(&'data (), &'file (), R)>,
+);
+
+impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> {
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
diff --git a/third_party/rust/object/src/read/read_cache.rs b/third_party/rust/object/src/read/read_cache.rs
new file mode 100644
index 0000000000..dfce1e1b1e
--- /dev/null
+++ b/third_party/rust/object/src/read/read_cache.rs
@@ -0,0 +1,182 @@
+use core::ops::Range;
+use std::boxed::Box;
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::io::{Read, Seek, SeekFrom};
+use std::mem;
+use std::vec::Vec;
+
+use crate::read::ReadRef;
+
+/// An implementation of `ReadRef` for data in a stream that implements
+/// `Read + Seek`.
+///
+/// Contains a cache of read-only blocks of data, allowing references to
+/// them to be returned. Entries in the cache are never removed.
+/// Entries are keyed on the offset and size of the read.
+/// Currently overlapping reads are considered separate reads.
+#[derive(Debug)]
+pub struct ReadCache<R: Read + Seek> {
+ cache: RefCell<ReadCacheInternal<R>>,
+}
+
+#[derive(Debug)]
+struct ReadCacheInternal<R: Read + Seek> {
+ read: R,
+ bufs: HashMap<(u64, u64), Box<[u8]>>,
+ strings: HashMap<(u64, u8), Box<[u8]>>,
+}
+
+impl<R: Read + Seek> ReadCache<R> {
+ /// Create an empty `ReadCache` for the given stream.
+ pub fn new(read: R) -> Self {
+ ReadCache {
+ cache: RefCell::new(ReadCacheInternal {
+ read,
+ bufs: HashMap::new(),
+ strings: HashMap::new(),
+ }),
+ }
+ }
+
+ /// Return an implementation of `ReadRef` that restricts reads
+ /// to the given range of the stream.
+ pub fn range(&self, offset: u64, size: u64) -> ReadCacheRange<'_, R> {
+ ReadCacheRange {
+ r: self,
+ offset,
+ size,
+ }
+ }
+
+ /// Free buffers used by the cache.
+ pub fn clear(&mut self) {
+ self.cache.borrow_mut().bufs.clear();
+ }
+
+ /// Unwrap this `ReadCache<R>`, returning the underlying reader.
+ pub fn into_inner(self) -> R {
+ self.cache.into_inner().read
+ }
+}
+
+impl<'a, R: Read + Seek> ReadRef<'a> for &'a ReadCache<R> {
+ fn len(self) -> Result<u64, ()> {
+ let cache = &mut *self.cache.borrow_mut();
+ cache.read.seek(SeekFrom::End(0)).map_err(|_| ())
+ }
+
+ fn read_bytes_at(self, offset: u64, size: u64) -> Result<&'a [u8], ()> {
+ if size == 0 {
+ return Ok(&[]);
+ }
+ let cache = &mut *self.cache.borrow_mut();
+ let buf = match cache.bufs.entry((offset, size)) {
+ Entry::Occupied(entry) => entry.into_mut(),
+ Entry::Vacant(entry) => {
+ let size = size.try_into().map_err(|_| ())?;
+ cache.read.seek(SeekFrom::Start(offset)).map_err(|_| ())?;
+ let mut bytes = vec![0; size].into_boxed_slice();
+ cache.read.read_exact(&mut bytes).map_err(|_| ())?;
+ entry.insert(bytes)
+ }
+ };
+ // Extend the lifetime to that of self.
+ // This is OK because we never mutate or remove entries.
+ Ok(unsafe { mem::transmute::<&[u8], &[u8]>(buf) })
+ }
+
+ fn read_bytes_at_until(self, range: Range<u64>, delimiter: u8) -> Result<&'a [u8], ()> {
+ let cache = &mut *self.cache.borrow_mut();
+ let buf = match cache.strings.entry((range.start, delimiter)) {
+ Entry::Occupied(entry) => entry.into_mut(),
+ Entry::Vacant(entry) => {
+ cache
+ .read
+ .seek(SeekFrom::Start(range.start))
+ .map_err(|_| ())?;
+
+ let max_check: usize = (range.end - range.start).try_into().map_err(|_| ())?;
+ // Strings should be relatively small.
+ // TODO: make this configurable?
+ let max_check = max_check.min(4096);
+
+ let mut bytes = Vec::new();
+ let mut checked = 0;
+ loop {
+ bytes.resize((checked + 256).min(max_check), 0);
+ let read = cache.read.read(&mut bytes[checked..]).map_err(|_| ())?;
+ if read == 0 {
+ return Err(());
+ }
+ if let Some(len) = memchr::memchr(delimiter, &bytes[checked..][..read]) {
+ bytes.truncate(checked + len);
+ break entry.insert(bytes.into_boxed_slice());
+ }
+ checked += read;
+ if checked >= max_check {
+ return Err(());
+ }
+ }
+ }
+ };
+ // Extend the lifetime to that of self.
+ // This is OK because we never mutate or remove entries.
+ Ok(unsafe { mem::transmute::<&[u8], &[u8]>(buf) })
+ }
+}
+
+/// An implementation of `ReadRef` for a range of data in a stream that
+/// implements `Read + Seek`.
+///
+/// Shares an underlying `ReadCache` with a lifetime of `'a`.
+#[derive(Debug)]
+pub struct ReadCacheRange<'a, R: Read + Seek> {
+ r: &'a ReadCache<R>,
+ offset: u64,
+ size: u64,
+}
+
+impl<'a, R: Read + Seek> Clone for ReadCacheRange<'a, R> {
+ fn clone(&self) -> Self {
+ Self {
+ r: self.r,
+ offset: self.offset,
+ size: self.size,
+ }
+ }
+}
+
+impl<'a, R: Read + Seek> Copy for ReadCacheRange<'a, R> {}
+
+impl<'a, R: Read + Seek> ReadRef<'a> for ReadCacheRange<'a, R> {
+ fn len(self) -> Result<u64, ()> {
+ Ok(self.size)
+ }
+
+ fn read_bytes_at(self, offset: u64, size: u64) -> Result<&'a [u8], ()> {
+ if size == 0 {
+ return Ok(&[]);
+ }
+ let end = offset.checked_add(size).ok_or(())?;
+ if end > self.size {
+ return Err(());
+ }
+ let r_offset = self.offset.checked_add(offset).ok_or(())?;
+ self.r.read_bytes_at(r_offset, size)
+ }
+
+ fn read_bytes_at_until(self, range: Range<u64>, delimiter: u8) -> Result<&'a [u8], ()> {
+ let r_start = self.offset.checked_add(range.start).ok_or(())?;
+ let r_end = self.offset.checked_add(range.end).ok_or(())?;
+ let bytes = self.r.read_bytes_at_until(r_start..r_end, delimiter)?;
+ let size = bytes.len().try_into().map_err(|_| ())?;
+ let end = range.start.checked_add(size).ok_or(())?;
+ if end > self.size {
+ return Err(());
+ }
+ Ok(bytes)
+ }
+}
diff --git a/third_party/rust/object/src/read/read_ref.rs b/third_party/rust/object/src/read/read_ref.rs
new file mode 100644
index 0000000000..a9b4252214
--- /dev/null
+++ b/third_party/rust/object/src/read/read_ref.rs
@@ -0,0 +1,137 @@
+#![allow(clippy::len_without_is_empty)]
+
+use core::convert::TryInto;
+use core::ops::Range;
+use core::{mem, result};
+
+use crate::pod::{from_bytes, slice_from_bytes, Pod};
+
+type Result<T> = result::Result<T, ()>;
+
+/// A trait for reading references to `Pod` types from a block of data.
+///
+/// This allows parsers to handle both of these cases:
+/// - the block of data exists in memory, and it is desirable
+/// to use references to this block instead of copying it,
+/// - the block of data exists in storage, and it is desirable
+/// to read on demand to minimize I/O and memory usage.
+///
+/// The methods accept `self` by value because `Self` is expected to behave
+/// similar to a reference: it may be a reference with a lifetime of `'a`,
+/// or it may be a wrapper of a reference.
+///
+/// The `Clone` and `Copy` bounds are for convenience, and since `Self` is
+/// expected to be similar to a reference, these are easily satisfied.
+///
+/// Object file parsers typically use offsets to locate the structures
+/// in the block, and will most commonly use the `*_at` methods to
+/// read a structure at a known offset.
+///
+/// Occasionally file parsers will need to treat the block as a stream,
+/// and so convenience methods are provided that update an offset with
+/// the size that was read.
+//
+// An alternative would be for methods to accept `&mut self` and use a
+// `seek` method instead of the `offset` parameters, but this is less
+// convenient for implementers.
+pub trait ReadRef<'a>: Clone + Copy {
+ /// The total size of the block of data.
+ fn len(self) -> Result<u64>;
+
+ /// Get a reference to a `u8` slice at the given offset.
+ ///
+ /// Returns an error if offset or size are out of bounds.
+ fn read_bytes_at(self, offset: u64, size: u64) -> Result<&'a [u8]>;
+
+ /// Get a reference to a delimited `u8` slice which starts at range.start.
+ ///
+ /// Does not include the delimiter.
+ ///
+ /// Returns an error if the range is out of bounds or the delimiter is
+ /// not found in the range.
+ fn read_bytes_at_until(self, range: Range<u64>, delimiter: u8) -> Result<&'a [u8]>;
+
+ /// Get a reference to a `u8` slice at the given offset, and update the offset.
+ ///
+ /// Returns an error if offset or size are out of bounds.
+ fn read_bytes(self, offset: &mut u64, size: u64) -> Result<&'a [u8]> {
+ let bytes = self.read_bytes_at(*offset, size)?;
+ *offset = offset.wrapping_add(size);
+ Ok(bytes)
+ }
+
+ /// Get a reference to a `Pod` type at the given offset, and update the offset.
+ ///
+ /// Returns an error if offset or size are out of bounds.
+ ///
+ /// The default implementation uses `read_bytes`, and returns an error if
+ /// `read_bytes` does not return bytes with the correct alignment for `T`.
+ /// Implementors may want to provide their own implementation that ensures
+ /// the alignment can be satisfied. Alternatively, only use this method with
+ /// types that do not need alignment (see the `unaligned` feature of this crate).
+ fn read<T: Pod>(self, offset: &mut u64) -> Result<&'a T> {
+ let size = mem::size_of::<T>().try_into().map_err(|_| ())?;
+ let bytes = self.read_bytes(offset, size)?;
+ let (t, _) = from_bytes(bytes)?;
+ Ok(t)
+ }
+
+ /// Get a reference to a `Pod` type at the given offset.
+ ///
+ /// Returns an error if offset or size are out of bounds.
+ ///
+ /// Also see the `read` method for information regarding alignment of `T`.
+ fn read_at<T: Pod>(self, mut offset: u64) -> Result<&'a T> {
+ self.read(&mut offset)
+ }
+
+ /// Get a reference to a slice of a `Pod` type at the given offset, and update the offset.
+ ///
+ /// Returns an error if offset or size are out of bounds.
+ ///
+ /// Also see the `read` method for information regarding alignment of `T`.
+ fn read_slice<T: Pod>(self, offset: &mut u64, count: usize) -> Result<&'a [T]> {
+ let size = count
+ .checked_mul(mem::size_of::<T>())
+ .ok_or(())?
+ .try_into()
+ .map_err(|_| ())?;
+ let bytes = self.read_bytes(offset, size)?;
+ let (t, _) = slice_from_bytes(bytes, count)?;
+ Ok(t)
+ }
+
+ /// Get a reference to a slice of a `Pod` type at the given offset.
+ ///
+ /// Returns an error if offset or size are out of bounds.
+ ///
+ /// Also see the `read` method for information regarding alignment of `T`.
+ fn read_slice_at<T: Pod>(self, mut offset: u64, count: usize) -> Result<&'a [T]> {
+ self.read_slice(&mut offset, count)
+ }
+}
+
+impl<'a> ReadRef<'a> for &'a [u8] {
+ fn len(self) -> Result<u64> {
+ self.len().try_into().map_err(|_| ())
+ }
+
+ fn read_bytes_at(self, offset: u64, size: u64) -> Result<&'a [u8]> {
+ let offset: usize = offset.try_into().map_err(|_| ())?;
+ let size: usize = size.try_into().map_err(|_| ())?;
+ self.get(offset..).ok_or(())?.get(..size).ok_or(())
+ }
+
+ fn read_bytes_at_until(self, range: Range<u64>, delimiter: u8) -> Result<&'a [u8]> {
+ let start: usize = range.start.try_into().map_err(|_| ())?;
+ let end: usize = range.end.try_into().map_err(|_| ())?;
+ let bytes = self.get(start..end).ok_or(())?;
+ match memchr::memchr(delimiter, bytes) {
+ Some(len) => {
+ // This will never fail.
+ bytes.get(..len).ok_or(())
+ }
+ None => Err(()),
+ }
+ }
+}
diff --git a/third_party/rust/object/src/read/traits.rs b/third_party/rust/object/src/read/traits.rs
new file mode 100644
index 0000000000..d35b0b0caa
--- /dev/null
+++ b/third_party/rust/object/src/read/traits.rs
@@ -0,0 +1,469 @@
+use alloc::borrow::Cow;
+use alloc::vec::Vec;
+
+use crate::read::{
+ self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export,
+ FileFlags, Import, ObjectKind, ObjectMap, Relocation, Result, SectionFlags, SectionIndex,
+ SectionKind, SegmentFlags, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName,
+ SymbolScope, SymbolSection,
+};
+use crate::Endianness;
+
+/// An object file.
+pub trait Object<'data: 'file, 'file>: read::private::Sealed {
+ /// A segment in the object file.
+ type Segment: ObjectSegment<'data>;
+
+ /// An iterator over the segments in the object file.
+ type SegmentIterator: Iterator<Item = Self::Segment>;
+
+ /// A section in the object file.
+ type Section: ObjectSection<'data>;
+
+ /// An iterator over the sections in the object file.
+ type SectionIterator: Iterator<Item = Self::Section>;
+
+ /// A COMDAT section group in the object file.
+ type Comdat: ObjectComdat<'data>;
+
+ /// An iterator over the COMDAT section groups in the object file.
+ type ComdatIterator: Iterator<Item = Self::Comdat>;
+
+ /// A symbol in the object file.
+ type Symbol: ObjectSymbol<'data>;
+
+ /// An iterator over symbols in the object file.
+ type SymbolIterator: Iterator<Item = Self::Symbol>;
+
+ /// A symbol table in the object file.
+ type SymbolTable: ObjectSymbolTable<
+ 'data,
+ Symbol = Self::Symbol,
+ SymbolIterator = Self::SymbolIterator,
+ >;
+
+ /// An iterator over dynamic relocations in the file.
+ ///
+ /// The first field in the item tuple is the address
+ /// that the relocation applies to.
+ type DynamicRelocationIterator: Iterator<Item = (u64, Relocation)>;
+
+ /// Get the architecture type of the file.
+ fn architecture(&self) -> Architecture;
+
+ /// Get the endianness of the file.
+ #[inline]
+ fn endianness(&self) -> Endianness {
+ if self.is_little_endian() {
+ Endianness::Little
+ } else {
+ Endianness::Big
+ }
+ }
+
+ /// Return true if the file is little endian, false if it is big endian.
+ fn is_little_endian(&self) -> bool;
+
+ /// Return true if the file can contain 64-bit addresses.
+ fn is_64(&self) -> bool;
+
+ /// Return the kind of this object.
+ fn kind(&self) -> ObjectKind;
+
+ /// Get an iterator over the segments in the file.
+ fn segments(&'file self) -> Self::SegmentIterator;
+
+ /// Get the section named `section_name`, if such a section exists.
+ ///
+ /// If `section_name` starts with a '.' then it is treated as a system section name,
+ /// and is compared using the conventions specific to the object file format. This
+ /// includes:
+ /// - if ".debug_str_offsets" is requested for a Mach-O object file, then the actual
+ /// section name that is searched for is "__debug_str_offs".
+ /// - if ".debug_info" is requested for an ELF object file, then
+ /// ".zdebug_info" may be returned (and similarly for other debug sections).
+ ///
+ /// For some object files, multiple segments may contain sections with the same
+ /// name. In this case, the first matching section will be used.
+ ///
+ /// This method skips over sections with invalid names.
+ fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section> {
+ self.section_by_name_bytes(section_name.as_bytes())
+ }
+
+ /// Like [`Self::section_by_name`], but allows names that are not UTF-8.
+ fn section_by_name_bytes(&'file self, section_name: &[u8]) -> Option<Self::Section>;
+
+ /// Get the section at the given index.
+ ///
+ /// The meaning of the index depends on the object file.
+ ///
+ /// For some object files, this requires iterating through all sections.
+ ///
+ /// Returns an error if the index is invalid.
+ fn section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>;
+
+ /// Get an iterator over the sections in the file.
+ fn sections(&'file self) -> Self::SectionIterator;
+
+ /// Get an iterator over the COMDAT section groups in the file.
+ fn comdats(&'file self) -> Self::ComdatIterator;
+
+ /// Get the symbol table, if any.
+ fn symbol_table(&'file self) -> Option<Self::SymbolTable>;
+
+ /// Get the debugging symbol at the given index.
+ ///
+ /// The meaning of the index depends on the object file.
+ ///
+ /// Returns an error if the index is invalid.
+ fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>;
+
+ /// Get an iterator over the debugging symbols in the file.
+ ///
+ /// This may skip over symbols that are malformed or unsupported.
+ ///
+ /// For Mach-O files, this does not include STAB entries.
+ fn symbols(&'file self) -> Self::SymbolIterator;
+
+ /// Get the dynamic linking symbol table, if any.
+ ///
+ /// Only ELF has a separate dynamic linking symbol table.
+ fn dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>;
+
+ /// Get an iterator over the dynamic linking symbols in the file.
+ ///
+ /// This may skip over symbols that are malformed or unsupported.
+ ///
+ /// Only ELF has separate dynamic linking symbols.
+ /// Other file formats will return an empty iterator.
+ fn dynamic_symbols(&'file self) -> Self::SymbolIterator;
+
+ /// Get the dynamic relocations for this file.
+ ///
+ /// Symbol indices in these relocations refer to the dynamic symbol table.
+ ///
+ /// Only ELF has dynamic relocations.
+ fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>;
+
+ /// Construct a map from addresses to symbol names.
+ ///
+ /// The map will only contain defined text and data symbols.
+ /// The dynamic symbol table will only be used if there are no debugging symbols.
+ fn symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>> {
+ let mut symbols = Vec::new();
+ if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) {
+ for symbol in table.symbols() {
+ if !symbol.is_definition() {
+ continue;
+ }
+ if let Ok(name) = symbol.name() {
+ symbols.push(SymbolMapName::new(symbol.address(), name));
+ }
+ }
+ }
+ SymbolMap::new(symbols)
+ }
+
+ /// Construct a map from addresses to symbol names and object file names.
+ ///
+ /// This is derived from Mach-O STAB entries.
+ fn object_map(&'file self) -> ObjectMap<'data> {
+ ObjectMap::default()
+ }
+
+ /// Get the imported symbols.
+ fn imports(&self) -> Result<Vec<Import<'data>>>;
+
+ /// Get the exported symbols that expose both a name and an address.
+ ///
+ /// Some file formats may provide other kinds of symbols, that can be retrieved using
+ /// the lower-level API.
+ fn exports(&self) -> Result<Vec<Export<'data>>>;
+
+ /// Return true if the file contains debug information sections, false if not.
+ fn has_debug_symbols(&self) -> bool;
+
+ /// The UUID from a Mach-O `LC_UUID` load command.
+ #[inline]
+ fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
+ Ok(None)
+ }
+
+ /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
+ #[inline]
+ fn build_id(&self) -> Result<Option<&'data [u8]>> {
+ Ok(None)
+ }
+
+ /// The filename and CRC from a `.gnu_debuglink` section.
+ #[inline]
+ fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> {
+ Ok(None)
+ }
+
+ /// The filename and build ID from a `.gnu_debugaltlink` section.
+ #[inline]
+ fn gnu_debugaltlink(&self) -> Result<Option<(&'data [u8], &'data [u8])>> {
+ Ok(None)
+ }
+
+ /// The filename and GUID from the PE CodeView section
+ #[inline]
+ fn pdb_info(&self) -> Result<Option<CodeView<'_>>> {
+ Ok(None)
+ }
+
+ /// Get the base address used for relative virtual addresses.
+ ///
+ /// Currently this is only non-zero for PE.
+ fn relative_address_base(&'file self) -> u64;
+
+ /// Get the virtual address of the entry point of the binary
+ fn entry(&'file self) -> u64;
+
+ /// File flags that are specific to each file format.
+ fn flags(&self) -> FileFlags;
+}
+
+/// A loadable segment defined in an object file.
+///
+/// For ELF, this is a program header with type `PT_LOAD`.
+/// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
+pub trait ObjectSegment<'data>: read::private::Sealed {
+ /// Returns the virtual address of the segment.
+ fn address(&self) -> u64;
+
+ /// Returns the size of the segment in memory.
+ fn size(&self) -> u64;
+
+ /// Returns the alignment of the segment in memory.
+ fn align(&self) -> u64;
+
+ /// Returns the offset and size of the segment in the file.
+ fn file_range(&self) -> (u64, u64);
+
+ /// Returns a reference to the file contents of the segment.
+ ///
+ /// The length of this data may be different from the size of the
+ /// segment in memory.
+ fn data(&self) -> Result<&'data [u8]>;
+
+ /// Return the segment data in the given range.
+ ///
+ /// Returns `Ok(None)` if the segment does not contain the given range.
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
+
+ /// Returns the name of the segment.
+ fn name_bytes(&self) -> Result<Option<&[u8]>>;
+
+ /// Returns the name of the segment.
+ ///
+ /// Returns an error if the name is not UTF-8.
+ fn name(&self) -> Result<Option<&str>>;
+
+ /// Return the flags of segment.
+ fn flags(&self) -> SegmentFlags;
+}
+
+/// A section defined in an object file.
+pub trait ObjectSection<'data>: read::private::Sealed {
+ /// An iterator over the relocations for a section.
+ ///
+ /// The first field in the item tuple is the section offset
+ /// that the relocation applies to.
+ type RelocationIterator: Iterator<Item = (u64, Relocation)>;
+
+ /// Returns the section index.
+ fn index(&self) -> SectionIndex;
+
+ /// Returns the address of the section.
+ fn address(&self) -> u64;
+
+ /// Returns the size of the section in memory.
+ fn size(&self) -> u64;
+
+ /// Returns the alignment of the section in memory.
+ fn align(&self) -> u64;
+
+ /// Returns offset and size of on-disk segment (if any).
+ fn file_range(&self) -> Option<(u64, u64)>;
+
+ /// Returns the raw contents of the section.
+ ///
+ /// The length of this data may be different from the size of the
+ /// section in memory.
+ ///
+ /// This does not do any decompression.
+ fn data(&self) -> Result<&'data [u8]>;
+
+ /// Return the raw contents of the section data in the given range.
+ ///
+ /// This does not do any decompression.
+ ///
+ /// Returns `Ok(None)` if the section does not contain the given range.
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
+
+ /// Returns the potentially compressed file range of the section,
+ /// along with information about the compression.
+ fn compressed_file_range(&self) -> Result<CompressedFileRange>;
+
+ /// Returns the potentially compressed contents of the section,
+ /// along with information about the compression.
+ fn compressed_data(&self) -> Result<CompressedData<'data>>;
+
+ /// Returns the uncompressed contents of the section.
+ ///
+ /// The length of this data may be different from the size of the
+ /// section in memory.
+ ///
+ /// If no compression is detected, then returns the data unchanged.
+ /// Returns `Err` if decompression fails.
+ fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> {
+ self.compressed_data()?.decompress()
+ }
+
+ /// Returns the name of the section.
+ fn name_bytes(&self) -> Result<&[u8]>;
+
+ /// Returns the name of the section.
+ ///
+ /// Returns an error if the name is not UTF-8.
+ fn name(&self) -> Result<&str>;
+
+ /// Returns the name of the segment for this section.
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>>;
+
+ /// Returns the name of the segment for this section.
+ ///
+ /// Returns an error if the name is not UTF-8.
+ fn segment_name(&self) -> Result<Option<&str>>;
+
+ /// Return the kind of this section.
+ fn kind(&self) -> SectionKind;
+
+ /// Get the relocations for this section.
+ fn relocations(&self) -> Self::RelocationIterator;
+
+ /// Section flags that are specific to each file format.
+ fn flags(&self) -> SectionFlags;
+}
+
+/// A COMDAT section group defined in an object file.
+pub trait ObjectComdat<'data>: read::private::Sealed {
+ /// An iterator over the sections in the object file.
+ type SectionIterator: Iterator<Item = SectionIndex>;
+
+ /// Returns the COMDAT selection kind.
+ fn kind(&self) -> ComdatKind;
+
+ /// Returns the index of the symbol used for the name of COMDAT section group.
+ fn symbol(&self) -> SymbolIndex;
+
+ /// Returns the name of the COMDAT section group.
+ fn name_bytes(&self) -> Result<&[u8]>;
+
+ /// Returns the name of the COMDAT section group.
+ ///
+ /// Returns an error if the name is not UTF-8.
+ fn name(&self) -> Result<&str>;
+
+ /// Get the sections in this section group.
+ fn sections(&self) -> Self::SectionIterator;
+}
+
+/// A symbol table.
+pub trait ObjectSymbolTable<'data>: read::private::Sealed {
+ /// A symbol table entry.
+ type Symbol: ObjectSymbol<'data>;
+
+ /// An iterator over the symbols in a symbol table.
+ type SymbolIterator: Iterator<Item = Self::Symbol>;
+
+ /// Get an iterator over the symbols in the table.
+ ///
+ /// This may skip over symbols that are malformed or unsupported.
+ fn symbols(&self) -> Self::SymbolIterator;
+
+ /// Get the symbol at the given index.
+ ///
+ /// The meaning of the index depends on the object file.
+ ///
+ /// Returns an error if the index is invalid.
+ fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>;
+}
+
+/// A symbol table entry.
+pub trait ObjectSymbol<'data>: read::private::Sealed {
+ /// The index of the symbol.
+ fn index(&self) -> SymbolIndex;
+
+ /// The name of the symbol.
+ fn name_bytes(&self) -> Result<&'data [u8]>;
+
+ /// The name of the symbol.
+ ///
+ /// Returns an error if the name is not UTF-8.
+ fn name(&self) -> Result<&'data str>;
+
+ /// The address of the symbol. May be zero if the address is unknown.
+ fn address(&self) -> u64;
+
+ /// The size of the symbol. May be zero if the size is unknown.
+ fn size(&self) -> u64;
+
+ /// Return the kind of this symbol.
+ fn kind(&self) -> SymbolKind;
+
+ /// Returns the section where the symbol is defined.
+ fn section(&self) -> SymbolSection;
+
+ /// Returns the section index for the section containing this symbol.
+ ///
+ /// May return `None` if the symbol is not defined in a section.
+ fn section_index(&self) -> Option<SectionIndex> {
+ self.section().index()
+ }
+
+ /// Return true if the symbol is undefined.
+ fn is_undefined(&self) -> bool;
+
+ /// Return true if the symbol is a definition of a function or data object
+ /// that has a known address.
+ fn is_definition(&self) -> bool;
+
+ /// Return true if the symbol is common data.
+ ///
+ /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
+ fn is_common(&self) -> bool;
+
+ /// Return true if the symbol is weak.
+ fn is_weak(&self) -> bool;
+
+ /// Returns the symbol scope.
+ fn scope(&self) -> SymbolScope;
+
+ /// Return true if the symbol visible outside of the compilation unit.
+ ///
+ /// This treats `SymbolScope::Unknown` as global.
+ fn is_global(&self) -> bool;
+
+ /// Return true if the symbol is only visible within the compilation unit.
+ fn is_local(&self) -> bool;
+
+ /// Symbol flags that are specific to each file format.
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex>;
+}
+
+/// An iterator for files that don't have dynamic relocations.
+#[derive(Debug)]
+pub struct NoDynamicRelocationIterator;
+
+impl Iterator for NoDynamicRelocationIterator {
+ type Item = (u64, Relocation);
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
diff --git a/third_party/rust/object/src/read/util.rs b/third_party/rust/object/src/read/util.rs
new file mode 100644
index 0000000000..7c3c65ec9e
--- /dev/null
+++ b/third_party/rust/object/src/read/util.rs
@@ -0,0 +1,425 @@
+use alloc::string::String;
+use core::convert::TryInto;
+use core::fmt;
+use core::marker::PhantomData;
+
+use crate::pod::{from_bytes, slice_from_bytes, Pod};
+use crate::ReadRef;
+
+/// A newtype for byte slices.
+///
+/// It has these important features:
+/// - no methods that can panic, such as `Index`
+/// - convenience methods for `Pod` types
+/// - a useful `Debug` implementation
+#[derive(Default, Clone, Copy, PartialEq, Eq)]
+pub struct Bytes<'data>(pub &'data [u8]);
+
+impl<'data> fmt::Debug for Bytes<'data> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ debug_list_bytes(self.0, fmt)
+ }
+}
+
+impl<'data> Bytes<'data> {
+ /// Return the length of the byte slice.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ /// Return true if the byte slice is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
+ /// Skip over the given number of bytes at the start of the byte slice.
+ ///
+ /// Modifies the byte slice to start after the bytes.
+ ///
+ /// Returns an error if there are too few bytes.
+ #[inline]
+ pub fn skip(&mut self, offset: usize) -> Result<(), ()> {
+ match self.0.get(offset..) {
+ Some(tail) => {
+ self.0 = tail;
+ Ok(())
+ }
+ None => {
+ self.0 = &[];
+ Err(())
+ }
+ }
+ }
+
+ /// Return a reference to the given number of bytes at the start of the byte slice.
+ ///
+ /// Modifies the byte slice to start after the bytes.
+ ///
+ /// Returns an error if there are too few bytes.
+ #[inline]
+ pub fn read_bytes(&mut self, count: usize) -> Result<Bytes<'data>, ()> {
+ match (self.0.get(..count), self.0.get(count..)) {
+ (Some(head), Some(tail)) => {
+ self.0 = tail;
+ Ok(Bytes(head))
+ }
+ _ => {
+ self.0 = &[];
+ Err(())
+ }
+ }
+ }
+
+ /// Return a reference to the given number of bytes at the given offset of the byte slice.
+ ///
+ /// Returns an error if the offset is invalid or there are too few bytes.
+ #[inline]
+ pub fn read_bytes_at(mut self, offset: usize, count: usize) -> Result<Bytes<'data>, ()> {
+ self.skip(offset)?;
+ self.read_bytes(count)
+ }
+
+ /// Return a reference to a `Pod` struct at the start of the byte slice.
+ ///
+ /// Modifies the byte slice to start after the bytes.
+ ///
+ /// Returns an error if there are too few bytes or the slice is incorrectly aligned.
+ #[inline]
+ pub fn read<T: Pod>(&mut self) -> Result<&'data T, ()> {
+ match from_bytes(self.0) {
+ Ok((value, tail)) => {
+ self.0 = tail;
+ Ok(value)
+ }
+ Err(()) => {
+ self.0 = &[];
+ Err(())
+ }
+ }
+ }
+
+ /// Return a reference to a `Pod` struct at the given offset of the byte slice.
+ ///
+ /// Returns an error if there are too few bytes or the offset is incorrectly aligned.
+ #[inline]
+ pub fn read_at<T: Pod>(mut self, offset: usize) -> Result<&'data T, ()> {
+ self.skip(offset)?;
+ self.read()
+ }
+
+ /// Return a reference to a slice of `Pod` structs at the start of the byte slice.
+ ///
+ /// Modifies the byte slice to start after the bytes.
+ ///
+ /// Returns an error if there are too few bytes or the offset is incorrectly aligned.
+ #[inline]
+ pub fn read_slice<T: Pod>(&mut self, count: usize) -> Result<&'data [T], ()> {
+ match slice_from_bytes(self.0, count) {
+ Ok((value, tail)) => {
+ self.0 = tail;
+ Ok(value)
+ }
+ Err(()) => {
+ self.0 = &[];
+ Err(())
+ }
+ }
+ }
+
+ /// Return a reference to a slice of `Pod` structs at the given offset of the byte slice.
+ ///
+ /// Returns an error if there are too few bytes or the offset is incorrectly aligned.
+ #[inline]
+ pub fn read_slice_at<T: Pod>(mut self, offset: usize, count: usize) -> Result<&'data [T], ()> {
+ self.skip(offset)?;
+ self.read_slice(count)
+ }
+
+ /// Read a null terminated string.
+ ///
+ /// Does not assume any encoding.
+ /// Reads past the null byte, but doesn't return it.
+ #[inline]
+ pub fn read_string(&mut self) -> Result<&'data [u8], ()> {
+ match memchr::memchr(b'\0', self.0) {
+ Some(null) => {
+ // These will never fail.
+ let bytes = self.read_bytes(null)?;
+ self.skip(1)?;
+ Ok(bytes.0)
+ }
+ None => {
+ self.0 = &[];
+ Err(())
+ }
+ }
+ }
+
+ /// Read a null terminated string at an offset.
+ ///
+ /// Does not assume any encoding. Does not return the null byte.
+ #[inline]
+ pub fn read_string_at(mut self, offset: usize) -> Result<&'data [u8], ()> {
+ self.skip(offset)?;
+ self.read_string()
+ }
+
+ /// Read an unsigned LEB128 number.
+ pub fn read_uleb128(&mut self) -> Result<u64, ()> {
+ let mut result = 0;
+ let mut shift = 0;
+
+ loop {
+ let byte = *self.read::<u8>()?;
+ if shift == 63 && byte != 0x00 && byte != 0x01 {
+ return Err(());
+ }
+ result |= u64::from(byte & 0x7f) << shift;
+ shift += 7;
+
+ if byte & 0x80 == 0 {
+ return Ok(result);
+ }
+ }
+ }
+
+ /// Read a signed LEB128 number.
+ pub fn read_sleb128(&mut self) -> Result<i64, ()> {
+ let mut result = 0;
+ let mut shift = 0;
+
+ loop {
+ let byte = *self.read::<u8>()?;
+ if shift == 63 && byte != 0x00 && byte != 0x7f {
+ return Err(());
+ }
+ result |= i64::from(byte & 0x7f) << shift;
+ shift += 7;
+
+ if byte & 0x80 == 0 {
+ if shift < 64 && (byte & 0x40) != 0 {
+ // Sign extend the result.
+ result |= !0 << shift;
+ }
+ return Ok(result);
+ }
+ }
+ }
+}
+
+// Only for Debug impl of `Bytes`.
+fn debug_list_bytes(bytes: &[u8], fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut list = fmt.debug_list();
+ list.entries(bytes.iter().take(8).copied().map(DebugByte));
+ if bytes.len() > 8 {
+ list.entry(&DebugLen(bytes.len()));
+ }
+ list.finish()
+}
+
+struct DebugByte(u8);
+
+impl fmt::Debug for DebugByte {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "0x{:02x}", self.0)
+ }
+}
+
+struct DebugLen(usize);
+
+impl fmt::Debug for DebugLen {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "...; {}", self.0)
+ }
+}
+
+/// A newtype for byte strings.
+///
+/// For byte slices that are strings of an unknown encoding.
+///
+/// Provides a `Debug` implementation that interprets the bytes as UTF-8.
+#[derive(Default, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct ByteString<'data>(pub &'data [u8]);
+
+impl<'data> fmt::Debug for ByteString<'data> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "\"{}\"", String::from_utf8_lossy(self.0))
+ }
+}
+
+#[allow(dead_code)]
+#[inline]
+pub(crate) fn align(offset: usize, size: usize) -> usize {
+ (offset + (size - 1)) & !(size - 1)
+}
+
+#[allow(dead_code)]
+pub(crate) fn data_range(
+ data: &[u8],
+ data_address: u64,
+ range_address: u64,
+ size: u64,
+) -> Option<&[u8]> {
+ let offset = range_address.checked_sub(data_address)?;
+ data.get(offset.try_into().ok()?..)?
+ .get(..size.try_into().ok()?)
+}
+
+/// A table of zero-terminated strings.
+///
+/// This is used for most file formats.
+#[derive(Debug, Clone, Copy)]
+pub struct StringTable<'data, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ data: Option<R>,
+ start: u64,
+ end: u64,
+ marker: PhantomData<&'data ()>,
+}
+
+impl<'data, R: ReadRef<'data>> StringTable<'data, R> {
+ /// Interpret the given data as a string table.
+ pub fn new(data: R, start: u64, end: u64) -> Self {
+ StringTable {
+ data: Some(data),
+ start,
+ end,
+ marker: PhantomData,
+ }
+ }
+
+ /// Return the string at the given offset.
+ pub fn get(&self, offset: u32) -> Result<&'data [u8], ()> {
+ match self.data {
+ Some(data) => {
+ let r_start = self.start.checked_add(offset.into()).ok_or(())?;
+ data.read_bytes_at_until(r_start..self.end, 0)
+ }
+ None => Err(()),
+ }
+ }
+}
+
+impl<'data, R: ReadRef<'data>> Default for StringTable<'data, R> {
+ fn default() -> Self {
+ StringTable {
+ data: None,
+ start: 0,
+ end: 0,
+ marker: PhantomData,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::pod::bytes_of;
+
+ #[test]
+ fn bytes() {
+ let x = u32::to_be(0x0123_4567);
+ let data = Bytes(bytes_of(&x));
+
+ let mut bytes = data;
+ assert_eq!(bytes.skip(0), Ok(()));
+ assert_eq!(bytes, data);
+
+ let mut bytes = data;
+ assert_eq!(bytes.skip(4), Ok(()));
+ assert_eq!(bytes, Bytes(&[]));
+
+ let mut bytes = data;
+ assert_eq!(bytes.skip(5), Err(()));
+ assert_eq!(bytes, Bytes(&[]));
+
+ let mut bytes = data;
+ assert_eq!(bytes.read_bytes(0), Ok(Bytes(&[])));
+ assert_eq!(bytes, data);
+
+ let mut bytes = data;
+ assert_eq!(bytes.read_bytes(4), Ok(data));
+ assert_eq!(bytes, Bytes(&[]));
+
+ let mut bytes = data;
+ assert_eq!(bytes.read_bytes(5), Err(()));
+ assert_eq!(bytes, Bytes(&[]));
+
+ assert_eq!(data.read_bytes_at(0, 0), Ok(Bytes(&[])));
+ assert_eq!(data.read_bytes_at(4, 0), Ok(Bytes(&[])));
+ assert_eq!(data.read_bytes_at(0, 4), Ok(data));
+ assert_eq!(data.read_bytes_at(1, 4), Err(()));
+
+ let mut bytes = data;
+ assert_eq!(bytes.read::<u16>(), Ok(&u16::to_be(0x0123)));
+ assert_eq!(bytes, Bytes(&[0x45, 0x67]));
+ assert_eq!(data.read_at::<u16>(2), Ok(&u16::to_be(0x4567)));
+ assert_eq!(data.read_at::<u16>(3), Err(()));
+ assert_eq!(data.read_at::<u16>(4), Err(()));
+
+ let mut bytes = data;
+ assert_eq!(bytes.read::<u32>(), Ok(&x));
+ assert_eq!(bytes, Bytes(&[]));
+
+ let mut bytes = data;
+ assert_eq!(bytes.read::<u64>(), Err(()));
+ assert_eq!(bytes, Bytes(&[]));
+
+ let mut bytes = data;
+ assert_eq!(bytes.read_slice::<u8>(0), Ok(&[][..]));
+ assert_eq!(bytes, data);
+
+ let mut bytes = data;
+ assert_eq!(bytes.read_slice::<u8>(4), Ok(data.0));
+ assert_eq!(bytes, Bytes(&[]));
+
+ let mut bytes = data;
+ assert_eq!(bytes.read_slice::<u8>(5), Err(()));
+ assert_eq!(bytes, Bytes(&[]));
+
+ assert_eq!(data.read_slice_at::<u8>(0, 0), Ok(&[][..]));
+ assert_eq!(data.read_slice_at::<u8>(4, 0), Ok(&[][..]));
+ assert_eq!(data.read_slice_at::<u8>(0, 4), Ok(data.0));
+ assert_eq!(data.read_slice_at::<u8>(1, 4), Err(()));
+
+ let data = Bytes(&[0x01, 0x02, 0x00, 0x04]);
+
+ let mut bytes = data;
+ assert_eq!(bytes.read_string(), Ok(&data.0[..2]));
+ assert_eq!(bytes.0, &data.0[3..]);
+
+ let mut bytes = data;
+ bytes.skip(3).unwrap();
+ assert_eq!(bytes.read_string(), Err(()));
+ assert_eq!(bytes.0, &[]);
+
+ assert_eq!(data.read_string_at(0), Ok(&data.0[..2]));
+ assert_eq!(data.read_string_at(1), Ok(&data.0[1..2]));
+ assert_eq!(data.read_string_at(2), Ok(&[][..]));
+ assert_eq!(data.read_string_at(3), Err(()));
+ }
+
+ #[test]
+ fn bytes_debug() {
+ assert_eq!(format!("{:?}", Bytes(&[])), "[]");
+ assert_eq!(format!("{:?}", Bytes(&[0x01])), "[0x01]");
+ assert_eq!(
+ format!(
+ "{:?}",
+ Bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08])
+ ),
+ "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]"
+ );
+ assert_eq!(
+ format!(
+ "{:?}",
+ Bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09])
+ ),
+ "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ...; 9]"
+ );
+ }
+}
diff --git a/third_party/rust/object/src/read/wasm.rs b/third_party/rust/object/src/read/wasm.rs
new file mode 100644
index 0000000000..b950ef2b2a
--- /dev/null
+++ b/third_party/rust/object/src/read/wasm.rs
@@ -0,0 +1,951 @@
+//! Support for reading Wasm files.
+//!
+//! Provides `WasmFile` and related types which implement the `Object` trait.
+//!
+//! Currently implements the minimum required to access DWARF debugging information.
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::marker::PhantomData;
+use core::ops::Range;
+use core::{slice, str};
+use wasmparser as wp;
+
+use crate::read::{
+ self, Architecture, ComdatKind, CompressedData, CompressedFileRange, Error, Export, FileFlags,
+ Import, NoDynamicRelocationIterator, Object, ObjectComdat, ObjectKind, ObjectSection,
+ ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Relocation, Result,
+ SectionFlags, SectionIndex, SectionKind, SegmentFlags, SymbolFlags, SymbolIndex, SymbolKind,
+ SymbolScope, SymbolSection,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(usize)]
+enum SectionId {
+ Custom = 0,
+ Type = 1,
+ Import = 2,
+ Function = 3,
+ Table = 4,
+ Memory = 5,
+ Global = 6,
+ Export = 7,
+ Start = 8,
+ Element = 9,
+ Code = 10,
+ Data = 11,
+ DataCount = 12,
+}
+// Update this constant when adding new section id:
+const MAX_SECTION_ID: usize = SectionId::DataCount as usize;
+
+/// A WebAssembly object file.
+#[derive(Debug)]
+pub struct WasmFile<'data, R = &'data [u8]> {
+ data: &'data [u8],
+ has_memory64: bool,
+ // All sections, including custom sections.
+ sections: Vec<SectionHeader<'data>>,
+ // Indices into `sections` of sections with a non-zero id.
+ id_sections: Box<[Option<usize>; MAX_SECTION_ID + 1]>,
+ // Whether the file has DWARF information.
+ has_debug_symbols: bool,
+ // Symbols collected from imports, exports, code and name sections.
+ symbols: Vec<WasmSymbolInternal<'data>>,
+ // Address of the function body for the entry point.
+ entry: u64,
+ marker: PhantomData<R>,
+}
+
+#[derive(Debug)]
+struct SectionHeader<'data> {
+ id: SectionId,
+ range: Range<usize>,
+ name: &'data str,
+}
+
+#[derive(Clone)]
+enum LocalFunctionKind {
+ Unknown,
+ Exported { symbol_ids: Vec<u32> },
+ Local { symbol_id: u32 },
+}
+
+impl<T> ReadError<T> for wasmparser::Result<T> {
+ fn read_error(self, error: &'static str) -> Result<T> {
+ self.map_err(|_| Error(error))
+ }
+}
+
+impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
+ /// Parse the raw wasm data.
+ pub fn parse(data: R) -> Result<Self> {
+ let len = data.len().read_error("Unknown Wasm file size")?;
+ let data = data.read_bytes_at(0, len).read_error("Wasm read failed")?;
+ let parser = wp::Parser::new(0).parse_all(data);
+
+ let mut file = WasmFile {
+ data,
+ has_memory64: false,
+ sections: Vec::new(),
+ id_sections: Default::default(),
+ has_debug_symbols: false,
+ symbols: Vec::new(),
+ entry: 0,
+ marker: PhantomData,
+ };
+
+ let mut main_file_symbol = Some(WasmSymbolInternal {
+ name: "",
+ address: 0,
+ size: 0,
+ kind: SymbolKind::File,
+ section: SymbolSection::None,
+ scope: SymbolScope::Compilation,
+ });
+
+ let mut imported_funcs_count = 0;
+ let mut local_func_kinds = Vec::new();
+ let mut entry_func_id = None;
+ let mut code_range_start = 0;
+ let mut code_func_index = 0;
+ // One-to-one mapping of globals to their value (if the global is a constant integer).
+ let mut global_values = Vec::new();
+
+ for payload in parser {
+ let payload = payload.read_error("Invalid Wasm section header")?;
+
+ match payload {
+ wp::Payload::TypeSection(section) => {
+ file.add_section(SectionId::Type, section.range(), "");
+ }
+ wp::Payload::ImportSection(section) => {
+ file.add_section(SectionId::Import, section.range(), "");
+ let mut last_module_name = None;
+
+ for import in section {
+ let import = import.read_error("Couldn't read an import item")?;
+ let module_name = import.module;
+
+ if last_module_name != Some(module_name) {
+ file.symbols.push(WasmSymbolInternal {
+ name: module_name,
+ address: 0,
+ size: 0,
+ kind: SymbolKind::File,
+ section: SymbolSection::None,
+ scope: SymbolScope::Dynamic,
+ });
+ last_module_name = Some(module_name);
+ }
+
+ let kind = match import.ty {
+ wp::TypeRef::Func(_) => {
+ imported_funcs_count += 1;
+ SymbolKind::Text
+ }
+ wp::TypeRef::Memory(memory) => {
+ file.has_memory64 |= memory.memory64;
+ SymbolKind::Data
+ }
+ wp::TypeRef::Table(_) | wp::TypeRef::Global(_) => SymbolKind::Data,
+ wp::TypeRef::Tag(_) => SymbolKind::Unknown,
+ };
+
+ file.symbols.push(WasmSymbolInternal {
+ name: import.name,
+ address: 0,
+ size: 0,
+ kind,
+ section: SymbolSection::Undefined,
+ scope: SymbolScope::Dynamic,
+ });
+ }
+ }
+ wp::Payload::FunctionSection(section) => {
+ file.add_section(SectionId::Function, section.range(), "");
+ local_func_kinds =
+ vec![LocalFunctionKind::Unknown; section.into_iter().count()];
+ }
+ wp::Payload::TableSection(section) => {
+ file.add_section(SectionId::Table, section.range(), "");
+ }
+ wp::Payload::MemorySection(section) => {
+ file.add_section(SectionId::Memory, section.range(), "");
+ for memory in section {
+ let memory = memory.read_error("Couldn't read a memory item")?;
+ file.has_memory64 |= memory.memory64;
+ }
+ }
+ wp::Payload::GlobalSection(section) => {
+ file.add_section(SectionId::Global, section.range(), "");
+ for global in section {
+ let global = global.read_error("Couldn't read a global item")?;
+ let mut address = None;
+ if !global.ty.mutable {
+ // There should be exactly one instruction.
+ let init = global.init_expr.get_operators_reader().read();
+ address = match init.read_error("Couldn't read a global init expr")? {
+ wp::Operator::I32Const { value } => Some(value as u64),
+ wp::Operator::I64Const { value } => Some(value as u64),
+ _ => None,
+ };
+ }
+ global_values.push(address);
+ }
+ }
+ wp::Payload::ExportSection(section) => {
+ file.add_section(SectionId::Export, section.range(), "");
+ if let Some(main_file_symbol) = main_file_symbol.take() {
+ file.symbols.push(main_file_symbol);
+ }
+
+ for export in section {
+ let export = export.read_error("Couldn't read an export item")?;
+
+ let (kind, section_idx) = match export.kind {
+ wp::ExternalKind::Func => {
+ if let Some(local_func_id) =
+ export.index.checked_sub(imported_funcs_count)
+ {
+ let local_func_kind =
+ &mut local_func_kinds[local_func_id as usize];
+ if let LocalFunctionKind::Unknown = local_func_kind {
+ *local_func_kind = LocalFunctionKind::Exported {
+ symbol_ids: Vec::new(),
+ };
+ }
+ let symbol_ids = match local_func_kind {
+ LocalFunctionKind::Exported { symbol_ids } => symbol_ids,
+ _ => unreachable!(),
+ };
+ symbol_ids.push(file.symbols.len() as u32);
+ }
+ (SymbolKind::Text, SectionId::Code)
+ }
+ wp::ExternalKind::Table
+ | wp::ExternalKind::Memory
+ | wp::ExternalKind::Global => (SymbolKind::Data, SectionId::Data),
+ // TODO
+ wp::ExternalKind::Tag => continue,
+ };
+
+ // Try to guess the symbol address. Rust and C export a global containing
+ // the address in linear memory of the symbol.
+ let mut address = 0;
+ if export.kind == wp::ExternalKind::Global {
+ if let Some(&Some(x)) = global_values.get(export.index as usize) {
+ address = x;
+ }
+ }
+
+ file.symbols.push(WasmSymbolInternal {
+ name: export.name,
+ address,
+ size: 0,
+ kind,
+ section: SymbolSection::Section(SectionIndex(section_idx as usize)),
+ scope: SymbolScope::Dynamic,
+ });
+ }
+ }
+ wp::Payload::StartSection { func, range, .. } => {
+ file.add_section(SectionId::Start, range, "");
+ entry_func_id = Some(func);
+ }
+ wp::Payload::ElementSection(section) => {
+ file.add_section(SectionId::Element, section.range(), "");
+ }
+ wp::Payload::CodeSectionStart { range, .. } => {
+ code_range_start = range.start;
+ file.add_section(SectionId::Code, range, "");
+ if let Some(main_file_symbol) = main_file_symbol.take() {
+ file.symbols.push(main_file_symbol);
+ }
+ }
+ wp::Payload::CodeSectionEntry(body) => {
+ let i = code_func_index;
+ code_func_index += 1;
+
+ let range = body.range();
+
+ let address = range.start as u64 - code_range_start as u64;
+ let size = (range.end - range.start) as u64;
+
+ if entry_func_id == Some(i as u32) {
+ file.entry = address;
+ }
+
+ let local_func_kind = &mut local_func_kinds[i];
+ match local_func_kind {
+ LocalFunctionKind::Unknown => {
+ *local_func_kind = LocalFunctionKind::Local {
+ symbol_id: file.symbols.len() as u32,
+ };
+ file.symbols.push(WasmSymbolInternal {
+ name: "",
+ address,
+ size,
+ kind: SymbolKind::Text,
+ section: SymbolSection::Section(SectionIndex(
+ SectionId::Code as usize,
+ )),
+ scope: SymbolScope::Compilation,
+ });
+ }
+ LocalFunctionKind::Exported { symbol_ids } => {
+ for symbol_id in core::mem::take(symbol_ids) {
+ let export_symbol = &mut file.symbols[symbol_id as usize];
+ export_symbol.address = address;
+ export_symbol.size = size;
+ }
+ }
+ _ => unreachable!(),
+ }
+ }
+ wp::Payload::DataSection(section) => {
+ file.add_section(SectionId::Data, section.range(), "");
+ }
+ wp::Payload::DataCountSection { range, .. } => {
+ file.add_section(SectionId::DataCount, range, "");
+ }
+ wp::Payload::CustomSection(section) => {
+ let name = section.name();
+ let size = section.data().len();
+ let mut range = section.range();
+ range.start = range.end - size;
+ file.add_section(SectionId::Custom, range, name);
+ if name == "name" {
+ for name in
+ wp::NameSectionReader::new(section.data(), section.data_offset())
+ {
+ // TODO: Right now, ill-formed name subsections
+ // are silently ignored in order to maintain
+ // compatibility with extended name sections, which
+ // are not yet supported by the version of
+ // `wasmparser` currently used.
+ // A better fix would be to update `wasmparser` to
+ // the newest version, but this requires
+ // a major rewrite of this file.
+ if let Ok(wp::Name::Function(name_map)) = name {
+ for naming in name_map {
+ let naming =
+ naming.read_error("Couldn't read a function name")?;
+ if let Some(local_index) =
+ naming.index.checked_sub(imported_funcs_count)
+ {
+ if let LocalFunctionKind::Local { symbol_id } =
+ local_func_kinds[local_index as usize]
+ {
+ file.symbols[symbol_id as usize].name = naming.name;
+ }
+ }
+ }
+ }
+ }
+ } else if name.starts_with(".debug_") {
+ file.has_debug_symbols = true;
+ }
+ }
+ _ => {}
+ }
+ }
+
+ Ok(file)
+ }
+
+ fn add_section(&mut self, id: SectionId, range: Range<usize>, name: &'data str) {
+ let section = SectionHeader { id, range, name };
+ self.id_sections[id as usize] = Some(self.sections.len());
+ self.sections.push(section);
+ }
+}
+
+impl<'data, R> read::private::Sealed for WasmFile<'data, R> {}
+
+impl<'data, 'file, R: ReadRef<'data>> Object<'data, 'file> for WasmFile<'data, R>
+where
+ 'data: 'file,
+ R: 'file,
+{
+ type Segment = WasmSegment<'data, 'file, R>;
+ type SegmentIterator = WasmSegmentIterator<'data, 'file, R>;
+ type Section = WasmSection<'data, 'file, R>;
+ type SectionIterator = WasmSectionIterator<'data, 'file, R>;
+ type Comdat = WasmComdat<'data, 'file, R>;
+ type ComdatIterator = WasmComdatIterator<'data, 'file, R>;
+ type Symbol = WasmSymbol<'data, 'file>;
+ type SymbolIterator = WasmSymbolIterator<'data, 'file>;
+ type SymbolTable = WasmSymbolTable<'data, 'file>;
+ type DynamicRelocationIterator = NoDynamicRelocationIterator;
+
+ #[inline]
+ fn architecture(&self) -> Architecture {
+ if self.has_memory64 {
+ Architecture::Wasm64
+ } else {
+ Architecture::Wasm32
+ }
+ }
+
+ #[inline]
+ fn is_little_endian(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn is_64(&self) -> bool {
+ self.has_memory64
+ }
+
+ fn kind(&self) -> ObjectKind {
+ // TODO: check for `linking` custom section
+ ObjectKind::Unknown
+ }
+
+ fn segments(&'file self) -> Self::SegmentIterator {
+ WasmSegmentIterator { file: self }
+ }
+
+ fn section_by_name_bytes(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<WasmSection<'data, 'file, R>> {
+ self.sections()
+ .find(|section| section.name_bytes() == Ok(section_name))
+ }
+
+ fn section_by_index(&'file self, index: SectionIndex) -> Result<WasmSection<'data, 'file, R>> {
+ // TODO: Missing sections should return an empty section.
+ let id_section = self
+ .id_sections
+ .get(index.0)
+ .and_then(|x| *x)
+ .read_error("Invalid Wasm section index")?;
+ let section = self.sections.get(id_section).unwrap();
+ Ok(WasmSection {
+ file: self,
+ section,
+ })
+ }
+
+ fn sections(&'file self) -> Self::SectionIterator {
+ WasmSectionIterator {
+ file: self,
+ sections: self.sections.iter(),
+ }
+ }
+
+ fn comdats(&'file self) -> Self::ComdatIterator {
+ WasmComdatIterator { file: self }
+ }
+
+ #[inline]
+ fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<WasmSymbol<'data, 'file>> {
+ let symbol = self
+ .symbols
+ .get(index.0)
+ .read_error("Invalid Wasm symbol index")?;
+ Ok(WasmSymbol { index, symbol })
+ }
+
+ fn symbols(&'file self) -> Self::SymbolIterator {
+ WasmSymbolIterator {
+ symbols: self.symbols.iter().enumerate(),
+ }
+ }
+
+ fn symbol_table(&'file self) -> Option<WasmSymbolTable<'data, 'file>> {
+ Some(WasmSymbolTable {
+ symbols: &self.symbols,
+ })
+ }
+
+ fn dynamic_symbols(&'file self) -> Self::SymbolIterator {
+ WasmSymbolIterator {
+ symbols: [].iter().enumerate(),
+ }
+ }
+
+ #[inline]
+ fn dynamic_symbol_table(&'file self) -> Option<WasmSymbolTable<'data, 'file>> {
+ None
+ }
+
+ #[inline]
+ fn dynamic_relocations(&self) -> Option<NoDynamicRelocationIterator> {
+ None
+ }
+
+ fn imports(&self) -> Result<Vec<Import<'data>>> {
+ // TODO: return entries in the import section
+ Ok(Vec::new())
+ }
+
+ fn exports(&self) -> Result<Vec<Export<'data>>> {
+ // TODO: return entries in the export section
+ Ok(Vec::new())
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ self.has_debug_symbols
+ }
+
+ fn relative_address_base(&self) -> u64 {
+ 0
+ }
+
+ #[inline]
+ fn entry(&'file self) -> u64 {
+ self.entry
+ }
+
+ #[inline]
+ fn flags(&self) -> FileFlags {
+ FileFlags::None
+ }
+}
+
+/// An iterator over the segments of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSegmentIterator<'data, 'file, R = &'data [u8]> {
+ #[allow(unused)]
+ file: &'file WasmFile<'data, R>,
+}
+
+impl<'data, 'file, R> Iterator for WasmSegmentIterator<'data, 'file, R> {
+ type Item = WasmSegment<'data, 'file, R>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A segment of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSegment<'data, 'file, R = &'data [u8]> {
+ #[allow(unused)]
+ file: &'file WasmFile<'data, R>,
+}
+
+impl<'data, 'file, R> read::private::Sealed for WasmSegment<'data, 'file, R> {}
+
+impl<'data, 'file, R> ObjectSegment<'data> for WasmSegment<'data, 'file, R> {
+ #[inline]
+ fn address(&self) -> u64 {
+ unreachable!()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ unreachable!()
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ unreachable!()
+ }
+
+ #[inline]
+ fn file_range(&self) -> (u64, u64) {
+ unreachable!()
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ unreachable!()
+ }
+
+ fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> {
+ unreachable!()
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<Option<&[u8]>> {
+ unreachable!()
+ }
+
+ #[inline]
+ fn name(&self) -> Result<Option<&str>> {
+ unreachable!()
+ }
+
+ #[inline]
+ fn flags(&self) -> SegmentFlags {
+ unreachable!()
+ }
+}
+
+/// An iterator over the sections of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSectionIterator<'data, 'file, R = &'data [u8]> {
+ file: &'file WasmFile<'data, R>,
+ sections: slice::Iter<'file, SectionHeader<'data>>,
+}
+
+impl<'data, 'file, R> Iterator for WasmSectionIterator<'data, 'file, R> {
+ type Item = WasmSection<'data, 'file, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let section = self.sections.next()?;
+ Some(WasmSection {
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A section of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSection<'data, 'file, R = &'data [u8]> {
+ file: &'file WasmFile<'data, R>,
+ section: &'file SectionHeader<'data>,
+}
+
+impl<'data, 'file, R> read::private::Sealed for WasmSection<'data, 'file, R> {}
+
+impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for WasmSection<'data, 'file, R> {
+ type RelocationIterator = WasmRelocationIterator<'data, 'file, R>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ // Note that we treat all custom sections as index 0.
+ // This is ok because they are never looked up by index.
+ SectionIndex(self.section.id as usize)
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ 0
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ let range = &self.section.range;
+ (range.end - range.start) as u64
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ 1
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ let range = &self.section.range;
+ Some((range.start as _, range.end as _))
+ }
+
+ #[inline]
+ fn data(&self) -> Result<&'data [u8]> {
+ let range = &self.section.range;
+ self.file
+ .data
+ .read_bytes_at(range.start as u64, range.end as u64 - range.start as u64)
+ .read_error("Invalid Wasm section size or offset")
+ }
+
+ fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> {
+ unimplemented!()
+ }
+
+ #[inline]
+ fn compressed_file_range(&self) -> Result<CompressedFileRange> {
+ Ok(CompressedFileRange::none(self.file_range()))
+ }
+
+ #[inline]
+ fn compressed_data(&self) -> Result<CompressedData<'data>> {
+ self.data().map(CompressedData::none)
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ self.name().map(str::as_bytes)
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ Ok(match self.section.id {
+ SectionId::Custom => self.section.name,
+ SectionId::Type => "<type>",
+ SectionId::Import => "<import>",
+ SectionId::Function => "<function>",
+ SectionId::Table => "<table>",
+ SectionId::Memory => "<memory>",
+ SectionId::Global => "<global>",
+ SectionId::Export => "<export>",
+ SectionId::Start => "<start>",
+ SectionId::Element => "<element>",
+ SectionId::Code => "<code>",
+ SectionId::Data => "<data>",
+ SectionId::DataCount => "<data_count>",
+ })
+ }
+
+ #[inline]
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn segment_name(&self) -> Result<Option<&str>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn kind(&self) -> SectionKind {
+ match self.section.id {
+ SectionId::Custom => match self.section.name {
+ "reloc." | "linking" => SectionKind::Linker,
+ _ => SectionKind::Other,
+ },
+ SectionId::Type => SectionKind::Metadata,
+ SectionId::Import => SectionKind::Linker,
+ SectionId::Function => SectionKind::Metadata,
+ SectionId::Table => SectionKind::UninitializedData,
+ SectionId::Memory => SectionKind::UninitializedData,
+ SectionId::Global => SectionKind::Data,
+ SectionId::Export => SectionKind::Linker,
+ SectionId::Start => SectionKind::Linker,
+ SectionId::Element => SectionKind::Data,
+ SectionId::Code => SectionKind::Text,
+ SectionId::Data => SectionKind::Data,
+ SectionId::DataCount => SectionKind::UninitializedData,
+ }
+ }
+
+ #[inline]
+ fn relocations(&self) -> WasmRelocationIterator<'data, 'file, R> {
+ WasmRelocationIterator(PhantomData)
+ }
+
+ #[inline]
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::None
+ }
+}
+
+/// An iterator over the COMDAT section groups of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmComdatIterator<'data, 'file, R = &'data [u8]> {
+ #[allow(unused)]
+ file: &'file WasmFile<'data, R>,
+}
+
+impl<'data, 'file, R> Iterator for WasmComdatIterator<'data, 'file, R> {
+ type Item = WasmComdat<'data, 'file, R>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A COMDAT section group of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmComdat<'data, 'file, R = &'data [u8]> {
+ #[allow(unused)]
+ file: &'file WasmFile<'data, R>,
+}
+
+impl<'data, 'file, R> read::private::Sealed for WasmComdat<'data, 'file, R> {}
+
+impl<'data, 'file, R> ObjectComdat<'data> for WasmComdat<'data, 'file, R> {
+ type SectionIterator = WasmComdatSectionIterator<'data, 'file, R>;
+
+ #[inline]
+ fn kind(&self) -> ComdatKind {
+ unreachable!();
+ }
+
+ #[inline]
+ fn symbol(&self) -> SymbolIndex {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn sections(&self) -> Self::SectionIterator {
+ unreachable!();
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmComdatSectionIterator<'data, 'file, R = &'data [u8]> {
+ #[allow(unused)]
+ file: &'file WasmFile<'data, R>,
+}
+
+impl<'data, 'file, R> Iterator for WasmComdatSectionIterator<'data, 'file, R> {
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A symbol table of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSymbolTable<'data, 'file> {
+ symbols: &'file [WasmSymbolInternal<'data>],
+}
+
+impl<'data, 'file> read::private::Sealed for WasmSymbolTable<'data, 'file> {}
+
+impl<'data, 'file> ObjectSymbolTable<'data> for WasmSymbolTable<'data, 'file> {
+ type Symbol = WasmSymbol<'data, 'file>;
+ type SymbolIterator = WasmSymbolIterator<'data, 'file>;
+
+ fn symbols(&self) -> Self::SymbolIterator {
+ WasmSymbolIterator {
+ symbols: self.symbols.iter().enumerate(),
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> {
+ let symbol = self
+ .symbols
+ .get(index.0)
+ .read_error("Invalid Wasm symbol index")?;
+ Ok(WasmSymbol { index, symbol })
+ }
+}
+
+/// An iterator over the symbols of a `WasmFile`.
+#[derive(Debug)]
+pub struct WasmSymbolIterator<'data, 'file> {
+ symbols: core::iter::Enumerate<slice::Iter<'file, WasmSymbolInternal<'data>>>,
+}
+
+impl<'data, 'file> Iterator for WasmSymbolIterator<'data, 'file> {
+ type Item = WasmSymbol<'data, 'file>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let (index, symbol) = self.symbols.next()?;
+ Some(WasmSymbol {
+ index: SymbolIndex(index),
+ symbol,
+ })
+ }
+}
+
+/// A symbol of a `WasmFile`.
+#[derive(Clone, Copy, Debug)]
+pub struct WasmSymbol<'data, 'file> {
+ index: SymbolIndex,
+ symbol: &'file WasmSymbolInternal<'data>,
+}
+
+#[derive(Clone, Debug)]
+struct WasmSymbolInternal<'data> {
+ name: &'data str,
+ address: u64,
+ size: u64,
+ kind: SymbolKind,
+ section: SymbolSection,
+ scope: SymbolScope,
+}
+
+impl<'data, 'file> read::private::Sealed for WasmSymbol<'data, 'file> {}
+
+impl<'data, 'file> ObjectSymbol<'data> for WasmSymbol<'data, 'file> {
+ #[inline]
+ fn index(&self) -> SymbolIndex {
+ self.index
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> read::Result<&'data [u8]> {
+ Ok(self.symbol.name.as_bytes())
+ }
+
+ #[inline]
+ fn name(&self) -> read::Result<&'data str> {
+ Ok(self.symbol.name)
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.symbol.address
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.symbol.size
+ }
+
+ #[inline]
+ fn kind(&self) -> SymbolKind {
+ self.symbol.kind
+ }
+
+ #[inline]
+ fn section(&self) -> SymbolSection {
+ self.symbol.section
+ }
+
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ self.symbol.section == SymbolSection::Undefined
+ }
+
+ #[inline]
+ fn is_definition(&self) -> bool {
+ self.symbol.kind == SymbolKind::Text && self.symbol.section != SymbolSection::Undefined
+ }
+
+ #[inline]
+ fn is_common(&self) -> bool {
+ self.symbol.section == SymbolSection::Common
+ }
+
+ #[inline]
+ fn is_weak(&self) -> bool {
+ false
+ }
+
+ #[inline]
+ fn scope(&self) -> SymbolScope {
+ self.symbol.scope
+ }
+
+ #[inline]
+ fn is_global(&self) -> bool {
+ self.symbol.scope != SymbolScope::Compilation
+ }
+
+ #[inline]
+ fn is_local(&self) -> bool {
+ self.symbol.scope == SymbolScope::Compilation
+ }
+
+ #[inline]
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
+ SymbolFlags::None
+ }
+}
+
+/// An iterator over the relocations in a `WasmSection`.
+#[derive(Debug)]
+pub struct WasmRelocationIterator<'data, 'file, R = &'data [u8]>(
+ PhantomData<(&'data (), &'file (), R)>,
+);
+
+impl<'data, 'file, R> Iterator for WasmRelocationIterator<'data, 'file, R> {
+ type Item = (u64, Relocation);
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/comdat.rs b/third_party/rust/object/src/read/xcoff/comdat.rs
new file mode 100644
index 0000000000..2b23d1dba8
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/comdat.rs
@@ -0,0 +1,129 @@
+//! XCOFF doesn't support the COMDAT section.
+
+use core::fmt::Debug;
+
+use crate::xcoff;
+
+use crate::read::{self, ComdatKind, ObjectComdat, ReadRef, Result, SectionIndex, SymbolIndex};
+
+use super::{FileHeader, XcoffFile};
+
+/// An iterator over the COMDAT section groups of a `XcoffFile32`.
+pub type XcoffComdatIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffComdatIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the COMDAT section groups of a `XcoffFile64`.
+pub type XcoffComdatIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffComdatIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the COMDAT section groups of a `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffComdatIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffComdatIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = XcoffComdat<'data, 'file, Xcoff, R>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A COMDAT section group of a `XcoffFile32`.
+pub type XcoffComdat32<'data, 'file, R = &'data [u8]> =
+ XcoffComdat<'data, 'file, xcoff::FileHeader32, R>;
+
+/// A COMDAT section group of a `XcoffFile64`.
+pub type XcoffComdat64<'data, 'file, R = &'data [u8]> =
+ XcoffComdat<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A COMDAT section group of a `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffComdat<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffComdat<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> ObjectComdat<'data> for XcoffComdat<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type SectionIterator = XcoffComdatSectionIterator<'data, 'file, Xcoff, R>;
+
+ #[inline]
+ fn kind(&self) -> ComdatKind {
+ unreachable!();
+ }
+
+ #[inline]
+ fn symbol(&self) -> SymbolIndex {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name_bytes(&self) -> Result<&[u8]> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn sections(&self) -> Self::SectionIterator {
+ unreachable!();
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of a `XcoffFile32`.
+pub type XcoffComdatSectionIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the sections in a COMDAT section group of a `XcoffFile64`.
+pub type XcoffComdatSectionIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the sections in a COMDAT section group of a `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffComdatSectionIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffComdatSectionIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = SectionIndex;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/file.rs b/third_party/rust/object/src/read/xcoff/file.rs
new file mode 100644
index 0000000000..bac9e70756
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/file.rs
@@ -0,0 +1,629 @@
+use core::fmt::Debug;
+use core::mem;
+
+use alloc::vec::Vec;
+
+use crate::read::{self, Error, NoDynamicRelocationIterator, Object, ReadError, ReadRef, Result};
+
+use crate::{
+ xcoff, Architecture, BigEndian as BE, FileFlags, ObjectKind, ObjectSection, Pod, SectionIndex,
+ SymbolIndex,
+};
+
+use super::{
+ CsectAux, FileAux, SectionHeader, SectionTable, Symbol, SymbolTable, XcoffComdat,
+ XcoffComdatIterator, XcoffSection, XcoffSectionIterator, XcoffSegment, XcoffSegmentIterator,
+ XcoffSymbol, XcoffSymbolIterator, XcoffSymbolTable,
+};
+
+/// A 32-bit XCOFF object file.
+pub type XcoffFile32<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader32, R>;
+/// A 64-bit XCOFF object file.
+pub type XcoffFile64<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader64, R>;
+
+/// A partially parsed XCOFF file.
+///
+/// Most of the functionality of this type is provided by the `Object` trait implementation.
+#[derive(Debug)]
+pub struct XcoffFile<'data, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) data: R,
+ pub(super) header: &'data Xcoff,
+ pub(super) aux_header: Option<&'data Xcoff::AuxHeader>,
+ pub(super) sections: SectionTable<'data, Xcoff>,
+ pub(super) symbols: SymbolTable<'data, Xcoff, R>,
+}
+
+impl<'data, Xcoff, R> XcoffFile<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ /// Parse the raw XCOFF file data.
+ pub fn parse(data: R) -> Result<Self> {
+ let mut offset = 0;
+ let header = Xcoff::parse(data, &mut offset)?;
+ let aux_header = header.aux_header(data, &mut offset)?;
+ let sections = header.sections(data, &mut offset)?;
+ let symbols = header.symbols(data)?;
+
+ Ok(XcoffFile {
+ data,
+ header,
+ aux_header,
+ sections,
+ symbols,
+ })
+ }
+
+ /// Returns the raw data.
+ pub fn data(&self) -> R {
+ self.data
+ }
+
+ /// Returns the raw XCOFF file header.
+ pub fn raw_header(&self) -> &'data Xcoff {
+ self.header
+ }
+}
+
+impl<'data, Xcoff, R> read::private::Sealed for XcoffFile<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> Object<'data, 'file> for XcoffFile<'data, Xcoff, R>
+where
+ 'data: 'file,
+ Xcoff: FileHeader,
+ R: 'file + ReadRef<'data>,
+{
+ type Segment = XcoffSegment<'data, 'file, Xcoff, R>;
+ type SegmentIterator = XcoffSegmentIterator<'data, 'file, Xcoff, R>;
+ type Section = XcoffSection<'data, 'file, Xcoff, R>;
+ type SectionIterator = XcoffSectionIterator<'data, 'file, Xcoff, R>;
+ type Comdat = XcoffComdat<'data, 'file, Xcoff, R>;
+ type ComdatIterator = XcoffComdatIterator<'data, 'file, Xcoff, R>;
+ type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>;
+ type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>;
+ type SymbolTable = XcoffSymbolTable<'data, 'file, Xcoff, R>;
+ type DynamicRelocationIterator = NoDynamicRelocationIterator;
+
+ fn architecture(&self) -> crate::Architecture {
+ if self.is_64() {
+ Architecture::PowerPc64
+ } else {
+ Architecture::PowerPc
+ }
+ }
+
+ fn is_little_endian(&self) -> bool {
+ false
+ }
+
+ fn is_64(&self) -> bool {
+ self.header.is_type_64()
+ }
+
+ fn kind(&self) -> ObjectKind {
+ let flags = self.header.f_flags();
+ if flags & xcoff::F_EXEC != 0 {
+ ObjectKind::Executable
+ } else if flags & xcoff::F_SHROBJ != 0 {
+ ObjectKind::Dynamic
+ } else if flags & xcoff::F_RELFLG == 0 {
+ ObjectKind::Relocatable
+ } else {
+ ObjectKind::Unknown
+ }
+ }
+
+ fn segments(&'file self) -> XcoffSegmentIterator<'data, 'file, Xcoff, R> {
+ XcoffSegmentIterator { file: self }
+ }
+
+ fn section_by_name_bytes(
+ &'file self,
+ section_name: &[u8],
+ ) -> Option<XcoffSection<'data, 'file, Xcoff, R>> {
+ self.sections()
+ .find(|section| section.name_bytes() == Ok(section_name))
+ }
+
+ fn section_by_index(
+ &'file self,
+ index: SectionIndex,
+ ) -> Result<XcoffSection<'data, 'file, Xcoff, R>> {
+ let section = self.sections.section(index)?;
+ Ok(XcoffSection {
+ file: self,
+ section,
+ index,
+ })
+ }
+
+ fn sections(&'file self) -> XcoffSectionIterator<'data, 'file, Xcoff, R> {
+ XcoffSectionIterator {
+ file: self,
+ iter: self.sections.iter().enumerate(),
+ }
+ }
+
+ fn comdats(&'file self) -> XcoffComdatIterator<'data, 'file, Xcoff, R> {
+ XcoffComdatIterator { file: self }
+ }
+
+ fn symbol_table(&'file self) -> Option<XcoffSymbolTable<'data, 'file, Xcoff, R>> {
+ if self.symbols.is_empty() {
+ return None;
+ }
+ Some(XcoffSymbolTable {
+ symbols: &self.symbols,
+ file: self,
+ })
+ }
+
+ fn symbol_by_index(
+ &'file self,
+ index: SymbolIndex,
+ ) -> Result<XcoffSymbol<'data, 'file, Xcoff, R>> {
+ let symbol = self.symbols.symbol(index.0)?;
+ Ok(XcoffSymbol {
+ symbols: &self.symbols,
+ index,
+ symbol,
+ file: self,
+ })
+ }
+
+ fn symbols(&'file self) -> XcoffSymbolIterator<'data, 'file, Xcoff, R> {
+ XcoffSymbolIterator {
+ symbols: &self.symbols,
+ index: 0,
+ file: self,
+ }
+ }
+
+ fn dynamic_symbol_table(&'file self) -> Option<XcoffSymbolTable<'data, 'file, Xcoff, R>> {
+ None
+ }
+
+ fn dynamic_symbols(&'file self) -> XcoffSymbolIterator<'data, 'file, Xcoff, R> {
+ // TODO: return the symbols in the STYP_LOADER section.
+ XcoffSymbolIterator {
+ file: self,
+ symbols: &self.symbols,
+ // Hack: don't return any.
+ index: self.symbols.len(),
+ }
+ }
+
+ fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator> {
+ // TODO: return the relocations in the STYP_LOADER section.
+ None
+ }
+
+ fn imports(&self) -> Result<alloc::vec::Vec<crate::Import<'data>>> {
+ // TODO: return the imports in the STYP_LOADER section.
+ Ok(Vec::new())
+ }
+
+ fn exports(&self) -> Result<alloc::vec::Vec<crate::Export<'data>>> {
+ // TODO: return the exports in the STYP_LOADER section.
+ Ok(Vec::new())
+ }
+
+ fn has_debug_symbols(&self) -> bool {
+ self.section_by_name(".debug").is_some() || self.section_by_name(".dwinfo").is_some()
+ }
+
+ fn relative_address_base(&'file self) -> u64 {
+ 0
+ }
+
+ fn entry(&'file self) -> u64 {
+ if let Some(aux_header) = self.aux_header {
+ aux_header.o_entry().into()
+ } else {
+ 0
+ }
+ }
+
+ fn flags(&self) -> FileFlags {
+ FileFlags::Xcoff {
+ f_flags: self.header.f_flags(),
+ }
+ }
+}
+
+/// A trait for generic access to `FileHeader32` and `FileHeader64`.
+#[allow(missing_docs)]
+pub trait FileHeader: Debug + Pod {
+ type Word: Into<u64>;
+ type AuxHeader: AuxHeader<Word = Self::Word>;
+ type SectionHeader: SectionHeader<Word = Self::Word>;
+ type Symbol: Symbol<Word = Self::Word>;
+ type FileAux: FileAux;
+ type CsectAux: CsectAux;
+
+ /// Return true if this type is a 64-bit header.
+ fn is_type_64(&self) -> bool;
+
+ fn f_magic(&self) -> u16;
+ fn f_nscns(&self) -> u16;
+ fn f_timdat(&self) -> u32;
+ fn f_symptr(&self) -> Self::Word;
+ fn f_nsyms(&self) -> u32;
+ fn f_opthdr(&self) -> u16;
+ fn f_flags(&self) -> u16;
+
+ // Provided methods.
+
+ /// Read the file header.
+ ///
+ /// Also checks that the magic field in the file header is a supported format.
+ fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> Result<&'data Self> {
+ let header = data
+ .read::<Self>(offset)
+ .read_error("Invalid XCOFF header size or alignment")?;
+ if !header.is_supported() {
+ return Err(Error("Unsupported XCOFF header"));
+ }
+ Ok(header)
+ }
+
+ fn is_supported(&self) -> bool {
+ (self.is_type_64() && self.f_magic() == xcoff::MAGIC_64)
+ || (!self.is_type_64() && self.f_magic() == xcoff::MAGIC_32)
+ }
+
+ /// Read the auxiliary file header.
+ fn aux_header<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: &mut u64,
+ ) -> Result<Option<&'data Self::AuxHeader>> {
+ let aux_header_size = self.f_opthdr();
+ if self.f_flags() & xcoff::F_EXEC == 0 {
+ // No auxiliary header is required for an object file that is not an executable.
+ // TODO: Some AIX programs generate auxiliary headers for 32-bit object files
+ // that end after the data_start field.
+ *offset += u64::from(aux_header_size);
+ return Ok(None);
+ }
+ // Executables, however, must have auxiliary headers that include the
+ // full structure definitions.
+ if aux_header_size != mem::size_of::<Self::AuxHeader>() as u16 {
+ *offset += u64::from(aux_header_size);
+ return Ok(None);
+ }
+ let aux_header = data
+ .read::<Self::AuxHeader>(offset)
+ .read_error("Invalid XCOFF auxiliary header size")?;
+ Ok(Some(aux_header))
+ }
+
+ /// Read the section table.
+ #[inline]
+ fn sections<'data, R: ReadRef<'data>>(
+ &self,
+ data: R,
+ offset: &mut u64,
+ ) -> Result<SectionTable<'data, Self>> {
+ SectionTable::parse(self, data, offset)
+ }
+
+ /// Return the symbol table.
+ #[inline]
+ fn symbols<'data, R: ReadRef<'data>>(&self, data: R) -> Result<SymbolTable<'data, Self, R>> {
+ SymbolTable::parse(*self, data)
+ }
+}
+
+impl FileHeader for xcoff::FileHeader32 {
+ type Word = u32;
+ type AuxHeader = xcoff::AuxHeader32;
+ type SectionHeader = xcoff::SectionHeader32;
+ type Symbol = xcoff::Symbol32;
+ type FileAux = xcoff::FileAux32;
+ type CsectAux = xcoff::CsectAux32;
+
+ fn is_type_64(&self) -> bool {
+ false
+ }
+
+ fn f_magic(&self) -> u16 {
+ self.f_magic.get(BE)
+ }
+
+ fn f_nscns(&self) -> u16 {
+ self.f_nscns.get(BE)
+ }
+
+ fn f_timdat(&self) -> u32 {
+ self.f_timdat.get(BE)
+ }
+
+ fn f_symptr(&self) -> Self::Word {
+ self.f_symptr.get(BE)
+ }
+
+ fn f_nsyms(&self) -> u32 {
+ self.f_nsyms.get(BE)
+ }
+
+ fn f_opthdr(&self) -> u16 {
+ self.f_opthdr.get(BE)
+ }
+
+ fn f_flags(&self) -> u16 {
+ self.f_flags.get(BE)
+ }
+}
+
+impl FileHeader for xcoff::FileHeader64 {
+ type Word = u64;
+ type AuxHeader = xcoff::AuxHeader64;
+ type SectionHeader = xcoff::SectionHeader64;
+ type Symbol = xcoff::Symbol64;
+ type FileAux = xcoff::FileAux64;
+ type CsectAux = xcoff::CsectAux64;
+
+ fn is_type_64(&self) -> bool {
+ true
+ }
+
+ fn f_magic(&self) -> u16 {
+ self.f_magic.get(BE)
+ }
+
+ fn f_nscns(&self) -> u16 {
+ self.f_nscns.get(BE)
+ }
+
+ fn f_timdat(&self) -> u32 {
+ self.f_timdat.get(BE)
+ }
+
+ fn f_symptr(&self) -> Self::Word {
+ self.f_symptr.get(BE)
+ }
+
+ fn f_nsyms(&self) -> u32 {
+ self.f_nsyms.get(BE)
+ }
+
+ fn f_opthdr(&self) -> u16 {
+ self.f_opthdr.get(BE)
+ }
+
+ fn f_flags(&self) -> u16 {
+ self.f_flags.get(BE)
+ }
+}
+
+#[allow(missing_docs)]
+pub trait AuxHeader: Debug + Pod {
+ type Word: Into<u64>;
+
+ fn o_vstamp(&self) -> u16;
+ fn o_tsize(&self) -> Self::Word;
+ fn o_dsize(&self) -> Self::Word;
+ fn o_bsize(&self) -> Self::Word;
+ fn o_entry(&self) -> Self::Word;
+ fn o_text_start(&self) -> Self::Word;
+ fn o_data_start(&self) -> Self::Word;
+ fn o_toc(&self) -> Self::Word;
+ fn o_snentry(&self) -> u16;
+ fn o_sntext(&self) -> u16;
+ fn o_sndata(&self) -> u16;
+ fn o_sntoc(&self) -> u16;
+ fn o_snloader(&self) -> u16;
+ fn o_snbss(&self) -> u16;
+ fn o_sntdata(&self) -> u16;
+ fn o_sntbss(&self) -> u16;
+ fn o_algntext(&self) -> u16;
+ fn o_algndata(&self) -> u16;
+ fn o_maxstack(&self) -> Self::Word;
+ fn o_maxdata(&self) -> Self::Word;
+ fn o_textpsize(&self) -> u8;
+ fn o_datapsize(&self) -> u8;
+ fn o_stackpsize(&self) -> u8;
+}
+
+impl AuxHeader for xcoff::AuxHeader32 {
+ type Word = u32;
+
+ fn o_vstamp(&self) -> u16 {
+ self.o_vstamp.get(BE)
+ }
+
+ fn o_tsize(&self) -> Self::Word {
+ self.o_tsize.get(BE)
+ }
+
+ fn o_dsize(&self) -> Self::Word {
+ self.o_dsize.get(BE)
+ }
+
+ fn o_bsize(&self) -> Self::Word {
+ self.o_bsize.get(BE)
+ }
+
+ fn o_entry(&self) -> Self::Word {
+ self.o_entry.get(BE)
+ }
+
+ fn o_text_start(&self) -> Self::Word {
+ self.o_text_start.get(BE)
+ }
+
+ fn o_data_start(&self) -> Self::Word {
+ self.o_data_start.get(BE)
+ }
+
+ fn o_toc(&self) -> Self::Word {
+ self.o_toc.get(BE)
+ }
+
+ fn o_snentry(&self) -> u16 {
+ self.o_snentry.get(BE)
+ }
+
+ fn o_sntext(&self) -> u16 {
+ self.o_sntext.get(BE)
+ }
+
+ fn o_sndata(&self) -> u16 {
+ self.o_sndata.get(BE)
+ }
+
+ fn o_sntoc(&self) -> u16 {
+ self.o_sntoc.get(BE)
+ }
+
+ fn o_snloader(&self) -> u16 {
+ self.o_snloader.get(BE)
+ }
+
+ fn o_snbss(&self) -> u16 {
+ self.o_snbss.get(BE)
+ }
+
+ fn o_sntdata(&self) -> u16 {
+ self.o_sntdata.get(BE)
+ }
+
+ fn o_sntbss(&self) -> u16 {
+ self.o_sntbss.get(BE)
+ }
+
+ fn o_algntext(&self) -> u16 {
+ self.o_algntext.get(BE)
+ }
+
+ fn o_algndata(&self) -> u16 {
+ self.o_algndata.get(BE)
+ }
+
+ fn o_maxstack(&self) -> Self::Word {
+ self.o_maxstack.get(BE)
+ }
+
+ fn o_maxdata(&self) -> Self::Word {
+ self.o_maxdata.get(BE)
+ }
+
+ fn o_textpsize(&self) -> u8 {
+ self.o_textpsize
+ }
+
+ fn o_datapsize(&self) -> u8 {
+ self.o_datapsize
+ }
+
+ fn o_stackpsize(&self) -> u8 {
+ self.o_stackpsize
+ }
+}
+
+impl AuxHeader for xcoff::AuxHeader64 {
+ type Word = u64;
+
+ fn o_vstamp(&self) -> u16 {
+ self.o_vstamp.get(BE)
+ }
+
+ fn o_tsize(&self) -> Self::Word {
+ self.o_tsize.get(BE)
+ }
+
+ fn o_dsize(&self) -> Self::Word {
+ self.o_dsize.get(BE)
+ }
+
+ fn o_bsize(&self) -> Self::Word {
+ self.o_bsize.get(BE)
+ }
+
+ fn o_entry(&self) -> Self::Word {
+ self.o_entry.get(BE)
+ }
+
+ fn o_text_start(&self) -> Self::Word {
+ self.o_text_start.get(BE)
+ }
+
+ fn o_data_start(&self) -> Self::Word {
+ self.o_data_start.get(BE)
+ }
+
+ fn o_toc(&self) -> Self::Word {
+ self.o_toc.get(BE)
+ }
+
+ fn o_snentry(&self) -> u16 {
+ self.o_snentry.get(BE)
+ }
+
+ fn o_sntext(&self) -> u16 {
+ self.o_sntext.get(BE)
+ }
+
+ fn o_sndata(&self) -> u16 {
+ self.o_sndata.get(BE)
+ }
+
+ fn o_sntoc(&self) -> u16 {
+ self.o_sntoc.get(BE)
+ }
+
+ fn o_snloader(&self) -> u16 {
+ self.o_snloader.get(BE)
+ }
+
+ fn o_snbss(&self) -> u16 {
+ self.o_snbss.get(BE)
+ }
+
+ fn o_sntdata(&self) -> u16 {
+ self.o_sntdata.get(BE)
+ }
+
+ fn o_sntbss(&self) -> u16 {
+ self.o_sntbss.get(BE)
+ }
+
+ fn o_algntext(&self) -> u16 {
+ self.o_algntext.get(BE)
+ }
+
+ fn o_algndata(&self) -> u16 {
+ self.o_algndata.get(BE)
+ }
+
+ fn o_maxstack(&self) -> Self::Word {
+ self.o_maxstack.get(BE)
+ }
+
+ fn o_maxdata(&self) -> Self::Word {
+ self.o_maxdata.get(BE)
+ }
+
+ fn o_textpsize(&self) -> u8 {
+ self.o_textpsize
+ }
+
+ fn o_datapsize(&self) -> u8 {
+ self.o_datapsize
+ }
+
+ fn o_stackpsize(&self) -> u8 {
+ self.o_stackpsize
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/mod.rs b/third_party/rust/object/src/read/xcoff/mod.rs
new file mode 100644
index 0000000000..136e31073b
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/mod.rs
@@ -0,0 +1,21 @@
+//! Support for reading AIX XCOFF files.
+//!
+//! Provides `XcoffFile` and related types which implement the `Object` trait.
+
+mod file;
+pub use file::*;
+
+mod section;
+pub use section::*;
+
+mod symbol;
+pub use symbol::*;
+
+mod relocation;
+pub use relocation::*;
+
+mod comdat;
+pub use comdat::*;
+
+mod segment;
+pub use segment::*;
diff --git a/third_party/rust/object/src/read/xcoff/relocation.rs b/third_party/rust/object/src/read/xcoff/relocation.rs
new file mode 100644
index 0000000000..78c6acfc7f
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/relocation.rs
@@ -0,0 +1,127 @@
+use alloc::fmt;
+use core::fmt::Debug;
+use core::slice;
+
+use crate::pod::Pod;
+use crate::{xcoff, BigEndian as BE, Relocation};
+
+use crate::read::{ReadRef, RelocationEncoding, RelocationKind, RelocationTarget, SymbolIndex};
+
+use super::{FileHeader, SectionHeader, XcoffFile};
+
+/// An iterator over the relocations in a `XcoffSection32`.
+pub type XcoffRelocationIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffRelocationIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the relocations in a `XcoffSection64`.
+pub type XcoffRelocationIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffRelocationIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the relocations in a `XcoffSection`.
+pub struct XcoffRelocationIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) relocations:
+ slice::Iter<'data, <<Xcoff as FileHeader>::SectionHeader as SectionHeader>::Rel>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffRelocationIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = (u64, Relocation);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.relocations.next().map(|relocation| {
+ let encoding = RelocationEncoding::Generic;
+ let (kind, addend) = match relocation.r_rtype() {
+ xcoff::R_POS
+ | xcoff::R_RL
+ | xcoff::R_RLA
+ | xcoff::R_BA
+ | xcoff::R_RBA
+ | xcoff::R_TLS => (RelocationKind::Absolute, 0),
+ xcoff::R_REL | xcoff::R_BR | xcoff::R_RBR => (RelocationKind::Relative, -4),
+ xcoff::R_TOC | xcoff::R_TOCL | xcoff::R_TOCU => (RelocationKind::Got, 0),
+ r_type => (RelocationKind::Xcoff(r_type), 0),
+ };
+ let size = (relocation.r_rsize() & 0x3F) + 1;
+ let target = RelocationTarget::Symbol(SymbolIndex(relocation.r_symndx() as usize));
+ (
+ relocation.r_vaddr().into(),
+ Relocation {
+ kind,
+ encoding,
+ size,
+ target,
+ addend,
+ implicit_addend: true,
+ },
+ )
+ })
+ }
+}
+
+impl<'data, 'file, Xcoff, R> fmt::Debug for XcoffRelocationIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("XcoffRelocationIterator").finish()
+ }
+}
+
+/// A trait for generic access to `Rel32` and `Rel64`.
+#[allow(missing_docs)]
+pub trait Rel: Debug + Pod {
+ type Word: Into<u64>;
+ fn r_vaddr(&self) -> Self::Word;
+ fn r_symndx(&self) -> u32;
+ fn r_rsize(&self) -> u8;
+ fn r_rtype(&self) -> u8;
+}
+
+impl Rel for xcoff::Rel32 {
+ type Word = u32;
+
+ fn r_vaddr(&self) -> Self::Word {
+ self.r_vaddr.get(BE)
+ }
+
+ fn r_symndx(&self) -> u32 {
+ self.r_symndx.get(BE)
+ }
+
+ fn r_rsize(&self) -> u8 {
+ self.r_rsize
+ }
+
+ fn r_rtype(&self) -> u8 {
+ self.r_rtype
+ }
+}
+
+impl Rel for xcoff::Rel64 {
+ type Word = u64;
+
+ fn r_vaddr(&self) -> Self::Word {
+ self.r_vaddr.get(BE)
+ }
+
+ fn r_symndx(&self) -> u32 {
+ self.r_symndx.get(BE)
+ }
+
+ fn r_rsize(&self) -> u8 {
+ self.r_rsize
+ }
+
+ fn r_rtype(&self) -> u8 {
+ self.r_rtype
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/section.rs b/third_party/rust/object/src/read/xcoff/section.rs
new file mode 100644
index 0000000000..77453fcd21
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/section.rs
@@ -0,0 +1,427 @@
+use core::fmt::Debug;
+use core::{iter, result, slice, str};
+
+use crate::{
+ xcoff, BigEndian as BE, CompressedData, CompressedFileRange, Pod, SectionFlags, SectionKind,
+};
+
+use crate::read::{self, Error, ObjectSection, ReadError, ReadRef, Result, SectionIndex};
+
+use super::{AuxHeader, FileHeader, Rel, XcoffFile, XcoffRelocationIterator};
+
+/// An iterator over the sections of an `XcoffFile32`.
+pub type XcoffSectionIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffSectionIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the sections of an `XcoffFile64`.
+pub type XcoffSectionIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffSectionIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the sections of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSectionIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) iter: iter::Enumerate<slice::Iter<'data, Xcoff::SectionHeader>>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffSectionIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = XcoffSection<'data, 'file, Xcoff, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| XcoffSection {
+ index: SectionIndex(index + 1),
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A section of an `XcoffFile32`.
+pub type XcoffSection32<'data, 'file, R = &'data [u8]> =
+ XcoffSection<'data, 'file, xcoff::FileHeader32, R>;
+/// A section of an `XcoffFile64`.
+pub type XcoffSection64<'data, 'file, R = &'data [u8]> =
+ XcoffSection<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A section of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSection<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) section: &'data Xcoff::SectionHeader,
+ pub(super) index: SectionIndex,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> XcoffSection<'data, 'file, Xcoff, R> {
+ fn bytes(&self) -> Result<&'data [u8]> {
+ self.section
+ .data(self.file.data)
+ .read_error("Invalid XCOFF section offset or size")
+ }
+}
+
+impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffSection<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> ObjectSection<'data> for XcoffSection<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type RelocationIterator = XcoffRelocationIterator<'data, 'file, Xcoff, R>;
+
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ fn address(&self) -> u64 {
+ self.section.s_paddr().into()
+ }
+
+ fn size(&self) -> u64 {
+ self.section.s_size().into()
+ }
+
+ fn align(&self) -> u64 {
+ // The default section alignment is 4.
+ if let Some(aux_header) = self.file.aux_header {
+ match self.kind() {
+ SectionKind::Text => aux_header.o_algntext().into(),
+ SectionKind::Data => aux_header.o_algndata().into(),
+ _ => 4,
+ }
+ } else {
+ 4
+ }
+ }
+
+ fn file_range(&self) -> Option<(u64, u64)> {
+ self.section.file_range()
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ fn compressed_file_range(&self) -> Result<CompressedFileRange> {
+ Ok(CompressedFileRange::none(self.file_range()))
+ }
+
+ fn compressed_data(&self) -> Result<CompressedData<'data>> {
+ self.data().map(CompressedData::none)
+ }
+
+ fn name_bytes(&self) -> read::Result<&[u8]> {
+ Ok(self.section.name())
+ }
+
+ fn name(&self) -> read::Result<&str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 XCOFF section name")
+ }
+
+ fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ fn segment_name(&self) -> Result<Option<&str>> {
+ Ok(None)
+ }
+
+ fn kind(&self) -> SectionKind {
+ let section_type = self.section.s_flags() as u16;
+ if section_type & xcoff::STYP_TEXT != 0 {
+ SectionKind::Text
+ } else if section_type & xcoff::STYP_DATA != 0 {
+ SectionKind::Data
+ } else if section_type & xcoff::STYP_TDATA != 0 {
+ SectionKind::Tls
+ } else if section_type & xcoff::STYP_BSS != 0 {
+ SectionKind::UninitializedData
+ } else if section_type & xcoff::STYP_TBSS != 0 {
+ SectionKind::UninitializedTls
+ } else if section_type & (xcoff::STYP_DEBUG | xcoff::STYP_DWARF) != 0 {
+ SectionKind::Debug
+ } else if section_type & (xcoff::STYP_LOADER | xcoff::STYP_OVRFLO) != 0 {
+ SectionKind::Metadata
+ } else if section_type
+ & (xcoff::STYP_INFO | xcoff::STYP_EXCEPT | xcoff::STYP_PAD | xcoff::STYP_TYPCHK)
+ != 0
+ {
+ SectionKind::Other
+ } else {
+ SectionKind::Unknown
+ }
+ }
+
+ fn relocations(&self) -> Self::RelocationIterator {
+ let rel = self.section.relocations(self.file.data).unwrap_or(&[]);
+ XcoffRelocationIterator {
+ file: self.file,
+ relocations: rel.iter(),
+ }
+ }
+
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::Xcoff {
+ s_flags: self.section.s_flags(),
+ }
+ }
+
+ fn uncompressed_data(&self) -> Result<alloc::borrow::Cow<'data, [u8]>> {
+ self.compressed_data()?.decompress()
+ }
+}
+
+/// The table of section headers in an XCOFF file.
+#[derive(Debug, Clone, Copy)]
+pub struct SectionTable<'data, Xcoff: FileHeader> {
+ sections: &'data [Xcoff::SectionHeader],
+}
+
+impl<'data, Xcoff> Default for SectionTable<'data, Xcoff>
+where
+ Xcoff: FileHeader,
+{
+ fn default() -> Self {
+ Self { sections: &[] }
+ }
+}
+
+impl<'data, Xcoff> SectionTable<'data, Xcoff>
+where
+ Xcoff: FileHeader,
+{
+ /// Parse the section table.
+ ///
+ /// `data` must be the entire file data.
+ /// `offset` must be after the optional file header.
+ pub fn parse<R: ReadRef<'data>>(header: &Xcoff, data: R, offset: &mut u64) -> Result<Self> {
+ let section_num = header.f_nscns();
+ if section_num == 0 {
+ return Ok(SectionTable::default());
+ }
+ let sections = data
+ .read_slice(offset, section_num as usize)
+ .read_error("Invalid XCOFF section headers")?;
+ Ok(SectionTable { sections })
+ }
+
+ /// Iterate over the section headers.
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'data, Xcoff::SectionHeader> {
+ self.sections.iter()
+ }
+
+ /// Return true if the section table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.sections.is_empty()
+ }
+
+ /// The number of section headers.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.sections.len()
+ }
+
+ /// Return the section header at the given index.
+ ///
+ /// The index is 1-based.
+ pub fn section(&self, index: SectionIndex) -> read::Result<&'data Xcoff::SectionHeader> {
+ self.sections
+ .get(index.0.wrapping_sub(1))
+ .read_error("Invalid XCOFF section index")
+ }
+}
+
+/// A trait for generic access to `SectionHeader32` and `SectionHeader64`.
+#[allow(missing_docs)]
+pub trait SectionHeader: Debug + Pod {
+ type Word: Into<u64>;
+ type HalfWord: Into<u32>;
+ type Xcoff: FileHeader<SectionHeader = Self, Word = Self::Word>;
+ type Rel: Rel<Word = Self::Word>;
+
+ fn s_name(&self) -> &[u8; 8];
+ fn s_paddr(&self) -> Self::Word;
+ fn s_vaddr(&self) -> Self::Word;
+ fn s_size(&self) -> Self::Word;
+ fn s_scnptr(&self) -> Self::Word;
+ fn s_relptr(&self) -> Self::Word;
+ fn s_lnnoptr(&self) -> Self::Word;
+ fn s_nreloc(&self) -> Self::HalfWord;
+ fn s_nlnno(&self) -> Self::HalfWord;
+ fn s_flags(&self) -> u32;
+
+ /// Return the section name.
+ fn name(&self) -> &[u8] {
+ let sectname = &self.s_name()[..];
+ match memchr::memchr(b'\0', sectname) {
+ Some(end) => &sectname[..end],
+ None => sectname,
+ }
+ }
+
+ /// Return the offset and size of the section in the file.
+ fn file_range(&self) -> Option<(u64, u64)> {
+ Some((self.s_scnptr().into(), self.s_size().into()))
+ }
+
+ /// Return the section data.
+ ///
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values.
+ fn data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> {
+ if let Some((offset, size)) = self.file_range() {
+ data.read_bytes_at(offset, size)
+ } else {
+ Ok(&[])
+ }
+ }
+
+ /// Read the relocations.
+ fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]>;
+}
+
+impl SectionHeader for xcoff::SectionHeader32 {
+ type Word = u32;
+ type HalfWord = u16;
+ type Xcoff = xcoff::FileHeader32;
+ type Rel = xcoff::Rel32;
+
+ fn s_name(&self) -> &[u8; 8] {
+ &self.s_name
+ }
+
+ fn s_paddr(&self) -> Self::Word {
+ self.s_paddr.get(BE)
+ }
+
+ fn s_vaddr(&self) -> Self::Word {
+ self.s_vaddr.get(BE)
+ }
+
+ fn s_size(&self) -> Self::Word {
+ self.s_size.get(BE)
+ }
+
+ fn s_scnptr(&self) -> Self::Word {
+ self.s_scnptr.get(BE)
+ }
+
+ fn s_relptr(&self) -> Self::Word {
+ self.s_relptr.get(BE)
+ }
+
+ fn s_lnnoptr(&self) -> Self::Word {
+ self.s_lnnoptr.get(BE)
+ }
+
+ fn s_nreloc(&self) -> Self::HalfWord {
+ self.s_nreloc.get(BE)
+ }
+
+ fn s_nlnno(&self) -> Self::HalfWord {
+ self.s_nlnno.get(BE)
+ }
+
+ fn s_flags(&self) -> u32 {
+ self.s_flags.get(BE)
+ }
+
+ /// Read the relocations in a XCOFF32 file.
+ ///
+ /// `data` must be the entire file data.
+ fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]> {
+ let reloc_num = self.s_nreloc() as usize;
+ // TODO: If more than 65,534 relocation entries are required, the field value will be 65535,
+ // and an STYP_OVRFLO section header will contain the actual count of relocation entries in
+ // the s_paddr field.
+ if reloc_num == 65535 {
+ return Err(Error("Overflow section is not supported yet."));
+ }
+ data.read_slice_at(self.s_relptr().into(), reloc_num)
+ .read_error("Invalid XCOFF relocation offset or number")
+ }
+}
+
+impl SectionHeader for xcoff::SectionHeader64 {
+ type Word = u64;
+ type HalfWord = u32;
+ type Xcoff = xcoff::FileHeader64;
+ type Rel = xcoff::Rel64;
+
+ fn s_name(&self) -> &[u8; 8] {
+ &self.s_name
+ }
+
+ fn s_paddr(&self) -> Self::Word {
+ self.s_paddr.get(BE)
+ }
+
+ fn s_vaddr(&self) -> Self::Word {
+ self.s_vaddr.get(BE)
+ }
+
+ fn s_size(&self) -> Self::Word {
+ self.s_size.get(BE)
+ }
+
+ fn s_scnptr(&self) -> Self::Word {
+ self.s_scnptr.get(BE)
+ }
+
+ fn s_relptr(&self) -> Self::Word {
+ self.s_relptr.get(BE)
+ }
+
+ fn s_lnnoptr(&self) -> Self::Word {
+ self.s_lnnoptr.get(BE)
+ }
+
+ fn s_nreloc(&self) -> Self::HalfWord {
+ self.s_nreloc.get(BE)
+ }
+
+ fn s_nlnno(&self) -> Self::HalfWord {
+ self.s_nlnno.get(BE)
+ }
+
+ fn s_flags(&self) -> u32 {
+ self.s_flags.get(BE)
+ }
+
+ /// Read the relocations in a XCOFF64 file.
+ ///
+ /// `data` must be the entire file data.
+ fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]> {
+ data.read_slice_at(self.s_relptr(), self.s_nreloc() as usize)
+ .read_error("Invalid XCOFF relocation offset or number")
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/segment.rs b/third_party/rust/object/src/read/xcoff/segment.rs
new file mode 100644
index 0000000000..7eca72367a
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/segment.rs
@@ -0,0 +1,113 @@
+//! TODO: Support the segment for XCOFF when auxiliary file header and loader section is ready.
+
+use core::fmt::Debug;
+use core::str;
+
+use crate::read::{self, ObjectSegment, ReadRef, Result};
+use crate::xcoff;
+
+use super::{FileHeader, XcoffFile};
+
+/// An iterator over the segments of an `XcoffFile32`.
+pub type XcoffSegmentIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffSegmentIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the segments of an `XcoffFile64`.
+pub type XcoffSegmentIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffSegmentIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the segments of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSegmentIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> Iterator for XcoffSegmentIterator<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = XcoffSegment<'data, 'file, Xcoff, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+/// A segment of an `XcoffFile32`.
+pub type XcoffSegment32<'data, 'file, R = &'data [u8]> =
+ XcoffSegment<'data, 'file, xcoff::FileHeader32, R>;
+/// A segment of an `XcoffFile64`.
+pub type XcoffSegment64<'data, 'file, R = &'data [u8]> =
+ XcoffSegment<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A loadable section of an `XcoffFile`.
+#[derive(Debug)]
+pub struct XcoffSegment<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ #[allow(unused)]
+ pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff, R> XcoffSegment<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffSegment<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Xcoff, R> ObjectSegment<'data> for XcoffSegment<'data, 'file, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn address(&self) -> u64 {
+ unreachable!();
+ }
+
+ fn size(&self) -> u64 {
+ unreachable!();
+ }
+
+ fn align(&self) -> u64 {
+ unreachable!();
+ }
+
+ fn file_range(&self) -> (u64, u64) {
+ unreachable!();
+ }
+
+ fn data(&self) -> Result<&'data [u8]> {
+ unreachable!();
+ }
+
+ fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> {
+ unreachable!();
+ }
+
+ fn name_bytes(&self) -> Result<Option<&[u8]>> {
+ unreachable!();
+ }
+
+ fn name(&self) -> Result<Option<&str>> {
+ unreachable!();
+ }
+
+ fn flags(&self) -> crate::SegmentFlags {
+ unreachable!();
+ }
+}
diff --git a/third_party/rust/object/src/read/xcoff/symbol.rs b/third_party/rust/object/src/read/xcoff/symbol.rs
new file mode 100644
index 0000000000..7ce215fac0
--- /dev/null
+++ b/third_party/rust/object/src/read/xcoff/symbol.rs
@@ -0,0 +1,695 @@
+use alloc::fmt;
+use core::convert::TryInto;
+use core::fmt::Debug;
+use core::marker::PhantomData;
+use core::str;
+
+use crate::endian::{BigEndian as BE, U32Bytes};
+use crate::pod::{bytes_of, Pod};
+use crate::read::util::StringTable;
+use crate::xcoff;
+
+use crate::read::{
+ self, Bytes, Error, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex,
+ SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
+};
+
+use super::{FileHeader, XcoffFile};
+
+/// A table of symbol entries in an XCOFF file.
+///
+/// Also includes the string table used for the symbol names.
+#[derive(Debug)]
+pub struct SymbolTable<'data, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ symbols: &'data [xcoff::SymbolBytes],
+ strings: StringTable<'data, R>,
+ header: PhantomData<Xcoff>,
+}
+
+impl<'data, Xcoff, R> Default for SymbolTable<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ fn default() -> Self {
+ Self {
+ symbols: &[],
+ strings: StringTable::default(),
+ header: PhantomData,
+ }
+ }
+}
+
+impl<'data, Xcoff, R> SymbolTable<'data, Xcoff, R>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ /// Parse the symbol table.
+ pub fn parse(header: Xcoff, data: R) -> Result<Self> {
+ let mut offset = header.f_symptr().into();
+ let (symbols, strings) = if offset != 0 {
+ let symbols = data
+ .read_slice(&mut offset, header.f_nsyms() as usize)
+ .read_error("Invalid XCOFF symbol table offset or size")?;
+
+ // Parse the string table.
+ // Note: don't update data when reading length; the length includes itself.
+ let length = data
+ .read_at::<U32Bytes<_>>(offset)
+ .read_error("Missing XCOFF string table")?
+ .get(BE);
+ let str_end = offset
+ .checked_add(length as u64)
+ .read_error("Invalid XCOFF string table length")?;
+ let strings = StringTable::new(data, offset, str_end);
+
+ (symbols, strings)
+ } else {
+ (&[][..], StringTable::default())
+ };
+
+ Ok(SymbolTable {
+ symbols,
+ strings,
+ header: PhantomData,
+ })
+ }
+
+ /// Return the symbol entry at the given index and offset.
+ pub fn get<T: Pod>(&self, index: usize, offset: usize) -> Result<&'data T> {
+ let entry = index
+ .checked_add(offset)
+ .and_then(|x| self.symbols.get(x))
+ .read_error("Invalid XCOFF symbol index")?;
+ let bytes = bytes_of(entry);
+ Bytes(bytes).read().read_error("Invalid XCOFF symbol data")
+ }
+
+ /// Return the symbol at the given index.
+ pub fn symbol(&self, index: usize) -> Result<&'data Xcoff::Symbol> {
+ self.get::<Xcoff::Symbol>(index, 0)
+ }
+
+ /// Return a file auxiliary symbol.
+ pub fn aux_file(&self, index: usize, offset: usize) -> Result<&'data Xcoff::FileAux> {
+ debug_assert!(self.symbol(index)?.has_aux_file());
+ let aux_file = self.get::<Xcoff::FileAux>(index, offset)?;
+ if let Some(aux_type) = aux_file.x_auxtype() {
+ if aux_type != xcoff::AUX_FILE {
+ return Err(Error("Invalid index for file auxiliary symbol."));
+ }
+ }
+ Ok(aux_file)
+ }
+
+ /// Return the csect auxiliary symbol.
+ pub fn aux_csect(&self, index: usize, offset: usize) -> Result<&'data Xcoff::CsectAux> {
+ debug_assert!(self.symbol(index)?.has_aux_csect());
+ let aux_csect = self.get::<Xcoff::CsectAux>(index, offset)?;
+ if let Some(aux_type) = aux_csect.x_auxtype() {
+ if aux_type != xcoff::AUX_CSECT {
+ return Err(Error("Invalid index/offset for csect auxiliary symbol."));
+ }
+ }
+ Ok(aux_csect)
+ }
+
+ /// Return true if the symbol table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.symbols.is_empty()
+ }
+
+ /// The number of symbol table entries.
+ ///
+ /// This includes auxiliary symbol table entries.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.symbols.len()
+ }
+}
+
+/// A symbol table of an `XcoffFile32`.
+pub type XcoffSymbolTable32<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolTable<'data, 'file, xcoff::FileHeader32, R>;
+/// A symbol table of an `XcoffFile64`.
+pub type XcoffSymbolTable64<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolTable<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A symbol table of an `XcoffFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct XcoffSymbolTable<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed
+ for XcoffSymbolTable<'data, 'file, Xcoff, R>
+{
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data>
+ for XcoffSymbolTable<'data, 'file, Xcoff, R>
+{
+ type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>;
+ type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>;
+
+ fn symbols(&self) -> Self::SymbolIterator {
+ XcoffSymbolIterator {
+ file: self.file,
+ symbols: self.symbols,
+ index: 0,
+ }
+ }
+
+ fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> {
+ let symbol = self.symbols.symbol(index.0)?;
+ Ok(XcoffSymbol {
+ file: self.file,
+ symbols: self.symbols,
+ index,
+ symbol,
+ })
+ }
+}
+
+/// An iterator over the symbols of an `XcoffFile32`.
+pub type XcoffSymbolIterator32<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolIterator<'data, 'file, xcoff::FileHeader32, R>;
+/// An iterator over the symbols of an `XcoffFile64`.
+pub type XcoffSymbolIterator64<'data, 'file, R = &'data [u8]> =
+ XcoffSymbolIterator<'data, 'file, xcoff::FileHeader64, R>;
+
+/// An iterator over the symbols of an `XcoffFile`.
+pub struct XcoffSymbolIterator<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
+ pub(super) index: usize,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> fmt::Debug
+ for XcoffSymbolIterator<'data, 'file, Xcoff, R>
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("XcoffSymbolIterator").finish()
+ }
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> Iterator
+ for XcoffSymbolIterator<'data, 'file, Xcoff, R>
+{
+ type Item = XcoffSymbol<'data, 'file, Xcoff, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let index = self.index;
+ let symbol = self.symbols.symbol(index).ok()?;
+ // TODO: skip over the auxiliary symbols for now.
+ self.index += 1 + symbol.n_numaux() as usize;
+ Some(XcoffSymbol {
+ file: self.file,
+ symbols: self.symbols,
+ index: SymbolIndex(index),
+ symbol,
+ })
+ }
+}
+
+/// A symbol of an `XcoffFile32`.
+pub type XcoffSymbol32<'data, 'file, R = &'data [u8]> =
+ XcoffSymbol<'data, 'file, xcoff::FileHeader32, R>;
+/// A symbol of an `XcoffFile64`.
+pub type XcoffSymbol64<'data, 'file, R = &'data [u8]> =
+ XcoffSymbol<'data, 'file, xcoff::FileHeader64, R>;
+
+/// A symbol of an `XcoffFile`.
+#[derive(Debug, Clone, Copy)]
+pub struct XcoffSymbol<'data, 'file, Xcoff, R = &'data [u8]>
+where
+ Xcoff: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(crate) file: &'file XcoffFile<'data, Xcoff, R>,
+ pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
+ pub(super) index: SymbolIndex,
+ pub(super) symbol: &'data Xcoff::Symbol,
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed
+ for XcoffSymbol<'data, 'file, Xcoff, R>
+{
+}
+
+impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data>
+ for XcoffSymbol<'data, 'file, Xcoff, R>
+{
+ #[inline]
+ fn index(&self) -> SymbolIndex {
+ self.index
+ }
+
+ fn name_bytes(&self) -> Result<&'data [u8]> {
+ if self.symbol.has_aux_file() {
+ // By convention the file name is in the first auxiliary entry.
+ self.symbols
+ .aux_file(self.index.0, 1)?
+ .fname(self.symbols.strings)
+ } else {
+ self.symbol.name(self.symbols.strings)
+ }
+ }
+
+ fn name(&self) -> Result<&'data str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 XCOFF symbol name")
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ match self.symbol.n_sclass() {
+ // Relocatable address.
+ xcoff::C_EXT
+ | xcoff::C_WEAKEXT
+ | xcoff::C_HIDEXT
+ | xcoff::C_FCN
+ | xcoff::C_BLOCK
+ | xcoff::C_STAT
+ | xcoff::C_INFO => self.symbol.n_value().into(),
+ _ => 0,
+ }
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ if self.symbol.has_aux_csect() {
+ // XCOFF32 must have the csect auxiliary entry as the last auxiliary entry.
+ // XCOFF64 doesn't require this, but conventionally does.
+ if let Ok(aux_csect) = self
+ .file
+ .symbols
+ .aux_csect(self.index.0, self.symbol.n_numaux() as usize)
+ {
+ let sym_type = aux_csect.sym_type() & 0x07;
+ if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM {
+ return aux_csect.x_scnlen();
+ }
+ }
+ }
+ 0
+ }
+
+ fn kind(&self) -> SymbolKind {
+ if self.symbol.has_aux_csect() {
+ if let Ok(aux_csect) = self
+ .file
+ .symbols
+ .aux_csect(self.index.0, self.symbol.n_numaux() as usize)
+ {
+ let sym_type = aux_csect.sym_type() & 0x07;
+ if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM {
+ return match aux_csect.x_smclas() {
+ xcoff::XMC_PR | xcoff::XMC_GL => SymbolKind::Text,
+ xcoff::XMC_RO | xcoff::XMC_RW | xcoff::XMC_TD | xcoff::XMC_BS => {
+ SymbolKind::Data
+ }
+ xcoff::XMC_TL | xcoff::XMC_UL => SymbolKind::Tls,
+ xcoff::XMC_DS | xcoff::XMC_TC0 | xcoff::XMC_TC => {
+ // `Metadata` might be a better kind for these if we had it.
+ SymbolKind::Data
+ }
+ _ => SymbolKind::Unknown,
+ };
+ } else if sym_type == xcoff::XTY_LD {
+ // A function entry point. Neither `Text` nor `Label` are a good fit for this.
+ return SymbolKind::Text;
+ } else if sym_type == xcoff::XTY_ER {
+ return SymbolKind::Unknown;
+ }
+ }
+ }
+ match self.symbol.n_sclass() {
+ xcoff::C_NULL => SymbolKind::Null,
+ xcoff::C_FILE => SymbolKind::File,
+ _ => SymbolKind::Unknown,
+ }
+ }
+
+ fn section(&self) -> SymbolSection {
+ match self.symbol.n_scnum() {
+ xcoff::N_ABS => SymbolSection::Absolute,
+ xcoff::N_UNDEF => SymbolSection::Undefined,
+ xcoff::N_DEBUG => SymbolSection::None,
+ index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)),
+ _ => SymbolSection::Unknown,
+ }
+ }
+
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ self.symbol.is_undefined()
+ }
+
+ /// Return true if the symbol is a definition of a function or data object.
+ #[inline]
+ fn is_definition(&self) -> bool {
+ if self.symbol.has_aux_csect() {
+ if let Ok(aux_csect) = self
+ .symbols
+ .aux_csect(self.index.0, self.symbol.n_numaux() as usize)
+ {
+ let smclas = aux_csect.x_smclas();
+ self.symbol.n_scnum() != xcoff::N_UNDEF
+ && (smclas == xcoff::XMC_PR
+ || smclas == xcoff::XMC_RW
+ || smclas == xcoff::XMC_RO)
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ fn is_common(&self) -> bool {
+ self.symbol.n_sclass() == xcoff::C_EXT && self.symbol.n_scnum() == xcoff::N_UNDEF
+ }
+
+ #[inline]
+ fn is_weak(&self) -> bool {
+ self.symbol.n_sclass() == xcoff::C_WEAKEXT
+ }
+
+ fn scope(&self) -> SymbolScope {
+ if self.symbol.n_scnum() == xcoff::N_UNDEF {
+ SymbolScope::Unknown
+ } else {
+ match self.symbol.n_sclass() {
+ xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => {
+ let visibility = self.symbol.n_type() & xcoff::SYM_V_MASK;
+ if visibility == xcoff::SYM_V_HIDDEN {
+ SymbolScope::Linkage
+ } else {
+ SymbolScope::Dynamic
+ }
+ }
+ _ => SymbolScope::Compilation,
+ }
+ }
+ }
+
+ #[inline]
+ fn is_global(&self) -> bool {
+ match self.symbol.n_sclass() {
+ xcoff::C_EXT | xcoff::C_WEAKEXT => true,
+ _ => false,
+ }
+ }
+
+ #[inline]
+ fn is_local(&self) -> bool {
+ !self.is_global()
+ }
+
+ #[inline]
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
+ let mut x_smtyp = 0;
+ let mut x_smclas = 0;
+ let mut containing_csect = None;
+ if self.symbol.has_aux_csect() {
+ if let Ok(aux_csect) = self
+ .file
+ .symbols
+ .aux_csect(self.index.0, self.symbol.n_numaux() as usize)
+ {
+ x_smtyp = aux_csect.x_smtyp();
+ x_smclas = aux_csect.x_smclas();
+ if x_smtyp == xcoff::XTY_LD {
+ containing_csect = Some(SymbolIndex(aux_csect.x_scnlen() as usize))
+ }
+ }
+ }
+ SymbolFlags::Xcoff {
+ n_sclass: self.symbol.n_sclass(),
+ x_smtyp,
+ x_smclas,
+ containing_csect,
+ }
+ }
+}
+
+/// A trait for generic access to `Symbol32` and `Symbol64`.
+#[allow(missing_docs)]
+pub trait Symbol: Debug + Pod {
+ type Word: Into<u64>;
+
+ fn n_value(&self) -> Self::Word;
+ fn n_scnum(&self) -> i16;
+ fn n_type(&self) -> u16;
+ fn n_sclass(&self) -> u8;
+ fn n_numaux(&self) -> u8;
+
+ fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]>;
+
+ /// Return true if the symbol is undefined.
+ #[inline]
+ fn is_undefined(&self) -> bool {
+ let n_sclass = self.n_sclass();
+ (n_sclass == xcoff::C_EXT || n_sclass == xcoff::C_WEAKEXT)
+ && self.n_scnum() == xcoff::N_UNDEF
+ }
+
+ /// Return true if the symbol has file auxiliary entry.
+ fn has_aux_file(&self) -> bool {
+ self.n_numaux() > 0 && self.n_sclass() == xcoff::C_FILE
+ }
+
+ /// Return true if the symbol has csect auxiliary entry.
+ ///
+ /// A csect auxiliary entry is required for each symbol table entry that has
+ /// a storage class value of C_EXT, C_WEAKEXT, or C_HIDEXT.
+ fn has_aux_csect(&self) -> bool {
+ let sclass = self.n_sclass();
+ self.n_numaux() > 0
+ && (sclass == xcoff::C_EXT || sclass == xcoff::C_WEAKEXT || sclass == xcoff::C_HIDEXT)
+ }
+}
+
+impl Symbol for xcoff::Symbol64 {
+ type Word = u64;
+
+ fn n_value(&self) -> Self::Word {
+ self.n_value.get(BE)
+ }
+
+ fn n_scnum(&self) -> i16 {
+ self.n_scnum.get(BE)
+ }
+
+ fn n_type(&self) -> u16 {
+ self.n_type.get(BE)
+ }
+
+ fn n_sclass(&self) -> u8 {
+ self.n_sclass
+ }
+
+ fn n_numaux(&self) -> u8 {
+ self.n_numaux
+ }
+
+ /// Parse the symbol name for XCOFF64.
+ fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ strings
+ .get(self.n_offset.get(BE))
+ .read_error("Invalid XCOFF symbol name offset")
+ }
+}
+
+impl Symbol for xcoff::Symbol32 {
+ type Word = u32;
+
+ fn n_value(&self) -> Self::Word {
+ self.n_value.get(BE)
+ }
+
+ fn n_scnum(&self) -> i16 {
+ self.n_scnum.get(BE)
+ }
+
+ fn n_type(&self) -> u16 {
+ self.n_type.get(BE)
+ }
+
+ fn n_sclass(&self) -> u8 {
+ self.n_sclass
+ }
+
+ fn n_numaux(&self) -> u8 {
+ self.n_numaux
+ }
+
+ /// Parse the symbol name for XCOFF32.
+ fn name<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ if self.n_name[0] == 0 {
+ // If the name starts with 0 then the last 4 bytes are a string table offset.
+ let offset = u32::from_be_bytes(self.n_name[4..8].try_into().unwrap());
+ strings
+ .get(offset)
+ .read_error("Invalid XCOFF symbol name offset")
+ } else {
+ // The name is inline and padded with nulls.
+ Ok(match memchr::memchr(b'\0', &self.n_name) {
+ Some(end) => &self.n_name[..end],
+ None => &self.n_name,
+ })
+ }
+ }
+}
+
+/// A trait for generic access to `FileAux32` and `FileAux64`.
+#[allow(missing_docs)]
+pub trait FileAux: Debug + Pod {
+ fn x_fname(&self) -> &[u8; 8];
+ fn x_ftype(&self) -> u8;
+ fn x_auxtype(&self) -> Option<u8>;
+
+ /// Parse the x_fname field, which may be an inline string or a string table offset.
+ fn fname<'data, R: ReadRef<'data>>(
+ &'data self,
+ strings: StringTable<'data, R>,
+ ) -> Result<&'data [u8]> {
+ let x_fname = self.x_fname();
+ if x_fname[0] == 0 {
+ // If the name starts with 0 then the last 4 bytes are a string table offset.
+ let offset = u32::from_be_bytes(x_fname[4..8].try_into().unwrap());
+ strings
+ .get(offset)
+ .read_error("Invalid XCOFF symbol name offset")
+ } else {
+ // The name is inline and padded with nulls.
+ Ok(match memchr::memchr(b'\0', x_fname) {
+ Some(end) => &x_fname[..end],
+ None => x_fname,
+ })
+ }
+ }
+}
+
+impl FileAux for xcoff::FileAux64 {
+ fn x_fname(&self) -> &[u8; 8] {
+ &self.x_fname
+ }
+
+ fn x_ftype(&self) -> u8 {
+ self.x_ftype
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ Some(self.x_auxtype)
+ }
+}
+
+impl FileAux for xcoff::FileAux32 {
+ fn x_fname(&self) -> &[u8; 8] {
+ &self.x_fname
+ }
+
+ fn x_ftype(&self) -> u8 {
+ self.x_ftype
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ None
+ }
+}
+
+/// A trait for generic access to `CsectAux32` and `CsectAux64`.
+#[allow(missing_docs)]
+pub trait CsectAux: Debug + Pod {
+ fn x_scnlen(&self) -> u64;
+ fn x_parmhash(&self) -> u32;
+ fn x_snhash(&self) -> u16;
+ fn x_smtyp(&self) -> u8;
+ fn x_smclas(&self) -> u8;
+ fn x_auxtype(&self) -> Option<u8>;
+
+ fn sym_type(&self) -> u8 {
+ self.x_smtyp() & 0x07
+ }
+}
+
+impl CsectAux for xcoff::CsectAux64 {
+ fn x_scnlen(&self) -> u64 {
+ self.x_scnlen_lo.get(BE) as u64 | ((self.x_scnlen_hi.get(BE) as u64) << 32)
+ }
+
+ fn x_parmhash(&self) -> u32 {
+ self.x_parmhash.get(BE)
+ }
+
+ fn x_snhash(&self) -> u16 {
+ self.x_snhash.get(BE)
+ }
+
+ fn x_smtyp(&self) -> u8 {
+ self.x_smtyp
+ }
+
+ fn x_smclas(&self) -> u8 {
+ self.x_smclas
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ Some(self.x_auxtype)
+ }
+}
+
+impl CsectAux for xcoff::CsectAux32 {
+ fn x_scnlen(&self) -> u64 {
+ self.x_scnlen.get(BE) as u64
+ }
+
+ fn x_parmhash(&self) -> u32 {
+ self.x_parmhash.get(BE)
+ }
+
+ fn x_snhash(&self) -> u16 {
+ self.x_snhash.get(BE)
+ }
+
+ fn x_smtyp(&self) -> u8 {
+ self.x_smtyp
+ }
+
+ fn x_smclas(&self) -> u8 {
+ self.x_smclas
+ }
+
+ fn x_auxtype(&self) -> Option<u8> {
+ None
+ }
+}
diff --git a/third_party/rust/object/src/write/coff.rs b/third_party/rust/object/src/write/coff.rs
new file mode 100644
index 0000000000..d2f7ccc640
--- /dev/null
+++ b/third_party/rust/object/src/write/coff.rs
@@ -0,0 +1,725 @@
+use alloc::vec::Vec;
+use core::mem;
+
+use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32};
+use crate::pe as coff;
+use crate::write::string::*;
+use crate::write::util::*;
+use crate::write::*;
+
+#[derive(Default, Clone, Copy)]
+struct SectionOffsets {
+ offset: usize,
+ str_id: Option<StringId>,
+ reloc_offset: usize,
+ selection: u8,
+ associative_section: u16,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ index: usize,
+ str_id: Option<StringId>,
+ aux_count: u8,
+}
+
+/// Internal format to use for the `.drectve` section containing linker
+/// directives for symbol exports.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum CoffExportStyle {
+ /// MSVC format supported by link.exe and LLD.
+ Msvc,
+ /// Gnu format supported by GNU LD and LLD.
+ Gnu,
+}
+
+impl<'a> Object<'a> {
+ pub(crate) fn coff_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
+ match section {
+ StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
+ StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
+ StandardSection::ReadOnlyData
+ | StandardSection::ReadOnlyDataWithRel
+ | StandardSection::ReadOnlyString => (
+ &[],
+ &b".rdata"[..],
+ SectionKind::ReadOnlyData,
+ SectionFlags::None,
+ ),
+ StandardSection::UninitializedData => (
+ &[],
+ &b".bss"[..],
+ SectionKind::UninitializedData,
+ SectionFlags::None,
+ ),
+ // TLS sections are data sections with a special name.
+ StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data, SectionFlags::None),
+ StandardSection::UninitializedTls => {
+ // Unsupported section.
+ (&[], &[], SectionKind::UninitializedTls, SectionFlags::None)
+ }
+ StandardSection::TlsVariables => {
+ // Unsupported section.
+ (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
+ }
+ StandardSection::Common => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Common, SectionFlags::None)
+ }
+ StandardSection::GnuProperty => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Note, SectionFlags::None)
+ }
+ }
+ }
+
+ pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
+ let mut name = section.to_vec();
+ name.push(b'$');
+ name.extend_from_slice(value);
+ name
+ }
+
+ pub(crate) fn coff_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 {
+ if relocation.kind == RelocationKind::GotRelative {
+ // Use a stub symbol for the relocation instead.
+ // This isn't really a GOT, but it's a similar purpose.
+ // TODO: need to handle DLL imports differently?
+ relocation.kind = RelocationKind::Relative;
+ relocation.symbol = self.coff_add_stub_symbol(relocation.symbol);
+ } else if relocation.kind == RelocationKind::PltRelative {
+ // Windows doesn't need a separate relocation type for
+ // references to functions in import libraries.
+ // For convenience, treat this the same as Relative.
+ relocation.kind = RelocationKind::Relative;
+ }
+
+ let constant = match self.architecture {
+ Architecture::I386 | Architecture::Arm | Architecture::Aarch64 => match relocation.kind
+ {
+ RelocationKind::Relative => {
+ // IMAGE_REL_I386_REL32, IMAGE_REL_ARM_REL32, IMAGE_REL_ARM64_REL32
+ relocation.addend + 4
+ }
+ _ => relocation.addend,
+ },
+ Architecture::X86_64 => match relocation.kind {
+ RelocationKind::Relative => {
+ // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5
+ if relocation.addend <= -4 && relocation.addend >= -9 {
+ 0
+ } else {
+ relocation.addend + 4
+ }
+ }
+ _ => relocation.addend,
+ },
+ _ => unimplemented!(),
+ };
+ relocation.addend -= constant;
+ constant
+ }
+
+ fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> SymbolId {
+ if let Some(stub_id) = self.stub_symbols.get(&symbol_id) {
+ return *stub_id;
+ }
+ let stub_size = self.architecture.address_size().unwrap().bytes();
+
+ let name = b".rdata$.refptr".to_vec();
+ let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData);
+ let section = self.section_mut(section_id);
+ section.set_data(vec![0; stub_size as usize], u64::from(stub_size));
+ section.relocations = vec![Relocation {
+ offset: 0,
+ size: stub_size * 8,
+ kind: RelocationKind::Absolute,
+ encoding: RelocationEncoding::Generic,
+ symbol: symbol_id,
+ addend: 0,
+ }];
+
+ let mut name = b".refptr.".to_vec();
+ name.extend_from_slice(&self.symbol(symbol_id).name);
+ let stub_id = self.add_raw_symbol(Symbol {
+ name,
+ value: 0,
+ size: u64::from(stub_size),
+ kind: SymbolKind::Data,
+ scope: SymbolScope::Compilation,
+ weak: false,
+ section: SymbolSection::Section(section_id),
+ flags: SymbolFlags::None,
+ });
+ self.stub_symbols.insert(symbol_id, stub_id);
+
+ stub_id
+ }
+
+ /// Appends linker directives to the `.drectve` section to tell the linker
+ /// to export all symbols with `SymbolScope::Dynamic`.
+ ///
+ /// This must be called after all symbols have been defined.
+ pub fn add_coff_exports(&mut self, style: CoffExportStyle) {
+ assert_eq!(self.format, BinaryFormat::Coff);
+
+ let mut directives = vec![];
+ for symbol in &self.symbols {
+ if symbol.scope == SymbolScope::Dynamic {
+ match style {
+ CoffExportStyle::Msvc => directives.extend(b" /EXPORT:\""),
+ CoffExportStyle::Gnu => directives.extend(b" -export:\""),
+ }
+ directives.extend(&symbol.name);
+ directives.extend(b"\"");
+ if symbol.kind != SymbolKind::Text {
+ match style {
+ CoffExportStyle::Msvc => directives.extend(b",DATA"),
+ CoffExportStyle::Gnu => directives.extend(b",data"),
+ }
+ }
+ }
+ }
+ let drectve = self.add_section(vec![], b".drectve".to_vec(), SectionKind::Linker);
+ self.append_section_data(drectve, &directives, 1);
+ }
+
+ pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ // Calculate offsets of everything, and build strtab.
+ let mut offset = 0;
+ let mut strtab = StringTable::default();
+
+ // COFF header.
+ offset += mem::size_of::<coff::ImageFileHeader>();
+
+ // Section headers.
+ offset += self.sections.len() * mem::size_of::<coff::ImageSectionHeader>();
+
+ // Calculate size of section data and add section strings to strtab.
+ let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
+ for (index, section) in self.sections.iter().enumerate() {
+ if section.name.len() > 8 {
+ section_offsets[index].str_id = Some(strtab.add(&section.name));
+ }
+
+ let len = section.data.len();
+ if len != 0 {
+ // TODO: not sure what alignment is required here, but this seems to match LLVM
+ offset = align(offset, 4);
+ section_offsets[index].offset = offset;
+ offset += len;
+ } else {
+ section_offsets[index].offset = 0;
+ }
+
+ // Calculate size of relocations.
+ let mut count = section.relocations.len();
+ if count != 0 {
+ section_offsets[index].reloc_offset = offset;
+ if count > 0xffff {
+ count += 1;
+ }
+ offset += count * mem::size_of::<coff::ImageRelocation>();
+ }
+ }
+
+ // Set COMDAT flags.
+ for comdat in &self.comdats {
+ let symbol = &self.symbols[comdat.symbol.0];
+ let comdat_section = match symbol.section {
+ SymbolSection::Section(id) => id.0,
+ _ => {
+ return Err(Error(format!(
+ "unsupported COMDAT symbol `{}` section {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.section
+ )));
+ }
+ };
+ section_offsets[comdat_section].selection = match comdat.kind {
+ ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES,
+ ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY,
+ ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE,
+ ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH,
+ ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST,
+ ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST,
+ ComdatKind::Unknown => {
+ return Err(Error(format!(
+ "unsupported COMDAT symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ comdat.kind
+ )));
+ }
+ };
+ for id in &comdat.sections {
+ let section = &self.sections[id.0];
+ if section.symbol.is_none() {
+ return Err(Error(format!(
+ "missing symbol for COMDAT section `{}`",
+ section.name().unwrap_or(""),
+ )));
+ }
+ if id.0 != comdat_section {
+ section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
+ section_offsets[id.0].associative_section = comdat_section as u16 + 1;
+ }
+ }
+ }
+
+ // Calculate size of symbols and add symbol strings to strtab.
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ let mut symtab_count = 0;
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ symbol_offsets[index].index = symtab_count;
+ symtab_count += 1;
+ match symbol.kind {
+ SymbolKind::File => {
+ // Name goes in auxiliary symbol records.
+ let aux_count = (symbol.name.len() + coff::IMAGE_SIZEOF_SYMBOL - 1)
+ / coff::IMAGE_SIZEOF_SYMBOL;
+ symbol_offsets[index].aux_count = aux_count as u8;
+ symtab_count += aux_count;
+ // Don't add name to strtab.
+ continue;
+ }
+ SymbolKind::Section => {
+ symbol_offsets[index].aux_count = 1;
+ symtab_count += 1;
+ }
+ _ => {}
+ }
+ if symbol.name.len() > 8 {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+ }
+
+ // Calculate size of symtab.
+ let symtab_offset = offset;
+ let symtab_len = symtab_count * coff::IMAGE_SIZEOF_SYMBOL;
+ offset += symtab_len;
+
+ // Calculate size of strtab.
+ let strtab_offset = offset;
+ let mut strtab_data = Vec::new();
+ // First 4 bytes of strtab are the length.
+ strtab.write(4, &mut strtab_data);
+ let strtab_len = strtab_data.len() + 4;
+ offset += strtab_len;
+
+ // Start writing.
+ buffer
+ .reserve(offset)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ let header = coff::ImageFileHeader {
+ machine: U16::new(
+ LE,
+ match self.architecture {
+ Architecture::Arm => coff::IMAGE_FILE_MACHINE_ARMNT,
+ Architecture::Aarch64 => coff::IMAGE_FILE_MACHINE_ARM64,
+ Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386,
+ Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ },
+ ),
+ number_of_sections: U16::new(LE, self.sections.len() as u16),
+ time_date_stamp: U32::default(),
+ pointer_to_symbol_table: U32::new(LE, symtab_offset as u32),
+ number_of_symbols: U32::new(LE, symtab_count as u32),
+ size_of_optional_header: U16::default(),
+ characteristics: match self.flags {
+ FileFlags::Coff { characteristics } => U16::new(LE, characteristics),
+ _ => U16::default(),
+ },
+ };
+ buffer.write(&header);
+
+ // Write section headers.
+ for (index, section) in self.sections.iter().enumerate() {
+ let mut characteristics = if let SectionFlags::Coff {
+ characteristics, ..
+ } = section.flags
+ {
+ characteristics
+ } else {
+ match section.kind {
+ SectionKind::Text => {
+ coff::IMAGE_SCN_CNT_CODE
+ | coff::IMAGE_SCN_MEM_EXECUTE
+ | coff::IMAGE_SCN_MEM_READ
+ }
+ SectionKind::Data => {
+ coff::IMAGE_SCN_CNT_INITIALIZED_DATA
+ | coff::IMAGE_SCN_MEM_READ
+ | coff::IMAGE_SCN_MEM_WRITE
+ }
+ SectionKind::UninitializedData => {
+ coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA
+ | coff::IMAGE_SCN_MEM_READ
+ | coff::IMAGE_SCN_MEM_WRITE
+ }
+ SectionKind::ReadOnlyData
+ | SectionKind::ReadOnlyDataWithRel
+ | SectionKind::ReadOnlyString => {
+ coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ
+ }
+ SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => {
+ coff::IMAGE_SCN_CNT_INITIALIZED_DATA
+ | coff::IMAGE_SCN_MEM_READ
+ | coff::IMAGE_SCN_MEM_DISCARDABLE
+ }
+ SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE,
+ SectionKind::Common
+ | SectionKind::Tls
+ | SectionKind::UninitializedTls
+ | SectionKind::TlsVariables
+ | SectionKind::Note
+ | SectionKind::Unknown
+ | SectionKind::Metadata
+ | SectionKind::Elf(_) => {
+ return Err(Error(format!(
+ "unimplemented section `{}` kind {:?}",
+ section.name().unwrap_or(""),
+ section.kind
+ )));
+ }
+ }
+ };
+ if section_offsets[index].selection != 0 {
+ characteristics |= coff::IMAGE_SCN_LNK_COMDAT;
+ };
+ if section.relocations.len() > 0xffff {
+ characteristics |= coff::IMAGE_SCN_LNK_NRELOC_OVFL;
+ }
+ characteristics |= match section.align {
+ 1 => coff::IMAGE_SCN_ALIGN_1BYTES,
+ 2 => coff::IMAGE_SCN_ALIGN_2BYTES,
+ 4 => coff::IMAGE_SCN_ALIGN_4BYTES,
+ 8 => coff::IMAGE_SCN_ALIGN_8BYTES,
+ 16 => coff::IMAGE_SCN_ALIGN_16BYTES,
+ 32 => coff::IMAGE_SCN_ALIGN_32BYTES,
+ 64 => coff::IMAGE_SCN_ALIGN_64BYTES,
+ 128 => coff::IMAGE_SCN_ALIGN_128BYTES,
+ 256 => coff::IMAGE_SCN_ALIGN_256BYTES,
+ 512 => coff::IMAGE_SCN_ALIGN_512BYTES,
+ 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES,
+ 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES,
+ 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES,
+ 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented section `{}` align {}",
+ section.name().unwrap_or(""),
+ section.align
+ )));
+ }
+ };
+ let mut coff_section = coff::ImageSectionHeader {
+ name: [0; 8],
+ virtual_size: U32::default(),
+ virtual_address: U32::default(),
+ size_of_raw_data: U32::new(LE, section.size as u32),
+ pointer_to_raw_data: U32::new(LE, section_offsets[index].offset as u32),
+ pointer_to_relocations: U32::new(LE, section_offsets[index].reloc_offset as u32),
+ pointer_to_linenumbers: U32::default(),
+ number_of_relocations: if section.relocations.len() > 0xffff {
+ U16::new(LE, 0xffff)
+ } else {
+ U16::new(LE, section.relocations.len() as u16)
+ },
+ number_of_linenumbers: U16::default(),
+ characteristics: U32::new(LE, characteristics),
+ };
+ if section.name.len() <= 8 {
+ coff_section.name[..section.name.len()].copy_from_slice(&section.name);
+ } else {
+ let mut str_offset = strtab.get_offset(section_offsets[index].str_id.unwrap());
+ if str_offset <= 9_999_999 {
+ let mut name = [0; 7];
+ let mut len = 0;
+ if str_offset == 0 {
+ name[6] = b'0';
+ len = 1;
+ } else {
+ while str_offset != 0 {
+ let rem = (str_offset % 10) as u8;
+ str_offset /= 10;
+ name[6 - len] = b'0' + rem;
+ len += 1;
+ }
+ }
+ coff_section.name = [0; 8];
+ coff_section.name[0] = b'/';
+ coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]);
+ } else if str_offset as u64 <= 0xf_ffff_ffff {
+ coff_section.name[0] = b'/';
+ coff_section.name[1] = b'/';
+ for i in 0..6 {
+ let rem = (str_offset % 64) as u8;
+ str_offset /= 64;
+ let c = match rem {
+ 0..=25 => b'A' + rem,
+ 26..=51 => b'a' + rem - 26,
+ 52..=61 => b'0' + rem - 52,
+ 62 => b'+',
+ 63 => b'/',
+ _ => unreachable!(),
+ };
+ coff_section.name[7 - i] = c;
+ }
+ } else {
+ return Err(Error(format!("invalid section name offset {}", str_offset)));
+ }
+ }
+ buffer.write(&coff_section);
+ }
+
+ // Write section data and relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ let len = section.data.len();
+ if len != 0 {
+ write_align(buffer, 4);
+ debug_assert_eq!(section_offsets[index].offset, buffer.len());
+ buffer.write_bytes(&section.data);
+ }
+
+ if !section.relocations.is_empty() {
+ debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
+ if section.relocations.len() > 0xffff {
+ let coff_relocation = coff::ImageRelocation {
+ virtual_address: U32Bytes::new(LE, section.relocations.len() as u32 + 1),
+ symbol_table_index: U32Bytes::new(LE, 0),
+ typ: U16Bytes::new(LE, 0),
+ };
+ buffer.write(&coff_relocation);
+ }
+ for reloc in &section.relocations {
+ //assert!(reloc.implicit_addend);
+ let typ = match self.architecture {
+ Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16,
+ (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16,
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL,
+ (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64,
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32,
+ (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1,
+ (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2,
+ (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3,
+ (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4,
+ (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL,
+ (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Arm => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM_ADDR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM_ADDR32NB,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM_REL32,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM_SECREL,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Aarch64 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32NB,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM64_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM64_SECREL,
+ (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_ARM64_ADDR64,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM64_REL32,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+ let coff_relocation = coff::ImageRelocation {
+ virtual_address: U32Bytes::new(LE, reloc.offset as u32),
+ symbol_table_index: U32Bytes::new(
+ LE,
+ symbol_offsets[reloc.symbol.0].index as u32,
+ ),
+ typ: U16Bytes::new(LE, typ),
+ };
+ buffer.write(&coff_relocation);
+ }
+ }
+ }
+
+ // Write symbols.
+ debug_assert_eq!(symtab_offset, buffer.len());
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ let mut name = &symbol.name[..];
+ let section_number = match symbol.section {
+ SymbolSection::None => {
+ debug_assert_eq!(symbol.kind, SymbolKind::File);
+ coff::IMAGE_SYM_DEBUG as u16
+ }
+ SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16,
+ SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16,
+ SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16,
+ SymbolSection::Section(id) => id.0 as u16 + 1,
+ };
+ let typ = if symbol.kind == SymbolKind::Text {
+ coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT
+ } else {
+ coff::IMAGE_SYM_TYPE_NULL
+ };
+ let storage_class = match symbol.kind {
+ SymbolKind::File => {
+ // Name goes in auxiliary symbol records.
+ name = b".file";
+ coff::IMAGE_SYM_CLASS_FILE
+ }
+ SymbolKind::Section => coff::IMAGE_SYM_CLASS_STATIC,
+ SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL,
+ SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
+ match symbol.section {
+ SymbolSection::None => {
+ return Err(Error(format!(
+ "missing section for symbol `{}`",
+ symbol.name().unwrap_or("")
+ )));
+ }
+ SymbolSection::Undefined | SymbolSection::Common => {
+ coff::IMAGE_SYM_CLASS_EXTERNAL
+ }
+ SymbolSection::Absolute | SymbolSection::Section(_) => {
+ match symbol.scope {
+ // TODO: does this need aux symbol records too?
+ _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL,
+ SymbolScope::Unknown => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` scope {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.scope
+ )));
+ }
+ SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC,
+ SymbolScope::Linkage | SymbolScope::Dynamic => {
+ coff::IMAGE_SYM_CLASS_EXTERNAL
+ }
+ }
+ }
+ }
+ }
+ SymbolKind::Unknown | SymbolKind::Null => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ };
+ let number_of_aux_symbols = symbol_offsets[index].aux_count;
+ let value = if symbol.section == SymbolSection::Common {
+ symbol.size as u32
+ } else {
+ symbol.value as u32
+ };
+ let mut coff_symbol = coff::ImageSymbol {
+ name: [0; 8],
+ value: U32Bytes::new(LE, value),
+ section_number: U16Bytes::new(LE, section_number),
+ typ: U16Bytes::new(LE, typ),
+ storage_class,
+ number_of_aux_symbols,
+ };
+ if name.len() <= 8 {
+ coff_symbol.name[..name.len()].copy_from_slice(name);
+ } else {
+ let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap());
+ coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32));
+ }
+ buffer.write(&coff_symbol);
+
+ // Write auxiliary symbols.
+ match symbol.kind {
+ SymbolKind::File => {
+ let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL;
+ debug_assert!(aux_len >= symbol.name.len());
+ let old_len = buffer.len();
+ buffer.write_bytes(&symbol.name);
+ buffer.resize(old_len + aux_len);
+ }
+ SymbolKind::Section => {
+ debug_assert_eq!(number_of_aux_symbols, 1);
+ let section_index = symbol.section.id().unwrap().0;
+ let section = &self.sections[section_index];
+ let aux = coff::ImageAuxSymbolSection {
+ length: U32Bytes::new(LE, section.size as u32),
+ number_of_relocations: if section.relocations.len() > 0xffff {
+ U16Bytes::new(LE, 0xffff)
+ } else {
+ U16Bytes::new(LE, section.relocations.len() as u16)
+ },
+ number_of_linenumbers: U16Bytes::default(),
+ check_sum: U32Bytes::new(LE, checksum(section.data())),
+ number: U16Bytes::new(
+ LE,
+ section_offsets[section_index].associative_section,
+ ),
+ selection: section_offsets[section_index].selection,
+ reserved: 0,
+ // TODO: bigobj
+ high_number: U16Bytes::default(),
+ };
+ buffer.write(&aux);
+ }
+ _ => {
+ debug_assert_eq!(number_of_aux_symbols, 0);
+ }
+ }
+ }
+
+ // Write strtab section.
+ debug_assert_eq!(strtab_offset, buffer.len());
+ buffer.write_bytes(&u32::to_le_bytes(strtab_len as u32));
+ buffer.write_bytes(&strtab_data);
+
+ debug_assert_eq!(offset, buffer.len());
+
+ Ok(())
+ }
+}
+
+// JamCRC
+fn checksum(data: &[u8]) -> u32 {
+ let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
+ hasher.update(data);
+ !hasher.finalize()
+}
diff --git a/third_party/rust/object/src/write/elf/mod.rs b/third_party/rust/object/src/write/elf/mod.rs
new file mode 100644
index 0000000000..3a4f3716e8
--- /dev/null
+++ b/third_party/rust/object/src/write/elf/mod.rs
@@ -0,0 +1,9 @@
+//! Support for writing ELF files.
+//!
+//! Provides [`Writer`] for low level writing of ELF files.
+//! This is also used to provide ELF support for [`write::Object`](crate::write::Object).
+
+mod object;
+
+mod writer;
+pub use writer::*;
diff --git a/third_party/rust/object/src/write/elf/object.rs b/third_party/rust/object/src/write/elf/object.rs
new file mode 100644
index 0000000000..acc820c9ec
--- /dev/null
+++ b/third_party/rust/object/src/write/elf/object.rs
@@ -0,0 +1,903 @@
+use alloc::vec::Vec;
+
+use crate::write::elf::writer::*;
+use crate::write::string::StringId;
+use crate::write::*;
+use crate::AddressSize;
+use crate::{elf, pod};
+
+#[derive(Clone, Copy)]
+struct ComdatOffsets {
+ offset: usize,
+ str_id: StringId,
+}
+
+#[derive(Clone, Copy)]
+struct SectionOffsets {
+ index: SectionIndex,
+ offset: usize,
+ str_id: StringId,
+ reloc_offset: usize,
+ reloc_str_id: Option<StringId>,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ index: SymbolIndex,
+ str_id: Option<StringId>,
+}
+
+// Public methods.
+impl<'a> Object<'a> {
+ /// Add a property with a u32 value to the ELF ".note.gnu.property" section.
+ ///
+ /// Requires `feature = "elf"`.
+ pub fn add_elf_gnu_property_u32(&mut self, property: u32, value: u32) {
+ if self.format != BinaryFormat::Elf {
+ return;
+ }
+
+ let align = if self.elf_is_64() { 8 } else { 4 };
+ let mut data = Vec::with_capacity(32);
+ let n_name = b"GNU\0";
+ data.extend_from_slice(pod::bytes_of(&elf::NoteHeader32 {
+ n_namesz: U32::new(self.endian, n_name.len() as u32),
+ n_descsz: U32::new(self.endian, util::align(3 * 4, align) as u32),
+ n_type: U32::new(self.endian, elf::NT_GNU_PROPERTY_TYPE_0),
+ }));
+ data.extend_from_slice(n_name);
+ // This happens to already be aligned correctly.
+ debug_assert_eq!(util::align(data.len(), align), data.len());
+ data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, property)));
+ // Value size
+ data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, 4)));
+ data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, value)));
+ util::write_align(&mut data, align);
+
+ let section = self.section_id(StandardSection::GnuProperty);
+ self.append_section_data(section, &data, align as u64);
+ }
+}
+
+// Private methods.
+impl<'a> Object<'a> {
+ pub(crate) fn elf_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
+ match section {
+ StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
+ StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
+ StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => (
+ &[],
+ &b".rodata"[..],
+ SectionKind::ReadOnlyData,
+ SectionFlags::None,
+ ),
+ StandardSection::ReadOnlyDataWithRel => (
+ &[],
+ b".data.rel.ro",
+ SectionKind::ReadOnlyDataWithRel,
+ SectionFlags::None,
+ ),
+ StandardSection::UninitializedData => (
+ &[],
+ &b".bss"[..],
+ SectionKind::UninitializedData,
+ SectionFlags::None,
+ ),
+ StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls, SectionFlags::None),
+ StandardSection::UninitializedTls => (
+ &[],
+ &b".tbss"[..],
+ SectionKind::UninitializedTls,
+ SectionFlags::None,
+ ),
+ StandardSection::TlsVariables => {
+ // Unsupported section.
+ (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
+ }
+ StandardSection::Common => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Common, SectionFlags::None)
+ }
+ StandardSection::GnuProperty => (
+ &[],
+ &b".note.gnu.property"[..],
+ SectionKind::Note,
+ SectionFlags::Elf {
+ sh_flags: u64::from(elf::SHF_ALLOC),
+ },
+ ),
+ }
+ }
+
+ pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
+ let mut name = section.to_vec();
+ name.push(b'.');
+ name.extend_from_slice(value);
+ name
+ }
+
+ fn elf_has_relocation_addend(&self) -> Result<bool> {
+ Ok(match self.architecture {
+ Architecture::Aarch64 => true,
+ Architecture::Aarch64_Ilp32 => true,
+ Architecture::Arm => false,
+ Architecture::Avr => true,
+ Architecture::Bpf => false,
+ Architecture::Csky => true,
+ Architecture::I386 => false,
+ Architecture::X86_64 => true,
+ Architecture::X86_64_X32 => true,
+ Architecture::Hexagon => true,
+ Architecture::LoongArch64 => true,
+ Architecture::Mips => false,
+ Architecture::Mips64 => true,
+ Architecture::Msp430 => true,
+ Architecture::PowerPc => true,
+ Architecture::PowerPc64 => true,
+ Architecture::Riscv64 => true,
+ Architecture::Riscv32 => true,
+ Architecture::S390x => true,
+ Architecture::Sbf => false,
+ Architecture::Sparc64 => true,
+ Architecture::Xtensa => true,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ })
+ }
+
+ pub(crate) fn elf_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> Result<i64> {
+ // Return true if we should use a section symbol to avoid preemption.
+ fn want_section_symbol(relocation: &Relocation, symbol: &Symbol) -> bool {
+ if symbol.scope != SymbolScope::Dynamic {
+ // Only dynamic symbols can be preemptible.
+ return false;
+ }
+ match symbol.kind {
+ SymbolKind::Text | SymbolKind::Data => {}
+ _ => return false,
+ }
+ match relocation.kind {
+ // Anything using GOT or PLT is preemptible.
+ // We also require that `Other` relocations must already be correct.
+ RelocationKind::Got
+ | RelocationKind::GotRelative
+ | RelocationKind::GotBaseRelative
+ | RelocationKind::PltRelative
+ | RelocationKind::Elf(_) => return false,
+ // Absolute relocations are preemptible for non-local data.
+ // TODO: not sure if this rule is exactly correct
+ // This rule was added to handle global data references in debuginfo.
+ // Maybe this should be a new relocation kind so that the caller can decide.
+ RelocationKind::Absolute => {
+ if symbol.kind == SymbolKind::Data {
+ return false;
+ }
+ }
+ _ => {}
+ }
+ true
+ }
+
+ // Use section symbols for relocations where required to avoid preemption.
+ // Otherwise, the linker will fail with:
+ // relocation R_X86_64_PC32 against symbol `SomeSymbolName' can not be used when
+ // making a shared object; recompile with -fPIC
+ let symbol = &self.symbols[relocation.symbol.0];
+ if want_section_symbol(relocation, symbol) {
+ if let Some(section) = symbol.section.id() {
+ relocation.addend += symbol.value as i64;
+ relocation.symbol = self.section_symbol(section);
+ }
+ }
+
+ // Determine whether the addend is stored in the relocation or the data.
+ if self.elf_has_relocation_addend()? {
+ Ok(0)
+ } else {
+ let constant = relocation.addend;
+ relocation.addend = 0;
+ Ok(constant)
+ }
+ }
+
+ pub(crate) fn elf_is_64(&self) -> bool {
+ match self.architecture.address_size().unwrap() {
+ AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false,
+ AddressSize::U64 => true,
+ }
+ }
+
+ pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ // Create reloc section header names so we can reference them.
+ let is_rela = self.elf_has_relocation_addend()?;
+ let reloc_names: Vec<_> = self
+ .sections
+ .iter()
+ .map(|section| {
+ let mut reloc_name = Vec::with_capacity(
+ if is_rela { ".rela".len() } else { ".rel".len() } + section.name.len(),
+ );
+ if !section.relocations.is_empty() {
+ reloc_name.extend_from_slice(if is_rela {
+ &b".rela"[..]
+ } else {
+ &b".rel"[..]
+ });
+ reloc_name.extend_from_slice(&section.name);
+ }
+ reloc_name
+ })
+ .collect();
+
+ // Start calculating offsets of everything.
+ let mut writer = Writer::new(self.endian, self.elf_is_64(), buffer);
+ writer.reserve_file_header();
+
+ // Calculate size of section data.
+ let mut comdat_offsets = Vec::with_capacity(self.comdats.len());
+ for comdat in &self.comdats {
+ if comdat.kind != ComdatKind::Any {
+ return Err(Error(format!(
+ "unsupported COMDAT symbol `{}` kind {:?}",
+ self.symbols[comdat.symbol.0].name().unwrap_or(""),
+ comdat.kind
+ )));
+ }
+
+ writer.reserve_section_index();
+ let offset = writer.reserve_comdat(comdat.sections.len());
+ let str_id = writer.add_section_name(b".group");
+ comdat_offsets.push(ComdatOffsets { offset, str_id });
+ }
+ let mut section_offsets = Vec::with_capacity(self.sections.len());
+ for (section, reloc_name) in self.sections.iter().zip(reloc_names.iter()) {
+ let index = writer.reserve_section_index();
+ let offset = writer.reserve(section.data.len(), section.align as usize);
+ let str_id = writer.add_section_name(&section.name);
+ let mut reloc_str_id = None;
+ if !section.relocations.is_empty() {
+ writer.reserve_section_index();
+ reloc_str_id = Some(writer.add_section_name(reloc_name));
+ }
+ section_offsets.push(SectionOffsets {
+ index,
+ offset,
+ str_id,
+ // Relocation data is reserved later.
+ reloc_offset: 0,
+ reloc_str_id,
+ });
+ }
+
+ // Calculate index of symbols and add symbol strings to strtab.
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ writer.reserve_null_symbol_index();
+ // Local symbols must come before global.
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if symbol.is_local() {
+ let section_index = symbol.section.id().map(|s| section_offsets[s.0].index);
+ symbol_offsets[index].index = writer.reserve_symbol_index(section_index);
+ }
+ }
+ let symtab_num_local = writer.symbol_count();
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if !symbol.is_local() {
+ let section_index = symbol.section.id().map(|s| section_offsets[s.0].index);
+ symbol_offsets[index].index = writer.reserve_symbol_index(section_index);
+ }
+ }
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if symbol.kind != SymbolKind::Section && !symbol.name.is_empty() {
+ symbol_offsets[index].str_id = Some(writer.add_string(&symbol.name));
+ }
+ }
+
+ // Calculate size of symbols.
+ writer.reserve_symtab_section_index();
+ writer.reserve_symtab();
+ if writer.symtab_shndx_needed() {
+ writer.reserve_symtab_shndx_section_index();
+ }
+ writer.reserve_symtab_shndx();
+ writer.reserve_strtab_section_index();
+ writer.reserve_strtab();
+
+ // Calculate size of relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ let count = section.relocations.len();
+ if count != 0 {
+ section_offsets[index].reloc_offset = writer.reserve_relocations(count, is_rela);
+ }
+ }
+
+ // Calculate size of section headers.
+ writer.reserve_shstrtab_section_index();
+ writer.reserve_shstrtab();
+ writer.reserve_section_headers();
+
+ // Start writing.
+ let e_type = elf::ET_REL;
+ let e_machine = match self.architecture {
+ Architecture::Aarch64 => elf::EM_AARCH64,
+ Architecture::Aarch64_Ilp32 => elf::EM_AARCH64,
+ Architecture::Arm => elf::EM_ARM,
+ Architecture::Avr => elf::EM_AVR,
+ Architecture::Bpf => elf::EM_BPF,
+ Architecture::Csky => elf::EM_CSKY,
+ Architecture::I386 => elf::EM_386,
+ Architecture::X86_64 => elf::EM_X86_64,
+ Architecture::X86_64_X32 => elf::EM_X86_64,
+ Architecture::Hexagon => elf::EM_HEXAGON,
+ Architecture::LoongArch64 => elf::EM_LOONGARCH,
+ Architecture::Mips => elf::EM_MIPS,
+ Architecture::Mips64 => elf::EM_MIPS,
+ Architecture::Msp430 => elf::EM_MSP430,
+ Architecture::PowerPc => elf::EM_PPC,
+ Architecture::PowerPc64 => elf::EM_PPC64,
+ Architecture::Riscv32 => elf::EM_RISCV,
+ Architecture::Riscv64 => elf::EM_RISCV,
+ Architecture::S390x => elf::EM_S390,
+ Architecture::Sbf => elf::EM_SBF,
+ Architecture::Sparc64 => elf::EM_SPARCV9,
+ Architecture::Xtensa => elf::EM_XTENSA,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+ let (os_abi, abi_version, e_flags) = if let FileFlags::Elf {
+ os_abi,
+ abi_version,
+ e_flags,
+ } = self.flags
+ {
+ (os_abi, abi_version, e_flags)
+ } else {
+ (elf::ELFOSABI_NONE, 0, 0)
+ };
+ writer.write_file_header(&FileHeader {
+ os_abi,
+ abi_version,
+ e_type,
+ e_machine,
+ e_entry: 0,
+ e_flags,
+ })?;
+
+ // Write section data.
+ for comdat in &self.comdats {
+ writer.write_comdat_header();
+ for section in &comdat.sections {
+ writer.write_comdat_entry(section_offsets[section.0].index);
+ }
+ }
+ for (index, section) in self.sections.iter().enumerate() {
+ writer.write_align(section.align as usize);
+ debug_assert_eq!(section_offsets[index].offset, writer.len());
+ writer.write(&section.data);
+ }
+
+ // Write symbols.
+ writer.write_null_symbol();
+ let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> {
+ let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags {
+ st_info
+ } else {
+ let st_type = match symbol.kind {
+ SymbolKind::Null => elf::STT_NOTYPE,
+ SymbolKind::Text => {
+ if symbol.is_undefined() {
+ elf::STT_NOTYPE
+ } else {
+ elf::STT_FUNC
+ }
+ }
+ SymbolKind::Data => {
+ if symbol.is_undefined() {
+ elf::STT_NOTYPE
+ } else if symbol.is_common() {
+ elf::STT_COMMON
+ } else {
+ elf::STT_OBJECT
+ }
+ }
+ SymbolKind::Section => elf::STT_SECTION,
+ SymbolKind::File => elf::STT_FILE,
+ SymbolKind::Tls => elf::STT_TLS,
+ SymbolKind::Label => elf::STT_NOTYPE,
+ SymbolKind::Unknown => {
+ if symbol.is_undefined() {
+ elf::STT_NOTYPE
+ } else {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ }
+ };
+ let st_bind = if symbol.weak {
+ elf::STB_WEAK
+ } else if symbol.is_undefined() {
+ elf::STB_GLOBAL
+ } else if symbol.is_local() {
+ elf::STB_LOCAL
+ } else {
+ elf::STB_GLOBAL
+ };
+ (st_bind << 4) + st_type
+ };
+ let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags {
+ st_other
+ } else if symbol.scope == SymbolScope::Linkage {
+ elf::STV_HIDDEN
+ } else {
+ elf::STV_DEFAULT
+ };
+ let (st_shndx, section) = match symbol.section {
+ SymbolSection::None => {
+ debug_assert_eq!(symbol.kind, SymbolKind::File);
+ (elf::SHN_ABS, None)
+ }
+ SymbolSection::Undefined => (elf::SHN_UNDEF, None),
+ SymbolSection::Absolute => (elf::SHN_ABS, None),
+ SymbolSection::Common => (elf::SHN_COMMON, None),
+ SymbolSection::Section(id) => (0, Some(section_offsets[id.0].index)),
+ };
+ writer.write_symbol(&Sym {
+ name: symbol_offsets[index].str_id,
+ section,
+ st_info,
+ st_other,
+ st_shndx,
+ st_value: symbol.value,
+ st_size: symbol.size,
+ });
+ Ok(())
+ };
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if symbol.is_local() {
+ write_symbol(index, symbol)?;
+ }
+ }
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if !symbol.is_local() {
+ write_symbol(index, symbol)?;
+ }
+ }
+ writer.write_symtab_shndx();
+ writer.write_strtab();
+
+ // Write relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ if !section.relocations.is_empty() {
+ writer.write_align_relocation();
+ debug_assert_eq!(section_offsets[index].reloc_offset, writer.len());
+ for reloc in &section.relocations {
+ let r_type = match self.architecture {
+ Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
+ elf::R_AARCH64_ABS64
+ }
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
+ elf::R_AARCH64_ABS32
+ }
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => {
+ elf::R_AARCH64_ABS16
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, 64) => {
+ elf::R_AARCH64_PREL64
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
+ elf::R_AARCH64_PREL32
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, 16) => {
+ elf::R_AARCH64_PREL16
+ }
+ (RelocationKind::Relative, RelocationEncoding::AArch64Call, 26)
+ | (RelocationKind::PltRelative, RelocationEncoding::AArch64Call, 26) => {
+ elf::R_AARCH64_CALL26
+ }
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Aarch64_Ilp32 => {
+ match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
+ elf::R_AARCH64_P32_ABS32
+ }
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented relocation {:?}",
+ reloc
+ )));
+ }
+ }
+ }
+ Architecture::Arm => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_ARM_ABS32,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Avr => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_AVR_32,
+ (RelocationKind::Absolute, _, 16) => elf::R_AVR_16,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Bpf => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 64) => elf::R_BPF_64_64,
+ (RelocationKind::Absolute, _, 32) => elf::R_BPF_64_32,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Csky => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_CKCORE_ADDR32,
+ (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
+ elf::R_CKCORE_PCREL32
+ }
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::I386 => match (reloc.kind, reloc.size) {
+ (RelocationKind::Absolute, 32) => elf::R_386_32,
+ (RelocationKind::Relative, 32) => elf::R_386_PC32,
+ (RelocationKind::Got, 32) => elf::R_386_GOT32,
+ (RelocationKind::PltRelative, 32) => elf::R_386_PLT32,
+ (RelocationKind::GotBaseOffset, 32) => elf::R_386_GOTOFF,
+ (RelocationKind::GotBaseRelative, 32) => elf::R_386_GOTPC,
+ (RelocationKind::Absolute, 16) => elf::R_386_16,
+ (RelocationKind::Relative, 16) => elf::R_386_PC16,
+ (RelocationKind::Absolute, 8) => elf::R_386_8,
+ (RelocationKind::Relative, 8) => elf::R_386_PC8,
+ (RelocationKind::Elf(x), _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::X86_64 | Architecture::X86_64_X32 => {
+ match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
+ elf::R_X86_64_64
+ }
+ (RelocationKind::Relative, _, 32) => elf::R_X86_64_PC32,
+ (RelocationKind::Got, _, 32) => elf::R_X86_64_GOT32,
+ (RelocationKind::PltRelative, _, 32) => elf::R_X86_64_PLT32,
+ (RelocationKind::GotRelative, _, 32) => elf::R_X86_64_GOTPCREL,
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
+ elf::R_X86_64_32
+ }
+ (RelocationKind::Absolute, RelocationEncoding::X86Signed, 32) => {
+ elf::R_X86_64_32S
+ }
+ (RelocationKind::Absolute, _, 16) => elf::R_X86_64_16,
+ (RelocationKind::Relative, _, 16) => elf::R_X86_64_PC16,
+ (RelocationKind::Absolute, _, 8) => elf::R_X86_64_8,
+ (RelocationKind::Relative, _, 8) => elf::R_X86_64_PC8,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented relocation {:?}",
+ reloc
+ )));
+ }
+ }
+ }
+ Architecture::Hexagon => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_HEX_32,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::LoongArch64 => match (reloc.kind, reloc.encoding, reloc.size)
+ {
+ (RelocationKind::Absolute, _, 32) => elf::R_LARCH_32,
+ (RelocationKind::Absolute, _, 64) => elf::R_LARCH_64,
+ (RelocationKind::Relative, _, 32) => elf::R_LARCH_32_PCREL,
+ (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 16)
+ | (
+ RelocationKind::PltRelative,
+ RelocationEncoding::LoongArchBranch,
+ 16,
+ ) => elf::R_LARCH_B16,
+ (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 21)
+ | (
+ RelocationKind::PltRelative,
+ RelocationEncoding::LoongArchBranch,
+ 21,
+ ) => elf::R_LARCH_B21,
+ (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 26)
+ | (
+ RelocationKind::PltRelative,
+ RelocationEncoding::LoongArchBranch,
+ 26,
+ ) => elf::R_LARCH_B26,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Mips | Architecture::Mips64 => {
+ match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 16) => elf::R_MIPS_16,
+ (RelocationKind::Absolute, _, 32) => elf::R_MIPS_32,
+ (RelocationKind::Absolute, _, 64) => elf::R_MIPS_64,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented relocation {:?}",
+ reloc
+ )));
+ }
+ }
+ }
+ Architecture::Msp430 => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_MSP430_32,
+ (RelocationKind::Absolute, _, 16) => elf::R_MSP430_16_BYTE,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::PowerPc => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_PPC_ADDR32,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::PowerPc64 => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_PPC64_ADDR32,
+ (RelocationKind::Absolute, _, 64) => elf::R_PPC64_ADDR64,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Riscv32 | Architecture::Riscv64 => {
+ match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_RISCV_32,
+ (RelocationKind::Absolute, _, 64) => elf::R_RISCV_64,
+ (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
+ elf::R_RISCV_32_PCREL
+ }
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented relocation {:?}",
+ reloc
+ )));
+ }
+ }
+ }
+ Architecture::S390x => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 8) => {
+ elf::R_390_8
+ }
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => {
+ elf::R_390_16
+ }
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
+ elf::R_390_32
+ }
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
+ elf::R_390_64
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, 16) => {
+ elf::R_390_PC16
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
+ elf::R_390_PC32
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, 64) => {
+ elf::R_390_PC64
+ }
+ (RelocationKind::Relative, RelocationEncoding::S390xDbl, 16) => {
+ elf::R_390_PC16DBL
+ }
+ (RelocationKind::Relative, RelocationEncoding::S390xDbl, 32) => {
+ elf::R_390_PC32DBL
+ }
+ (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 16) => {
+ elf::R_390_PLT16DBL
+ }
+ (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 32) => {
+ elf::R_390_PLT32DBL
+ }
+ (RelocationKind::Got, RelocationEncoding::Generic, 16) => {
+ elf::R_390_GOT16
+ }
+ (RelocationKind::Got, RelocationEncoding::Generic, 32) => {
+ elf::R_390_GOT32
+ }
+ (RelocationKind::Got, RelocationEncoding::Generic, 64) => {
+ elf::R_390_GOT64
+ }
+ (RelocationKind::GotRelative, RelocationEncoding::S390xDbl, 32) => {
+ elf::R_390_GOTENT
+ }
+ (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 16) => {
+ elf::R_390_GOTOFF16
+ }
+ (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 32) => {
+ elf::R_390_GOTOFF32
+ }
+ (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 64) => {
+ elf::R_390_GOTOFF64
+ }
+ (RelocationKind::GotBaseRelative, RelocationEncoding::Generic, 64) => {
+ elf::R_390_GOTPC
+ }
+ (RelocationKind::GotBaseRelative, RelocationEncoding::S390xDbl, 32) => {
+ elf::R_390_GOTPCDBL
+ }
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Sbf => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 64) => elf::R_SBF_64_64,
+ (RelocationKind::Absolute, _, 32) => elf::R_SBF_64_32,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Sparc64 => match (reloc.kind, reloc.encoding, reloc.size) {
+ // TODO: use R_SPARC_32/R_SPARC_64 if aligned.
+ (RelocationKind::Absolute, _, 32) => elf::R_SPARC_UA32,
+ (RelocationKind::Absolute, _, 64) => elf::R_SPARC_UA64,
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Xtensa => match (reloc.kind, reloc.encoding, reloc.size) {
+ (RelocationKind::Absolute, _, 32) => elf::R_XTENSA_32,
+ (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
+ elf::R_XTENSA_32_PCREL
+ }
+ (RelocationKind::Elf(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ _ => {
+ if let RelocationKind::Elf(x) = reloc.kind {
+ x
+ } else {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ }
+ };
+ let r_sym = symbol_offsets[reloc.symbol.0].index.0;
+ writer.write_relocation(
+ is_rela,
+ &Rel {
+ r_offset: reloc.offset,
+ r_sym,
+ r_type,
+ r_addend: reloc.addend,
+ },
+ );
+ }
+ }
+ }
+
+ writer.write_shstrtab();
+
+ // Write section headers.
+ writer.write_null_section_header();
+
+ let symtab_index = writer.symtab_index();
+ for (comdat, comdat_offset) in self.comdats.iter().zip(comdat_offsets.iter()) {
+ writer.write_comdat_section_header(
+ comdat_offset.str_id,
+ symtab_index,
+ symbol_offsets[comdat.symbol.0].index,
+ comdat_offset.offset,
+ comdat.sections.len(),
+ );
+ }
+ for (index, section) in self.sections.iter().enumerate() {
+ let sh_type = match section.kind {
+ SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS,
+ SectionKind::Note => elf::SHT_NOTE,
+ SectionKind::Elf(sh_type) => sh_type,
+ _ => elf::SHT_PROGBITS,
+ };
+ let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags {
+ sh_flags
+ } else {
+ match section.kind {
+ SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR,
+ SectionKind::Data | SectionKind::ReadOnlyDataWithRel => {
+ elf::SHF_ALLOC | elf::SHF_WRITE
+ }
+ SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
+ SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE,
+ SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
+ SectionKind::ReadOnlyData => elf::SHF_ALLOC,
+ SectionKind::ReadOnlyString => {
+ elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE
+ }
+ SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE,
+ SectionKind::Other
+ | SectionKind::Debug
+ | SectionKind::Metadata
+ | SectionKind::Linker
+ | SectionKind::Note
+ | SectionKind::Elf(_) => 0,
+ SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => {
+ return Err(Error(format!(
+ "unimplemented section `{}` kind {:?}",
+ section.name().unwrap_or(""),
+ section.kind
+ )));
+ }
+ }
+ .into()
+ };
+ // TODO: not sure if this is correct, maybe user should determine this
+ let sh_entsize = match section.kind {
+ SectionKind::ReadOnlyString | SectionKind::OtherString => 1,
+ _ => 0,
+ };
+ writer.write_section_header(&SectionHeader {
+ name: Some(section_offsets[index].str_id),
+ sh_type,
+ sh_flags,
+ sh_addr: 0,
+ sh_offset: section_offsets[index].offset as u64,
+ sh_size: section.size,
+ sh_link: 0,
+ sh_info: 0,
+ sh_addralign: section.align,
+ sh_entsize,
+ });
+
+ if !section.relocations.is_empty() {
+ writer.write_relocation_section_header(
+ section_offsets[index].reloc_str_id.unwrap(),
+ section_offsets[index].index,
+ symtab_index,
+ section_offsets[index].reloc_offset,
+ section.relocations.len(),
+ is_rela,
+ );
+ }
+ }
+
+ writer.write_symtab_section_header(symtab_num_local);
+ writer.write_symtab_shndx_section_header();
+ writer.write_strtab_section_header();
+ writer.write_shstrtab_section_header();
+
+ debug_assert_eq!(writer.reserved_len(), writer.len());
+
+ Ok(())
+ }
+}
diff --git a/third_party/rust/object/src/write/elf/writer.rs b/third_party/rust/object/src/write/elf/writer.rs
new file mode 100644
index 0000000000..9750924969
--- /dev/null
+++ b/third_party/rust/object/src/write/elf/writer.rs
@@ -0,0 +1,2143 @@
+//! Helper for writing ELF files.
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::mem;
+
+use crate::elf;
+use crate::endian::*;
+use crate::pod;
+use crate::write::string::{StringId, StringTable};
+use crate::write::util;
+use crate::write::{Error, Result, WritableBuffer};
+
+/// The index of an ELF section.
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SectionIndex(pub u32);
+
+/// The index of an ELF symbol.
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SymbolIndex(pub u32);
+
+/// A helper for writing ELF files.
+///
+/// Writing uses a two phase approach. The first phase builds up all of the information
+/// that may need to be known ahead of time:
+/// - build string tables
+/// - reserve section indices
+/// - reserve symbol indices
+/// - reserve file ranges for headers and sections
+///
+/// Some of the information has ordering requirements. For example, strings must be added
+/// to string tables before reserving the file range for the string table. Symbol indices
+/// must be reserved after reserving the section indices they reference. There are debug
+/// asserts to check some of these requirements.
+///
+/// The second phase writes everything out in order. Thus the caller must ensure writing
+/// is in the same order that file ranges were reserved. There are debug asserts to assist
+/// with checking this.
+#[allow(missing_debug_implementations)]
+pub struct Writer<'a> {
+ endian: Endianness,
+ is_64: bool,
+ is_mips64el: bool,
+ elf_align: usize,
+
+ buffer: &'a mut dyn WritableBuffer,
+ len: usize,
+
+ segment_offset: usize,
+ segment_num: u32,
+
+ section_offset: usize,
+ section_num: u32,
+
+ shstrtab: StringTable<'a>,
+ shstrtab_str_id: Option<StringId>,
+ shstrtab_index: SectionIndex,
+ shstrtab_offset: usize,
+ shstrtab_data: Vec<u8>,
+
+ need_strtab: bool,
+ strtab: StringTable<'a>,
+ strtab_str_id: Option<StringId>,
+ strtab_index: SectionIndex,
+ strtab_offset: usize,
+ strtab_data: Vec<u8>,
+
+ symtab_str_id: Option<StringId>,
+ symtab_index: SectionIndex,
+ symtab_offset: usize,
+ symtab_num: u32,
+
+ need_symtab_shndx: bool,
+ symtab_shndx_str_id: Option<StringId>,
+ symtab_shndx_offset: usize,
+ symtab_shndx_data: Vec<u8>,
+
+ need_dynstr: bool,
+ dynstr: StringTable<'a>,
+ dynstr_str_id: Option<StringId>,
+ dynstr_index: SectionIndex,
+ dynstr_offset: usize,
+ dynstr_data: Vec<u8>,
+
+ dynsym_str_id: Option<StringId>,
+ dynsym_index: SectionIndex,
+ dynsym_offset: usize,
+ dynsym_num: u32,
+
+ dynamic_str_id: Option<StringId>,
+ dynamic_offset: usize,
+ dynamic_num: usize,
+
+ hash_str_id: Option<StringId>,
+ hash_offset: usize,
+ hash_size: usize,
+
+ gnu_hash_str_id: Option<StringId>,
+ gnu_hash_offset: usize,
+ gnu_hash_size: usize,
+
+ gnu_versym_str_id: Option<StringId>,
+ gnu_versym_offset: usize,
+
+ gnu_verdef_str_id: Option<StringId>,
+ gnu_verdef_offset: usize,
+ gnu_verdef_size: usize,
+ gnu_verdef_count: u16,
+ gnu_verdef_remaining: u16,
+ gnu_verdaux_remaining: u16,
+
+ gnu_verneed_str_id: Option<StringId>,
+ gnu_verneed_offset: usize,
+ gnu_verneed_size: usize,
+ gnu_verneed_count: u16,
+ gnu_verneed_remaining: u16,
+ gnu_vernaux_remaining: u16,
+
+ gnu_attributes_str_id: Option<StringId>,
+ gnu_attributes_offset: usize,
+ gnu_attributes_size: usize,
+}
+
+impl<'a> Writer<'a> {
+ /// Create a new `Writer` for the given endianness and ELF class.
+ pub fn new(endian: Endianness, is_64: bool, buffer: &'a mut dyn WritableBuffer) -> Self {
+ let elf_align = if is_64 { 8 } else { 4 };
+ Writer {
+ endian,
+ is_64,
+ // Determined later.
+ is_mips64el: false,
+ elf_align,
+
+ buffer,
+ len: 0,
+
+ segment_offset: 0,
+ segment_num: 0,
+
+ section_offset: 0,
+ section_num: 0,
+
+ shstrtab: StringTable::default(),
+ shstrtab_str_id: None,
+ shstrtab_index: SectionIndex(0),
+ shstrtab_offset: 0,
+ shstrtab_data: Vec::new(),
+
+ need_strtab: false,
+ strtab: StringTable::default(),
+ strtab_str_id: None,
+ strtab_index: SectionIndex(0),
+ strtab_offset: 0,
+ strtab_data: Vec::new(),
+
+ symtab_str_id: None,
+ symtab_index: SectionIndex(0),
+ symtab_offset: 0,
+ symtab_num: 0,
+
+ need_symtab_shndx: false,
+ symtab_shndx_str_id: None,
+ symtab_shndx_offset: 0,
+ symtab_shndx_data: Vec::new(),
+
+ need_dynstr: false,
+ dynstr: StringTable::default(),
+ dynstr_str_id: None,
+ dynstr_index: SectionIndex(0),
+ dynstr_offset: 0,
+ dynstr_data: Vec::new(),
+
+ dynsym_str_id: None,
+ dynsym_index: SectionIndex(0),
+ dynsym_offset: 0,
+ dynsym_num: 0,
+
+ dynamic_str_id: None,
+ dynamic_offset: 0,
+ dynamic_num: 0,
+
+ hash_str_id: None,
+ hash_offset: 0,
+ hash_size: 0,
+
+ gnu_hash_str_id: None,
+ gnu_hash_offset: 0,
+ gnu_hash_size: 0,
+
+ gnu_versym_str_id: None,
+ gnu_versym_offset: 0,
+
+ gnu_verdef_str_id: None,
+ gnu_verdef_offset: 0,
+ gnu_verdef_size: 0,
+ gnu_verdef_count: 0,
+ gnu_verdef_remaining: 0,
+ gnu_verdaux_remaining: 0,
+
+ gnu_verneed_str_id: None,
+ gnu_verneed_offset: 0,
+ gnu_verneed_size: 0,
+ gnu_verneed_count: 0,
+ gnu_verneed_remaining: 0,
+ gnu_vernaux_remaining: 0,
+
+ gnu_attributes_str_id: None,
+ gnu_attributes_offset: 0,
+ gnu_attributes_size: 0,
+ }
+ }
+
+ /// Return the current file length that has been reserved.
+ pub fn reserved_len(&self) -> usize {
+ self.len
+ }
+
+ /// Return the current file length that has been written.
+ #[allow(clippy::len_without_is_empty)]
+ pub fn len(&self) -> usize {
+ self.buffer.len()
+ }
+
+ /// Reserve a file range with the given size and starting alignment.
+ ///
+ /// Returns the aligned offset of the start of the range.
+ pub fn reserve(&mut self, len: usize, align_start: usize) -> usize {
+ if align_start > 1 {
+ self.len = util::align(self.len, align_start);
+ }
+ let offset = self.len;
+ self.len += len;
+ offset
+ }
+
+ /// Write alignment padding bytes.
+ pub fn write_align(&mut self, align_start: usize) {
+ if align_start > 1 {
+ util::write_align(self.buffer, align_start);
+ }
+ }
+
+ /// Write data.
+ ///
+ /// This is typically used to write section data.
+ pub fn write(&mut self, data: &[u8]) {
+ self.buffer.write_bytes(data);
+ }
+
+ /// Reserve the file range up to the given file offset.
+ pub fn reserve_until(&mut self, offset: usize) {
+ debug_assert!(self.len <= offset);
+ self.len = offset;
+ }
+
+ /// Write padding up to the given file offset.
+ pub fn pad_until(&mut self, offset: usize) {
+ debug_assert!(self.buffer.len() <= offset);
+ self.buffer.resize(offset);
+ }
+
+ fn file_header_size(&self) -> usize {
+ if self.is_64 {
+ mem::size_of::<elf::FileHeader64<Endianness>>()
+ } else {
+ mem::size_of::<elf::FileHeader32<Endianness>>()
+ }
+ }
+
+ /// Reserve the range for the file header.
+ ///
+ /// This must be at the start of the file.
+ pub fn reserve_file_header(&mut self) {
+ debug_assert_eq!(self.len, 0);
+ self.reserve(self.file_header_size(), 1);
+ }
+
+ /// Write the file header.
+ ///
+ /// This must be at the start of the file.
+ ///
+ /// Fields that can be derived from known information are automatically set by this function.
+ pub fn write_file_header(&mut self, header: &FileHeader) -> Result<()> {
+ debug_assert_eq!(self.buffer.len(), 0);
+
+ self.is_mips64el =
+ self.is_64 && self.endian.is_little_endian() && header.e_machine == elf::EM_MIPS;
+
+ // Start writing.
+ self.buffer
+ .reserve(self.len)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ let e_ident = elf::Ident {
+ magic: elf::ELFMAG,
+ class: if self.is_64 {
+ elf::ELFCLASS64
+ } else {
+ elf::ELFCLASS32
+ },
+ data: if self.endian.is_little_endian() {
+ elf::ELFDATA2LSB
+ } else {
+ elf::ELFDATA2MSB
+ },
+ version: elf::EV_CURRENT,
+ os_abi: header.os_abi,
+ abi_version: header.abi_version,
+ padding: [0; 7],
+ };
+
+ let e_ehsize = self.file_header_size() as u16;
+
+ let e_phoff = self.segment_offset as u64;
+ let e_phentsize = if self.segment_num == 0 {
+ 0
+ } else {
+ self.program_header_size() as u16
+ };
+ // TODO: overflow
+ let e_phnum = self.segment_num as u16;
+
+ let e_shoff = self.section_offset as u64;
+ let e_shentsize = if self.section_num == 0 {
+ 0
+ } else {
+ self.section_header_size() as u16
+ };
+ let e_shnum = if self.section_num >= elf::SHN_LORESERVE.into() {
+ 0
+ } else {
+ self.section_num as u16
+ };
+ let e_shstrndx = if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() {
+ elf::SHN_XINDEX
+ } else {
+ self.shstrtab_index.0 as u16
+ };
+
+ let endian = self.endian;
+ if self.is_64 {
+ let file = elf::FileHeader64 {
+ e_ident,
+ e_type: U16::new(endian, header.e_type),
+ e_machine: U16::new(endian, header.e_machine),
+ e_version: U32::new(endian, elf::EV_CURRENT.into()),
+ e_entry: U64::new(endian, header.e_entry),
+ e_phoff: U64::new(endian, e_phoff),
+ e_shoff: U64::new(endian, e_shoff),
+ e_flags: U32::new(endian, header.e_flags),
+ e_ehsize: U16::new(endian, e_ehsize),
+ e_phentsize: U16::new(endian, e_phentsize),
+ e_phnum: U16::new(endian, e_phnum),
+ e_shentsize: U16::new(endian, e_shentsize),
+ e_shnum: U16::new(endian, e_shnum),
+ e_shstrndx: U16::new(endian, e_shstrndx),
+ };
+ self.buffer.write(&file)
+ } else {
+ let file = elf::FileHeader32 {
+ e_ident,
+ e_type: U16::new(endian, header.e_type),
+ e_machine: U16::new(endian, header.e_machine),
+ e_version: U32::new(endian, elf::EV_CURRENT.into()),
+ e_entry: U32::new(endian, header.e_entry as u32),
+ e_phoff: U32::new(endian, e_phoff as u32),
+ e_shoff: U32::new(endian, e_shoff as u32),
+ e_flags: U32::new(endian, header.e_flags),
+ e_ehsize: U16::new(endian, e_ehsize),
+ e_phentsize: U16::new(endian, e_phentsize),
+ e_phnum: U16::new(endian, e_phnum),
+ e_shentsize: U16::new(endian, e_shentsize),
+ e_shnum: U16::new(endian, e_shnum),
+ e_shstrndx: U16::new(endian, e_shstrndx),
+ };
+ self.buffer.write(&file);
+ }
+
+ Ok(())
+ }
+
+ fn program_header_size(&self) -> usize {
+ if self.is_64 {
+ mem::size_of::<elf::ProgramHeader64<Endianness>>()
+ } else {
+ mem::size_of::<elf::ProgramHeader32<Endianness>>()
+ }
+ }
+
+ /// Reserve the range for the program headers.
+ pub fn reserve_program_headers(&mut self, num: u32) {
+ debug_assert_eq!(self.segment_offset, 0);
+ if num == 0 {
+ return;
+ }
+ self.segment_num = num;
+ self.segment_offset =
+ self.reserve(num as usize * self.program_header_size(), self.elf_align);
+ }
+
+ /// Write alignment padding bytes prior to the program headers.
+ pub fn write_align_program_headers(&mut self) {
+ if self.segment_offset == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.segment_offset, self.buffer.len());
+ }
+
+ /// Write a program header.
+ pub fn write_program_header(&mut self, header: &ProgramHeader) {
+ let endian = self.endian;
+ if self.is_64 {
+ let header = elf::ProgramHeader64 {
+ p_type: U32::new(endian, header.p_type),
+ p_flags: U32::new(endian, header.p_flags),
+ p_offset: U64::new(endian, header.p_offset),
+ p_vaddr: U64::new(endian, header.p_vaddr),
+ p_paddr: U64::new(endian, header.p_paddr),
+ p_filesz: U64::new(endian, header.p_filesz),
+ p_memsz: U64::new(endian, header.p_memsz),
+ p_align: U64::new(endian, header.p_align),
+ };
+ self.buffer.write(&header);
+ } else {
+ let header = elf::ProgramHeader32 {
+ p_type: U32::new(endian, header.p_type),
+ p_offset: U32::new(endian, header.p_offset as u32),
+ p_vaddr: U32::new(endian, header.p_vaddr as u32),
+ p_paddr: U32::new(endian, header.p_paddr as u32),
+ p_filesz: U32::new(endian, header.p_filesz as u32),
+ p_memsz: U32::new(endian, header.p_memsz as u32),
+ p_flags: U32::new(endian, header.p_flags),
+ p_align: U32::new(endian, header.p_align as u32),
+ };
+ self.buffer.write(&header);
+ }
+ }
+
+ /// Reserve the section index for the null section header.
+ ///
+ /// The null section header is usually automatically reserved,
+ /// but this can be used to force an empty section table.
+ ///
+ /// This must be called before [`Self::reserve_section_headers`].
+ pub fn reserve_null_section_index(&mut self) -> SectionIndex {
+ debug_assert_eq!(self.section_num, 0);
+ if self.section_num == 0 {
+ self.section_num = 1;
+ }
+ SectionIndex(0)
+ }
+
+ /// Reserve a section table index.
+ ///
+ /// Automatically also reserves the null section header if required.
+ ///
+ /// This must be called before [`Self::reserve_section_headers`].
+ pub fn reserve_section_index(&mut self) -> SectionIndex {
+ debug_assert_eq!(self.section_offset, 0);
+ if self.section_num == 0 {
+ self.section_num = 1;
+ }
+ let index = self.section_num;
+ self.section_num += 1;
+ SectionIndex(index)
+ }
+
+ fn section_header_size(&self) -> usize {
+ if self.is_64 {
+ mem::size_of::<elf::SectionHeader64<Endianness>>()
+ } else {
+ mem::size_of::<elf::SectionHeader32<Endianness>>()
+ }
+ }
+
+ /// Reserve the range for the section headers.
+ ///
+ /// This function does nothing if no sections were reserved.
+ /// This must be called after [`Self::reserve_section_index`]
+ /// and other functions that reserve section indices.
+ pub fn reserve_section_headers(&mut self) {
+ debug_assert_eq!(self.section_offset, 0);
+ if self.section_num == 0 {
+ return;
+ }
+ self.section_offset = self.reserve(
+ self.section_num as usize * self.section_header_size(),
+ self.elf_align,
+ );
+ }
+
+ /// Write the null section header.
+ ///
+ /// This must be the first section header that is written.
+ /// This function does nothing if no sections were reserved.
+ pub fn write_null_section_header(&mut self) {
+ if self.section_num == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.section_offset, self.buffer.len());
+ self.write_section_header(&SectionHeader {
+ name: None,
+ sh_type: 0,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: 0,
+ sh_size: if self.section_num >= elf::SHN_LORESERVE.into() {
+ self.section_num.into()
+ } else {
+ 0
+ },
+ sh_link: if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() {
+ self.shstrtab_index.0
+ } else {
+ 0
+ },
+ // TODO: e_phnum overflow
+ sh_info: 0,
+ sh_addralign: 0,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Write a section header.
+ pub fn write_section_header(&mut self, section: &SectionHeader) {
+ let sh_name = if let Some(name) = section.name {
+ self.shstrtab.get_offset(name) as u32
+ } else {
+ 0
+ };
+ let endian = self.endian;
+ if self.is_64 {
+ let section = elf::SectionHeader64 {
+ sh_name: U32::new(endian, sh_name),
+ sh_type: U32::new(endian, section.sh_type),
+ sh_flags: U64::new(endian, section.sh_flags),
+ sh_addr: U64::new(endian, section.sh_addr),
+ sh_offset: U64::new(endian, section.sh_offset),
+ sh_size: U64::new(endian, section.sh_size),
+ sh_link: U32::new(endian, section.sh_link),
+ sh_info: U32::new(endian, section.sh_info),
+ sh_addralign: U64::new(endian, section.sh_addralign),
+ sh_entsize: U64::new(endian, section.sh_entsize),
+ };
+ self.buffer.write(&section);
+ } else {
+ let section = elf::SectionHeader32 {
+ sh_name: U32::new(endian, sh_name),
+ sh_type: U32::new(endian, section.sh_type),
+ sh_flags: U32::new(endian, section.sh_flags as u32),
+ sh_addr: U32::new(endian, section.sh_addr as u32),
+ sh_offset: U32::new(endian, section.sh_offset as u32),
+ sh_size: U32::new(endian, section.sh_size as u32),
+ sh_link: U32::new(endian, section.sh_link),
+ sh_info: U32::new(endian, section.sh_info),
+ sh_addralign: U32::new(endian, section.sh_addralign as u32),
+ sh_entsize: U32::new(endian, section.sh_entsize as u32),
+ };
+ self.buffer.write(&section);
+ }
+ }
+
+ /// Add a section name to the section header string table.
+ ///
+ /// This will be stored in the `.shstrtab` section.
+ ///
+ /// This must be called before [`Self::reserve_shstrtab`].
+ pub fn add_section_name(&mut self, name: &'a [u8]) -> StringId {
+ debug_assert_eq!(self.shstrtab_offset, 0);
+ self.shstrtab.add(name)
+ }
+
+ /// Reserve the range for the section header string table.
+ ///
+ /// This range is used for a section named `.shstrtab`.
+ ///
+ /// This function does nothing if no sections were reserved.
+ /// This must be called after [`Self::add_section_name`].
+ /// and other functions that reserve section names and indices.
+ pub fn reserve_shstrtab(&mut self) {
+ debug_assert_eq!(self.shstrtab_offset, 0);
+ if self.section_num == 0 {
+ return;
+ }
+ // Start with null section name.
+ self.shstrtab_data = vec![0];
+ self.shstrtab.write(1, &mut self.shstrtab_data);
+ self.shstrtab_offset = self.reserve(self.shstrtab_data.len(), 1);
+ }
+
+ /// Write the section header string table.
+ ///
+ /// This function does nothing if the section was not reserved.
+ pub fn write_shstrtab(&mut self) {
+ if self.shstrtab_offset == 0 {
+ return;
+ }
+ debug_assert_eq!(self.shstrtab_offset, self.buffer.len());
+ self.buffer.write_bytes(&self.shstrtab_data);
+ }
+
+ /// Reserve the section index for the section header string table.
+ ///
+ /// This must be called before [`Self::reserve_shstrtab`]
+ /// and [`Self::reserve_section_headers`].
+ pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex {
+ debug_assert_eq!(self.shstrtab_index, SectionIndex(0));
+ self.shstrtab_str_id = Some(self.add_section_name(&b".shstrtab"[..]));
+ self.shstrtab_index = self.reserve_section_index();
+ self.shstrtab_index
+ }
+
+ /// Write the section header for the section header string table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_shstrtab_section_header(&mut self) {
+ if self.shstrtab_index == SectionIndex(0) {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.shstrtab_str_id,
+ sh_type: elf::SHT_STRTAB,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: self.shstrtab_offset as u64,
+ sh_size: self.shstrtab_data.len() as u64,
+ sh_link: 0,
+ sh_info: 0,
+ sh_addralign: 1,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Add a string to the string table.
+ ///
+ /// This will be stored in the `.strtab` section.
+ ///
+ /// This must be called before [`Self::reserve_strtab`].
+ pub fn add_string(&mut self, name: &'a [u8]) -> StringId {
+ debug_assert_eq!(self.strtab_offset, 0);
+ self.need_strtab = true;
+ self.strtab.add(name)
+ }
+
+ /// Return true if `.strtab` is needed.
+ pub fn strtab_needed(&self) -> bool {
+ self.need_strtab
+ }
+
+ /// Reserve the range for the string table.
+ ///
+ /// This range is used for a section named `.strtab`.
+ ///
+ /// This function does nothing if no strings or symbols were defined.
+ /// This must be called after [`Self::add_string`].
+ pub fn reserve_strtab(&mut self) {
+ debug_assert_eq!(self.strtab_offset, 0);
+ if !self.need_strtab {
+ return;
+ }
+ // Start with null string.
+ self.strtab_data = vec![0];
+ self.strtab.write(1, &mut self.strtab_data);
+ self.strtab_offset = self.reserve(self.strtab_data.len(), 1);
+ }
+
+ /// Write the string table.
+ ///
+ /// This function does nothing if the section was not reserved.
+ pub fn write_strtab(&mut self) {
+ if self.strtab_offset == 0 {
+ return;
+ }
+ debug_assert_eq!(self.strtab_offset, self.buffer.len());
+ self.buffer.write_bytes(&self.strtab_data);
+ }
+
+ /// Reserve the section index for the string table.
+ ///
+ /// This must be called before [`Self::reserve_section_headers`].
+ pub fn reserve_strtab_section_index(&mut self) -> SectionIndex {
+ debug_assert_eq!(self.strtab_index, SectionIndex(0));
+ self.strtab_str_id = Some(self.add_section_name(&b".strtab"[..]));
+ self.strtab_index = self.reserve_section_index();
+ self.strtab_index
+ }
+
+ /// Write the section header for the string table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_strtab_section_header(&mut self) {
+ if self.strtab_index == SectionIndex(0) {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.strtab_str_id,
+ sh_type: elf::SHT_STRTAB,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: self.strtab_offset as u64,
+ sh_size: self.strtab_data.len() as u64,
+ sh_link: 0,
+ sh_info: 0,
+ sh_addralign: 1,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Reserve the null symbol table entry.
+ ///
+ /// This will be stored in the `.symtab` section.
+ ///
+ /// The null symbol table entry is usually automatically reserved,
+ /// but this can be used to force an empty symbol table.
+ ///
+ /// This must be called before [`Self::reserve_symtab`].
+ pub fn reserve_null_symbol_index(&mut self) -> SymbolIndex {
+ debug_assert_eq!(self.symtab_offset, 0);
+ debug_assert_eq!(self.symtab_num, 0);
+ self.symtab_num = 1;
+ // The symtab must link to a strtab.
+ self.need_strtab = true;
+ SymbolIndex(0)
+ }
+
+ /// Reserve a symbol table entry.
+ ///
+ /// This will be stored in the `.symtab` section.
+ ///
+ /// `section_index` is used to determine whether `.symtab_shndx` is required.
+ ///
+ /// Automatically also reserves the null symbol if required.
+ /// Callers may assume that the returned indices will be sequential
+ /// starting at 1.
+ ///
+ /// This must be called before [`Self::reserve_symtab`] and
+ /// [`Self::reserve_symtab_shndx`].
+ pub fn reserve_symbol_index(&mut self, section_index: Option<SectionIndex>) -> SymbolIndex {
+ debug_assert_eq!(self.symtab_offset, 0);
+ debug_assert_eq!(self.symtab_shndx_offset, 0);
+ if self.symtab_num == 0 {
+ self.symtab_num = 1;
+ // The symtab must link to a strtab.
+ self.need_strtab = true;
+ }
+ let index = self.symtab_num;
+ self.symtab_num += 1;
+ if let Some(section_index) = section_index {
+ if section_index.0 >= elf::SHN_LORESERVE.into() {
+ self.need_symtab_shndx = true;
+ }
+ }
+ SymbolIndex(index)
+ }
+
+ /// Return the number of reserved symbol table entries.
+ ///
+ /// Includes the null symbol.
+ pub fn symbol_count(&self) -> u32 {
+ self.symtab_num
+ }
+
+ fn symbol_size(&self) -> usize {
+ if self.is_64 {
+ mem::size_of::<elf::Sym64<Endianness>>()
+ } else {
+ mem::size_of::<elf::Sym32<Endianness>>()
+ }
+ }
+
+ /// Reserve the range for the symbol table.
+ ///
+ /// This range is used for a section named `.symtab`.
+ /// This function does nothing if no symbols were reserved.
+ /// This must be called after [`Self::reserve_symbol_index`].
+ pub fn reserve_symtab(&mut self) {
+ debug_assert_eq!(self.symtab_offset, 0);
+ if self.symtab_num == 0 {
+ return;
+ }
+ self.symtab_offset = self.reserve(
+ self.symtab_num as usize * self.symbol_size(),
+ self.elf_align,
+ );
+ }
+
+ /// Write the null symbol.
+ ///
+ /// This must be the first symbol that is written.
+ /// This function does nothing if no symbols were reserved.
+ pub fn write_null_symbol(&mut self) {
+ if self.symtab_num == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.symtab_offset, self.buffer.len());
+ if self.is_64 {
+ self.buffer.write(&elf::Sym64::<Endianness>::default());
+ } else {
+ self.buffer.write(&elf::Sym32::<Endianness>::default());
+ }
+
+ if self.need_symtab_shndx {
+ self.symtab_shndx_data.write_pod(&U32::new(self.endian, 0));
+ }
+ }
+
+ /// Write a symbol.
+ pub fn write_symbol(&mut self, sym: &Sym) {
+ let st_name = if let Some(name) = sym.name {
+ self.strtab.get_offset(name) as u32
+ } else {
+ 0
+ };
+ let st_shndx = if let Some(section) = sym.section {
+ if section.0 >= elf::SHN_LORESERVE as u32 {
+ elf::SHN_XINDEX
+ } else {
+ section.0 as u16
+ }
+ } else {
+ sym.st_shndx
+ };
+
+ let endian = self.endian;
+ if self.is_64 {
+ let sym = elf::Sym64 {
+ st_name: U32::new(endian, st_name),
+ st_info: sym.st_info,
+ st_other: sym.st_other,
+ st_shndx: U16::new(endian, st_shndx),
+ st_value: U64::new(endian, sym.st_value),
+ st_size: U64::new(endian, sym.st_size),
+ };
+ self.buffer.write(&sym);
+ } else {
+ let sym = elf::Sym32 {
+ st_name: U32::new(endian, st_name),
+ st_info: sym.st_info,
+ st_other: sym.st_other,
+ st_shndx: U16::new(endian, st_shndx),
+ st_value: U32::new(endian, sym.st_value as u32),
+ st_size: U32::new(endian, sym.st_size as u32),
+ };
+ self.buffer.write(&sym);
+ }
+
+ if self.need_symtab_shndx {
+ let section_index = sym.section.unwrap_or(SectionIndex(0));
+ self.symtab_shndx_data
+ .write_pod(&U32::new(self.endian, section_index.0));
+ }
+ }
+
+ /// Reserve the section index for the symbol table.
+ ///
+ /// This must be called before [`Self::reserve_section_headers`].
+ pub fn reserve_symtab_section_index(&mut self) -> SectionIndex {
+ debug_assert_eq!(self.symtab_index, SectionIndex(0));
+ self.symtab_str_id = Some(self.add_section_name(&b".symtab"[..]));
+ self.symtab_index = self.reserve_section_index();
+ self.symtab_index
+ }
+
+ /// Return the section index of the symbol table.
+ pub fn symtab_index(&mut self) -> SectionIndex {
+ self.symtab_index
+ }
+
+ /// Write the section header for the symbol table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_symtab_section_header(&mut self, num_local: u32) {
+ if self.symtab_index == SectionIndex(0) {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.symtab_str_id,
+ sh_type: elf::SHT_SYMTAB,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: self.symtab_offset as u64,
+ sh_size: self.symtab_num as u64 * self.symbol_size() as u64,
+ sh_link: self.strtab_index.0,
+ sh_info: num_local,
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: self.symbol_size() as u64,
+ });
+ }
+
+ /// Return true if `.symtab_shndx` is needed.
+ pub fn symtab_shndx_needed(&self) -> bool {
+ self.need_symtab_shndx
+ }
+
+ /// Reserve the range for the extended section indices for the symbol table.
+ ///
+ /// This range is used for a section named `.symtab_shndx`.
+ /// This also reserves a section index.
+ ///
+ /// This function does nothing if extended section indices are not needed.
+ /// This must be called after [`Self::reserve_symbol_index`].
+ pub fn reserve_symtab_shndx(&mut self) {
+ debug_assert_eq!(self.symtab_shndx_offset, 0);
+ if !self.need_symtab_shndx {
+ return;
+ }
+ self.symtab_shndx_offset = self.reserve(self.symtab_num as usize * 4, 4);
+ self.symtab_shndx_data.reserve(self.symtab_num as usize * 4);
+ }
+
+ /// Write the extended section indices for the symbol table.
+ ///
+ /// This function does nothing if the section was not reserved.
+ pub fn write_symtab_shndx(&mut self) {
+ if self.symtab_shndx_offset == 0 {
+ return;
+ }
+ debug_assert_eq!(self.symtab_shndx_offset, self.buffer.len());
+ debug_assert_eq!(self.symtab_num as usize * 4, self.symtab_shndx_data.len());
+ self.buffer.write_bytes(&self.symtab_shndx_data);
+ }
+
+ /// Reserve the section index for the extended section indices symbol table.
+ ///
+ /// You should check [`Self::symtab_shndx_needed`] before calling this
+ /// unless you have other means of knowing if this section is needed.
+ ///
+ /// This must be called before [`Self::reserve_section_headers`].
+ pub fn reserve_symtab_shndx_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.symtab_shndx_str_id.is_none());
+ self.symtab_shndx_str_id = Some(self.add_section_name(&b".symtab_shndx"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Write the section header for the extended section indices for the symbol table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_symtab_shndx_section_header(&mut self) {
+ if self.symtab_shndx_str_id.is_none() {
+ return;
+ }
+ let sh_size = if self.symtab_shndx_offset == 0 {
+ 0
+ } else {
+ (self.symtab_num * 4) as u64
+ };
+ self.write_section_header(&SectionHeader {
+ name: self.symtab_shndx_str_id,
+ sh_type: elf::SHT_SYMTAB_SHNDX,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: self.symtab_shndx_offset as u64,
+ sh_size,
+ sh_link: self.symtab_index.0,
+ sh_info: 0,
+ sh_addralign: 4,
+ sh_entsize: 4,
+ });
+ }
+
+ /// Add a string to the dynamic string table.
+ ///
+ /// This will be stored in the `.dynstr` section.
+ ///
+ /// This must be called before [`Self::reserve_dynstr`].
+ pub fn add_dynamic_string(&mut self, name: &'a [u8]) -> StringId {
+ debug_assert_eq!(self.dynstr_offset, 0);
+ self.need_dynstr = true;
+ self.dynstr.add(name)
+ }
+
+ /// Get a string that was previously added to the dynamic string table.
+ ///
+ /// Panics if the string was not added.
+ pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId {
+ self.dynstr.get_id(name)
+ }
+
+ /// Return true if `.dynstr` is needed.
+ pub fn dynstr_needed(&self) -> bool {
+ self.need_dynstr
+ }
+
+ /// Reserve the range for the dynamic string table.
+ ///
+ /// This range is used for a section named `.dynstr`.
+ ///
+ /// This function does nothing if no dynamic strings or symbols were defined.
+ /// This must be called after [`Self::add_dynamic_string`].
+ pub fn reserve_dynstr(&mut self) {
+ debug_assert_eq!(self.dynstr_offset, 0);
+ if !self.need_dynstr {
+ return;
+ }
+ // Start with null string.
+ self.dynstr_data = vec![0];
+ self.dynstr.write(1, &mut self.dynstr_data);
+ self.dynstr_offset = self.reserve(self.dynstr_data.len(), 1);
+ }
+
+ /// Write the dynamic string table.
+ ///
+ /// This function does nothing if the section was not reserved.
+ pub fn write_dynstr(&mut self) {
+ if self.dynstr_offset == 0 {
+ return;
+ }
+ debug_assert_eq!(self.dynstr_offset, self.buffer.len());
+ self.buffer.write_bytes(&self.dynstr_data);
+ }
+
+ /// Reserve the section index for the dynamic string table.
+ ///
+ /// This must be called before [`Self::reserve_section_headers`].
+ pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex {
+ debug_assert_eq!(self.dynstr_index, SectionIndex(0));
+ self.dynstr_str_id = Some(self.add_section_name(&b".dynstr"[..]));
+ self.dynstr_index = self.reserve_section_index();
+ self.dynstr_index
+ }
+
+ /// Return the section index of the dynamic string table.
+ pub fn dynstr_index(&mut self) -> SectionIndex {
+ self.dynstr_index
+ }
+
+ /// Write the section header for the dynamic string table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_dynstr_section_header(&mut self, sh_addr: u64) {
+ if self.dynstr_index == SectionIndex(0) {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.dynstr_str_id,
+ sh_type: elf::SHT_STRTAB,
+ sh_flags: elf::SHF_ALLOC.into(),
+ sh_addr,
+ sh_offset: self.dynstr_offset as u64,
+ sh_size: self.dynstr_data.len() as u64,
+ sh_link: 0,
+ sh_info: 0,
+ sh_addralign: 1,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Reserve the null dynamic symbol table entry.
+ ///
+ /// This will be stored in the `.dynsym` section.
+ ///
+ /// The null dynamic symbol table entry is usually automatically reserved,
+ /// but this can be used to force an empty dynamic symbol table.
+ ///
+ /// This must be called before [`Self::reserve_dynsym`].
+ pub fn reserve_null_dynamic_symbol_index(&mut self) -> SymbolIndex {
+ debug_assert_eq!(self.dynsym_offset, 0);
+ debug_assert_eq!(self.dynsym_num, 0);
+ self.dynsym_num = 1;
+ // The symtab must link to a strtab.
+ self.need_dynstr = true;
+ SymbolIndex(0)
+ }
+
+ /// Reserve a dynamic symbol table entry.
+ ///
+ /// This will be stored in the `.dynsym` section.
+ ///
+ /// Automatically also reserves the null symbol if required.
+ /// Callers may assume that the returned indices will be sequential
+ /// starting at 1.
+ ///
+ /// This must be called before [`Self::reserve_dynsym`].
+ pub fn reserve_dynamic_symbol_index(&mut self) -> SymbolIndex {
+ debug_assert_eq!(self.dynsym_offset, 0);
+ if self.dynsym_num == 0 {
+ self.dynsym_num = 1;
+ // The symtab must link to a strtab.
+ self.need_dynstr = true;
+ }
+ let index = self.dynsym_num;
+ self.dynsym_num += 1;
+ SymbolIndex(index)
+ }
+
+ /// Return the number of reserved dynamic symbols.
+ ///
+ /// Includes the null symbol.
+ pub fn dynamic_symbol_count(&mut self) -> u32 {
+ self.dynsym_num
+ }
+
+ /// Reserve the range for the dynamic symbol table.
+ ///
+ /// This range is used for a section named `.dynsym`.
+ ///
+ /// This function does nothing if no dynamic symbols were reserved.
+ /// This must be called after [`Self::reserve_dynamic_symbol_index`].
+ pub fn reserve_dynsym(&mut self) {
+ debug_assert_eq!(self.dynsym_offset, 0);
+ if self.dynsym_num == 0 {
+ return;
+ }
+ self.dynsym_offset = self.reserve(
+ self.dynsym_num as usize * self.symbol_size(),
+ self.elf_align,
+ );
+ }
+
+ /// Write the null dynamic symbol.
+ ///
+ /// This must be the first dynamic symbol that is written.
+ /// This function does nothing if no dynamic symbols were reserved.
+ pub fn write_null_dynamic_symbol(&mut self) {
+ if self.dynsym_num == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.dynsym_offset, self.buffer.len());
+ if self.is_64 {
+ self.buffer.write(&elf::Sym64::<Endianness>::default());
+ } else {
+ self.buffer.write(&elf::Sym32::<Endianness>::default());
+ }
+ }
+
+ /// Write a dynamic symbol.
+ pub fn write_dynamic_symbol(&mut self, sym: &Sym) {
+ let st_name = if let Some(name) = sym.name {
+ self.dynstr.get_offset(name) as u32
+ } else {
+ 0
+ };
+
+ let st_shndx = if let Some(section) = sym.section {
+ if section.0 >= elf::SHN_LORESERVE as u32 {
+ // TODO: we don't actually write out .dynsym_shndx yet.
+ // This is unlikely to be needed though.
+ elf::SHN_XINDEX
+ } else {
+ section.0 as u16
+ }
+ } else {
+ sym.st_shndx
+ };
+
+ let endian = self.endian;
+ if self.is_64 {
+ let sym = elf::Sym64 {
+ st_name: U32::new(endian, st_name),
+ st_info: sym.st_info,
+ st_other: sym.st_other,
+ st_shndx: U16::new(endian, st_shndx),
+ st_value: U64::new(endian, sym.st_value),
+ st_size: U64::new(endian, sym.st_size),
+ };
+ self.buffer.write(&sym);
+ } else {
+ let sym = elf::Sym32 {
+ st_name: U32::new(endian, st_name),
+ st_info: sym.st_info,
+ st_other: sym.st_other,
+ st_shndx: U16::new(endian, st_shndx),
+ st_value: U32::new(endian, sym.st_value as u32),
+ st_size: U32::new(endian, sym.st_size as u32),
+ };
+ self.buffer.write(&sym);
+ }
+ }
+
+ /// Reserve the section index for the dynamic symbol table.
+ ///
+ /// This must be called before [`Self::reserve_section_headers`].
+ pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex {
+ debug_assert_eq!(self.dynsym_index, SectionIndex(0));
+ self.dynsym_str_id = Some(self.add_section_name(&b".dynsym"[..]));
+ self.dynsym_index = self.reserve_section_index();
+ self.dynsym_index
+ }
+
+ /// Return the section index of the dynamic symbol table.
+ pub fn dynsym_index(&mut self) -> SectionIndex {
+ self.dynsym_index
+ }
+
+ /// Write the section header for the dynamic symbol table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_dynsym_section_header(&mut self, sh_addr: u64, num_local: u32) {
+ if self.dynsym_index == SectionIndex(0) {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.dynsym_str_id,
+ sh_type: elf::SHT_DYNSYM,
+ sh_flags: elf::SHF_ALLOC.into(),
+ sh_addr,
+ sh_offset: self.dynsym_offset as u64,
+ sh_size: self.dynsym_num as u64 * self.symbol_size() as u64,
+ sh_link: self.dynstr_index.0,
+ sh_info: num_local,
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: self.symbol_size() as u64,
+ });
+ }
+
+ fn dyn_size(&self) -> usize {
+ if self.is_64 {
+ mem::size_of::<elf::Dyn64<Endianness>>()
+ } else {
+ mem::size_of::<elf::Dyn32<Endianness>>()
+ }
+ }
+
+ /// Reserve the range for the `.dynamic` section.
+ ///
+ /// This function does nothing if `dynamic_num` is zero.
+ pub fn reserve_dynamic(&mut self, dynamic_num: usize) {
+ debug_assert_eq!(self.dynamic_offset, 0);
+ if dynamic_num == 0 {
+ return;
+ }
+ self.dynamic_num = dynamic_num;
+ self.dynamic_offset = self.reserve(dynamic_num * self.dyn_size(), self.elf_align);
+ }
+
+ /// Write alignment padding bytes prior to the `.dynamic` section.
+ ///
+ /// This function does nothing if the section was not reserved.
+ pub fn write_align_dynamic(&mut self) {
+ if self.dynamic_offset == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.dynamic_offset, self.buffer.len());
+ }
+
+ /// Write a dynamic string entry.
+ pub fn write_dynamic_string(&mut self, tag: u32, id: StringId) {
+ self.write_dynamic(tag, self.dynstr.get_offset(id) as u64);
+ }
+
+ /// Write a dynamic value entry.
+ pub fn write_dynamic(&mut self, d_tag: u32, d_val: u64) {
+ debug_assert!(self.dynamic_offset <= self.buffer.len());
+ let endian = self.endian;
+ if self.is_64 {
+ let d = elf::Dyn64 {
+ d_tag: U64::new(endian, d_tag.into()),
+ d_val: U64::new(endian, d_val),
+ };
+ self.buffer.write(&d);
+ } else {
+ let d = elf::Dyn32 {
+ d_tag: U32::new(endian, d_tag),
+ d_val: U32::new(endian, d_val as u32),
+ };
+ self.buffer.write(&d);
+ }
+ debug_assert!(
+ self.dynamic_offset + self.dynamic_num * self.dyn_size() >= self.buffer.len()
+ );
+ }
+
+ /// Reserve the section index for the dynamic table.
+ pub fn reserve_dynamic_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.dynamic_str_id.is_none());
+ self.dynamic_str_id = Some(self.add_section_name(&b".dynamic"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Write the section header for the dynamic table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_dynamic_section_header(&mut self, sh_addr: u64) {
+ if self.dynamic_str_id.is_none() {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.dynamic_str_id,
+ sh_type: elf::SHT_DYNAMIC,
+ sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC).into(),
+ sh_addr,
+ sh_offset: self.dynamic_offset as u64,
+ sh_size: (self.dynamic_num * self.dyn_size()) as u64,
+ sh_link: self.dynstr_index.0,
+ sh_info: 0,
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: self.dyn_size() as u64,
+ });
+ }
+
+ fn rel_size(&self, is_rela: bool) -> usize {
+ if self.is_64 {
+ if is_rela {
+ mem::size_of::<elf::Rela64<Endianness>>()
+ } else {
+ mem::size_of::<elf::Rel64<Endianness>>()
+ }
+ } else {
+ if is_rela {
+ mem::size_of::<elf::Rela32<Endianness>>()
+ } else {
+ mem::size_of::<elf::Rel32<Endianness>>()
+ }
+ }
+ }
+
+ /// Reserve a file range for a SysV hash section.
+ ///
+ /// `symbol_count` is the number of symbols in the hash,
+ /// not the total number of symbols.
+ pub fn reserve_hash(&mut self, bucket_count: u32, chain_count: u32) {
+ self.hash_size = mem::size_of::<elf::HashHeader<Endianness>>()
+ + bucket_count as usize * 4
+ + chain_count as usize * 4;
+ self.hash_offset = self.reserve(self.hash_size, self.elf_align);
+ }
+
+ /// Write a SysV hash section.
+ ///
+ /// `chain_count` is the number of symbols in the hash.
+ /// The argument to `hash` will be in the range `0..chain_count`.
+ pub fn write_hash<F>(&mut self, bucket_count: u32, chain_count: u32, hash: F)
+ where
+ F: Fn(u32) -> Option<u32>,
+ {
+ let mut buckets = vec![U32::new(self.endian, 0); bucket_count as usize];
+ let mut chains = vec![U32::new(self.endian, 0); chain_count as usize];
+ for i in 0..chain_count {
+ if let Some(hash) = hash(i) {
+ let bucket = hash % bucket_count;
+ chains[i as usize] = buckets[bucket as usize];
+ buckets[bucket as usize] = U32::new(self.endian, i);
+ }
+ }
+
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.hash_offset, self.buffer.len());
+ self.buffer.write(&elf::HashHeader {
+ bucket_count: U32::new(self.endian, bucket_count),
+ chain_count: U32::new(self.endian, chain_count),
+ });
+ self.buffer.write_slice(&buckets);
+ self.buffer.write_slice(&chains);
+ }
+
+ /// Reserve the section index for the SysV hash table.
+ pub fn reserve_hash_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.hash_str_id.is_none());
+ self.hash_str_id = Some(self.add_section_name(&b".hash"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Write the section header for the SysV hash table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_hash_section_header(&mut self, sh_addr: u64) {
+ if self.hash_str_id.is_none() {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.hash_str_id,
+ sh_type: elf::SHT_HASH,
+ sh_flags: elf::SHF_ALLOC.into(),
+ sh_addr,
+ sh_offset: self.hash_offset as u64,
+ sh_size: self.hash_size as u64,
+ sh_link: self.dynsym_index.0,
+ sh_info: 0,
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: 4,
+ });
+ }
+
+ /// Reserve a file range for a GNU hash section.
+ ///
+ /// `symbol_count` is the number of symbols in the hash,
+ /// not the total number of symbols.
+ pub fn reserve_gnu_hash(&mut self, bloom_count: u32, bucket_count: u32, symbol_count: u32) {
+ self.gnu_hash_size = mem::size_of::<elf::GnuHashHeader<Endianness>>()
+ + bloom_count as usize * self.elf_align
+ + bucket_count as usize * 4
+ + symbol_count as usize * 4;
+ self.gnu_hash_offset = self.reserve(self.gnu_hash_size, self.elf_align);
+ }
+
+ /// Write a GNU hash section.
+ ///
+ /// `symbol_count` is the number of symbols in the hash.
+ /// The argument to `hash` will be in the range `0..symbol_count`.
+ ///
+ /// This requires that symbols are already sorted by bucket.
+ pub fn write_gnu_hash<F>(
+ &mut self,
+ symbol_base: u32,
+ bloom_shift: u32,
+ bloom_count: u32,
+ bucket_count: u32,
+ symbol_count: u32,
+ hash: F,
+ ) where
+ F: Fn(u32) -> u32,
+ {
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.gnu_hash_offset, self.buffer.len());
+ self.buffer.write(&elf::GnuHashHeader {
+ bucket_count: U32::new(self.endian, bucket_count),
+ symbol_base: U32::new(self.endian, symbol_base),
+ bloom_count: U32::new(self.endian, bloom_count),
+ bloom_shift: U32::new(self.endian, bloom_shift),
+ });
+
+ // Calculate and write bloom filter.
+ if self.is_64 {
+ let mut bloom_filters = vec![0; bloom_count as usize];
+ for i in 0..symbol_count {
+ let h = hash(i);
+ bloom_filters[((h / 64) & (bloom_count - 1)) as usize] |=
+ 1 << (h % 64) | 1 << ((h >> bloom_shift) % 64);
+ }
+ for bloom_filter in bloom_filters {
+ self.buffer.write(&U64::new(self.endian, bloom_filter));
+ }
+ } else {
+ let mut bloom_filters = vec![0; bloom_count as usize];
+ for i in 0..symbol_count {
+ let h = hash(i);
+ bloom_filters[((h / 32) & (bloom_count - 1)) as usize] |=
+ 1 << (h % 32) | 1 << ((h >> bloom_shift) % 32);
+ }
+ for bloom_filter in bloom_filters {
+ self.buffer.write(&U32::new(self.endian, bloom_filter));
+ }
+ }
+
+ // Write buckets.
+ //
+ // This requires that symbols are already sorted by bucket.
+ let mut bucket = 0;
+ for i in 0..symbol_count {
+ let symbol_bucket = hash(i) % bucket_count;
+ while bucket < symbol_bucket {
+ self.buffer.write(&U32::new(self.endian, 0));
+ bucket += 1;
+ }
+ if bucket == symbol_bucket {
+ self.buffer.write(&U32::new(self.endian, symbol_base + i));
+ bucket += 1;
+ }
+ }
+ while bucket < bucket_count {
+ self.buffer.write(&U32::new(self.endian, 0));
+ bucket += 1;
+ }
+
+ // Write hash values.
+ for i in 0..symbol_count {
+ let mut h = hash(i);
+ if i == symbol_count - 1 || h % bucket_count != hash(i + 1) % bucket_count {
+ h |= 1;
+ } else {
+ h &= !1;
+ }
+ self.buffer.write(&U32::new(self.endian, h));
+ }
+ }
+
+ /// Reserve the section index for the GNU hash table.
+ pub fn reserve_gnu_hash_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.gnu_hash_str_id.is_none());
+ self.gnu_hash_str_id = Some(self.add_section_name(&b".gnu.hash"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Write the section header for the GNU hash table.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_gnu_hash_section_header(&mut self, sh_addr: u64) {
+ if self.gnu_hash_str_id.is_none() {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.gnu_hash_str_id,
+ sh_type: elf::SHT_GNU_HASH,
+ sh_flags: elf::SHF_ALLOC.into(),
+ sh_addr,
+ sh_offset: self.gnu_hash_offset as u64,
+ sh_size: self.gnu_hash_size as u64,
+ sh_link: self.dynsym_index.0,
+ sh_info: 0,
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Reserve the range for the `.gnu.version` section.
+ ///
+ /// This function does nothing if no dynamic symbols were reserved.
+ pub fn reserve_gnu_versym(&mut self) {
+ debug_assert_eq!(self.gnu_versym_offset, 0);
+ if self.dynsym_num == 0 {
+ return;
+ }
+ self.gnu_versym_offset = self.reserve(self.dynsym_num as usize * 2, 2);
+ }
+
+ /// Write the null symbol version entry.
+ ///
+ /// This must be the first symbol version that is written.
+ /// This function does nothing if no dynamic symbols were reserved.
+ pub fn write_null_gnu_versym(&mut self) {
+ if self.dynsym_num == 0 {
+ return;
+ }
+ util::write_align(self.buffer, 2);
+ debug_assert_eq!(self.gnu_versym_offset, self.buffer.len());
+ self.write_gnu_versym(0);
+ }
+
+ /// Write a symbol version entry.
+ pub fn write_gnu_versym(&mut self, versym: u16) {
+ self.buffer.write(&U16::new(self.endian, versym));
+ }
+
+ /// Reserve the section index for the `.gnu.version` section.
+ pub fn reserve_gnu_versym_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.gnu_versym_str_id.is_none());
+ self.gnu_versym_str_id = Some(self.add_section_name(&b".gnu.version"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Write the section header for the `.gnu.version` section.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_gnu_versym_section_header(&mut self, sh_addr: u64) {
+ if self.gnu_versym_str_id.is_none() {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.gnu_versym_str_id,
+ sh_type: elf::SHT_GNU_VERSYM,
+ sh_flags: elf::SHF_ALLOC.into(),
+ sh_addr,
+ sh_offset: self.gnu_versym_offset as u64,
+ sh_size: self.dynsym_num as u64 * 2,
+ sh_link: self.dynsym_index.0,
+ sh_info: 0,
+ sh_addralign: 2,
+ sh_entsize: 2,
+ });
+ }
+
+ /// Reserve the range for the `.gnu.version_d` section.
+ pub fn reserve_gnu_verdef(&mut self, verdef_count: usize, verdaux_count: usize) {
+ debug_assert_eq!(self.gnu_verdef_offset, 0);
+ if verdef_count == 0 {
+ return;
+ }
+ self.gnu_verdef_size = verdef_count * mem::size_of::<elf::Verdef<Endianness>>()
+ + verdaux_count * mem::size_of::<elf::Verdaux<Endianness>>();
+ self.gnu_verdef_offset = self.reserve(self.gnu_verdef_size, self.elf_align);
+ self.gnu_verdef_count = verdef_count as u16;
+ self.gnu_verdef_remaining = self.gnu_verdef_count;
+ }
+
+ /// Write alignment padding bytes prior to a `.gnu.version_d` section.
+ pub fn write_align_gnu_verdef(&mut self) {
+ if self.gnu_verdef_offset == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.gnu_verdef_offset, self.buffer.len());
+ }
+
+ /// Write a version definition entry.
+ pub fn write_gnu_verdef(&mut self, verdef: &Verdef) {
+ debug_assert_ne!(self.gnu_verdef_remaining, 0);
+ self.gnu_verdef_remaining -= 1;
+ let vd_next = if self.gnu_verdef_remaining == 0 {
+ 0
+ } else {
+ mem::size_of::<elf::Verdef<Endianness>>() as u32
+ + verdef.aux_count as u32 * mem::size_of::<elf::Verdaux<Endianness>>() as u32
+ };
+
+ self.gnu_verdaux_remaining = verdef.aux_count;
+ let vd_aux = if verdef.aux_count == 0 {
+ 0
+ } else {
+ mem::size_of::<elf::Verdef<Endianness>>() as u32
+ };
+
+ self.buffer.write(&elf::Verdef {
+ vd_version: U16::new(self.endian, verdef.version),
+ vd_flags: U16::new(self.endian, verdef.flags),
+ vd_ndx: U16::new(self.endian, verdef.index),
+ vd_cnt: U16::new(self.endian, verdef.aux_count),
+ vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))),
+ vd_aux: U32::new(self.endian, vd_aux),
+ vd_next: U32::new(self.endian, vd_next),
+ });
+ self.write_gnu_verdaux(verdef.name);
+ }
+
+ /// Write a version definition auxiliary entry.
+ pub fn write_gnu_verdaux(&mut self, name: StringId) {
+ debug_assert_ne!(self.gnu_verdaux_remaining, 0);
+ self.gnu_verdaux_remaining -= 1;
+ let vda_next = if self.gnu_verdaux_remaining == 0 {
+ 0
+ } else {
+ mem::size_of::<elf::Verdaux<Endianness>>() as u32
+ };
+ self.buffer.write(&elf::Verdaux {
+ vda_name: U32::new(self.endian, self.dynstr.get_offset(name) as u32),
+ vda_next: U32::new(self.endian, vda_next),
+ });
+ }
+
+ /// Reserve the section index for the `.gnu.version_d` section.
+ pub fn reserve_gnu_verdef_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.gnu_verdef_str_id.is_none());
+ self.gnu_verdef_str_id = Some(self.add_section_name(&b".gnu.version_d"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Write the section header for the `.gnu.version_d` section.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_gnu_verdef_section_header(&mut self, sh_addr: u64) {
+ if self.gnu_verdef_str_id.is_none() {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.gnu_verdef_str_id,
+ sh_type: elf::SHT_GNU_VERDEF,
+ sh_flags: elf::SHF_ALLOC.into(),
+ sh_addr,
+ sh_offset: self.gnu_verdef_offset as u64,
+ sh_size: self.gnu_verdef_size as u64,
+ sh_link: self.dynstr_index.0,
+ sh_info: self.gnu_verdef_count.into(),
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Reserve the range for the `.gnu.version_r` section.
+ pub fn reserve_gnu_verneed(&mut self, verneed_count: usize, vernaux_count: usize) {
+ debug_assert_eq!(self.gnu_verneed_offset, 0);
+ if verneed_count == 0 {
+ return;
+ }
+ self.gnu_verneed_size = verneed_count * mem::size_of::<elf::Verneed<Endianness>>()
+ + vernaux_count * mem::size_of::<elf::Vernaux<Endianness>>();
+ self.gnu_verneed_offset = self.reserve(self.gnu_verneed_size, self.elf_align);
+ self.gnu_verneed_count = verneed_count as u16;
+ self.gnu_verneed_remaining = self.gnu_verneed_count;
+ }
+
+ /// Write alignment padding bytes prior to a `.gnu.version_r` section.
+ pub fn write_align_gnu_verneed(&mut self) {
+ if self.gnu_verneed_offset == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.gnu_verneed_offset, self.buffer.len());
+ }
+
+ /// Write a version need entry.
+ pub fn write_gnu_verneed(&mut self, verneed: &Verneed) {
+ debug_assert_ne!(self.gnu_verneed_remaining, 0);
+ self.gnu_verneed_remaining -= 1;
+ let vn_next = if self.gnu_verneed_remaining == 0 {
+ 0
+ } else {
+ mem::size_of::<elf::Verneed<Endianness>>() as u32
+ + verneed.aux_count as u32 * mem::size_of::<elf::Vernaux<Endianness>>() as u32
+ };
+
+ self.gnu_vernaux_remaining = verneed.aux_count;
+ let vn_aux = if verneed.aux_count == 0 {
+ 0
+ } else {
+ mem::size_of::<elf::Verneed<Endianness>>() as u32
+ };
+
+ self.buffer.write(&elf::Verneed {
+ vn_version: U16::new(self.endian, verneed.version),
+ vn_cnt: U16::new(self.endian, verneed.aux_count),
+ vn_file: U32::new(self.endian, self.dynstr.get_offset(verneed.file) as u32),
+ vn_aux: U32::new(self.endian, vn_aux),
+ vn_next: U32::new(self.endian, vn_next),
+ });
+ }
+
+ /// Write a version need auxiliary entry.
+ pub fn write_gnu_vernaux(&mut self, vernaux: &Vernaux) {
+ debug_assert_ne!(self.gnu_vernaux_remaining, 0);
+ self.gnu_vernaux_remaining -= 1;
+ let vna_next = if self.gnu_vernaux_remaining == 0 {
+ 0
+ } else {
+ mem::size_of::<elf::Vernaux<Endianness>>() as u32
+ };
+ self.buffer.write(&elf::Vernaux {
+ vna_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(vernaux.name))),
+ vna_flags: U16::new(self.endian, vernaux.flags),
+ vna_other: U16::new(self.endian, vernaux.index),
+ vna_name: U32::new(self.endian, self.dynstr.get_offset(vernaux.name) as u32),
+ vna_next: U32::new(self.endian, vna_next),
+ });
+ }
+
+ /// Reserve the section index for the `.gnu.version_r` section.
+ pub fn reserve_gnu_verneed_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.gnu_verneed_str_id.is_none());
+ self.gnu_verneed_str_id = Some(self.add_section_name(&b".gnu.version_r"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Write the section header for the `.gnu.version_r` section.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_gnu_verneed_section_header(&mut self, sh_addr: u64) {
+ if self.gnu_verneed_str_id.is_none() {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.gnu_verneed_str_id,
+ sh_type: elf::SHT_GNU_VERNEED,
+ sh_flags: elf::SHF_ALLOC.into(),
+ sh_addr,
+ sh_offset: self.gnu_verneed_offset as u64,
+ sh_size: self.gnu_verneed_size as u64,
+ sh_link: self.dynstr_index.0,
+ sh_info: self.gnu_verneed_count.into(),
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Reserve the section index for the `.gnu.attributes` section.
+ pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex {
+ debug_assert!(self.gnu_attributes_str_id.is_none());
+ self.gnu_attributes_str_id = Some(self.add_section_name(&b".gnu.attributes"[..]));
+ self.reserve_section_index()
+ }
+
+ /// Reserve the range for the `.gnu.attributes` section.
+ pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) {
+ debug_assert_eq!(self.gnu_attributes_offset, 0);
+ if gnu_attributes_size == 0 {
+ return;
+ }
+ self.gnu_attributes_size = gnu_attributes_size;
+ self.gnu_attributes_offset = self.reserve(self.gnu_attributes_size, self.elf_align);
+ }
+
+ /// Write the section header for the `.gnu.attributes` section.
+ ///
+ /// This function does nothing if the section index was not reserved.
+ pub fn write_gnu_attributes_section_header(&mut self) {
+ if self.gnu_attributes_str_id.is_none() {
+ return;
+ }
+ self.write_section_header(&SectionHeader {
+ name: self.gnu_attributes_str_id,
+ sh_type: elf::SHT_GNU_ATTRIBUTES,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: self.gnu_attributes_offset as u64,
+ sh_size: self.gnu_attributes_size as u64,
+ sh_link: self.dynstr_index.0,
+ sh_info: 0, // TODO
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: 0,
+ });
+ }
+
+ /// Write the data for the `.gnu.attributes` section.
+ pub fn write_gnu_attributes(&mut self, data: &[u8]) {
+ if self.gnu_attributes_offset == 0 {
+ return;
+ }
+ util::write_align(self.buffer, self.elf_align);
+ debug_assert_eq!(self.gnu_attributes_offset, self.buffer.len());
+ self.buffer.write_bytes(data);
+ }
+
+ /// Reserve a file range for the given number of relocations.
+ ///
+ /// Returns the offset of the range.
+ pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> usize {
+ self.reserve(count * self.rel_size(is_rela), self.elf_align)
+ }
+
+ /// Write alignment padding bytes prior to a relocation section.
+ pub fn write_align_relocation(&mut self) {
+ util::write_align(self.buffer, self.elf_align);
+ }
+
+ /// Write a relocation.
+ pub fn write_relocation(&mut self, is_rela: bool, rel: &Rel) {
+ let endian = self.endian;
+ if self.is_64 {
+ if is_rela {
+ let rel = elf::Rela64 {
+ r_offset: U64::new(endian, rel.r_offset),
+ r_info: elf::Rela64::r_info(endian, self.is_mips64el, rel.r_sym, rel.r_type),
+ r_addend: I64::new(endian, rel.r_addend),
+ };
+ self.buffer.write(&rel);
+ } else {
+ let rel = elf::Rel64 {
+ r_offset: U64::new(endian, rel.r_offset),
+ r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type),
+ };
+ self.buffer.write(&rel);
+ }
+ } else {
+ if is_rela {
+ let rel = elf::Rela32 {
+ r_offset: U32::new(endian, rel.r_offset as u32),
+ r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
+ r_addend: I32::new(endian, rel.r_addend as i32),
+ };
+ self.buffer.write(&rel);
+ } else {
+ let rel = elf::Rel32 {
+ r_offset: U32::new(endian, rel.r_offset as u32),
+ r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
+ };
+ self.buffer.write(&rel);
+ }
+ }
+ }
+
+ /// Write the section header for a relocation section.
+ ///
+ /// `section` is the index of the section the relocations apply to,
+ /// or 0 if none.
+ ///
+ /// `symtab` is the index of the symbol table the relocations refer to,
+ /// or 0 if none.
+ ///
+ /// `offset` is the file offset of the relocations.
+ pub fn write_relocation_section_header(
+ &mut self,
+ name: StringId,
+ section: SectionIndex,
+ symtab: SectionIndex,
+ offset: usize,
+ count: usize,
+ is_rela: bool,
+ ) {
+ self.write_section_header(&SectionHeader {
+ name: Some(name),
+ sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL },
+ sh_flags: elf::SHF_INFO_LINK.into(),
+ sh_addr: 0,
+ sh_offset: offset as u64,
+ sh_size: (count * self.rel_size(is_rela)) as u64,
+ sh_link: symtab.0,
+ sh_info: section.0,
+ sh_addralign: self.elf_align as u64,
+ sh_entsize: self.rel_size(is_rela) as u64,
+ });
+ }
+
+ /// Reserve a file range for a COMDAT section.
+ ///
+ /// `count` is the number of sections in the COMDAT group.
+ ///
+ /// Returns the offset of the range.
+ pub fn reserve_comdat(&mut self, count: usize) -> usize {
+ self.reserve((count + 1) * 4, 4)
+ }
+
+ /// Write `GRP_COMDAT` at the start of the COMDAT section.
+ pub fn write_comdat_header(&mut self) {
+ util::write_align(self.buffer, 4);
+ self.buffer.write(&U32::new(self.endian, elf::GRP_COMDAT));
+ }
+
+ /// Write an entry in a COMDAT section.
+ pub fn write_comdat_entry(&mut self, entry: SectionIndex) {
+ self.buffer.write(&U32::new(self.endian, entry.0));
+ }
+
+ /// Write the section header for a COMDAT section.
+ pub fn write_comdat_section_header(
+ &mut self,
+ name: StringId,
+ symtab: SectionIndex,
+ symbol: SymbolIndex,
+ offset: usize,
+ count: usize,
+ ) {
+ self.write_section_header(&SectionHeader {
+ name: Some(name),
+ sh_type: elf::SHT_GROUP,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: offset as u64,
+ sh_size: ((count + 1) * 4) as u64,
+ sh_link: symtab.0,
+ sh_info: symbol.0,
+ sh_addralign: 4,
+ sh_entsize: 4,
+ });
+ }
+
+ /// Return a helper for writing an attributes section.
+ pub fn attributes_writer(&self) -> AttributesWriter {
+ AttributesWriter::new(self.endian)
+ }
+}
+
+/// A helper for writing an attributes section.
+///
+/// Attributes have a variable length encoding, so it is awkward to write them in a
+/// single pass. Instead, we build the entire attributes section data in memory, using
+/// placeholders for unknown lengths that are filled in later.
+#[allow(missing_debug_implementations)]
+pub struct AttributesWriter {
+ endian: Endianness,
+ data: Vec<u8>,
+ subsection_offset: usize,
+ subsubsection_offset: usize,
+}
+
+impl AttributesWriter {
+ /// Create a new `AttributesWriter` for the given endianness.
+ pub fn new(endian: Endianness) -> Self {
+ AttributesWriter {
+ endian,
+ data: vec![0x41],
+ subsection_offset: 0,
+ subsubsection_offset: 0,
+ }
+ }
+
+ /// Start a new subsection with the given vendor name.
+ pub fn start_subsection(&mut self, vendor: &[u8]) {
+ debug_assert_eq!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ self.subsection_offset = self.data.len();
+ self.data.extend_from_slice(&[0; 4]);
+ self.data.extend_from_slice(vendor);
+ self.data.push(0);
+ }
+
+ /// End the subsection.
+ ///
+ /// The subsection length is automatically calculated and written.
+ pub fn end_subsection(&mut self) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ let length = self.data.len() - self.subsection_offset;
+ self.data[self.subsection_offset..][..4]
+ .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
+ self.subsection_offset = 0;
+ }
+
+ /// Start a new sub-subsection with the given tag.
+ pub fn start_subsubsection(&mut self, tag: u8) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ self.subsubsection_offset = self.data.len();
+ self.data.push(tag);
+ self.data.extend_from_slice(&[0; 4]);
+ }
+
+ /// Write a section or symbol index to the sub-subsection.
+ ///
+ /// The user must also call this function to write the terminating 0 index.
+ pub fn write_subsubsection_index(&mut self, index: u32) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ util::write_uleb128(&mut self.data, u64::from(index));
+ }
+
+ /// Write raw index data to the sub-subsection.
+ ///
+ /// The terminating 0 index is automatically written.
+ pub fn write_subsubsection_indices(&mut self, indices: &[u8]) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ self.data.extend_from_slice(indices);
+ self.data.push(0);
+ }
+
+ /// Write an attribute tag to the sub-subsection.
+ pub fn write_attribute_tag(&mut self, tag: u64) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ util::write_uleb128(&mut self.data, tag);
+ }
+
+ /// Write an attribute integer value to the sub-subsection.
+ pub fn write_attribute_integer(&mut self, value: u64) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ util::write_uleb128(&mut self.data, value);
+ }
+
+ /// Write an attribute string value to the sub-subsection.
+ ///
+ /// The value must not include the null terminator.
+ pub fn write_attribute_string(&mut self, value: &[u8]) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ self.data.extend_from_slice(value);
+ self.data.push(0);
+ }
+
+ /// Write raw attribute data to the sub-subsection.
+ pub fn write_subsubsection_attributes(&mut self, attributes: &[u8]) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ self.data.extend_from_slice(attributes);
+ }
+
+ /// End the sub-subsection.
+ ///
+ /// The sub-subsection length is automatically calculated and written.
+ pub fn end_subsubsection(&mut self) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ let length = self.data.len() - self.subsubsection_offset;
+ self.data[self.subsubsection_offset + 1..][..4]
+ .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
+ self.subsubsection_offset = 0;
+ }
+
+ /// Return the completed section data.
+ pub fn data(self) -> Vec<u8> {
+ debug_assert_eq!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ self.data
+ }
+}
+
+/// Native endian version of [`elf::FileHeader64`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct FileHeader {
+ pub os_abi: u8,
+ pub abi_version: u8,
+ pub e_type: u16,
+ pub e_machine: u16,
+ pub e_entry: u64,
+ pub e_flags: u32,
+}
+
+/// Native endian version of [`elf::ProgramHeader64`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct ProgramHeader {
+ pub p_type: u32,
+ pub p_flags: u32,
+ pub p_offset: u64,
+ pub p_vaddr: u64,
+ pub p_paddr: u64,
+ pub p_filesz: u64,
+ pub p_memsz: u64,
+ pub p_align: u64,
+}
+
+/// Native endian version of [`elf::SectionHeader64`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct SectionHeader {
+ pub name: Option<StringId>,
+ pub sh_type: u32,
+ pub sh_flags: u64,
+ pub sh_addr: u64,
+ pub sh_offset: u64,
+ pub sh_size: u64,
+ pub sh_link: u32,
+ pub sh_info: u32,
+ pub sh_addralign: u64,
+ pub sh_entsize: u64,
+}
+
+/// Native endian version of [`elf::Sym64`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct Sym {
+ pub name: Option<StringId>,
+ pub section: Option<SectionIndex>,
+ pub st_info: u8,
+ pub st_other: u8,
+ pub st_shndx: u16,
+ pub st_value: u64,
+ pub st_size: u64,
+}
+
+/// Unified native endian version of [`elf::Rel64`] and [`elf::Rela64`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct Rel {
+ pub r_offset: u64,
+ pub r_sym: u32,
+ pub r_type: u32,
+ pub r_addend: i64,
+}
+
+/// Information required for writing [`elf::Verdef`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct Verdef {
+ pub version: u16,
+ pub flags: u16,
+ pub index: u16,
+ pub aux_count: u16,
+ /// The name for the first [`elf::Verdaux`] entry.
+ pub name: StringId,
+}
+
+/// Information required for writing [`elf::Verneed`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct Verneed {
+ pub version: u16,
+ pub aux_count: u16,
+ pub file: StringId,
+}
+
+/// Information required for writing [`elf::Vernaux`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct Vernaux {
+ pub flags: u16,
+ pub index: u16,
+ pub name: StringId,
+}
diff --git a/third_party/rust/object/src/write/macho.rs b/third_party/rust/object/src/write/macho.rs
new file mode 100644
index 0000000000..e3ce55bb4e
--- /dev/null
+++ b/third_party/rust/object/src/write/macho.rs
@@ -0,0 +1,966 @@
+use core::mem;
+
+use crate::endian::*;
+use crate::macho;
+use crate::write::string::*;
+use crate::write::util::*;
+use crate::write::*;
+use crate::AddressSize;
+
+#[derive(Default, Clone, Copy)]
+struct SectionOffsets {
+ index: usize,
+ offset: usize,
+ address: u64,
+ reloc_offset: usize,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ emit: bool,
+ index: usize,
+ str_id: Option<StringId>,
+}
+
+/// The customizable portion of a [`macho::BuildVersionCommand`].
+#[derive(Debug, Default, Clone, Copy)]
+#[non_exhaustive] // May want to add the tool list?
+pub struct MachOBuildVersion {
+ /// One of the `PLATFORM_` constants (for example,
+ /// [`object::macho::PLATFORM_MACOS`](macho::PLATFORM_MACOS)).
+ pub platform: u32,
+ /// The minimum OS version, where `X.Y.Z` is encoded in nibbles as
+ /// `xxxx.yy.zz`.
+ pub minos: u32,
+ /// The SDK version as `X.Y.Z`, where `X.Y.Z` is encoded in nibbles as
+ /// `xxxx.yy.zz`.
+ pub sdk: u32,
+}
+
+impl MachOBuildVersion {
+ fn cmdsize(&self) -> u32 {
+ // Same size for both endianness, and we don't have `ntools`.
+ let sz = mem::size_of::<macho::BuildVersionCommand<Endianness>>();
+ debug_assert!(sz <= u32::MAX as usize);
+ sz as u32
+ }
+}
+
+// Public methods.
+impl<'a> Object<'a> {
+ /// Specify information for a Mach-O `LC_BUILD_VERSION` command.
+ ///
+ /// Requires `feature = "macho"`.
+ #[inline]
+ pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) {
+ self.macho_build_version = Some(info);
+ }
+}
+
+// Private methods.
+impl<'a> Object<'a> {
+ pub(crate) fn macho_set_subsections_via_symbols(&mut self) {
+ let flags = match self.flags {
+ FileFlags::MachO { flags } => flags,
+ _ => 0,
+ };
+ self.flags = FileFlags::MachO {
+ flags: flags | macho::MH_SUBSECTIONS_VIA_SYMBOLS,
+ };
+ }
+
+ pub(crate) fn macho_segment_name(&self, segment: StandardSegment) -> &'static [u8] {
+ match segment {
+ StandardSegment::Text => &b"__TEXT"[..],
+ StandardSegment::Data => &b"__DATA"[..],
+ StandardSegment::Debug => &b"__DWARF"[..],
+ }
+ }
+
+ pub(crate) fn macho_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
+ match section {
+ StandardSection::Text => (
+ &b"__TEXT"[..],
+ &b"__text"[..],
+ SectionKind::Text,
+ SectionFlags::None,
+ ),
+ StandardSection::Data => (
+ &b"__DATA"[..],
+ &b"__data"[..],
+ SectionKind::Data,
+ SectionFlags::None,
+ ),
+ StandardSection::ReadOnlyData => (
+ &b"__TEXT"[..],
+ &b"__const"[..],
+ SectionKind::ReadOnlyData,
+ SectionFlags::None,
+ ),
+ StandardSection::ReadOnlyDataWithRel => (
+ &b"__DATA"[..],
+ &b"__const"[..],
+ SectionKind::ReadOnlyDataWithRel,
+ SectionFlags::None,
+ ),
+ StandardSection::ReadOnlyString => (
+ &b"__TEXT"[..],
+ &b"__cstring"[..],
+ SectionKind::ReadOnlyString,
+ SectionFlags::None,
+ ),
+ StandardSection::UninitializedData => (
+ &b"__DATA"[..],
+ &b"__bss"[..],
+ SectionKind::UninitializedData,
+ SectionFlags::None,
+ ),
+ StandardSection::Tls => (
+ &b"__DATA"[..],
+ &b"__thread_data"[..],
+ SectionKind::Tls,
+ SectionFlags::None,
+ ),
+ StandardSection::UninitializedTls => (
+ &b"__DATA"[..],
+ &b"__thread_bss"[..],
+ SectionKind::UninitializedTls,
+ SectionFlags::None,
+ ),
+ StandardSection::TlsVariables => (
+ &b"__DATA"[..],
+ &b"__thread_vars"[..],
+ SectionKind::TlsVariables,
+ SectionFlags::None,
+ ),
+ StandardSection::Common => (
+ &b"__DATA"[..],
+ &b"__common"[..],
+ SectionKind::Common,
+ SectionFlags::None,
+ ),
+ StandardSection::GnuProperty => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Note, SectionFlags::None)
+ }
+ }
+ }
+
+ fn macho_tlv_bootstrap(&mut self) -> SymbolId {
+ match self.tlv_bootstrap {
+ Some(id) => id,
+ None => {
+ let id = self.add_symbol(Symbol {
+ name: b"_tlv_bootstrap".to_vec(),
+ value: 0,
+ size: 0,
+ kind: SymbolKind::Text,
+ scope: SymbolScope::Dynamic,
+ weak: false,
+ section: SymbolSection::Undefined,
+ flags: SymbolFlags::None,
+ });
+ self.tlv_bootstrap = Some(id);
+ id
+ }
+ }
+ }
+
+ /// Create the `__thread_vars` entry for a TLS variable.
+ ///
+ /// The symbol given by `symbol_id` will be updated to point to this entry.
+ ///
+ /// A new `SymbolId` will be returned. The caller must update this symbol
+ /// to point to the initializer.
+ ///
+ /// If `symbol_id` is not for a TLS variable, then it is returned unchanged.
+ pub(crate) fn macho_add_thread_var(&mut self, symbol_id: SymbolId) -> SymbolId {
+ let symbol = self.symbol_mut(symbol_id);
+ if symbol.kind != SymbolKind::Tls {
+ return symbol_id;
+ }
+
+ // Create the initializer symbol.
+ let mut name = symbol.name.clone();
+ name.extend_from_slice(b"$tlv$init");
+ let init_symbol_id = self.add_raw_symbol(Symbol {
+ name,
+ value: 0,
+ size: 0,
+ kind: SymbolKind::Tls,
+ scope: SymbolScope::Compilation,
+ weak: false,
+ section: SymbolSection::Undefined,
+ flags: SymbolFlags::None,
+ });
+
+ // Add the tlv entry.
+ // Three pointers in size:
+ // - __tlv_bootstrap - used to make sure support exists
+ // - spare pointer - used when mapped by the runtime
+ // - pointer to symbol initializer
+ let section = self.section_id(StandardSection::TlsVariables);
+ let address_size = self.architecture.address_size().unwrap().bytes();
+ let size = u64::from(address_size) * 3;
+ let data = vec![0; size as usize];
+ let offset = self.append_section_data(section, &data, u64::from(address_size));
+
+ let tlv_bootstrap = self.macho_tlv_bootstrap();
+ self.add_relocation(
+ section,
+ Relocation {
+ offset,
+ size: address_size * 8,
+ kind: RelocationKind::Absolute,
+ encoding: RelocationEncoding::Generic,
+ symbol: tlv_bootstrap,
+ addend: 0,
+ },
+ )
+ .unwrap();
+ self.add_relocation(
+ section,
+ Relocation {
+ offset: offset + u64::from(address_size) * 2,
+ size: address_size * 8,
+ kind: RelocationKind::Absolute,
+ encoding: RelocationEncoding::Generic,
+ symbol: init_symbol_id,
+ addend: 0,
+ },
+ )
+ .unwrap();
+
+ // Update the symbol to point to the tlv.
+ let symbol = self.symbol_mut(symbol_id);
+ symbol.value = offset;
+ symbol.size = size;
+ symbol.section = SymbolSection::Section(section);
+
+ init_symbol_id
+ }
+
+ pub(crate) fn macho_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 {
+ let constant = match relocation.kind {
+ // AArch64Call relocations have special handling for the addend, so don't adjust it
+ RelocationKind::Relative if relocation.encoding == RelocationEncoding::AArch64Call => 0,
+ RelocationKind::Relative
+ | RelocationKind::GotRelative
+ | RelocationKind::PltRelative => relocation.addend + 4,
+ _ => relocation.addend,
+ };
+ // Aarch64 relocs of these sizes act as if they are double-word length
+ if self.architecture == Architecture::Aarch64 && matches!(relocation.size, 12 | 21 | 26) {
+ relocation.size = 32;
+ }
+ relocation.addend -= constant;
+ constant
+ }
+
+ pub(crate) fn macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ let address_size = self.architecture.address_size().unwrap();
+ let endian = self.endian;
+ let macho32 = MachO32 { endian };
+ let macho64 = MachO64 { endian };
+ let macho: &dyn MachO = match address_size {
+ AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => &macho32,
+ AddressSize::U64 => &macho64,
+ };
+ let pointer_align = address_size.bytes() as usize;
+
+ // Calculate offsets of everything, and build strtab.
+ let mut offset = 0;
+
+ // Calculate size of Mach-O header.
+ offset += macho.mach_header_size();
+
+ // Calculate size of commands.
+ let mut ncmds = 0;
+ let command_offset = offset;
+
+ let build_version_offset = offset;
+ if let Some(version) = &self.macho_build_version {
+ offset += version.cmdsize() as usize;
+ ncmds += 1;
+ }
+
+ // Calculate size of segment command and section headers.
+ let segment_command_offset = offset;
+ let segment_command_len =
+ macho.segment_command_size() + self.sections.len() * macho.section_header_size();
+ offset += segment_command_len;
+ ncmds += 1;
+
+ // Calculate size of symtab command.
+ let symtab_command_offset = offset;
+ let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>();
+ offset += symtab_command_len;
+ ncmds += 1;
+
+ let sizeofcmds = offset - command_offset;
+
+ // Calculate size of section data.
+ // Section data can immediately follow the load commands without any alignment padding.
+ let segment_file_offset = offset;
+ let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
+ let mut address = 0;
+ for (index, section) in self.sections.iter().enumerate() {
+ section_offsets[index].index = 1 + index;
+ if !section.is_bss() {
+ address = align_u64(address, section.align);
+ section_offsets[index].address = address;
+ section_offsets[index].offset = segment_file_offset + address as usize;
+ address += section.size;
+ }
+ }
+ let segment_file_size = address as usize;
+ offset += address as usize;
+ for (index, section) in self.sections.iter().enumerate() {
+ if section.is_bss() {
+ debug_assert!(section.data.is_empty());
+ address = align_u64(address, section.align);
+ section_offsets[index].address = address;
+ address += section.size;
+ }
+ }
+
+ // Count symbols and add symbol strings to strtab.
+ let mut strtab = StringTable::default();
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ let mut nsyms = 0;
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ // The unified API allows creating symbols that we don't emit, so filter
+ // them out here.
+ //
+ // Since we don't actually emit the symbol kind, we validate it here too.
+ match symbol.kind {
+ SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls | SymbolKind::Unknown => {}
+ SymbolKind::File | SymbolKind::Section => continue,
+ SymbolKind::Null | SymbolKind::Label => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ }
+ symbol_offsets[index].emit = true;
+ symbol_offsets[index].index = nsyms;
+ nsyms += 1;
+ if !symbol.name.is_empty() {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+ }
+
+ // Calculate size of symtab.
+ offset = align(offset, pointer_align);
+ let symtab_offset = offset;
+ let symtab_len = nsyms * macho.nlist_size();
+ offset += symtab_len;
+
+ // Calculate size of strtab.
+ let strtab_offset = offset;
+ // Start with null name.
+ let mut strtab_data = vec![0];
+ strtab.write(1, &mut strtab_data);
+ offset += strtab_data.len();
+
+ // Calculate size of relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ let count = section.relocations.len();
+ if count != 0 {
+ offset = align(offset, 4);
+ section_offsets[index].reloc_offset = offset;
+ let len = count * mem::size_of::<macho::Relocation<Endianness>>();
+ offset += len;
+ }
+ }
+
+ // Start writing.
+ buffer
+ .reserve(offset)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ let (cputype, cpusubtype) = match self.architecture {
+ Architecture::Arm => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL),
+ Architecture::Aarch64 => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL),
+ Architecture::Aarch64_Ilp32 => {
+ (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8)
+ }
+ Architecture::I386 => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL),
+ Architecture::X86_64 => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL),
+ Architecture::PowerPc => (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL),
+ Architecture::PowerPc64 => (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL),
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+
+ let flags = match self.flags {
+ FileFlags::MachO { flags } => flags,
+ _ => 0,
+ };
+ macho.write_mach_header(
+ buffer,
+ MachHeader {
+ cputype,
+ cpusubtype,
+ filetype: macho::MH_OBJECT,
+ ncmds,
+ sizeofcmds: sizeofcmds as u32,
+ flags,
+ },
+ );
+
+ if let Some(version) = &self.macho_build_version {
+ debug_assert_eq!(build_version_offset, buffer.len());
+ buffer.write(&macho::BuildVersionCommand {
+ cmd: U32::new(endian, macho::LC_BUILD_VERSION),
+ cmdsize: U32::new(endian, version.cmdsize()),
+ platform: U32::new(endian, version.platform),
+ minos: U32::new(endian, version.minos),
+ sdk: U32::new(endian, version.sdk),
+ ntools: U32::new(endian, 0),
+ });
+ }
+
+ // Write segment command.
+ debug_assert_eq!(segment_command_offset, buffer.len());
+ macho.write_segment_command(
+ buffer,
+ SegmentCommand {
+ cmdsize: segment_command_len as u32,
+ segname: [0; 16],
+ vmaddr: 0,
+ vmsize: address,
+ fileoff: segment_file_offset as u64,
+ filesize: segment_file_size as u64,
+ maxprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE,
+ initprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE,
+ nsects: self.sections.len() as u32,
+ flags: 0,
+ },
+ );
+
+ // Write section headers.
+ for (index, section) in self.sections.iter().enumerate() {
+ let mut sectname = [0; 16];
+ sectname
+ .get_mut(..section.name.len())
+ .ok_or_else(|| {
+ Error(format!(
+ "section name `{}` is too long",
+ section.name().unwrap_or(""),
+ ))
+ })?
+ .copy_from_slice(&section.name);
+ let mut segname = [0; 16];
+ segname
+ .get_mut(..section.segment.len())
+ .ok_or_else(|| {
+ Error(format!(
+ "segment name `{}` is too long",
+ section.segment().unwrap_or(""),
+ ))
+ })?
+ .copy_from_slice(&section.segment);
+ let flags = if let SectionFlags::MachO { flags } = section.flags {
+ flags
+ } else {
+ match section.kind {
+ SectionKind::Text => {
+ macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS
+ }
+ SectionKind::Data => 0,
+ SectionKind::ReadOnlyData | SectionKind::ReadOnlyDataWithRel => 0,
+ SectionKind::ReadOnlyString => macho::S_CSTRING_LITERALS,
+ SectionKind::UninitializedData | SectionKind::Common => macho::S_ZEROFILL,
+ SectionKind::Tls => macho::S_THREAD_LOCAL_REGULAR,
+ SectionKind::UninitializedTls => macho::S_THREAD_LOCAL_ZEROFILL,
+ SectionKind::TlsVariables => macho::S_THREAD_LOCAL_VARIABLES,
+ SectionKind::Debug => macho::S_ATTR_DEBUG,
+ SectionKind::OtherString => macho::S_CSTRING_LITERALS,
+ SectionKind::Other | SectionKind::Linker | SectionKind::Metadata => 0,
+ SectionKind::Note | SectionKind::Unknown | SectionKind::Elf(_) => {
+ return Err(Error(format!(
+ "unimplemented section `{}` kind {:?}",
+ section.name().unwrap_or(""),
+ section.kind
+ )));
+ }
+ }
+ };
+ macho.write_section(
+ buffer,
+ SectionHeader {
+ sectname,
+ segname,
+ addr: section_offsets[index].address,
+ size: section.size,
+ offset: section_offsets[index].offset as u32,
+ align: section.align.trailing_zeros(),
+ reloff: section_offsets[index].reloc_offset as u32,
+ nreloc: section.relocations.len() as u32,
+ flags,
+ },
+ );
+ }
+
+ // Write symtab command.
+ debug_assert_eq!(symtab_command_offset, buffer.len());
+ let symtab_command = macho::SymtabCommand {
+ cmd: U32::new(endian, macho::LC_SYMTAB),
+ cmdsize: U32::new(endian, symtab_command_len as u32),
+ symoff: U32::new(endian, symtab_offset as u32),
+ nsyms: U32::new(endian, nsyms as u32),
+ stroff: U32::new(endian, strtab_offset as u32),
+ strsize: U32::new(endian, strtab_data.len() as u32),
+ };
+ buffer.write(&symtab_command);
+
+ // Write section data.
+ for (index, section) in self.sections.iter().enumerate() {
+ if !section.is_bss() {
+ buffer.resize(section_offsets[index].offset);
+ buffer.write_bytes(&section.data);
+ }
+ }
+ debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len());
+
+ // Write symtab.
+ write_align(buffer, pointer_align);
+ debug_assert_eq!(symtab_offset, buffer.len());
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if !symbol_offsets[index].emit {
+ continue;
+ }
+ // TODO: N_STAB
+ let (mut n_type, n_sect) = match symbol.section {
+ SymbolSection::Undefined => (macho::N_UNDF | macho::N_EXT, 0),
+ SymbolSection::Absolute => (macho::N_ABS, 0),
+ SymbolSection::Section(id) => (macho::N_SECT, id.0 + 1),
+ SymbolSection::None | SymbolSection::Common => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` section {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.section
+ )));
+ }
+ };
+ match symbol.scope {
+ SymbolScope::Unknown | SymbolScope::Compilation => {}
+ SymbolScope::Linkage => {
+ n_type |= macho::N_EXT | macho::N_PEXT;
+ }
+ SymbolScope::Dynamic => {
+ n_type |= macho::N_EXT;
+ }
+ }
+
+ let n_desc = if let SymbolFlags::MachO { n_desc } = symbol.flags {
+ n_desc
+ } else {
+ let mut n_desc = 0;
+ if symbol.weak {
+ if symbol.is_undefined() {
+ n_desc |= macho::N_WEAK_REF;
+ } else {
+ n_desc |= macho::N_WEAK_DEF;
+ }
+ }
+ n_desc
+ };
+
+ let n_value = match symbol.section.id() {
+ Some(section) => section_offsets[section.0].address + symbol.value,
+ None => symbol.value,
+ };
+
+ let n_strx = symbol_offsets[index]
+ .str_id
+ .map(|id| strtab.get_offset(id))
+ .unwrap_or(0);
+
+ macho.write_nlist(
+ buffer,
+ Nlist {
+ n_strx: n_strx as u32,
+ n_type,
+ n_sect: n_sect as u8,
+ n_desc,
+ n_value,
+ },
+ );
+ }
+
+ // Write strtab.
+ debug_assert_eq!(strtab_offset, buffer.len());
+ buffer.write_bytes(&strtab_data);
+
+ // Write relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ if !section.relocations.is_empty() {
+ write_align(buffer, 4);
+ debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
+ for reloc in &section.relocations {
+ let r_extern;
+ let mut r_symbolnum;
+ let symbol = &self.symbols[reloc.symbol.0];
+ if symbol.kind == SymbolKind::Section {
+ r_symbolnum = section_offsets[symbol.section.id().unwrap().0].index as u32;
+ r_extern = false;
+ } else {
+ r_symbolnum = symbol_offsets[reloc.symbol.0].index as u32;
+ r_extern = true;
+ }
+ let r_length = match reloc.size {
+ 8 => 0,
+ 16 => 1,
+ 32 => 2,
+ 64 => 3,
+ _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))),
+ };
+ let (r_pcrel, r_type) = match self.architecture {
+ Architecture::I386 => match reloc.kind {
+ RelocationKind::Absolute => (false, macho::GENERIC_RELOC_VANILLA),
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::X86_64 => match (reloc.kind, reloc.encoding, reloc.addend) {
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => {
+ (false, macho::X86_64_RELOC_UNSIGNED)
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, -4) => {
+ (true, macho::X86_64_RELOC_SIGNED)
+ }
+ (RelocationKind::Relative, RelocationEncoding::X86RipRelative, -4) => {
+ (true, macho::X86_64_RELOC_SIGNED)
+ }
+ (RelocationKind::Relative, RelocationEncoding::X86Branch, -4) => {
+ (true, macho::X86_64_RELOC_BRANCH)
+ }
+ (RelocationKind::PltRelative, RelocationEncoding::X86Branch, -4) => {
+ (true, macho::X86_64_RELOC_BRANCH)
+ }
+ (RelocationKind::GotRelative, RelocationEncoding::Generic, -4) => {
+ (true, macho::X86_64_RELOC_GOT)
+ }
+ (
+ RelocationKind::GotRelative,
+ RelocationEncoding::X86RipRelativeMovq,
+ -4,
+ ) => (true, macho::X86_64_RELOC_GOT_LOAD),
+ (RelocationKind::MachO { value, relative }, _, _) => (relative, value),
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => {
+ match (reloc.kind, reloc.encoding, reloc.addend) {
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => {
+ (false, macho::ARM64_RELOC_UNSIGNED)
+ }
+ (RelocationKind::Relative, RelocationEncoding::AArch64Call, 0) => {
+ (true, macho::ARM64_RELOC_BRANCH26)
+ }
+ // Non-zero addend, so we have to encode the addend separately
+ (
+ RelocationKind::Relative,
+ RelocationEncoding::AArch64Call,
+ value,
+ ) => {
+ // first emit the BR26 relocation
+ let reloc_info = macho::RelocationInfo {
+ r_address: reloc.offset as u32,
+ r_symbolnum,
+ r_pcrel: true,
+ r_length,
+ r_extern: true,
+ r_type: macho::ARM64_RELOC_BRANCH26,
+ };
+ buffer.write(&reloc_info.relocation(endian));
+
+ // set up a separate relocation for the addend
+ r_symbolnum = value as u32;
+ (false, macho::ARM64_RELOC_ADDEND)
+ }
+ (
+ RelocationKind::MachO { value, relative },
+ RelocationEncoding::Generic,
+ 0,
+ ) => (relative, value),
+ _ => {
+ return Err(Error(format!(
+ "unimplemented relocation {:?}",
+ reloc
+ )));
+ }
+ }
+ }
+ _ => {
+ if let RelocationKind::MachO { value, relative } = reloc.kind {
+ (relative, value)
+ } else {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ }
+ };
+ let reloc_info = macho::RelocationInfo {
+ r_address: reloc.offset as u32,
+ r_symbolnum,
+ r_pcrel,
+ r_length,
+ r_extern,
+ r_type,
+ };
+ buffer.write(&reloc_info.relocation(endian));
+ }
+ }
+ }
+
+ debug_assert_eq!(offset, buffer.len());
+
+ Ok(())
+ }
+}
+
+struct MachHeader {
+ cputype: u32,
+ cpusubtype: u32,
+ filetype: u32,
+ ncmds: u32,
+ sizeofcmds: u32,
+ flags: u32,
+}
+
+struct SegmentCommand {
+ cmdsize: u32,
+ segname: [u8; 16],
+ vmaddr: u64,
+ vmsize: u64,
+ fileoff: u64,
+ filesize: u64,
+ maxprot: u32,
+ initprot: u32,
+ nsects: u32,
+ flags: u32,
+}
+
+pub struct SectionHeader {
+ sectname: [u8; 16],
+ segname: [u8; 16],
+ addr: u64,
+ size: u64,
+ offset: u32,
+ align: u32,
+ reloff: u32,
+ nreloc: u32,
+ flags: u32,
+}
+
+struct Nlist {
+ n_strx: u32,
+ n_type: u8,
+ n_sect: u8,
+ n_desc: u16,
+ n_value: u64,
+}
+
+trait MachO {
+ fn mach_header_size(&self) -> usize;
+ fn segment_command_size(&self) -> usize;
+ fn section_header_size(&self) -> usize;
+ fn nlist_size(&self) -> usize;
+ fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader);
+ fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand);
+ fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader);
+ fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist);
+}
+
+struct MachO32<E> {
+ endian: E,
+}
+
+impl<E: Endian> MachO for MachO32<E> {
+ fn mach_header_size(&self) -> usize {
+ mem::size_of::<macho::MachHeader32<E>>()
+ }
+
+ fn segment_command_size(&self) -> usize {
+ mem::size_of::<macho::SegmentCommand32<E>>()
+ }
+
+ fn section_header_size(&self) -> usize {
+ mem::size_of::<macho::Section32<E>>()
+ }
+
+ fn nlist_size(&self) -> usize {
+ mem::size_of::<macho::Nlist32<E>>()
+ }
+
+ fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) {
+ let endian = self.endian;
+ let magic = if endian.is_big_endian() {
+ macho::MH_MAGIC
+ } else {
+ macho::MH_CIGAM
+ };
+ let header = macho::MachHeader32 {
+ magic: U32::new(BigEndian, magic),
+ cputype: U32::new(endian, header.cputype),
+ cpusubtype: U32::new(endian, header.cpusubtype),
+ filetype: U32::new(endian, header.filetype),
+ ncmds: U32::new(endian, header.ncmds),
+ sizeofcmds: U32::new(endian, header.sizeofcmds),
+ flags: U32::new(endian, header.flags),
+ };
+ buffer.write(&header);
+ }
+
+ fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) {
+ let endian = self.endian;
+ let segment = macho::SegmentCommand32 {
+ cmd: U32::new(endian, macho::LC_SEGMENT),
+ cmdsize: U32::new(endian, segment.cmdsize),
+ segname: segment.segname,
+ vmaddr: U32::new(endian, segment.vmaddr as u32),
+ vmsize: U32::new(endian, segment.vmsize as u32),
+ fileoff: U32::new(endian, segment.fileoff as u32),
+ filesize: U32::new(endian, segment.filesize as u32),
+ maxprot: U32::new(endian, segment.maxprot),
+ initprot: U32::new(endian, segment.initprot),
+ nsects: U32::new(endian, segment.nsects),
+ flags: U32::new(endian, segment.flags),
+ };
+ buffer.write(&segment);
+ }
+
+ fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
+ let endian = self.endian;
+ let section = macho::Section32 {
+ sectname: section.sectname,
+ segname: section.segname,
+ addr: U32::new(endian, section.addr as u32),
+ size: U32::new(endian, section.size as u32),
+ offset: U32::new(endian, section.offset),
+ align: U32::new(endian, section.align),
+ reloff: U32::new(endian, section.reloff),
+ nreloc: U32::new(endian, section.nreloc),
+ flags: U32::new(endian, section.flags),
+ reserved1: U32::default(),
+ reserved2: U32::default(),
+ };
+ buffer.write(&section);
+ }
+
+ fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) {
+ let endian = self.endian;
+ let nlist = macho::Nlist32 {
+ n_strx: U32::new(endian, nlist.n_strx),
+ n_type: nlist.n_type,
+ n_sect: nlist.n_sect,
+ n_desc: U16::new(endian, nlist.n_desc),
+ n_value: U32::new(endian, nlist.n_value as u32),
+ };
+ buffer.write(&nlist);
+ }
+}
+
+struct MachO64<E> {
+ endian: E,
+}
+
+impl<E: Endian> MachO for MachO64<E> {
+ fn mach_header_size(&self) -> usize {
+ mem::size_of::<macho::MachHeader64<E>>()
+ }
+
+ fn segment_command_size(&self) -> usize {
+ mem::size_of::<macho::SegmentCommand64<E>>()
+ }
+
+ fn section_header_size(&self) -> usize {
+ mem::size_of::<macho::Section64<E>>()
+ }
+
+ fn nlist_size(&self) -> usize {
+ mem::size_of::<macho::Nlist64<E>>()
+ }
+
+ fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) {
+ let endian = self.endian;
+ let magic = if endian.is_big_endian() {
+ macho::MH_MAGIC_64
+ } else {
+ macho::MH_CIGAM_64
+ };
+ let header = macho::MachHeader64 {
+ magic: U32::new(BigEndian, magic),
+ cputype: U32::new(endian, header.cputype),
+ cpusubtype: U32::new(endian, header.cpusubtype),
+ filetype: U32::new(endian, header.filetype),
+ ncmds: U32::new(endian, header.ncmds),
+ sizeofcmds: U32::new(endian, header.sizeofcmds),
+ flags: U32::new(endian, header.flags),
+ reserved: U32::default(),
+ };
+ buffer.write(&header);
+ }
+
+ fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) {
+ let endian = self.endian;
+ let segment = macho::SegmentCommand64 {
+ cmd: U32::new(endian, macho::LC_SEGMENT_64),
+ cmdsize: U32::new(endian, segment.cmdsize),
+ segname: segment.segname,
+ vmaddr: U64::new(endian, segment.vmaddr),
+ vmsize: U64::new(endian, segment.vmsize),
+ fileoff: U64::new(endian, segment.fileoff),
+ filesize: U64::new(endian, segment.filesize),
+ maxprot: U32::new(endian, segment.maxprot),
+ initprot: U32::new(endian, segment.initprot),
+ nsects: U32::new(endian, segment.nsects),
+ flags: U32::new(endian, segment.flags),
+ };
+ buffer.write(&segment);
+ }
+
+ fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
+ let endian = self.endian;
+ let section = macho::Section64 {
+ sectname: section.sectname,
+ segname: section.segname,
+ addr: U64::new(endian, section.addr),
+ size: U64::new(endian, section.size),
+ offset: U32::new(endian, section.offset),
+ align: U32::new(endian, section.align),
+ reloff: U32::new(endian, section.reloff),
+ nreloc: U32::new(endian, section.nreloc),
+ flags: U32::new(endian, section.flags),
+ reserved1: U32::default(),
+ reserved2: U32::default(),
+ reserved3: U32::default(),
+ };
+ buffer.write(&section);
+ }
+
+ fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) {
+ let endian = self.endian;
+ let nlist = macho::Nlist64 {
+ n_strx: U32::new(endian, nlist.n_strx),
+ n_type: nlist.n_type,
+ n_sect: nlist.n_sect,
+ n_desc: U16::new(endian, nlist.n_desc),
+ n_value: U64Bytes::new(endian, nlist.n_value),
+ };
+ buffer.write(&nlist);
+ }
+}
diff --git a/third_party/rust/object/src/write/mod.rs b/third_party/rust/object/src/write/mod.rs
new file mode 100644
index 0000000000..711ff16d2a
--- /dev/null
+++ b/third_party/rust/object/src/write/mod.rs
@@ -0,0 +1,943 @@
+//! Interface for writing object files.
+
+use alloc::borrow::Cow;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::{fmt, result, str};
+#[cfg(not(feature = "std"))]
+use hashbrown::HashMap;
+#[cfg(feature = "std")]
+use std::{boxed::Box, collections::HashMap, error, io};
+
+use crate::endian::{Endianness, U32, U64};
+use crate::{
+ Architecture, BinaryFormat, ComdatKind, FileFlags, RelocationEncoding, RelocationKind,
+ SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
+};
+
+#[cfg(feature = "coff")]
+mod coff;
+#[cfg(feature = "coff")]
+pub use coff::CoffExportStyle;
+
+#[cfg(feature = "elf")]
+pub mod elf;
+
+#[cfg(feature = "macho")]
+mod macho;
+#[cfg(feature = "macho")]
+pub use macho::MachOBuildVersion;
+
+#[cfg(feature = "pe")]
+pub mod pe;
+
+#[cfg(feature = "xcoff")]
+mod xcoff;
+
+mod string;
+pub use string::StringId;
+
+mod util;
+pub use util::*;
+
+/// The error type used within the write module.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Error(String);
+
+impl fmt::Display for Error {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(&self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl error::Error for Error {}
+
+/// The result type used within the write module.
+pub type Result<T> = result::Result<T, Error>;
+
+/// A writable relocatable object file.
+#[derive(Debug)]
+pub struct Object<'a> {
+ format: BinaryFormat,
+ architecture: Architecture,
+ endian: Endianness,
+ sections: Vec<Section<'a>>,
+ standard_sections: HashMap<StandardSection, SectionId>,
+ symbols: Vec<Symbol>,
+ symbol_map: HashMap<Vec<u8>, SymbolId>,
+ stub_symbols: HashMap<SymbolId, SymbolId>,
+ comdats: Vec<Comdat>,
+ /// File flags that are specific to each file format.
+ pub flags: FileFlags,
+ /// The symbol name mangling scheme.
+ pub mangling: Mangling,
+ /// Mach-O "_tlv_bootstrap" symbol.
+ tlv_bootstrap: Option<SymbolId>,
+ #[cfg(feature = "macho")]
+ macho_build_version: Option<MachOBuildVersion>,
+}
+
+impl<'a> Object<'a> {
+ /// Create an empty object file.
+ pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object<'a> {
+ Object {
+ format,
+ architecture,
+ endian,
+ sections: Vec::new(),
+ standard_sections: HashMap::new(),
+ symbols: Vec::new(),
+ symbol_map: HashMap::new(),
+ stub_symbols: HashMap::new(),
+ comdats: Vec::new(),
+ flags: FileFlags::None,
+ mangling: Mangling::default(format, architecture),
+ tlv_bootstrap: None,
+ #[cfg(feature = "macho")]
+ macho_build_version: None,
+ }
+ }
+
+ /// Return the file format.
+ #[inline]
+ pub fn format(&self) -> BinaryFormat {
+ self.format
+ }
+
+ /// Return the architecture.
+ #[inline]
+ pub fn architecture(&self) -> Architecture {
+ self.architecture
+ }
+
+ /// Return the current mangling setting.
+ #[inline]
+ pub fn mangling(&self) -> Mangling {
+ self.mangling
+ }
+
+ /// Specify the mangling setting.
+ #[inline]
+ pub fn set_mangling(&mut self, mangling: Mangling) {
+ self.mangling = mangling;
+ }
+
+ /// Return the name for a standard segment.
+ ///
+ /// This will vary based on the file format.
+ #[allow(unused_variables)]
+ pub fn segment_name(&self, segment: StandardSegment) -> &'static [u8] {
+ match self.format {
+ #[cfg(feature = "coff")]
+ BinaryFormat::Coff => &[],
+ #[cfg(feature = "elf")]
+ BinaryFormat::Elf => &[],
+ #[cfg(feature = "macho")]
+ BinaryFormat::MachO => self.macho_segment_name(segment),
+ _ => unimplemented!(),
+ }
+ }
+
+ /// Get the section with the given `SectionId`.
+ #[inline]
+ pub fn section(&self, section: SectionId) -> &Section<'a> {
+ &self.sections[section.0]
+ }
+
+ /// Mutably get the section with the given `SectionId`.
+ #[inline]
+ pub fn section_mut(&mut self, section: SectionId) -> &mut Section<'a> {
+ &mut self.sections[section.0]
+ }
+
+ /// Set the data for an existing section.
+ ///
+ /// Must not be called for sections that already have data, or that contain uninitialized data.
+ pub fn set_section_data<T>(&mut self, section: SectionId, data: T, align: u64)
+ where
+ T: Into<Cow<'a, [u8]>>,
+ {
+ self.sections[section.0].set_data(data, align)
+ }
+
+ /// Append data to an existing section. Returns the section offset of the data.
+ pub fn append_section_data(&mut self, section: SectionId, data: &[u8], align: u64) -> u64 {
+ self.sections[section.0].append_data(data, align)
+ }
+
+ /// Append zero-initialized data to an existing section. Returns the section offset of the data.
+ pub fn append_section_bss(&mut self, section: SectionId, size: u64, align: u64) -> u64 {
+ self.sections[section.0].append_bss(size, align)
+ }
+
+ /// Return the `SectionId` of a standard section.
+ ///
+ /// If the section doesn't already exist then it is created.
+ pub fn section_id(&mut self, section: StandardSection) -> SectionId {
+ self.standard_sections
+ .get(&section)
+ .cloned()
+ .unwrap_or_else(|| {
+ let (segment, name, kind, flags) = self.section_info(section);
+ let id = self.add_section(segment.to_vec(), name.to_vec(), kind);
+ self.section_mut(id).flags = flags;
+ id
+ })
+ }
+
+ /// Add a new section and return its `SectionId`.
+ ///
+ /// This also creates a section symbol.
+ pub fn add_section(&mut self, segment: Vec<u8>, name: Vec<u8>, kind: SectionKind) -> SectionId {
+ let id = SectionId(self.sections.len());
+ self.sections.push(Section {
+ segment,
+ name,
+ kind,
+ size: 0,
+ align: 1,
+ data: Cow::Borrowed(&[]),
+ relocations: Vec::new(),
+ symbol: None,
+ flags: SectionFlags::None,
+ });
+
+ // Add to self.standard_sections if required. This may match multiple standard sections.
+ let section = &self.sections[id.0];
+ for standard_section in StandardSection::all() {
+ if !self.standard_sections.contains_key(standard_section) {
+ let (segment, name, kind, _flags) = self.section_info(*standard_section);
+ if segment == &*section.segment && name == &*section.name && kind == section.kind {
+ self.standard_sections.insert(*standard_section, id);
+ }
+ }
+ }
+
+ id
+ }
+
+ fn section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
+ match self.format {
+ #[cfg(feature = "coff")]
+ BinaryFormat::Coff => self.coff_section_info(section),
+ #[cfg(feature = "elf")]
+ BinaryFormat::Elf => self.elf_section_info(section),
+ #[cfg(feature = "macho")]
+ BinaryFormat::MachO => self.macho_section_info(section),
+ #[cfg(feature = "xcoff")]
+ BinaryFormat::Xcoff => self.xcoff_section_info(section),
+ _ => unimplemented!(),
+ }
+ }
+
+ /// Add a subsection. Returns the `SectionId` and section offset of the data.
+ pub fn add_subsection(
+ &mut self,
+ section: StandardSection,
+ name: &[u8],
+ data: &[u8],
+ align: u64,
+ ) -> (SectionId, u64) {
+ let section_id = if self.has_subsections_via_symbols() {
+ self.set_subsections_via_symbols();
+ self.section_id(section)
+ } else {
+ let (segment, name, kind, flags) = self.subsection_info(section, name);
+ let id = self.add_section(segment.to_vec(), name, kind);
+ self.section_mut(id).flags = flags;
+ id
+ };
+ let offset = self.append_section_data(section_id, data, align);
+ (section_id, offset)
+ }
+
+ fn has_subsections_via_symbols(&self) -> bool {
+ match self.format {
+ BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Xcoff => false,
+ BinaryFormat::MachO => true,
+ _ => unimplemented!(),
+ }
+ }
+
+ fn set_subsections_via_symbols(&mut self) {
+ match self.format {
+ #[cfg(feature = "macho")]
+ BinaryFormat::MachO => self.macho_set_subsections_via_symbols(),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn subsection_info(
+ &self,
+ section: StandardSection,
+ value: &[u8],
+ ) -> (&'static [u8], Vec<u8>, SectionKind, SectionFlags) {
+ let (segment, section, kind, flags) = self.section_info(section);
+ let name = self.subsection_name(section, value);
+ (segment, name, kind, flags)
+ }
+
+ #[allow(unused_variables)]
+ fn subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
+ debug_assert!(!self.has_subsections_via_symbols());
+ match self.format {
+ #[cfg(feature = "coff")]
+ BinaryFormat::Coff => self.coff_subsection_name(section, value),
+ #[cfg(feature = "elf")]
+ BinaryFormat::Elf => self.elf_subsection_name(section, value),
+ _ => unimplemented!(),
+ }
+ }
+
+ /// Get the COMDAT section group with the given `ComdatId`.
+ #[inline]
+ pub fn comdat(&self, comdat: ComdatId) -> &Comdat {
+ &self.comdats[comdat.0]
+ }
+
+ /// Mutably get the COMDAT section group with the given `ComdatId`.
+ #[inline]
+ pub fn comdat_mut(&mut self, comdat: ComdatId) -> &mut Comdat {
+ &mut self.comdats[comdat.0]
+ }
+
+ /// Add a new COMDAT section group and return its `ComdatId`.
+ pub fn add_comdat(&mut self, comdat: Comdat) -> ComdatId {
+ let comdat_id = ComdatId(self.comdats.len());
+ self.comdats.push(comdat);
+ comdat_id
+ }
+
+ /// Get the `SymbolId` of the symbol with the given name.
+ pub fn symbol_id(&self, name: &[u8]) -> Option<SymbolId> {
+ self.symbol_map.get(name).cloned()
+ }
+
+ /// Get the symbol with the given `SymbolId`.
+ #[inline]
+ pub fn symbol(&self, symbol: SymbolId) -> &Symbol {
+ &self.symbols[symbol.0]
+ }
+
+ /// Mutably get the symbol with the given `SymbolId`.
+ #[inline]
+ pub fn symbol_mut(&mut self, symbol: SymbolId) -> &mut Symbol {
+ &mut self.symbols[symbol.0]
+ }
+
+ /// Add a new symbol and return its `SymbolId`.
+ pub fn add_symbol(&mut self, mut symbol: Symbol) -> SymbolId {
+ // Defined symbols must have a scope.
+ debug_assert!(symbol.is_undefined() || symbol.scope != SymbolScope::Unknown);
+ if symbol.kind == SymbolKind::Section {
+ // There can only be one section symbol, but update its flags, since
+ // the automatically generated section symbol will have none.
+ let symbol_id = self.section_symbol(symbol.section.id().unwrap());
+ if symbol.flags != SymbolFlags::None {
+ self.symbol_mut(symbol_id).flags = symbol.flags;
+ }
+ return symbol_id;
+ }
+ if !symbol.name.is_empty()
+ && (symbol.kind == SymbolKind::Text
+ || symbol.kind == SymbolKind::Data
+ || symbol.kind == SymbolKind::Tls)
+ {
+ let unmangled_name = symbol.name.clone();
+ if let Some(prefix) = self.mangling.global_prefix() {
+ symbol.name.insert(0, prefix);
+ }
+ let symbol_id = self.add_raw_symbol(symbol);
+ self.symbol_map.insert(unmangled_name, symbol_id);
+ symbol_id
+ } else {
+ self.add_raw_symbol(symbol)
+ }
+ }
+
+ fn add_raw_symbol(&mut self, symbol: Symbol) -> SymbolId {
+ let symbol_id = SymbolId(self.symbols.len());
+ self.symbols.push(symbol);
+ symbol_id
+ }
+
+ /// Return true if the file format supports `StandardSection::UninitializedTls`.
+ #[inline]
+ pub fn has_uninitialized_tls(&self) -> bool {
+ self.format != BinaryFormat::Coff
+ }
+
+ /// Return true if the file format supports `StandardSection::Common`.
+ #[inline]
+ pub fn has_common(&self) -> bool {
+ self.format == BinaryFormat::MachO
+ }
+
+ /// Add a new common symbol and return its `SymbolId`.
+ ///
+ /// For Mach-O, this appends the symbol to the `__common` section.
+ pub fn add_common_symbol(&mut self, mut symbol: Symbol, size: u64, align: u64) -> SymbolId {
+ if self.has_common() {
+ let symbol_id = self.add_symbol(symbol);
+ let section = self.section_id(StandardSection::Common);
+ self.add_symbol_bss(symbol_id, section, size, align);
+ symbol_id
+ } else {
+ symbol.section = SymbolSection::Common;
+ symbol.size = size;
+ self.add_symbol(symbol)
+ }
+ }
+
+ /// Add a new file symbol and return its `SymbolId`.
+ pub fn add_file_symbol(&mut self, name: Vec<u8>) -> SymbolId {
+ self.add_raw_symbol(Symbol {
+ name,
+ value: 0,
+ size: 0,
+ kind: SymbolKind::File,
+ scope: SymbolScope::Compilation,
+ weak: false,
+ section: SymbolSection::None,
+ flags: SymbolFlags::None,
+ })
+ }
+
+ /// Get the symbol for a section.
+ pub fn section_symbol(&mut self, section_id: SectionId) -> SymbolId {
+ let section = &mut self.sections[section_id.0];
+ if let Some(symbol) = section.symbol {
+ return symbol;
+ }
+ let name = if self.format == BinaryFormat::Coff {
+ section.name.clone()
+ } else {
+ Vec::new()
+ };
+ let symbol_id = SymbolId(self.symbols.len());
+ self.symbols.push(Symbol {
+ name,
+ value: 0,
+ size: 0,
+ kind: SymbolKind::Section,
+ scope: SymbolScope::Compilation,
+ weak: false,
+ section: SymbolSection::Section(section_id),
+ flags: SymbolFlags::None,
+ });
+ section.symbol = Some(symbol_id);
+ symbol_id
+ }
+
+ /// Append data to an existing section, and update a symbol to refer to it.
+ ///
+ /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
+ /// symbol will indirectly point to the added data via the `__thread_vars` entry.
+ ///
+ /// Returns the section offset of the data.
+ pub fn add_symbol_data(
+ &mut self,
+ symbol_id: SymbolId,
+ section: SectionId,
+ data: &[u8],
+ align: u64,
+ ) -> u64 {
+ let offset = self.append_section_data(section, data, align);
+ self.set_symbol_data(symbol_id, section, offset, data.len() as u64);
+ offset
+ }
+
+ /// Append zero-initialized data to an existing section, and update a symbol to refer to it.
+ ///
+ /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
+ /// symbol will indirectly point to the added data via the `__thread_vars` entry.
+ ///
+ /// Returns the section offset of the data.
+ pub fn add_symbol_bss(
+ &mut self,
+ symbol_id: SymbolId,
+ section: SectionId,
+ size: u64,
+ align: u64,
+ ) -> u64 {
+ let offset = self.append_section_bss(section, size, align);
+ self.set_symbol_data(symbol_id, section, offset, size);
+ offset
+ }
+
+ /// Update a symbol to refer to the given data within a section.
+ ///
+ /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
+ /// symbol will indirectly point to the data via the `__thread_vars` entry.
+ #[allow(unused_mut)]
+ pub fn set_symbol_data(
+ &mut self,
+ mut symbol_id: SymbolId,
+ section: SectionId,
+ offset: u64,
+ size: u64,
+ ) {
+ // Defined symbols must have a scope.
+ debug_assert!(self.symbol(symbol_id).scope != SymbolScope::Unknown);
+ match self.format {
+ #[cfg(feature = "macho")]
+ BinaryFormat::MachO => symbol_id = self.macho_add_thread_var(symbol_id),
+ _ => {}
+ }
+ let symbol = self.symbol_mut(symbol_id);
+ symbol.value = offset;
+ symbol.size = size;
+ symbol.section = SymbolSection::Section(section);
+ }
+
+ /// Convert a symbol to a section symbol and offset.
+ ///
+ /// Returns `None` if the symbol does not have a section.
+ pub fn symbol_section_and_offset(&mut self, symbol_id: SymbolId) -> Option<(SymbolId, u64)> {
+ let symbol = self.symbol(symbol_id);
+ if symbol.kind == SymbolKind::Section {
+ return Some((symbol_id, 0));
+ }
+ let symbol_offset = symbol.value;
+ let section = symbol.section.id()?;
+ let section_symbol = self.section_symbol(section);
+ Some((section_symbol, symbol_offset))
+ }
+
+ /// Add a relocation to a section.
+ ///
+ /// Relocations must only be added after the referenced symbols have been added
+ /// and defined (if applicable).
+ pub fn add_relocation(&mut self, section: SectionId, mut relocation: Relocation) -> Result<()> {
+ let addend = match self.format {
+ #[cfg(feature = "coff")]
+ BinaryFormat::Coff => self.coff_fixup_relocation(&mut relocation),
+ #[cfg(feature = "elf")]
+ BinaryFormat::Elf => self.elf_fixup_relocation(&mut relocation)?,
+ #[cfg(feature = "macho")]
+ BinaryFormat::MachO => self.macho_fixup_relocation(&mut relocation),
+ #[cfg(feature = "xcoff")]
+ BinaryFormat::Xcoff => self.xcoff_fixup_relocation(&mut relocation),
+ _ => unimplemented!(),
+ };
+ if addend != 0 {
+ self.write_relocation_addend(section, &relocation, addend)?;
+ }
+ self.sections[section.0].relocations.push(relocation);
+ Ok(())
+ }
+
+ fn write_relocation_addend(
+ &mut self,
+ section: SectionId,
+ relocation: &Relocation,
+ addend: i64,
+ ) -> Result<()> {
+ let data = self.sections[section.0].data_mut();
+ let offset = relocation.offset as usize;
+ match relocation.size {
+ 32 => data.write_at(offset, &U32::new(self.endian, addend as u32)),
+ 64 => data.write_at(offset, &U64::new(self.endian, addend as u64)),
+ _ => {
+ return Err(Error(format!(
+ "unimplemented relocation addend {:?}",
+ relocation
+ )));
+ }
+ }
+ .map_err(|_| {
+ Error(format!(
+ "invalid relocation offset {}+{} (max {})",
+ relocation.offset,
+ relocation.size,
+ data.len()
+ ))
+ })
+ }
+
+ /// Write the object to a `Vec`.
+ pub fn write(&self) -> Result<Vec<u8>> {
+ let mut buffer = Vec::new();
+ self.emit(&mut buffer)?;
+ Ok(buffer)
+ }
+
+ /// Write the object to a `Write` implementation.
+ ///
+ /// Also flushes the writer.
+ ///
+ /// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter)
+ /// instead of an unbuffered writer like [`File`](std::fs::File).
+ #[cfg(feature = "std")]
+ pub fn write_stream<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> {
+ let mut stream = StreamingBuffer::new(w);
+ self.emit(&mut stream)?;
+ stream.result()?;
+ stream.into_inner().flush()?;
+ Ok(())
+ }
+
+ /// Write the object to a `WritableBuffer`.
+ pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ match self.format {
+ #[cfg(feature = "coff")]
+ BinaryFormat::Coff => self.coff_write(buffer),
+ #[cfg(feature = "elf")]
+ BinaryFormat::Elf => self.elf_write(buffer),
+ #[cfg(feature = "macho")]
+ BinaryFormat::MachO => self.macho_write(buffer),
+ #[cfg(feature = "xcoff")]
+ BinaryFormat::Xcoff => self.xcoff_write(buffer),
+ _ => unimplemented!(),
+ }
+ }
+}
+
+/// A standard segment kind.
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[non_exhaustive]
+pub enum StandardSegment {
+ Text,
+ Data,
+ Debug,
+}
+
+/// A standard section kind.
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[non_exhaustive]
+pub enum StandardSection {
+ Text,
+ Data,
+ ReadOnlyData,
+ ReadOnlyDataWithRel,
+ ReadOnlyString,
+ UninitializedData,
+ Tls,
+ /// Zero-fill TLS initializers. Unsupported for COFF.
+ UninitializedTls,
+ /// TLS variable structures. Only supported for Mach-O.
+ TlsVariables,
+ /// Common data. Only supported for Mach-O.
+ Common,
+ /// Notes for GNU properties. Only supported for ELF.
+ GnuProperty,
+}
+
+impl StandardSection {
+ /// Return the section kind of a standard section.
+ pub fn kind(self) -> SectionKind {
+ match self {
+ StandardSection::Text => SectionKind::Text,
+ StandardSection::Data => SectionKind::Data,
+ StandardSection::ReadOnlyData => SectionKind::ReadOnlyData,
+ StandardSection::ReadOnlyDataWithRel => SectionKind::ReadOnlyDataWithRel,
+ StandardSection::ReadOnlyString => SectionKind::ReadOnlyString,
+ StandardSection::UninitializedData => SectionKind::UninitializedData,
+ StandardSection::Tls => SectionKind::Tls,
+ StandardSection::UninitializedTls => SectionKind::UninitializedTls,
+ StandardSection::TlsVariables => SectionKind::TlsVariables,
+ StandardSection::Common => SectionKind::Common,
+ StandardSection::GnuProperty => SectionKind::Note,
+ }
+ }
+
+ // TODO: remembering to update this is error-prone, can we do better?
+ fn all() -> &'static [StandardSection] {
+ &[
+ StandardSection::Text,
+ StandardSection::Data,
+ StandardSection::ReadOnlyData,
+ StandardSection::ReadOnlyDataWithRel,
+ StandardSection::ReadOnlyString,
+ StandardSection::UninitializedData,
+ StandardSection::Tls,
+ StandardSection::UninitializedTls,
+ StandardSection::TlsVariables,
+ StandardSection::Common,
+ StandardSection::GnuProperty,
+ ]
+ }
+}
+
+/// An identifier used to reference a section.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SectionId(usize);
+
+/// A section in an object file.
+#[derive(Debug)]
+pub struct Section<'a> {
+ segment: Vec<u8>,
+ name: Vec<u8>,
+ kind: SectionKind,
+ size: u64,
+ align: u64,
+ data: Cow<'a, [u8]>,
+ relocations: Vec<Relocation>,
+ symbol: Option<SymbolId>,
+ /// Section flags that are specific to each file format.
+ pub flags: SectionFlags,
+}
+
+impl<'a> Section<'a> {
+ /// Try to convert the name to a utf8 string.
+ #[inline]
+ pub fn name(&self) -> Option<&str> {
+ str::from_utf8(&self.name).ok()
+ }
+
+ /// Try to convert the segment to a utf8 string.
+ #[inline]
+ pub fn segment(&self) -> Option<&str> {
+ str::from_utf8(&self.segment).ok()
+ }
+
+ /// Return true if this section contains zerofill data.
+ #[inline]
+ pub fn is_bss(&self) -> bool {
+ self.kind.is_bss()
+ }
+
+ /// Set the data for a section.
+ ///
+ /// Must not be called for sections that already have data, or that contain uninitialized data.
+ pub fn set_data<T>(&mut self, data: T, align: u64)
+ where
+ T: Into<Cow<'a, [u8]>>,
+ {
+ debug_assert!(!self.is_bss());
+ debug_assert_eq!(align & (align - 1), 0);
+ debug_assert!(self.data.is_empty());
+ self.data = data.into();
+ self.size = self.data.len() as u64;
+ self.align = align;
+ }
+
+ /// Append data to a section.
+ ///
+ /// Must not be called for sections that contain uninitialized data.
+ pub fn append_data(&mut self, append_data: &[u8], align: u64) -> u64 {
+ debug_assert!(!self.is_bss());
+ debug_assert_eq!(align & (align - 1), 0);
+ if self.align < align {
+ self.align = align;
+ }
+ let align = align as usize;
+ let data = self.data.to_mut();
+ let mut offset = data.len();
+ if offset & (align - 1) != 0 {
+ offset += align - (offset & (align - 1));
+ data.resize(offset, 0);
+ }
+ data.extend_from_slice(append_data);
+ self.size = data.len() as u64;
+ offset as u64
+ }
+
+ /// Append uninitialized data to a section.
+ ///
+ /// Must not be called for sections that contain initialized data.
+ pub fn append_bss(&mut self, size: u64, align: u64) -> u64 {
+ debug_assert!(self.is_bss());
+ debug_assert_eq!(align & (align - 1), 0);
+ if self.align < align {
+ self.align = align;
+ }
+ let mut offset = self.size;
+ if offset & (align - 1) != 0 {
+ offset += align - (offset & (align - 1));
+ self.size = offset;
+ }
+ self.size += size;
+ offset
+ }
+
+ /// Returns the section as-built so far.
+ ///
+ /// This requires that the section is not a bss section.
+ pub fn data(&self) -> &[u8] {
+ debug_assert!(!self.is_bss());
+ &self.data
+ }
+
+ /// Returns the section as-built so far.
+ ///
+ /// This requires that the section is not a bss section.
+ pub fn data_mut(&mut self) -> &mut [u8] {
+ debug_assert!(!self.is_bss());
+ self.data.to_mut()
+ }
+}
+
+/// The section where a symbol is defined.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SymbolSection {
+ /// The section is not applicable for this symbol (such as file symbols).
+ None,
+ /// The symbol is undefined.
+ Undefined,
+ /// The symbol has an absolute value.
+ Absolute,
+ /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
+ Common,
+ /// The symbol is defined in the given section.
+ Section(SectionId),
+}
+
+impl SymbolSection {
+ /// Returns the section id for the section where the symbol is defined.
+ ///
+ /// May return `None` if the symbol is not defined in a section.
+ #[inline]
+ pub fn id(self) -> Option<SectionId> {
+ if let SymbolSection::Section(id) = self {
+ Some(id)
+ } else {
+ None
+ }
+ }
+}
+
+/// An identifier used to reference a symbol.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SymbolId(usize);
+
+/// A symbol in an object file.
+#[derive(Debug)]
+pub struct Symbol {
+ /// The name of the symbol.
+ pub name: Vec<u8>,
+ /// The value of the symbol.
+ ///
+ /// If the symbol defined in a section, then this is the section offset of the symbol.
+ pub value: u64,
+ /// The size of the symbol.
+ pub size: u64,
+ /// The kind of the symbol.
+ pub kind: SymbolKind,
+ /// The scope of the symbol.
+ pub scope: SymbolScope,
+ /// Whether the symbol has weak binding.
+ pub weak: bool,
+ /// The section containing the symbol.
+ pub section: SymbolSection,
+ /// Symbol flags that are specific to each file format.
+ pub flags: SymbolFlags<SectionId, SymbolId>,
+}
+
+impl Symbol {
+ /// Try to convert the name to a utf8 string.
+ #[inline]
+ pub fn name(&self) -> Option<&str> {
+ str::from_utf8(&self.name).ok()
+ }
+
+ /// Return true if the symbol is undefined.
+ #[inline]
+ pub fn is_undefined(&self) -> bool {
+ self.section == SymbolSection::Undefined
+ }
+
+ /// Return true if the symbol is common data.
+ ///
+ /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
+ #[inline]
+ pub fn is_common(&self) -> bool {
+ self.section == SymbolSection::Common
+ }
+
+ /// Return true if the symbol scope is local.
+ #[inline]
+ pub fn is_local(&self) -> bool {
+ self.scope == SymbolScope::Compilation
+ }
+}
+
+/// A relocation in an object file.
+#[derive(Debug)]
+pub struct Relocation {
+ /// The section offset of the place of the relocation.
+ pub offset: u64,
+ /// The size in bits of the place of relocation.
+ pub size: u8,
+ /// The operation used to calculate the result of the relocation.
+ pub kind: RelocationKind,
+ /// Information about how the result of the relocation operation is encoded in the place.
+ pub encoding: RelocationEncoding,
+ /// The symbol referred to by the relocation.
+ ///
+ /// This may be a section symbol.
+ pub symbol: SymbolId,
+ /// The addend to use in the relocation calculation.
+ ///
+ /// This may be in addition to an implicit addend stored at the place of the relocation.
+ pub addend: i64,
+}
+
+/// An identifier used to reference a COMDAT section group.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct ComdatId(usize);
+
+/// A COMDAT section group.
+#[derive(Debug)]
+pub struct Comdat {
+ /// The COMDAT selection kind.
+ ///
+ /// This determines the way in which the linker resolves multiple definitions of the COMDAT
+ /// sections.
+ pub kind: ComdatKind,
+ /// The COMDAT symbol.
+ ///
+ /// If this symbol is referenced, then all sections in the group will be included by the
+ /// linker.
+ pub symbol: SymbolId,
+ /// The sections in the group.
+ pub sections: Vec<SectionId>,
+}
+
+/// The symbol name mangling scheme.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum Mangling {
+ /// No symbol mangling.
+ None,
+ /// Windows COFF symbol mangling.
+ Coff,
+ /// Windows COFF i386 symbol mangling.
+ CoffI386,
+ /// ELF symbol mangling.
+ Elf,
+ /// Mach-O symbol mangling.
+ MachO,
+ /// Xcoff symbol mangling.
+ Xcoff,
+}
+
+impl Mangling {
+ /// Return the default symboling mangling for the given format and architecture.
+ pub fn default(format: BinaryFormat, architecture: Architecture) -> Self {
+ match (format, architecture) {
+ (BinaryFormat::Coff, Architecture::I386) => Mangling::CoffI386,
+ (BinaryFormat::Coff, _) => Mangling::Coff,
+ (BinaryFormat::Elf, _) => Mangling::Elf,
+ (BinaryFormat::MachO, _) => Mangling::MachO,
+ (BinaryFormat::Xcoff, _) => Mangling::Xcoff,
+ _ => Mangling::None,
+ }
+ }
+
+ /// Return the prefix to use for global symbols.
+ pub fn global_prefix(self) -> Option<u8> {
+ match self {
+ Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None,
+ Mangling::CoffI386 | Mangling::MachO => Some(b'_'),
+ }
+ }
+}
diff --git a/third_party/rust/object/src/write/pe.rs b/third_party/rust/object/src/write/pe.rs
new file mode 100644
index 0000000000..70da3a0937
--- /dev/null
+++ b/third_party/rust/object/src/write/pe.rs
@@ -0,0 +1,847 @@
+//! Helper for writing PE files.
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::mem;
+
+use crate::endian::{LittleEndian as LE, *};
+use crate::pe;
+use crate::write::util;
+use crate::write::{Error, Result, WritableBuffer};
+
+/// A helper for writing PE files.
+///
+/// Writing uses a two phase approach. The first phase reserves file ranges and virtual
+/// address ranges for everything in the order that they will be written.
+///
+/// The second phase writes everything out in order. Thus the caller must ensure writing
+/// is in the same order that file ranges were reserved.
+#[allow(missing_debug_implementations)]
+pub struct Writer<'a> {
+ is_64: bool,
+ section_alignment: u32,
+ file_alignment: u32,
+
+ buffer: &'a mut dyn WritableBuffer,
+ len: u32,
+ virtual_len: u32,
+ headers_len: u32,
+
+ code_address: u32,
+ data_address: u32,
+ code_len: u32,
+ data_len: u32,
+ bss_len: u32,
+
+ nt_headers_offset: u32,
+ data_directories: Vec<DataDirectory>,
+ section_header_num: u16,
+ sections: Vec<Section>,
+
+ symbol_offset: u32,
+ symbol_num: u32,
+
+ reloc_blocks: Vec<RelocBlock>,
+ relocs: Vec<U16<LE>>,
+ reloc_offset: u32,
+}
+
+impl<'a> Writer<'a> {
+ /// Create a new `Writer`.
+ pub fn new(
+ is_64: bool,
+ section_alignment: u32,
+ file_alignment: u32,
+ buffer: &'a mut dyn WritableBuffer,
+ ) -> Self {
+ Writer {
+ is_64,
+ section_alignment,
+ file_alignment,
+
+ buffer,
+ len: 0,
+ virtual_len: 0,
+ headers_len: 0,
+
+ code_address: 0,
+ data_address: 0,
+ code_len: 0,
+ data_len: 0,
+ bss_len: 0,
+
+ nt_headers_offset: 0,
+ data_directories: Vec::new(),
+ section_header_num: 0,
+ sections: Vec::new(),
+
+ symbol_offset: 0,
+ symbol_num: 0,
+
+ reloc_blocks: Vec::new(),
+ relocs: Vec::new(),
+ reloc_offset: 0,
+ }
+ }
+
+ /// Return the current virtual address size that has been reserved.
+ ///
+ /// This is only valid after section headers have been reserved.
+ pub fn virtual_len(&self) -> u32 {
+ self.virtual_len
+ }
+
+ /// Reserve a virtual address range with the given size.
+ ///
+ /// The reserved length will be increased to match the section alignment.
+ ///
+ /// Returns the aligned offset of the start of the range.
+ pub fn reserve_virtual(&mut self, len: u32) -> u32 {
+ let offset = self.virtual_len;
+ self.virtual_len += len;
+ self.virtual_len = util::align_u32(self.virtual_len, self.section_alignment);
+ offset
+ }
+
+ /// Reserve up to the given virtual address.
+ ///
+ /// The reserved length will be increased to match the section alignment.
+ pub fn reserve_virtual_until(&mut self, address: u32) {
+ debug_assert!(self.virtual_len <= address);
+ self.virtual_len = util::align_u32(address, self.section_alignment);
+ }
+
+ /// Return the current file length that has been reserved.
+ pub fn reserved_len(&self) -> u32 {
+ self.len
+ }
+
+ /// Return the current file length that has been written.
+ #[allow(clippy::len_without_is_empty)]
+ pub fn len(&self) -> usize {
+ self.buffer.len()
+ }
+
+ /// Reserve a file range with the given size and starting alignment.
+ ///
+ /// Returns the aligned offset of the start of the range.
+ pub fn reserve(&mut self, len: u32, align_start: u32) -> u32 {
+ if len == 0 {
+ return self.len;
+ }
+ self.reserve_align(align_start);
+ let offset = self.len;
+ self.len += len;
+ offset
+ }
+
+ /// Reserve a file range with the given size and using the file alignment.
+ ///
+ /// Returns the aligned offset of the start of the range.
+ pub fn reserve_file(&mut self, len: u32) -> u32 {
+ self.reserve(len, self.file_alignment)
+ }
+
+ /// Write data.
+ pub fn write(&mut self, data: &[u8]) {
+ self.buffer.write_bytes(data);
+ }
+
+ /// Reserve alignment padding bytes.
+ pub fn reserve_align(&mut self, align_start: u32) {
+ self.len = util::align_u32(self.len, align_start);
+ }
+
+ /// Write alignment padding bytes.
+ pub fn write_align(&mut self, align_start: u32) {
+ util::write_align(self.buffer, align_start as usize);
+ }
+
+ /// Write padding up to the next multiple of file alignment.
+ pub fn write_file_align(&mut self) {
+ self.write_align(self.file_alignment);
+ }
+
+ /// Reserve the file range up to the given file offset.
+ pub fn reserve_until(&mut self, offset: u32) {
+ debug_assert!(self.len <= offset);
+ self.len = offset;
+ }
+
+ /// Write padding up to the given file offset.
+ pub fn pad_until(&mut self, offset: u32) {
+ debug_assert!(self.buffer.len() <= offset as usize);
+ self.buffer.resize(offset as usize);
+ }
+
+ /// Reserve the range for the DOS header.
+ ///
+ /// This must be at the start of the file.
+ ///
+ /// When writing, you may use `write_custom_dos_header` or `write_empty_dos_header`.
+ pub fn reserve_dos_header(&mut self) {
+ debug_assert_eq!(self.len, 0);
+ self.reserve(mem::size_of::<pe::ImageDosHeader>() as u32, 1);
+ }
+
+ /// Write a custom DOS header.
+ ///
+ /// This must be at the start of the file.
+ pub fn write_custom_dos_header(&mut self, dos_header: &pe::ImageDosHeader) -> Result<()> {
+ debug_assert_eq!(self.buffer.len(), 0);
+
+ // Start writing.
+ self.buffer
+ .reserve(self.len as usize)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ self.buffer.write(dos_header);
+ Ok(())
+ }
+
+ /// Write the DOS header for a file without a stub.
+ ///
+ /// This must be at the start of the file.
+ ///
+ /// Uses default values for all fields.
+ pub fn write_empty_dos_header(&mut self) -> Result<()> {
+ self.write_custom_dos_header(&pe::ImageDosHeader {
+ e_magic: U16::new(LE, pe::IMAGE_DOS_SIGNATURE),
+ e_cblp: U16::new(LE, 0),
+ e_cp: U16::new(LE, 0),
+ e_crlc: U16::new(LE, 0),
+ e_cparhdr: U16::new(LE, 0),
+ e_minalloc: U16::new(LE, 0),
+ e_maxalloc: U16::new(LE, 0),
+ e_ss: U16::new(LE, 0),
+ e_sp: U16::new(LE, 0),
+ e_csum: U16::new(LE, 0),
+ e_ip: U16::new(LE, 0),
+ e_cs: U16::new(LE, 0),
+ e_lfarlc: U16::new(LE, 0),
+ e_ovno: U16::new(LE, 0),
+ e_res: [U16::new(LE, 0); 4],
+ e_oemid: U16::new(LE, 0),
+ e_oeminfo: U16::new(LE, 0),
+ e_res2: [U16::new(LE, 0); 10],
+ e_lfanew: U32::new(LE, self.nt_headers_offset),
+ })
+ }
+
+ /// Reserve a fixed DOS header and stub.
+ ///
+ /// Use `reserve_dos_header` and `reserve` if you need a custom stub.
+ pub fn reserve_dos_header_and_stub(&mut self) {
+ self.reserve_dos_header();
+ self.reserve(64, 1);
+ }
+
+ /// Write a fixed DOS header and stub.
+ ///
+ /// Use `write_custom_dos_header` and `write` if you need a custom stub.
+ pub fn write_dos_header_and_stub(&mut self) -> Result<()> {
+ self.write_custom_dos_header(&pe::ImageDosHeader {
+ e_magic: U16::new(LE, pe::IMAGE_DOS_SIGNATURE),
+ e_cblp: U16::new(LE, 0x90),
+ e_cp: U16::new(LE, 3),
+ e_crlc: U16::new(LE, 0),
+ e_cparhdr: U16::new(LE, 4),
+ e_minalloc: U16::new(LE, 0),
+ e_maxalloc: U16::new(LE, 0xffff),
+ e_ss: U16::new(LE, 0),
+ e_sp: U16::new(LE, 0xb8),
+ e_csum: U16::new(LE, 0),
+ e_ip: U16::new(LE, 0),
+ e_cs: U16::new(LE, 0),
+ e_lfarlc: U16::new(LE, 0x40),
+ e_ovno: U16::new(LE, 0),
+ e_res: [U16::new(LE, 0); 4],
+ e_oemid: U16::new(LE, 0),
+ e_oeminfo: U16::new(LE, 0),
+ e_res2: [U16::new(LE, 0); 10],
+ e_lfanew: U32::new(LE, self.nt_headers_offset),
+ })?;
+
+ #[rustfmt::skip]
+ self.buffer.write_bytes(&[
+ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
+ 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+ 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
+ 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ]);
+
+ Ok(())
+ }
+
+ fn nt_headers_size(&self) -> u32 {
+ if self.is_64 {
+ mem::size_of::<pe::ImageNtHeaders64>() as u32
+ } else {
+ mem::size_of::<pe::ImageNtHeaders32>() as u32
+ }
+ }
+
+ fn optional_header_size(&self) -> u32 {
+ let size = if self.is_64 {
+ mem::size_of::<pe::ImageOptionalHeader64>() as u32
+ } else {
+ mem::size_of::<pe::ImageOptionalHeader32>() as u32
+ };
+ size + self.data_directories.len() as u32 * mem::size_of::<pe::ImageDataDirectory>() as u32
+ }
+
+ /// Return the offset of the NT headers, if reserved.
+ pub fn nt_headers_offset(&self) -> u32 {
+ self.nt_headers_offset
+ }
+
+ /// Reserve the range for the NT headers.
+ pub fn reserve_nt_headers(&mut self, data_directory_num: usize) {
+ debug_assert_eq!(self.nt_headers_offset, 0);
+ self.nt_headers_offset = self.reserve(self.nt_headers_size(), 8);
+ self.data_directories = vec![DataDirectory::default(); data_directory_num];
+ self.reserve(
+ data_directory_num as u32 * mem::size_of::<pe::ImageDataDirectory>() as u32,
+ 1,
+ );
+ }
+
+ /// Set the virtual address and size of a data directory.
+ pub fn set_data_directory(&mut self, index: usize, virtual_address: u32, size: u32) {
+ self.data_directories[index] = DataDirectory {
+ virtual_address,
+ size,
+ }
+ }
+
+ /// Write the NT headers.
+ pub fn write_nt_headers(&mut self, nt_headers: NtHeaders) {
+ self.pad_until(self.nt_headers_offset);
+ self.buffer.write(&U32::new(LE, pe::IMAGE_NT_SIGNATURE));
+ let file_header = pe::ImageFileHeader {
+ machine: U16::new(LE, nt_headers.machine),
+ number_of_sections: U16::new(LE, self.section_header_num),
+ time_date_stamp: U32::new(LE, nt_headers.time_date_stamp),
+ pointer_to_symbol_table: U32::new(LE, self.symbol_offset),
+ number_of_symbols: U32::new(LE, self.symbol_num),
+ size_of_optional_header: U16::new(LE, self.optional_header_size() as u16),
+ characteristics: U16::new(LE, nt_headers.characteristics),
+ };
+ self.buffer.write(&file_header);
+ if self.is_64 {
+ let optional_header = pe::ImageOptionalHeader64 {
+ magic: U16::new(LE, pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC),
+ major_linker_version: nt_headers.major_linker_version,
+ minor_linker_version: nt_headers.minor_linker_version,
+ size_of_code: U32::new(LE, self.code_len),
+ size_of_initialized_data: U32::new(LE, self.data_len),
+ size_of_uninitialized_data: U32::new(LE, self.bss_len),
+ address_of_entry_point: U32::new(LE, nt_headers.address_of_entry_point),
+ base_of_code: U32::new(LE, self.code_address),
+ image_base: U64::new(LE, nt_headers.image_base),
+ section_alignment: U32::new(LE, self.section_alignment),
+ file_alignment: U32::new(LE, self.file_alignment),
+ major_operating_system_version: U16::new(
+ LE,
+ nt_headers.major_operating_system_version,
+ ),
+ minor_operating_system_version: U16::new(
+ LE,
+ nt_headers.minor_operating_system_version,
+ ),
+ major_image_version: U16::new(LE, nt_headers.major_image_version),
+ minor_image_version: U16::new(LE, nt_headers.minor_image_version),
+ major_subsystem_version: U16::new(LE, nt_headers.major_subsystem_version),
+ minor_subsystem_version: U16::new(LE, nt_headers.minor_subsystem_version),
+ win32_version_value: U32::new(LE, 0),
+ size_of_image: U32::new(LE, self.virtual_len),
+ size_of_headers: U32::new(LE, self.headers_len),
+ check_sum: U32::new(LE, 0),
+ subsystem: U16::new(LE, nt_headers.subsystem),
+ dll_characteristics: U16::new(LE, nt_headers.dll_characteristics),
+ size_of_stack_reserve: U64::new(LE, nt_headers.size_of_stack_reserve),
+ size_of_stack_commit: U64::new(LE, nt_headers.size_of_stack_commit),
+ size_of_heap_reserve: U64::new(LE, nt_headers.size_of_heap_reserve),
+ size_of_heap_commit: U64::new(LE, nt_headers.size_of_heap_commit),
+ loader_flags: U32::new(LE, 0),
+ number_of_rva_and_sizes: U32::new(LE, self.data_directories.len() as u32),
+ };
+ self.buffer.write(&optional_header);
+ } else {
+ let optional_header = pe::ImageOptionalHeader32 {
+ magic: U16::new(LE, pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC),
+ major_linker_version: nt_headers.major_linker_version,
+ minor_linker_version: nt_headers.minor_linker_version,
+ size_of_code: U32::new(LE, self.code_len),
+ size_of_initialized_data: U32::new(LE, self.data_len),
+ size_of_uninitialized_data: U32::new(LE, self.bss_len),
+ address_of_entry_point: U32::new(LE, nt_headers.address_of_entry_point),
+ base_of_code: U32::new(LE, self.code_address),
+ base_of_data: U32::new(LE, self.data_address),
+ image_base: U32::new(LE, nt_headers.image_base as u32),
+ section_alignment: U32::new(LE, self.section_alignment),
+ file_alignment: U32::new(LE, self.file_alignment),
+ major_operating_system_version: U16::new(
+ LE,
+ nt_headers.major_operating_system_version,
+ ),
+ minor_operating_system_version: U16::new(
+ LE,
+ nt_headers.minor_operating_system_version,
+ ),
+ major_image_version: U16::new(LE, nt_headers.major_image_version),
+ minor_image_version: U16::new(LE, nt_headers.minor_image_version),
+ major_subsystem_version: U16::new(LE, nt_headers.major_subsystem_version),
+ minor_subsystem_version: U16::new(LE, nt_headers.minor_subsystem_version),
+ win32_version_value: U32::new(LE, 0),
+ size_of_image: U32::new(LE, self.virtual_len),
+ size_of_headers: U32::new(LE, self.headers_len),
+ check_sum: U32::new(LE, 0),
+ subsystem: U16::new(LE, nt_headers.subsystem),
+ dll_characteristics: U16::new(LE, nt_headers.dll_characteristics),
+ size_of_stack_reserve: U32::new(LE, nt_headers.size_of_stack_reserve as u32),
+ size_of_stack_commit: U32::new(LE, nt_headers.size_of_stack_commit as u32),
+ size_of_heap_reserve: U32::new(LE, nt_headers.size_of_heap_reserve as u32),
+ size_of_heap_commit: U32::new(LE, nt_headers.size_of_heap_commit as u32),
+ loader_flags: U32::new(LE, 0),
+ number_of_rva_and_sizes: U32::new(LE, self.data_directories.len() as u32),
+ };
+ self.buffer.write(&optional_header);
+ }
+
+ for dir in &self.data_directories {
+ self.buffer.write(&pe::ImageDataDirectory {
+ virtual_address: U32::new(LE, dir.virtual_address),
+ size: U32::new(LE, dir.size),
+ })
+ }
+ }
+
+ /// Reserve the section headers.
+ ///
+ /// The number of reserved section headers must be the same as the number of sections that
+ /// are later reserved.
+ // TODO: change this to a maximum number of sections?
+ pub fn reserve_section_headers(&mut self, section_header_num: u16) {
+ debug_assert_eq!(self.section_header_num, 0);
+ self.section_header_num = section_header_num;
+ self.reserve(
+ u32::from(section_header_num) * mem::size_of::<pe::ImageSectionHeader>() as u32,
+ 1,
+ );
+ // Padding before sections must be included in headers_len.
+ self.reserve_align(self.file_alignment);
+ self.headers_len = self.len;
+ self.reserve_virtual(self.len);
+ }
+
+ /// Write the section headers.
+ ///
+ /// This uses information that was recorded when the sections were reserved.
+ pub fn write_section_headers(&mut self) {
+ debug_assert_eq!(self.section_header_num as usize, self.sections.len());
+ for section in &self.sections {
+ let section_header = pe::ImageSectionHeader {
+ name: section.name,
+ virtual_size: U32::new(LE, section.range.virtual_size),
+ virtual_address: U32::new(LE, section.range.virtual_address),
+ size_of_raw_data: U32::new(LE, section.range.file_size),
+ pointer_to_raw_data: U32::new(LE, section.range.file_offset),
+ pointer_to_relocations: U32::new(LE, 0),
+ pointer_to_linenumbers: U32::new(LE, 0),
+ number_of_relocations: U16::new(LE, 0),
+ number_of_linenumbers: U16::new(LE, 0),
+ characteristics: U32::new(LE, section.characteristics),
+ };
+ self.buffer.write(&section_header);
+ }
+ }
+
+ /// Reserve a section.
+ ///
+ /// Returns the file range and virtual address range that are reserved
+ /// for the section.
+ pub fn reserve_section(
+ &mut self,
+ name: [u8; 8],
+ characteristics: u32,
+ virtual_size: u32,
+ data_size: u32,
+ ) -> SectionRange {
+ let virtual_address = self.reserve_virtual(virtual_size);
+
+ // Padding after section must be included in section file size.
+ let file_size = util::align_u32(data_size, self.file_alignment);
+ let file_offset = if file_size != 0 {
+ self.reserve(file_size, self.file_alignment)
+ } else {
+ 0
+ };
+
+ // Sizes in optional header use the virtual size with the file alignment.
+ let aligned_virtual_size = util::align_u32(virtual_size, self.file_alignment);
+ if characteristics & pe::IMAGE_SCN_CNT_CODE != 0 {
+ if self.code_address == 0 {
+ self.code_address = virtual_address;
+ }
+ self.code_len += aligned_virtual_size;
+ } else if characteristics & pe::IMAGE_SCN_CNT_INITIALIZED_DATA != 0 {
+ if self.data_address == 0 {
+ self.data_address = virtual_address;
+ }
+ self.data_len += aligned_virtual_size;
+ } else if characteristics & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 {
+ if self.data_address == 0 {
+ self.data_address = virtual_address;
+ }
+ self.bss_len += aligned_virtual_size;
+ }
+
+ let range = SectionRange {
+ virtual_address,
+ virtual_size,
+ file_offset,
+ file_size,
+ };
+ self.sections.push(Section {
+ name,
+ characteristics,
+ range,
+ });
+ range
+ }
+
+ /// Write the data for a section.
+ pub fn write_section(&mut self, offset: u32, data: &[u8]) {
+ if data.is_empty() {
+ return;
+ }
+ self.pad_until(offset);
+ self.write(data);
+ self.write_align(self.file_alignment);
+ }
+
+ /// Reserve a `.text` section.
+ ///
+ /// Contains executable code.
+ pub fn reserve_text_section(&mut self, size: u32) -> SectionRange {
+ self.reserve_section(
+ *b".text\0\0\0",
+ pe::IMAGE_SCN_CNT_CODE | pe::IMAGE_SCN_MEM_EXECUTE | pe::IMAGE_SCN_MEM_READ,
+ size,
+ size,
+ )
+ }
+
+ /// Reserve a `.data` section.
+ ///
+ /// Contains initialized data.
+ ///
+ /// May also contain uninitialized data if `virtual_size` is greater than `data_size`.
+ pub fn reserve_data_section(&mut self, virtual_size: u32, data_size: u32) -> SectionRange {
+ self.reserve_section(
+ *b".data\0\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE,
+ virtual_size,
+ data_size,
+ )
+ }
+
+ /// Reserve a `.rdata` section.
+ ///
+ /// Contains read-only initialized data.
+ pub fn reserve_rdata_section(&mut self, size: u32) -> SectionRange {
+ self.reserve_section(
+ *b".rdata\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
+ size,
+ size,
+ )
+ }
+
+ /// Reserve a `.bss` section.
+ ///
+ /// Contains uninitialized data.
+ pub fn reserve_bss_section(&mut self, size: u32) -> SectionRange {
+ self.reserve_section(
+ *b".bss\0\0\0\0",
+ pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE,
+ size,
+ 0,
+ )
+ }
+
+ /// Reserve an `.idata` section.
+ ///
+ /// Contains import tables. Note that it is permissible to store import tables in a different
+ /// section.
+ ///
+ /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_IMPORT` data directory.
+ pub fn reserve_idata_section(&mut self, size: u32) -> SectionRange {
+ let range = self.reserve_section(
+ *b".idata\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE,
+ size,
+ size,
+ );
+ let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_IMPORT];
+ debug_assert_eq!(dir.virtual_address, 0);
+ *dir = DataDirectory {
+ virtual_address: range.virtual_address,
+ size,
+ };
+ range
+ }
+
+ /// Reserve an `.edata` section.
+ ///
+ /// Contains export tables.
+ ///
+ /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_EXPORT` data directory.
+ pub fn reserve_edata_section(&mut self, size: u32) -> SectionRange {
+ let range = self.reserve_section(
+ *b".edata\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
+ size,
+ size,
+ );
+ let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_EXPORT];
+ debug_assert_eq!(dir.virtual_address, 0);
+ *dir = DataDirectory {
+ virtual_address: range.virtual_address,
+ size,
+ };
+ range
+ }
+
+ /// Reserve a `.pdata` section.
+ ///
+ /// Contains exception information.
+ ///
+ /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_EXCEPTION` data directory.
+ pub fn reserve_pdata_section(&mut self, size: u32) -> SectionRange {
+ let range = self.reserve_section(
+ *b".pdata\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
+ size,
+ size,
+ );
+ let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_EXCEPTION];
+ debug_assert_eq!(dir.virtual_address, 0);
+ *dir = DataDirectory {
+ virtual_address: range.virtual_address,
+ size,
+ };
+ range
+ }
+
+ /// Reserve a `.xdata` section.
+ ///
+ /// Contains exception information.
+ pub fn reserve_xdata_section(&mut self, size: u32) -> SectionRange {
+ self.reserve_section(
+ *b".xdata\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
+ size,
+ size,
+ )
+ }
+
+ /// Reserve a `.rsrc` section.
+ ///
+ /// Contains the resource directory.
+ ///
+ /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_RESOURCE` data directory.
+ pub fn reserve_rsrc_section(&mut self, size: u32) -> SectionRange {
+ let range = self.reserve_section(
+ *b".rsrc\0\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
+ size,
+ size,
+ );
+ let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_RESOURCE];
+ debug_assert_eq!(dir.virtual_address, 0);
+ *dir = DataDirectory {
+ virtual_address: range.virtual_address,
+ size,
+ };
+ range
+ }
+
+ /// Add a base relocation.
+ ///
+ /// `typ` must be one of the `IMAGE_REL_BASED_*` constants.
+ pub fn add_reloc(&mut self, mut virtual_address: u32, typ: u16) {
+ let reloc = U16::new(LE, typ << 12 | (virtual_address & 0xfff) as u16);
+ virtual_address &= !0xfff;
+ if let Some(block) = self.reloc_blocks.last_mut() {
+ if block.virtual_address == virtual_address {
+ self.relocs.push(reloc);
+ block.count += 1;
+ return;
+ }
+ // Blocks must have an even number of relocations.
+ if block.count & 1 != 0 {
+ self.relocs.push(U16::new(LE, 0));
+ block.count += 1;
+ }
+ debug_assert!(block.virtual_address < virtual_address);
+ }
+ self.relocs.push(reloc);
+ self.reloc_blocks.push(RelocBlock {
+ virtual_address,
+ count: 1,
+ });
+ }
+
+ /// Return true if a base relocation has been added.
+ pub fn has_relocs(&mut self) -> bool {
+ !self.relocs.is_empty()
+ }
+
+ /// Reserve a `.reloc` section.
+ ///
+ /// This contains the base relocations that were added with `add_reloc`.
+ ///
+ /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_BASERELOC` data directory.
+ pub fn reserve_reloc_section(&mut self) -> SectionRange {
+ if let Some(block) = self.reloc_blocks.last_mut() {
+ // Blocks must have an even number of relocations.
+ if block.count & 1 != 0 {
+ self.relocs.push(U16::new(LE, 0));
+ block.count += 1;
+ }
+ }
+ let size = self.reloc_blocks.iter().map(RelocBlock::size).sum();
+ let range = self.reserve_section(
+ *b".reloc\0\0",
+ pe::IMAGE_SCN_CNT_INITIALIZED_DATA
+ | pe::IMAGE_SCN_MEM_READ
+ | pe::IMAGE_SCN_MEM_DISCARDABLE,
+ size,
+ size,
+ );
+ let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ debug_assert_eq!(dir.virtual_address, 0);
+ *dir = DataDirectory {
+ virtual_address: range.virtual_address,
+ size,
+ };
+ self.reloc_offset = range.file_offset;
+ range
+ }
+
+ /// Write a `.reloc` section.
+ ///
+ /// This contains the base relocations that were added with `add_reloc`.
+ pub fn write_reloc_section(&mut self) {
+ if self.reloc_offset == 0 {
+ return;
+ }
+ self.pad_until(self.reloc_offset);
+
+ let mut total = 0;
+ for block in &self.reloc_blocks {
+ self.buffer.write(&pe::ImageBaseRelocation {
+ virtual_address: U32::new(LE, block.virtual_address),
+ size_of_block: U32::new(LE, block.size()),
+ });
+ self.buffer
+ .write_slice(&self.relocs[total..][..block.count as usize]);
+ total += block.count as usize;
+ }
+ debug_assert_eq!(total, self.relocs.len());
+
+ self.write_align(self.file_alignment);
+ }
+
+ /// Reserve the certificate table.
+ ///
+ /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_SECURITY` data directory.
+ // TODO: reserve individual certificates
+ pub fn reserve_certificate_table(&mut self, size: u32) {
+ let size = util::align_u32(size, 8);
+ let offset = self.reserve(size, 8);
+ let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_SECURITY];
+ debug_assert_eq!(dir.virtual_address, 0);
+ *dir = DataDirectory {
+ virtual_address: offset,
+ size,
+ };
+ }
+
+ /// Write the certificate table.
+ // TODO: write individual certificates
+ pub fn write_certificate_table(&mut self, data: &[u8]) {
+ let dir = self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_SECURITY];
+ self.pad_until(dir.virtual_address);
+ self.write(data);
+ self.pad_until(dir.virtual_address + dir.size);
+ }
+}
+
+/// Information required for writing [`pe::ImageNtHeaders32`] or [`pe::ImageNtHeaders64`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct NtHeaders {
+ // ImageFileHeader
+ pub machine: u16,
+ pub time_date_stamp: u32,
+ pub characteristics: u16,
+ // ImageOptionalHeader
+ pub major_linker_version: u8,
+ pub minor_linker_version: u8,
+ pub address_of_entry_point: u32,
+ pub image_base: u64,
+ pub major_operating_system_version: u16,
+ pub minor_operating_system_version: u16,
+ pub major_image_version: u16,
+ pub minor_image_version: u16,
+ pub major_subsystem_version: u16,
+ pub minor_subsystem_version: u16,
+ pub subsystem: u16,
+ pub dll_characteristics: u16,
+ pub size_of_stack_reserve: u64,
+ pub size_of_stack_commit: u64,
+ pub size_of_heap_reserve: u64,
+ pub size_of_heap_commit: u64,
+}
+
+#[derive(Default, Clone, Copy)]
+struct DataDirectory {
+ virtual_address: u32,
+ size: u32,
+}
+
+/// Information required for writing [`pe::ImageSectionHeader`].
+#[allow(missing_docs)]
+#[derive(Debug, Clone)]
+pub struct Section {
+ pub name: [u8; pe::IMAGE_SIZEOF_SHORT_NAME],
+ pub characteristics: u32,
+ pub range: SectionRange,
+}
+
+/// The file range and virtual address range for a section.
+#[allow(missing_docs)]
+#[derive(Debug, Default, Clone, Copy)]
+pub struct SectionRange {
+ pub virtual_address: u32,
+ pub virtual_size: u32,
+ pub file_offset: u32,
+ pub file_size: u32,
+}
+
+struct RelocBlock {
+ virtual_address: u32,
+ count: u32,
+}
+
+impl RelocBlock {
+ fn size(&self) -> u32 {
+ mem::size_of::<pe::ImageBaseRelocation>() as u32 + self.count * mem::size_of::<u16>() as u32
+ }
+}
diff --git a/third_party/rust/object/src/write/string.rs b/third_party/rust/object/src/write/string.rs
new file mode 100644
index 0000000000..b23274a0af
--- /dev/null
+++ b/third_party/rust/object/src/write/string.rs
@@ -0,0 +1,159 @@
+use alloc::vec::Vec;
+
+#[cfg(feature = "std")]
+type IndexSet<K> = indexmap::IndexSet<K>;
+#[cfg(not(feature = "std"))]
+type IndexSet<K> = indexmap::IndexSet<K, hashbrown::hash_map::DefaultHashBuilder>;
+
+/// An identifier for an entry in a string table.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct StringId(usize);
+
+#[derive(Debug, Default)]
+pub(crate) struct StringTable<'a> {
+ strings: IndexSet<&'a [u8]>,
+ offsets: Vec<usize>,
+}
+
+impl<'a> StringTable<'a> {
+ /// Add a string to the string table.
+ ///
+ /// Panics if the string table has already been written, or
+ /// if the string contains a null byte.
+ pub fn add(&mut self, string: &'a [u8]) -> StringId {
+ assert!(self.offsets.is_empty());
+ assert!(!string.contains(&0));
+ let id = self.strings.insert_full(string).0;
+ StringId(id)
+ }
+
+ /// Return the id of the given string.
+ ///
+ /// Panics if the string is not in the string table.
+ pub fn get_id(&self, string: &[u8]) -> StringId {
+ let id = self.strings.get_index_of(string).unwrap();
+ StringId(id)
+ }
+
+ /// Return the string for the given id.
+ ///
+ /// Panics if the string is not in the string table.
+ pub fn get_string(&self, id: StringId) -> &'a [u8] {
+ self.strings.get_index(id.0).unwrap()
+ }
+
+ /// Return the offset of the given string.
+ ///
+ /// Panics if the string table has not been written, or
+ /// if the string is not in the string table.
+ pub fn get_offset(&self, id: StringId) -> usize {
+ self.offsets[id.0]
+ }
+
+ /// Append the string table to the given `Vec`, and
+ /// calculate the list of string offsets.
+ ///
+ /// `base` is the initial string table offset. For example,
+ /// this should be 1 for ELF, to account for the initial
+ /// null byte (which must have been written by the caller).
+ pub fn write(&mut self, base: usize, w: &mut Vec<u8>) {
+ assert!(self.offsets.is_empty());
+
+ let mut ids: Vec<_> = (0..self.strings.len()).collect();
+ sort(&mut ids, 1, &self.strings);
+
+ self.offsets = vec![0; ids.len()];
+ let mut offset = base;
+ let mut previous = &[][..];
+ for id in ids {
+ let string = self.strings.get_index(id).unwrap();
+ if previous.ends_with(string) {
+ self.offsets[id] = offset - string.len() - 1;
+ } else {
+ self.offsets[id] = offset;
+ w.extend_from_slice(string);
+ w.push(0);
+ offset += string.len() + 1;
+ previous = string;
+ }
+ }
+ }
+}
+
+// Multi-key quicksort.
+//
+// Ordering is such that if a string is a suffix of at least one other string,
+// then it is placed immediately after one of those strings. That is:
+// - comparison starts at the end of the string
+// - shorter strings come later
+//
+// Based on the implementation in LLVM.
+fn sort(mut ids: &mut [usize], mut pos: usize, strings: &IndexSet<&[u8]>) {
+ loop {
+ if ids.len() <= 1 {
+ return;
+ }
+
+ let pivot = byte(ids[0], pos, strings);
+ let mut lower = 0;
+ let mut upper = ids.len();
+ let mut i = 1;
+ while i < upper {
+ let b = byte(ids[i], pos, strings);
+ if b > pivot {
+ ids.swap(lower, i);
+ lower += 1;
+ i += 1;
+ } else if b < pivot {
+ upper -= 1;
+ ids.swap(upper, i);
+ } else {
+ i += 1;
+ }
+ }
+
+ sort(&mut ids[..lower], pos, strings);
+ sort(&mut ids[upper..], pos, strings);
+
+ if pivot == 0 {
+ return;
+ }
+ ids = &mut ids[lower..upper];
+ pos += 1;
+ }
+}
+
+fn byte(id: usize, pos: usize, strings: &IndexSet<&[u8]>) -> u8 {
+ let string = strings.get_index(id).unwrap();
+ let len = string.len();
+ if len >= pos {
+ string[len - pos]
+ } else {
+ // We know the strings don't contain null bytes.
+ 0
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn string_table() {
+ let mut table = StringTable::default();
+ let id0 = table.add(b"");
+ let id1 = table.add(b"foo");
+ let id2 = table.add(b"bar");
+ let id3 = table.add(b"foobar");
+
+ let mut data = Vec::new();
+ data.push(0);
+ table.write(1, &mut data);
+ assert_eq!(data, b"\0foobar\0foo\0");
+
+ assert_eq!(table.get_offset(id0), 11);
+ assert_eq!(table.get_offset(id1), 8);
+ assert_eq!(table.get_offset(id2), 4);
+ assert_eq!(table.get_offset(id3), 1);
+ }
+}
diff --git a/third_party/rust/object/src/write/util.rs b/third_party/rust/object/src/write/util.rs
new file mode 100644
index 0000000000..b05b14d927
--- /dev/null
+++ b/third_party/rust/object/src/write/util.rs
@@ -0,0 +1,260 @@
+use alloc::vec::Vec;
+#[cfg(feature = "std")]
+use std::{io, mem};
+
+use crate::pod::{bytes_of, bytes_of_slice, Pod};
+
+/// Trait for writable buffer.
+#[allow(clippy::len_without_is_empty)]
+pub trait WritableBuffer {
+ /// Returns position/offset for data to be written at.
+ ///
+ /// Should only be used in debug assertions
+ fn len(&self) -> usize;
+
+ /// Reserves specified number of bytes in the buffer.
+ ///
+ /// This will be called exactly once before writing anything to the buffer,
+ /// and the given size is the exact total number of bytes that will be written.
+ fn reserve(&mut self, size: usize) -> Result<(), ()>;
+
+ /// Writes zero bytes at the end of the buffer until the buffer
+ /// has the specified length.
+ fn resize(&mut self, new_len: usize);
+
+ /// Writes the specified slice of bytes at the end of the buffer.
+ fn write_bytes(&mut self, val: &[u8]);
+
+ /// Writes the specified `Pod` type at the end of the buffer.
+ fn write_pod<T: Pod>(&mut self, val: &T)
+ where
+ Self: Sized,
+ {
+ self.write_bytes(bytes_of(val))
+ }
+
+ /// Writes the specified `Pod` slice at the end of the buffer.
+ fn write_pod_slice<T: Pod>(&mut self, val: &[T])
+ where
+ Self: Sized,
+ {
+ self.write_bytes(bytes_of_slice(val))
+ }
+}
+
+impl<'a> dyn WritableBuffer + 'a {
+ /// Writes the specified `Pod` type at the end of the buffer.
+ pub fn write<T: Pod>(&mut self, val: &T) {
+ self.write_bytes(bytes_of(val))
+ }
+
+ /// Writes the specified `Pod` slice at the end of the buffer.
+ pub fn write_slice<T: Pod>(&mut self, val: &[T]) {
+ self.write_bytes(bytes_of_slice(val))
+ }
+}
+
+impl WritableBuffer for Vec<u8> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn reserve(&mut self, size: usize) -> Result<(), ()> {
+ debug_assert!(self.is_empty());
+ self.reserve(size);
+ Ok(())
+ }
+
+ #[inline]
+ fn resize(&mut self, new_len: usize) {
+ debug_assert!(new_len >= self.len());
+ self.resize(new_len, 0);
+ }
+
+ #[inline]
+ fn write_bytes(&mut self, val: &[u8]) {
+ debug_assert!(self.len() + val.len() <= self.capacity());
+ self.extend_from_slice(val)
+ }
+}
+
+/// A [`WritableBuffer`] that streams data to a [`Write`](std::io::Write) implementation.
+///
+/// [`Self::result`] must be called to determine if an I/O error occurred during writing.
+///
+/// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter)
+/// instead of an unbuffered writer like [`File`](std::fs::File).
+#[cfg(feature = "std")]
+#[derive(Debug)]
+pub struct StreamingBuffer<W> {
+ writer: W,
+ len: usize,
+ result: Result<(), io::Error>,
+}
+
+#[cfg(feature = "std")]
+impl<W> StreamingBuffer<W> {
+ /// Create a new `StreamingBuffer` backed by the given writer.
+ pub fn new(writer: W) -> Self {
+ StreamingBuffer {
+ writer,
+ len: 0,
+ result: Ok(()),
+ }
+ }
+
+ /// Unwraps this [`StreamingBuffer`] giving back the original writer.
+ pub fn into_inner(self) -> W {
+ self.writer
+ }
+
+ /// Returns any error that occurred during writing.
+ pub fn result(&mut self) -> Result<(), io::Error> {
+ mem::replace(&mut self.result, Ok(()))
+ }
+}
+
+#[cfg(feature = "std")]
+impl<W: io::Write> WritableBuffer for StreamingBuffer<W> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.len
+ }
+
+ #[inline]
+ fn reserve(&mut self, _size: usize) -> Result<(), ()> {
+ Ok(())
+ }
+
+ #[inline]
+ fn resize(&mut self, new_len: usize) {
+ debug_assert!(self.len <= new_len);
+ while self.len < new_len {
+ let write_amt = (new_len - self.len - 1) % 1024 + 1;
+ self.write_bytes(&[0; 1024][..write_amt]);
+ }
+ }
+
+ #[inline]
+ fn write_bytes(&mut self, val: &[u8]) {
+ if self.result.is_ok() {
+ self.result = self.writer.write_all(val);
+ }
+ self.len += val.len();
+ }
+}
+
+/// A trait for mutable byte slices.
+///
+/// It provides convenience methods for `Pod` types.
+pub(crate) trait BytesMut {
+ fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()>;
+}
+
+impl<'a> BytesMut for &'a mut [u8] {
+ #[inline]
+ fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()> {
+ let src = bytes_of(val);
+ let dest = self.get_mut(offset..).ok_or(())?;
+ let dest = dest.get_mut(..src.len()).ok_or(())?;
+ dest.copy_from_slice(src);
+ Ok(())
+ }
+}
+
+/// Write an unsigned number using the LEB128 encoding to a buffer.
+///
+/// Returns the number of bytes written.
+pub(crate) fn write_uleb128(buf: &mut Vec<u8>, mut val: u64) -> usize {
+ let mut len = 0;
+ loop {
+ let mut byte = (val & 0x7f) as u8;
+ val >>= 7;
+ let done = val == 0;
+ if !done {
+ byte |= 0x80;
+ }
+
+ buf.push(byte);
+ len += 1;
+
+ if done {
+ return len;
+ }
+ }
+}
+
+/// Write a signed number using the LEB128 encoding to a buffer.
+///
+/// Returns the number of bytes written.
+#[allow(dead_code)]
+pub(crate) fn write_sleb128<W>(buf: &mut Vec<u8>, mut val: i64) -> usize {
+ let mut len = 0;
+ loop {
+ let mut byte = val as u8;
+ // Keep the sign bit for testing
+ val >>= 6;
+ let done = val == 0 || val == -1;
+ if done {
+ byte &= !0x80;
+ } else {
+ // Remove the sign bit
+ val >>= 1;
+ byte |= 0x80;
+ }
+
+ buf.push(byte);
+ len += 1;
+
+ if done {
+ return len;
+ }
+ }
+}
+
+pub(crate) fn align(offset: usize, size: usize) -> usize {
+ (offset + (size - 1)) & !(size - 1)
+}
+
+#[allow(dead_code)]
+pub(crate) fn align_u32(offset: u32, size: u32) -> u32 {
+ (offset + (size - 1)) & !(size - 1)
+}
+
+#[allow(dead_code)]
+pub(crate) fn align_u64(offset: u64, size: u64) -> u64 {
+ (offset + (size - 1)) & !(size - 1)
+}
+
+pub(crate) fn write_align(buffer: &mut dyn WritableBuffer, size: usize) {
+ let new_len = align(buffer.len(), size);
+ buffer.resize(new_len);
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn bytes_mut() {
+ let data = vec![0x01, 0x23, 0x45, 0x67];
+
+ let mut bytes = data.clone();
+ bytes.extend_from_slice(bytes_of(&u16::to_be(0x89ab)));
+ assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]);
+
+ let mut bytes = data.clone();
+ assert_eq!(bytes.write_at(0, &u16::to_be(0x89ab)), Ok(()));
+ assert_eq!(bytes, [0x89, 0xab, 0x45, 0x67]);
+
+ let mut bytes = data.clone();
+ assert_eq!(bytes.write_at(2, &u16::to_be(0x89ab)), Ok(()));
+ assert_eq!(bytes, [0x01, 0x23, 0x89, 0xab]);
+
+ assert_eq!(bytes.write_at(3, &u16::to_be(0x89ab)), Err(()));
+ assert_eq!(bytes.write_at(4, &u16::to_be(0x89ab)), Err(()));
+ assert_eq!(vec![].write_at(0, &u32::to_be(0x89ab)), Err(()));
+ }
+}
diff --git a/third_party/rust/object/src/write/xcoff.rs b/third_party/rust/object/src/write/xcoff.rs
new file mode 100644
index 0000000000..6c9a803845
--- /dev/null
+++ b/third_party/rust/object/src/write/xcoff.rs
@@ -0,0 +1,556 @@
+use core::mem;
+
+use crate::endian::{BigEndian as BE, I16, U16, U32};
+use crate::write::string::*;
+use crate::write::util::*;
+use crate::write::*;
+
+use crate::{xcoff, AddressSize};
+
+#[derive(Default, Clone, Copy)]
+struct SectionOffsets {
+ address: u64,
+ data_offset: usize,
+ reloc_offset: usize,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ index: usize,
+ str_id: Option<StringId>,
+ aux_count: u8,
+ storage_class: u8,
+}
+
+impl<'a> Object<'a> {
+ pub(crate) fn xcoff_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
+ match section {
+ StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
+ StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
+ StandardSection::ReadOnlyData
+ | StandardSection::ReadOnlyDataWithRel
+ | StandardSection::ReadOnlyString => (
+ &[],
+ &b".rdata"[..],
+ SectionKind::ReadOnlyData,
+ SectionFlags::None,
+ ),
+ StandardSection::UninitializedData => (
+ &[],
+ &b".bss"[..],
+ SectionKind::UninitializedData,
+ SectionFlags::None,
+ ),
+ StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls, SectionFlags::None),
+ StandardSection::UninitializedTls => (
+ &[],
+ &b".tbss"[..],
+ SectionKind::UninitializedTls,
+ SectionFlags::None,
+ ),
+ StandardSection::TlsVariables => {
+ // Unsupported section.
+ (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
+ }
+ StandardSection::Common => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Common, SectionFlags::None)
+ }
+ StandardSection::GnuProperty => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Note, SectionFlags::None)
+ }
+ }
+ }
+
+ pub(crate) fn xcoff_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 {
+ let constant = match relocation.kind {
+ RelocationKind::Relative => relocation.addend + 4,
+ _ => relocation.addend,
+ };
+ relocation.addend -= constant;
+ constant
+ }
+
+ pub(crate) fn xcoff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ let is_64 = match self.architecture.address_size().unwrap() {
+ AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false,
+ AddressSize::U64 => true,
+ };
+
+ let (hdr_size, sechdr_size, rel_size, sym_size) = if is_64 {
+ (
+ mem::size_of::<xcoff::FileHeader64>(),
+ mem::size_of::<xcoff::SectionHeader64>(),
+ mem::size_of::<xcoff::Rel64>(),
+ mem::size_of::<xcoff::Symbol64>(),
+ )
+ } else {
+ (
+ mem::size_of::<xcoff::FileHeader32>(),
+ mem::size_of::<xcoff::SectionHeader32>(),
+ mem::size_of::<xcoff::Rel32>(),
+ mem::size_of::<xcoff::Symbol32>(),
+ )
+ };
+
+ // Calculate offsets and build strtab.
+ let mut offset = 0;
+ let mut strtab = StringTable::default();
+ // We place the shared address 0 immediately after the section header table.
+ let mut address = 0;
+
+ // XCOFF file header.
+ offset += hdr_size;
+ // Section headers.
+ offset += self.sections.len() * sechdr_size;
+
+ // Calculate size of section data.
+ let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
+ for (index, section) in self.sections.iter().enumerate() {
+ let len = section.data.len();
+ let sectype = section.kind;
+ // Section address should be 0 for all sections except the .text, .data, and .bss sections.
+ if sectype == SectionKind::Data
+ || sectype == SectionKind::Text
+ || sectype == SectionKind::UninitializedData
+ {
+ section_offsets[index].address = address as u64;
+ address += len;
+ address = align(address, 4);
+ } else {
+ section_offsets[index].address = 0;
+ }
+ if len != 0 {
+ // Set the default section alignment as 4.
+ offset = align(offset, 4);
+ section_offsets[index].data_offset = offset;
+ offset += len;
+ } else {
+ section_offsets[index].data_offset = 0;
+ }
+ }
+
+ // Calculate size of relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ let count = section.relocations.len();
+ if count != 0 {
+ section_offsets[index].reloc_offset = offset;
+ offset += count * rel_size;
+ } else {
+ section_offsets[index].reloc_offset = 0;
+ }
+ }
+
+ // Calculate size of symbols.
+ let mut file_str_id = None;
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ let mut symtab_count = 0;
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ symbol_offsets[index].index = symtab_count;
+ symtab_count += 1;
+
+ let storage_class = if let SymbolFlags::Xcoff { n_sclass, .. } = symbol.flags {
+ n_sclass
+ } else {
+ match symbol.kind {
+ SymbolKind::Null => xcoff::C_NULL,
+ SymbolKind::File => xcoff::C_FILE,
+ SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
+ if symbol.is_local() {
+ xcoff::C_STAT
+ } else if symbol.weak {
+ xcoff::C_WEAKEXT
+ } else {
+ xcoff::C_EXT
+ }
+ }
+ SymbolKind::Section | SymbolKind::Label | SymbolKind::Unknown => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ }
+ };
+ symbol_offsets[index].storage_class = storage_class;
+
+ if storage_class == xcoff::C_FILE {
+ if is_64 && file_str_id.is_none() {
+ file_str_id = Some(strtab.add(b".file"));
+ }
+ if symbol.name.len() > 8 {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+ } else if is_64 || symbol.name.len() > 8 {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+
+ symbol_offsets[index].aux_count = 0;
+ match storage_class {
+ xcoff::C_FILE => {
+ symbol_offsets[index].aux_count = 1;
+ symtab_count += 1;
+ }
+ xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => {
+ symbol_offsets[index].aux_count = 1;
+ symtab_count += 1;
+ }
+ // TODO: support auxiliary entry for other types of symbol.
+ _ => {}
+ }
+ }
+ let symtab_offset = offset;
+ let symtab_len = symtab_count * sym_size;
+ offset += symtab_len;
+
+ // Calculate size of strtab.
+ let strtab_offset = offset;
+ let mut strtab_data = Vec::new();
+ // First 4 bytes of strtab are the length.
+ strtab.write(4, &mut strtab_data);
+ let strtab_len = strtab_data.len() + 4;
+ offset += strtab_len;
+
+ // Start writing.
+ buffer
+ .reserve(offset)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ if is_64 {
+ let header = xcoff::FileHeader64 {
+ f_magic: U16::new(BE, xcoff::MAGIC_64),
+ f_nscns: U16::new(BE, self.sections.len() as u16),
+ f_timdat: U32::new(BE, 0),
+ f_symptr: U64::new(BE, symtab_offset as u64),
+ f_nsyms: U32::new(BE, symtab_count as u32),
+ f_opthdr: U16::new(BE, 0),
+ f_flags: match self.flags {
+ FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags),
+ _ => U16::default(),
+ },
+ };
+ buffer.write(&header);
+ } else {
+ let header = xcoff::FileHeader32 {
+ f_magic: U16::new(BE, xcoff::MAGIC_32),
+ f_nscns: U16::new(BE, self.sections.len() as u16),
+ f_timdat: U32::new(BE, 0),
+ f_symptr: U32::new(BE, symtab_offset as u32),
+ f_nsyms: U32::new(BE, symtab_count as u32),
+ f_opthdr: U16::new(BE, 0),
+ f_flags: match self.flags {
+ FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags),
+ _ => U16::default(),
+ },
+ };
+ buffer.write(&header);
+ }
+
+ // Write section headers.
+ for (index, section) in self.sections.iter().enumerate() {
+ let mut sectname = [0; 8];
+ sectname
+ .get_mut(..section.name.len())
+ .ok_or_else(|| {
+ Error(format!(
+ "section name `{}` is too long",
+ section.name().unwrap_or(""),
+ ))
+ })?
+ .copy_from_slice(&section.name);
+ let flags = if let SectionFlags::Xcoff { s_flags } = section.flags {
+ s_flags
+ } else {
+ match section.kind {
+ SectionKind::Text
+ | SectionKind::ReadOnlyData
+ | SectionKind::ReadOnlyString
+ | SectionKind::ReadOnlyDataWithRel => xcoff::STYP_TEXT,
+ SectionKind::Data => xcoff::STYP_DATA,
+ SectionKind::UninitializedData => xcoff::STYP_BSS,
+ SectionKind::Tls => xcoff::STYP_TDATA,
+ SectionKind::UninitializedTls => xcoff::STYP_TBSS,
+ SectionKind::OtherString => xcoff::STYP_INFO,
+ SectionKind::Debug => xcoff::STYP_DEBUG,
+ SectionKind::Other | SectionKind::Metadata => 0,
+ SectionKind::Note
+ | SectionKind::Linker
+ | SectionKind::Common
+ | SectionKind::Unknown
+ | SectionKind::TlsVariables
+ | SectionKind::Elf(_) => {
+ return Err(Error(format!(
+ "unimplemented section `{}` kind {:?}",
+ section.name().unwrap_or(""),
+ section.kind
+ )));
+ }
+ }
+ .into()
+ };
+ if is_64 {
+ let section_header = xcoff::SectionHeader64 {
+ s_name: sectname,
+ s_paddr: U64::new(BE, section_offsets[index].address),
+ // This field has the same value as the s_paddr field.
+ s_vaddr: U64::new(BE, section_offsets[index].address),
+ s_size: U64::new(BE, section.data.len() as u64),
+ s_scnptr: U64::new(BE, section_offsets[index].data_offset as u64),
+ s_relptr: U64::new(BE, section_offsets[index].reloc_offset as u64),
+ s_lnnoptr: U64::new(BE, 0),
+ s_nreloc: U32::new(BE, section.relocations.len() as u32),
+ s_nlnno: U32::new(BE, 0),
+ s_flags: U32::new(BE, flags),
+ s_reserve: U32::new(BE, 0),
+ };
+ buffer.write(&section_header);
+ } else {
+ let section_header = xcoff::SectionHeader32 {
+ s_name: sectname,
+ s_paddr: U32::new(BE, section_offsets[index].address as u32),
+ // This field has the same value as the s_paddr field.
+ s_vaddr: U32::new(BE, section_offsets[index].address as u32),
+ s_size: U32::new(BE, section.data.len() as u32),
+ s_scnptr: U32::new(BE, section_offsets[index].data_offset as u32),
+ s_relptr: U32::new(BE, section_offsets[index].reloc_offset as u32),
+ s_lnnoptr: U32::new(BE, 0),
+ // TODO: If more than 65,534 relocation entries are required, the field
+ // value will be 65535, and an STYP_OVRFLO section header will contain
+ // the actual count of relocation entries in the s_paddr field.
+ s_nreloc: U16::new(BE, section.relocations.len() as u16),
+ s_nlnno: U16::new(BE, 0),
+ s_flags: U32::new(BE, flags),
+ };
+ buffer.write(&section_header);
+ }
+ }
+
+ // Write section data.
+ for (index, section) in self.sections.iter().enumerate() {
+ let len = section.data.len();
+ if len != 0 {
+ write_align(buffer, 4);
+ debug_assert_eq!(section_offsets[index].data_offset, buffer.len());
+ buffer.write_bytes(&section.data);
+ }
+ }
+
+ // Write relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ if !section.relocations.is_empty() {
+ debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
+ for reloc in &section.relocations {
+ let rtype = match reloc.kind {
+ RelocationKind::Absolute => xcoff::R_POS,
+ RelocationKind::Relative => xcoff::R_REL,
+ RelocationKind::Got => xcoff::R_TOC,
+ RelocationKind::Xcoff(x) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ };
+ if is_64 {
+ let xcoff_rel = xcoff::Rel64 {
+ r_vaddr: U64::new(BE, reloc.offset),
+ r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32),
+ // Specifies the bit length of the relocatable reference minus one.
+ r_rsize: (reloc.size - 1),
+ r_rtype: rtype,
+ };
+ buffer.write(&xcoff_rel);
+ } else {
+ let xcoff_rel = xcoff::Rel32 {
+ r_vaddr: U32::new(BE, reloc.offset as u32),
+ r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32),
+ r_rsize: (reloc.size - 1),
+ r_rtype: rtype,
+ };
+ buffer.write(&xcoff_rel);
+ }
+ }
+ }
+ }
+
+ // Write symbols.
+ debug_assert_eq!(symtab_offset, buffer.len());
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ let (n_value, section_kind) = if let SymbolSection::Section(id) = symbol.section {
+ (
+ section_offsets[id.0].address + symbol.value,
+ self.sections[id.0].kind,
+ )
+ } else {
+ (symbol.value, SectionKind::Unknown)
+ };
+ let n_scnum = match symbol.section {
+ SymbolSection::None => {
+ debug_assert_eq!(symbol.kind, SymbolKind::File);
+ xcoff::N_DEBUG
+ }
+ SymbolSection::Undefined | SymbolSection::Common => xcoff::N_UNDEF,
+ SymbolSection::Absolute => xcoff::N_ABS,
+ SymbolSection::Section(id) => id.0 as i16 + 1,
+ };
+ let n_sclass = symbol_offsets[index].storage_class;
+ let n_type = if (symbol.scope == SymbolScope::Linkage)
+ && (n_sclass == xcoff::C_EXT
+ || n_sclass == xcoff::C_WEAKEXT
+ || n_sclass == xcoff::C_HIDEXT)
+ {
+ xcoff::SYM_V_HIDDEN
+ } else {
+ 0
+ };
+ let n_numaux = symbol_offsets[index].aux_count;
+ if is_64 {
+ let str_id = if n_sclass == xcoff::C_FILE {
+ file_str_id.unwrap()
+ } else {
+ symbol_offsets[index].str_id.unwrap()
+ };
+ let xcoff_sym = xcoff::Symbol64 {
+ n_value: U64::new(BE, n_value),
+ n_offset: U32::new(BE, strtab.get_offset(str_id) as u32),
+ n_scnum: I16::new(BE, n_scnum),
+ n_type: U16::new(BE, n_type),
+ n_sclass,
+ n_numaux,
+ };
+ buffer.write(&xcoff_sym);
+ } else {
+ let mut sym_name = [0; 8];
+ if n_sclass == xcoff::C_FILE {
+ sym_name[..5].copy_from_slice(b".file");
+ } else if symbol.name.len() <= 8 {
+ sym_name[..symbol.name.len()].copy_from_slice(&symbol.name[..]);
+ } else {
+ let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap());
+ sym_name[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32));
+ }
+ let xcoff_sym = xcoff::Symbol32 {
+ n_name: sym_name,
+ n_value: U32::new(BE, n_value as u32),
+ n_scnum: I16::new(BE, n_scnum),
+ n_type: U16::new(BE, n_type),
+ n_sclass,
+ n_numaux,
+ };
+ buffer.write(&xcoff_sym);
+ }
+ // Generate auxiliary entries.
+ if n_sclass == xcoff::C_FILE {
+ debug_assert_eq!(n_numaux, 1);
+ let mut x_fname = [0; 8];
+ if symbol.name.len() <= 8 {
+ x_fname[..symbol.name.len()].copy_from_slice(&symbol.name[..]);
+ } else {
+ let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap());
+ x_fname[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32));
+ }
+ if is_64 {
+ let file_aux = xcoff::FileAux64 {
+ x_fname,
+ x_fpad: Default::default(),
+ x_ftype: xcoff::XFT_FN,
+ x_freserve: Default::default(),
+ x_auxtype: xcoff::AUX_FILE,
+ };
+ buffer.write(&file_aux);
+ } else {
+ let file_aux = xcoff::FileAux32 {
+ x_fname,
+ x_fpad: Default::default(),
+ x_ftype: xcoff::XFT_FN,
+ x_freserve: Default::default(),
+ };
+ buffer.write(&file_aux);
+ }
+ } else if n_sclass == xcoff::C_EXT
+ || n_sclass == xcoff::C_WEAKEXT
+ || n_sclass == xcoff::C_HIDEXT
+ {
+ debug_assert_eq!(n_numaux, 1);
+ let (x_smtyp, x_smclas) = if let SymbolFlags::Xcoff {
+ x_smtyp, x_smclas, ..
+ } = symbol.flags
+ {
+ (x_smtyp, x_smclas)
+ } else {
+ match symbol.kind {
+ SymbolKind::Text => (xcoff::XTY_SD, xcoff::XMC_PR),
+ SymbolKind::Data => {
+ if section_kind == SectionKind::UninitializedData {
+ (xcoff::XTY_CM, xcoff::XMC_BS)
+ } else if section_kind == SectionKind::ReadOnlyData {
+ (xcoff::XTY_SD, xcoff::XMC_RO)
+ } else {
+ (xcoff::XTY_SD, xcoff::XMC_RW)
+ }
+ }
+ SymbolKind::Tls => {
+ if section_kind == SectionKind::UninitializedTls {
+ (xcoff::XTY_CM, xcoff::XMC_UL)
+ } else {
+ (xcoff::XTY_SD, xcoff::XMC_TL)
+ }
+ }
+ _ => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ }
+ };
+ let scnlen = if let SymbolFlags::Xcoff {
+ containing_csect: Some(containing_csect),
+ ..
+ } = symbol.flags
+ {
+ symbol_offsets[containing_csect.0].index as u64
+ } else {
+ symbol.size
+ };
+ if is_64 {
+ let csect_aux = xcoff::CsectAux64 {
+ x_scnlen_lo: U32::new(BE, (scnlen & 0xFFFFFFFF) as u32),
+ x_scnlen_hi: U32::new(BE, ((scnlen >> 32) & 0xFFFFFFFF) as u32),
+ x_parmhash: U32::new(BE, 0),
+ x_snhash: U16::new(BE, 0),
+ x_smtyp,
+ x_smclas,
+ pad: 0,
+ x_auxtype: xcoff::AUX_CSECT,
+ };
+ buffer.write(&csect_aux);
+ } else {
+ let csect_aux = xcoff::CsectAux32 {
+ x_scnlen: U32::new(BE, scnlen as u32),
+ x_parmhash: U32::new(BE, 0),
+ x_snhash: U16::new(BE, 0),
+ x_smtyp,
+ x_smclas,
+ x_stab: U32::new(BE, 0),
+ x_snstab: U16::new(BE, 0),
+ };
+ buffer.write(&csect_aux);
+ }
+ }
+ }
+
+ // Write string table.
+ debug_assert_eq!(strtab_offset, buffer.len());
+ buffer.write_bytes(&u32::to_be_bytes(strtab_len as u32));
+ buffer.write_bytes(&strtab_data);
+
+ debug_assert_eq!(offset, buffer.len());
+ Ok(())
+ }
+}
diff --git a/third_party/rust/object/src/xcoff.rs b/third_party/rust/object/src/xcoff.rs
new file mode 100644
index 0000000000..0386989261
--- /dev/null
+++ b/third_party/rust/object/src/xcoff.rs
@@ -0,0 +1,893 @@
+//! XCOFF definitions
+//!
+//! These definitions are independent of read/write support, although we do implement
+//! some traits useful for those.
+//!
+//! This module is the equivalent of /usr/include/xcoff.h, and is based heavily on it.
+
+#![allow(missing_docs)]
+
+use crate::endian::{BigEndian as BE, I16, U16, U32, U64};
+use crate::pod::Pod;
+
+/// The header at the start of every 32-bit XCOFF file.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FileHeader32 {
+ /// Magic number. Must be 0x01DF.
+ pub f_magic: U16<BE>,
+ /// Number of sections.
+ pub f_nscns: U16<BE>,
+ /// Time and date of file creation.
+ pub f_timdat: U32<BE>,
+ /// Byte offset to symbol table start.
+ pub f_symptr: U32<BE>,
+ /// Number of entries in symbol table.
+ pub f_nsyms: U32<BE>,
+ /// Number of bytes in optional header
+ pub f_opthdr: U16<BE>,
+ /// Extra flags.
+ pub f_flags: U16<BE>,
+}
+
+/// The header at the start of every 64-bit XCOFF file.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FileHeader64 {
+ /// Magic number. Must be 0x01F7.
+ pub f_magic: U16<BE>,
+ /// Number of sections.
+ pub f_nscns: U16<BE>,
+ /// Time and date of file creation
+ pub f_timdat: U32<BE>,
+ /// Byte offset to symbol table start.
+ pub f_symptr: U64<BE>,
+ /// Number of bytes in optional header
+ pub f_opthdr: U16<BE>,
+ /// Extra flags.
+ pub f_flags: U16<BE>,
+ /// Number of entries in symbol table.
+ pub f_nsyms: U32<BE>,
+}
+
+// Values for `f_magic`.
+//
+/// the 64-bit mach magic number
+pub const MAGIC_64: u16 = 0x01F7;
+/// the 32-bit mach magic number
+pub const MAGIC_32: u16 = 0x01DF;
+
+// Values for `f_flags`.
+//
+/// Indicates that the relocation information for binding has been removed from
+/// the file.
+pub const F_RELFLG: u16 = 0x0001;
+/// Indicates that the file is executable. No unresolved external references exist.
+pub const F_EXEC: u16 = 0x0002;
+/// Indicates that line numbers have been stripped from the file by a utility program.
+pub const F_LNNO: u16 = 0x0004;
+/// Indicates that the file was profiled with the fdpr command.
+pub const F_FDPR_PROF: u16 = 0x0010;
+/// Indicates that the file was reordered with the fdpr command.
+pub const F_FDPR_OPTI: u16 = 0x0020;
+/// Indicates that the file uses Very Large Program Support.
+pub const F_DSA: u16 = 0x0040;
+/// Indicates that one of the members of the auxiliary header specifying the
+/// medium page sizes is non-zero.
+pub const F_VARPG: u16 = 0x0100;
+/// Indicates the file is dynamically loadable and executable. External references
+/// are resolved by way of imports, and the file might contain exports and loader
+/// relocation.
+pub const F_DYNLOAD: u16 = 0x1000;
+/// Indicates the file is a shared object (shared library). The file is separately
+/// loadable. That is, it is not normally bound with other objects, and its loader
+/// exports symbols are used as automatic import symbols for other object files.
+pub const F_SHROBJ: u16 = 0x2000;
+/// If the object file is a member of an archive, it can be loaded by the system
+/// loader, but the member is ignored by the binder. If the object file is not in
+/// an archive, this flag has no effect.
+pub const F_LOADONLY: u16 = 0x4000;
+
+/// The auxiliary header immediately following file header. If the value of the
+/// f_opthdr field in the file header is 0, the auxiliary header does not exist.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AuxHeader32 {
+ /// Flags.
+ pub o_mflag: U16<BE>,
+ /// Version.
+ pub o_vstamp: U16<BE>,
+ /// Text size in bytes.
+ pub o_tsize: U32<BE>,
+ /// Initialized data size in bytes.
+ pub o_dsize: U32<BE>,
+ /// Uninitialized data size in bytes.
+ pub o_bsize: U32<BE>,
+ /// Entry point descriptor (virtual address).
+ pub o_entry: U32<BE>,
+ /// Base address of text (virtual address).
+ pub o_text_start: U32<BE>,
+ /// Base address of data (virtual address).
+ pub o_data_start: U32<BE>,
+ /// Address of TOC anchor.
+ pub o_toc: U32<BE>,
+ /// Section number for entry point.
+ pub o_snentry: U16<BE>,
+ /// Section number for .text.
+ pub o_sntext: U16<BE>,
+ /// Section number for .data.
+ pub o_sndata: U16<BE>,
+ /// Section number for TOC.
+ pub o_sntoc: U16<BE>,
+ /// Section number for loader data.
+ pub o_snloader: U16<BE>,
+ /// Section number for .bss.
+ pub o_snbss: U16<BE>,
+ /// Maximum alignment for .text.
+ pub o_algntext: U16<BE>,
+ /// Maximum alignment for .data.
+ pub o_algndata: U16<BE>,
+ /// Module type field.
+ pub o_modtype: U16<BE>,
+ /// Bit flags - cpu types of objects.
+ pub o_cpuflag: u8,
+ /// Reserved for CPU type.
+ pub o_cputype: u8,
+ /// Maximum stack size allowed (bytes).
+ pub o_maxstack: U32<BE>,
+ /// Maximum data size allowed (bytes).
+ pub o_maxdata: U32<BE>,
+ /// Reserved for debuggers.
+ pub o_debugger: U32<BE>,
+ /// Requested text page size.
+ pub o_textpsize: u8,
+ /// Requested data page size.
+ pub o_datapsize: u8,
+ /// Requested stack page size.
+ pub o_stackpsize: u8,
+ /// Flags and thread-local storage alignment.
+ pub o_flags: u8,
+ /// Section number for .tdata.
+ pub o_sntdata: U16<BE>,
+ /// Section number for .tbss.
+ pub o_sntbss: U16<BE>,
+}
+
+/// The auxiliary header immediately following file header. If the value of the
+/// f_opthdr field in the file header is 0, the auxiliary header does not exist.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct AuxHeader64 {
+ /// Flags.
+ pub o_mflag: U16<BE>,
+ /// Version.
+ pub o_vstamp: U16<BE>,
+ /// Reserved for debuggers.
+ pub o_debugger: U32<BE>,
+ /// Base address of text (virtual address).
+ pub o_text_start: U64<BE>,
+ /// Base address of data (virtual address).
+ pub o_data_start: U64<BE>,
+ /// Address of TOC anchor.
+ pub o_toc: U64<BE>,
+ /// Section number for entry point.
+ pub o_snentry: U16<BE>,
+ /// Section number for .text.
+ pub o_sntext: U16<BE>,
+ /// Section number for .data.
+ pub o_sndata: U16<BE>,
+ /// Section number for TOC.
+ pub o_sntoc: U16<BE>,
+ /// Section number for loader data.
+ pub o_snloader: U16<BE>,
+ /// Section number for .bss.
+ pub o_snbss: U16<BE>,
+ /// Maximum alignment for .text.
+ pub o_algntext: U16<BE>,
+ /// Maximum alignment for .data.
+ pub o_algndata: U16<BE>,
+ /// Module type field.
+ pub o_modtype: U16<BE>,
+ /// Bit flags - cpu types of objects.
+ pub o_cpuflag: u8,
+ /// Reserved for CPU type.
+ pub o_cputype: u8,
+ /// Requested text page size.
+ pub o_textpsize: u8,
+ /// Requested data page size.
+ pub o_datapsize: u8,
+ /// Requested stack page size.
+ pub o_stackpsize: u8,
+ /// Flags and thread-local storage alignment.
+ pub o_flags: u8,
+ /// Text size in bytes.
+ pub o_tsize: U64<BE>,
+ /// Initialized data size in bytes.
+ pub o_dsize: U64<BE>,
+ /// Uninitialized data size in bytes.
+ pub o_bsize: U64<BE>,
+ /// Entry point descriptor (virtual address).
+ pub o_entry: U64<BE>,
+ /// Maximum stack size allowed (bytes).
+ pub o_maxstack: U64<BE>,
+ /// Maximum data size allowed (bytes).
+ pub o_maxdata: U64<BE>,
+ /// Section number for .tdata.
+ pub o_sntdata: U16<BE>,
+ /// Section number for .tbss.
+ pub o_sntbss: U16<BE>,
+ /// XCOFF64 flags.
+ pub o_x64flags: U16<BE>,
+ /// Reserved.
+ pub o_resv3a: U16<BE>,
+ /// Reserved.
+ pub o_resv3: [U32<BE>; 2],
+}
+
+/// Some AIX programs generate auxiliary headers for 32-bit object files that
+/// end after the data_start field.
+pub const AOUTHSZ_SHORT: u16 = 28;
+
+/// Section header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SectionHeader32 {
+ /// Section name.
+ pub s_name: [u8; 8],
+ /// Physical address.
+ pub s_paddr: U32<BE>,
+ /// Virtual address (same as physical address).
+ pub s_vaddr: U32<BE>,
+ /// Section size.
+ pub s_size: U32<BE>,
+ /// Offset in file to raw data for section.
+ pub s_scnptr: U32<BE>,
+ /// Offset in file to relocation entries for section.
+ pub s_relptr: U32<BE>,
+ /// Offset in file to line number entries for section.
+ pub s_lnnoptr: U32<BE>,
+ /// Number of relocation entries.
+ pub s_nreloc: U16<BE>,
+ /// Number of line number entries.
+ pub s_nlnno: U16<BE>,
+ /// Flags to define the section type.
+ pub s_flags: U32<BE>,
+}
+
+/// Section header.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SectionHeader64 {
+ /// Section name.
+ pub s_name: [u8; 8],
+ /// Physical address.
+ pub s_paddr: U64<BE>,
+ /// Virtual address (same as physical address).
+ pub s_vaddr: U64<BE>,
+ /// Section size.
+ pub s_size: U64<BE>,
+ /// Offset in file to raw data for section.
+ pub s_scnptr: U64<BE>,
+ /// Offset in file to relocation entries for section.
+ pub s_relptr: U64<BE>,
+ /// Offset in file to line number entries for section.
+ pub s_lnnoptr: U64<BE>,
+ /// Number of relocation entries.
+ pub s_nreloc: U32<BE>,
+ /// Number of line number entries.
+ pub s_nlnno: U32<BE>,
+ /// Flags to define the section type.
+ pub s_flags: U32<BE>,
+ /// Reserved.
+ pub s_reserve: U32<BE>,
+}
+
+// Values for `s_flags`.
+//
+/// "regular" section
+pub const STYP_REG: u16 = 0x00;
+/// Specifies a pad section. A section of this type is used to provide alignment
+/// padding between sections within an XCOFF executable object file. This section
+/// header type is obsolete since padding is allowed in an XCOFF file without a
+/// corresponding pad section header.
+pub const STYP_PAD: u16 = 0x08;
+/// Specifies a DWARF debugging section, which provide source file and symbol
+/// information for the symbolic debugger.
+pub const STYP_DWARF: u16 = 0x10;
+/// Specifies an executable text (code) section. A section of this type contains
+/// the executable instructions of a program.
+pub const STYP_TEXT: u16 = 0x20;
+/// Specifies an initialized data section. A section of this type contains the
+/// initialized data and the TOC of a program.
+pub const STYP_DATA: u16 = 0x40;
+/// Specifies an uninitialized data section. A section header of this type
+/// defines the uninitialized data of a program.
+pub const STYP_BSS: u16 = 0x80;
+/// Specifies an exception section. A section of this type provides information
+/// to identify the reason that a trap or exception occurred within an executable
+/// object program.
+pub const STYP_EXCEPT: u16 = 0x0100;
+/// Specifies a comment section. A section of this type provides comments or data
+/// to special processing utility programs.
+pub const STYP_INFO: u16 = 0x0200;
+/// Specifies an initialized thread-local data section.
+pub const STYP_TDATA: u16 = 0x0400;
+/// Specifies an uninitialized thread-local data section.
+pub const STYP_TBSS: u16 = 0x0800;
+/// Specifies a loader section. A section of this type contains object file
+/// information for the system loader to load an XCOFF executable. The information
+/// includes imported symbols, exported symbols, relocation data, type-check
+/// information, and shared object names.
+pub const STYP_LOADER: u16 = 0x1000;
+/// Specifies a debug section. A section of this type contains stabstring
+/// information used by the symbolic debugger.
+pub const STYP_DEBUG: u16 = 0x2000;
+/// Specifies a type-check section. A section of this type contains
+/// parameter/argument type-check strings used by the binder.
+pub const STYP_TYPCHK: u16 = 0x4000;
+/// Specifies a relocation or line-number field overflow section. A section
+/// header of this type contains the count of relocation entries and line
+/// number entries for some other section. This section header is required
+/// when either of the counts exceeds 65,534.
+pub const STYP_OVRFLO: u16 = 0x8000;
+
+pub const SIZEOF_SYMBOL: usize = 18;
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct SymbolBytes(pub [u8; SIZEOF_SYMBOL]);
+
+/// Symbol table entry.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Symbol32 {
+ /// Symbol name.
+ ///
+ /// If first 4 bytes are 0, then second 4 bytes are offset into string table.
+ pub n_name: [u8; 8],
+ /// Symbol value; storage class-dependent.
+ pub n_value: U32<BE>,
+ /// Section number of symbol.
+ pub n_scnum: I16<BE>,
+ /// Basic and derived type specification.
+ pub n_type: U16<BE>,
+ /// Storage class of symbol.
+ pub n_sclass: u8,
+ /// Number of auxiliary entries.
+ pub n_numaux: u8,
+}
+
+/// Symbol table entry.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Symbol64 {
+ /// Symbol value; storage class-dependent.
+ pub n_value: U64<BE>,
+ /// Offset of the name in string table or .debug section.
+ pub n_offset: U32<BE>,
+ /// Section number of symbol.
+ pub n_scnum: I16<BE>,
+ /// Basic and derived type specification.
+ pub n_type: U16<BE>,
+ /// Storage class of symbol.
+ pub n_sclass: u8,
+ /// Number of auxiliary entries.
+ pub n_numaux: u8,
+}
+
+// Values for `n_scnum`.
+//
+/// A special symbolic debugging symbol.
+pub const N_DEBUG: i16 = -2;
+/// An absolute symbol. The symbol has a value but is not relocatable.
+pub const N_ABS: i16 = -1;
+/// An undefined external symbol.
+pub const N_UNDEF: i16 = 0;
+
+// Vlaues for `n_type`.
+//
+/// Values for visibility as they would appear when encoded in the high 4 bits
+/// of the 16-bit unsigned n_type field of symbol table entries. Valid for
+/// 32-bit XCOFF only when the o_vstamp in the auxiliary header is greater than 1.
+pub const SYM_V_MASK: u16 = 0xF000;
+pub const SYM_V_INTERNAL: u16 = 0x1000;
+pub const SYM_V_HIDDEN: u16 = 0x2000;
+pub const SYM_V_PROTECTED: u16 = 0x3000;
+pub const SYM_V_EXPORTED: u16 = 0x4000;
+
+// Values for `n_sclass`.
+//
+// Storage classes used for symbolic debugging symbols.
+//
+/// Source file name and compiler information.
+pub const C_FILE: u8 = 103;
+/// Beginning of include file.
+pub const C_BINCL: u8 = 108;
+/// Ending of include file.
+pub const C_EINCL: u8 = 109;
+/// Global variable.
+pub const C_GSYM: u8 = 128;
+/// Statically allocated symbol.
+pub const C_STSYM: u8 = 133;
+/// Beginning of common block.
+pub const C_BCOMM: u8 = 135;
+/// End of common block.
+pub const C_ECOMM: u8 = 137;
+/// Alternate entry.
+pub const C_ENTRY: u8 = 141;
+/// Beginning of static block.
+pub const C_BSTAT: u8 = 143;
+/// End of static block.
+pub const C_ESTAT: u8 = 144;
+/// Global thread-local variable.
+pub const C_GTLS: u8 = 145;
+/// Static thread-local variable.
+pub const C_STTLS: u8 = 146;
+/// DWARF section symbol.
+pub const C_DWARF: u8 = 112;
+//
+// Storage classes used for absolute symbols.
+//
+/// Automatic variable allocated on stack.
+pub const C_LSYM: u8 = 129;
+/// Argument to subroutine allocated on stack.
+pub const C_PSYM: u8 = 130;
+/// Register variable.
+pub const C_RSYM: u8 = 131;
+/// Argument to function or procedure stored in register.
+pub const C_RPSYM: u8 = 132;
+/// Local member of common block.
+pub const C_ECOML: u8 = 136;
+/// Function or procedure.
+pub const C_FUN: u8 = 142;
+//
+// Storage classes used for undefined external symbols or symbols of general sections.
+//
+/// External symbol.
+pub const C_EXT: u8 = 2;
+/// Weak external symbol.
+pub const C_WEAKEXT: u8 = 111;
+//
+// Storage classes used for symbols of general sections.
+//
+/// Symbol table entry marked for deletion.
+pub const C_NULL: u8 = 0;
+/// Static.
+pub const C_STAT: u8 = 3;
+/// Beginning or end of inner block.
+pub const C_BLOCK: u8 = 100;
+/// Beginning or end of function.
+pub const C_FCN: u8 = 101;
+/// Un-named external symbol.
+pub const C_HIDEXT: u8 = 107;
+/// Comment string in .info section.
+pub const C_INFO: u8 = 110;
+/// Declaration of object (type).
+pub const C_DECL: u8 = 140;
+//
+// Storage classes - Obsolete/Undocumented.
+//
+/// Automatic variable.
+pub const C_AUTO: u8 = 1;
+/// Register variable.
+pub const C_REG: u8 = 4;
+/// External definition.
+pub const C_EXTDEF: u8 = 5;
+/// Label.
+pub const C_LABEL: u8 = 6;
+/// Undefined label.
+pub const C_ULABEL: u8 = 7;
+/// Member of structure.
+pub const C_MOS: u8 = 8;
+/// Function argument.
+pub const C_ARG: u8 = 9;
+/// Structure tag.
+pub const C_STRTAG: u8 = 10;
+/// Member of union.
+pub const C_MOU: u8 = 11;
+/// Union tag.
+pub const C_UNTAG: u8 = 12;
+/// Type definition.
+pub const C_TPDEF: u8 = 13;
+/// Undefined static.
+pub const C_USTATIC: u8 = 14;
+/// Enumeration tag.
+pub const C_ENTAG: u8 = 15;
+/// Member of enumeration.
+pub const C_MOE: u8 = 16;
+/// Register parameter.
+pub const C_REGPARM: u8 = 17;
+/// Bit field.
+pub const C_FIELD: u8 = 18;
+/// End of structure.
+pub const C_EOS: u8 = 102;
+/// Duplicate tag.
+pub const C_ALIAS: u8 = 105;
+/// Special storage class for external.
+pub const C_HIDDEN: u8 = 106;
+/// Physical end of function.
+pub const C_EFCN: u8 = 255;
+/// Reserved.
+pub const C_TCSYM: u8 = 134;
+
+/// File Auxiliary Entry for C_FILE Symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FileAux32 {
+ /// The source file name or compiler-related string.
+ ///
+ /// If first 4 bytes are 0, then second 4 bytes are offset into string table.
+ pub x_fname: [u8; 8],
+ /// Pad size for file name.
+ pub x_fpad: [u8; 6],
+ /// The source-file string type.
+ pub x_ftype: u8,
+ /// Reserved.
+ pub x_freserve: [u8; 3],
+}
+
+/// File Auxiliary Entry for C_FILE Symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FileAux64 {
+ /// The source file name or compiler-related string.
+ ///
+ /// If first 4 bytes are 0, then second 4 bytes are offset into string table.
+ pub x_fname: [u8; 8],
+ /// Pad size for file name.
+ pub x_fpad: [u8; 6],
+ /// The source-file string type.
+ pub x_ftype: u8,
+ /// Reserved.
+ pub x_freserve: [u8; 2],
+ /// Specifies the type of auxiliary entry. Contains _AUX_FILE for this auxiliary entry.
+ pub x_auxtype: u8,
+}
+
+// Values for `x_ftype`.
+//
+/// Specifies the source-file name.
+pub const XFT_FN: u8 = 0;
+/// Specifies the compiler time stamp.
+pub const XFT_CT: u8 = 1;
+/// Specifies the compiler version number.
+pub const XFT_CV: u8 = 2;
+/// Specifies compiler-defined information.
+pub const XFT_CD: u8 = 128;
+
+/// Csect auxiliary entry for C_EXT, C_WEAKEXT, and C_HIDEXT symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct CsectAux32 {
+ /// Section length.
+ pub x_scnlen: U32<BE>,
+ /// Offset of parameter type-check hash in .typchk section.
+ pub x_parmhash: U32<BE>,
+ /// .typchk section number.
+ pub x_snhash: U16<BE>,
+ /// Symbol alignment and type.
+ pub x_smtyp: u8,
+ /// Storage mapping class.
+ pub x_smclas: u8,
+ /// Reserved.
+ pub x_stab: U32<BE>,
+ /// x_snstab.
+ pub x_snstab: U16<BE>,
+}
+
+/// Csect auxiliary entry for C_EXT, C_WEAKEXT, and C_HIDEXT symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct CsectAux64 {
+ /// Low 4 bytes of section length.
+ pub x_scnlen_lo: U32<BE>,
+ /// Offset of parameter type-check hash in .typchk section.
+ pub x_parmhash: U32<BE>,
+ /// .typchk section number.
+ pub x_snhash: U16<BE>,
+ /// Symbol alignment and type.
+ pub x_smtyp: u8,
+ /// Storage mapping class.
+ pub x_smclas: u8,
+ /// High 4 bytes of section length.
+ pub x_scnlen_hi: U32<BE>,
+ /// Reserved.
+ pub pad: u8,
+ /// Contains _AUX_CSECT; indicates type of auxiliary entry.
+ pub x_auxtype: u8,
+}
+
+// Values for `x_smtyp`.
+//
+/// External reference.
+pub const XTY_ER: u8 = 0;
+/// Csect definition for initialized storage.
+pub const XTY_SD: u8 = 1;
+/// Defines an entry point to an initialized csect.
+pub const XTY_LD: u8 = 2;
+/// Common csect definition. For uninitialized storage.
+pub const XTY_CM: u8 = 3;
+
+// Values for `x_smclas`.
+//
+// READ ONLY CLASSES
+//
+/// Program Code
+pub const XMC_PR: u8 = 0;
+/// Read Only Constant
+pub const XMC_RO: u8 = 1;
+/// Debug Dictionary Table
+pub const XMC_DB: u8 = 2;
+/// Global Linkage (Interfile Interface Code)
+pub const XMC_GL: u8 = 6;
+/// Extended Operation (Pseudo Machine Instruction)
+pub const XMC_XO: u8 = 7;
+/// Supervisor Call (32-bit process only)
+pub const XMC_SV: u8 = 8;
+/// Supervisor Call for 64-bit process
+pub const XMC_SV64: u8 = 17;
+/// Supervisor Call for both 32- and 64-bit processes
+pub const XMC_SV3264: u8 = 18;
+/// Traceback Index csect
+pub const XMC_TI: u8 = 12;
+/// Traceback Table csect
+pub const XMC_TB: u8 = 13;
+//
+// READ WRITE CLASSES
+//
+/// Read Write Data
+pub const XMC_RW: u8 = 5;
+/// TOC Anchor for TOC Addressability
+pub const XMC_TC0: u8 = 15;
+/// General TOC item
+pub const XMC_TC: u8 = 3;
+/// Scalar data item in the TOC
+pub const XMC_TD: u8 = 16;
+/// Descriptor csect
+pub const XMC_DS: u8 = 10;
+/// Unclassified - Treated as Read Write
+pub const XMC_UA: u8 = 4;
+/// BSS class (uninitialized static internal)
+pub const XMC_BS: u8 = 9;
+/// Un-named Fortran Common
+pub const XMC_UC: u8 = 11;
+/// Initialized thread-local variable
+pub const XMC_TL: u8 = 20;
+/// Uninitialized thread-local variable
+pub const XMC_UL: u8 = 21;
+/// Symbol mapped at the end of TOC
+pub const XMC_TE: u8 = 22;
+
+/// Function auxiliary entry.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FunAux32 {
+ /// File offset to exception table entry.
+ pub x_exptr: U32<BE>,
+ /// Size of function in bytes.
+ pub x_fsize: U32<BE>,
+ /// File pointer to line number
+ pub x_lnnoptr: U32<BE>,
+ /// Symbol table index of next entry beyond this function.
+ pub x_endndx: U32<BE>,
+ /// Pad
+ pub pad: U16<BE>,
+}
+
+/// Function auxiliary entry.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct FunAux64 {
+ /// File pointer to line number
+ pub x_lnnoptr: U64<BE>,
+ /// Size of function in bytes.
+ pub x_fsize: U32<BE>,
+ /// Symbol table index of next entry beyond this function.
+ pub x_endndx: U32<BE>,
+ /// Pad
+ pub pad: u8,
+ /// Contains _AUX_FCN; Type of auxiliary entry.
+ pub x_auxtype: u8,
+}
+
+/// Exception auxiliary entry. (XCOFF64 only)
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct ExpAux {
+ /// File offset to exception table entry.
+ pub x_exptr: U64<BE>,
+ /// Size of function in bytes.
+ pub x_fsize: U32<BE>,
+ /// Symbol table index of next entry beyond this function.
+ pub x_endndx: U32<BE>,
+ /// Pad
+ pub pad: u8,
+ /// Contains _AUX_EXCEPT; Type of auxiliary entry
+ pub x_auxtype: u8,
+}
+
+/// Block auxiliary entry for the C_BLOCK and C_FCN Symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct BlockAux32 {
+ /// Reserved.
+ pub pad: [u8; 2],
+ /// High-order 2 bytes of the source line number.
+ pub x_lnnohi: U16<BE>,
+ /// Low-order 2 bytes of the source line number.
+ pub x_lnnolo: U16<BE>,
+ /// Reserved.
+ pub pad2: [u8; 12],
+}
+
+/// Block auxiliary entry for the C_BLOCK and C_FCN Symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct BlockAux64 {
+ /// Source line number.
+ pub x_lnno: U32<BE>,
+ /// Reserved.
+ pub pad: [u8; 13],
+ /// Contains _AUX_SYM; Type of auxiliary entry.
+ pub x_auxtype: u8,
+}
+
+/// Section auxiliary entry for the C_STAT Symbol. (XCOFF32 Only)
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct StatAux {
+ /// Section length.
+ pub x_scnlen: U32<BE>,
+ /// Number of relocation entries.
+ pub x_nreloc: U16<BE>,
+ /// Number of line numbers.
+ pub x_nlinno: U16<BE>,
+ /// Reserved.
+ pub pad: [u8; 10],
+}
+
+/// Section auxiliary entry Format for C_DWARF symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DwarfAux32 {
+ /// Length of portion of section represented by symbol.
+ pub x_scnlen: U32<BE>,
+ /// Reserved.
+ pub pad: [u8; 4],
+ /// Number of relocation entries in section.
+ pub x_nreloc: U32<BE>,
+ /// Reserved.
+ pub pad2: [u8; 6],
+}
+
+/// Section auxiliary entry Format for C_DWARF symbols.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DwarfAux64 {
+ /// Length of portion of section represented by symbol.
+ pub x_scnlen: U64<BE>,
+ /// Number of relocation entries in section.
+ pub x_nreloc: U64<BE>,
+ /// Reserved.
+ pub pad: u8,
+ /// Contains _AUX_SECT; Type of Auxiliary entry.
+ pub x_auxtype: u8,
+}
+
+// Values for `x_auxtype`
+//
+/// Identifies an exception auxiliary entry.
+pub const AUX_EXCEPT: u8 = 255;
+/// Identifies a function auxiliary entry.
+pub const AUX_FCN: u8 = 254;
+/// Identifies a symbol auxiliary entry.
+pub const AUX_SYM: u8 = 253;
+/// Identifies a file auxiliary entry.
+pub const AUX_FILE: u8 = 252;
+/// Identifies a csect auxiliary entry.
+pub const AUX_CSECT: u8 = 251;
+/// Identifies a SECT auxiliary entry.
+pub const AUX_SECT: u8 = 250;
+
+/// Relocation table entry
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Rel32 {
+ /// Virtual address (position) in section to be relocated.
+ pub r_vaddr: U32<BE>,
+ /// Symbol table index of item that is referenced.
+ pub r_symndx: U32<BE>,
+ /// Relocation size and information.
+ pub r_rsize: u8,
+ /// Relocation type.
+ pub r_rtype: u8,
+}
+
+/// Relocation table entry
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Rel64 {
+ /// Virtual address (position) in section to be relocated.
+ pub r_vaddr: U64<BE>,
+ /// Symbol table index of item that is referenced.
+ pub r_symndx: U32<BE>,
+ /// Relocation size and information.
+ pub r_rsize: u8,
+ /// Relocation type.
+ pub r_rtype: u8,
+}
+
+// Values for `r_rtype`.
+//
+/// Positive relocation.
+pub const R_POS: u8 = 0x00;
+/// Positive indirect load relocation.
+pub const R_RL: u8 = 0x0c;
+/// Positive load address relocation. Modifiable instruction.
+pub const R_RLA: u8 = 0x0d;
+/// Negative relocation.
+pub const R_NEG: u8 = 0x01;
+/// Relative to self relocation.
+pub const R_REL: u8 = 0x02;
+/// Relative to the TOC relocation.
+pub const R_TOC: u8 = 0x03;
+/// TOC relative indirect load relocation.
+pub const R_TRL: u8 = 0x12;
+/// Relative to the TOC or to the thread-local storage base relocation.
+pub const R_TRLA: u8 = 0x13;
+/// Global linkage-external TOC address relocation.
+pub const R_GL: u8 = 0x05;
+/// Local object TOC address relocation.
+pub const R_TCL: u8 = 0x06;
+/// A non-relocating relocation.
+pub const R_REF: u8 = 0x0f;
+/// Branch absolute relocation. References a non-modifiable instruction.
+pub const R_BA: u8 = 0x08;
+/// Branch relative to self relocation. References a non-modifiable instruction.
+pub const R_BR: u8 = 0x0a;
+/// Branch absolute relocation. References a modifiable instruction.
+pub const R_RBA: u8 = 0x18;
+/// Branch relative to self relocation. References a modifiable instruction.
+pub const R_RBR: u8 = 0x1a;
+/// General-dynamic reference to TLS symbol.
+pub const R_TLS: u8 = 0x20;
+/// Initial-exec reference to TLS symbol.
+pub const R_TLS_IE: u8 = 0x21;
+/// Local-dynamic reference to TLS symbol.
+pub const R_TLS_LD: u8 = 0x22;
+/// Local-exec reference to TLS symbol.
+pub const R_TLS_LE: u8 = 0x23;
+/// Module reference to TLS.
+pub const R_TLSM: u8 = 0x24;
+/// Module reference to the local TLS storage.
+pub const R_TLSML: u8 = 0x25;
+/// Relative to TOC upper.
+pub const R_TOCU: u8 = 0x30;
+/// Relative to TOC lower.
+pub const R_TOCL: u8 = 0x31;
+
+unsafe_impl_pod!(
+ FileHeader32,
+ FileHeader64,
+ AuxHeader32,
+ AuxHeader64,
+ SectionHeader32,
+ SectionHeader64,
+ SymbolBytes,
+ Symbol32,
+ Symbol64,
+ FileAux32,
+ FileAux64,
+ CsectAux32,
+ CsectAux64,
+ FunAux32,
+ FunAux64,
+ ExpAux,
+ BlockAux32,
+ BlockAux64,
+ StatAux,
+ DwarfAux32,
+ DwarfAux64,
+ Rel32,
+ Rel64,
+);