diff options
Diffstat (limited to 'vendor/object/src')
74 files changed, 44300 insertions, 0 deletions
diff --git a/vendor/object/src/archive.rs b/vendor/object/src/archive.rs new file mode 100644 index 0000000..6271d07 --- /dev/null +++ b/vendor/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/vendor/object/src/common.rs b/vendor/object/src/common.rs new file mode 100644 index 0000000..36f6656 --- /dev/null +++ b/vendor/object/src/common.rs @@ -0,0 +1,536 @@ +/// 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, +    Sharc, +    Sparc64, +    Wasm32, +    Wasm64, +    Xtensa, +} + +/// A CPU sub-architecture. +#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum SubArchitecture { +    Arm64E, +    Arm64EC, +} + +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::Sharc => Some(AddressSize::U32), +            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, + +    /// SHARC+ 48-bit Type A instruction +    /// +    /// Represents these possible variants, each with a corresponding +    /// `R_SHARC_*` constant: +    /// +    /// * 24-bit absolute address +    /// * 32-bit absolute address +    /// * 6-bit relative address +    /// * 24-bit relative address +    /// * 6-bit absolute address in the immediate value field +    /// * 16-bit absolute address in the immediate value field +    SharcTypeA, + +    /// SHARC+ 32-bit Type B instruction +    /// +    /// Represents these possible variants, each with a corresponding +    /// `R_SHARC_*` constant: +    /// +    /// * 6-bit absolute address in the immediate value field +    /// * 7-bit absolute address in the immediate value field +    /// * 16-bit absolute address +    /// * 6-bit relative address +    SharcTypeB, +} + +/// 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/vendor/object/src/elf.rs b/vendor/object/src/elf.rs new file mode 100644 index 0000000..f620171 --- /dev/null +++ b/vendor/object/src/elf.rs @@ -0,0 +1,6287 @@ +//! 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_PAUTH: u32 = 0xc0000001; + +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; + +// ADI SHARC specific definitions + +// SHARC values for `Rel*::r_type` + +/// 24-bit absolute address in bits 23:0 of a 48-bit instr +/// +/// Targets: +/// +/// * Type 25a (PC_DIRECT) +pub const R_SHARC_ADDR24_V3: u32 = 0x0b; + +/// 32-bit absolute address in bits 31:0 of a 48-bit instr +/// +/// Targets: +/// +/// * Type 14a +/// * Type 14d +/// * Type 15a +/// * Type 16a +/// * Type 17a +/// * Type 18a +/// * Type 19a +pub const R_SHARC_ADDR32_V3: u32 = 0x0c; + +/// 32-bit absolute address in bits 31:0 of a 32-bit data location +/// +/// Represented with `RelocationEncoding::Generic` +pub const R_SHARC_ADDR_VAR_V3: u32 = 0x0d; + +/// 6-bit PC-relative address in bits 32:27 of a 48-bit instr +/// +/// Targets: +/// +/// * Type 9a +/// * Type 10a +pub const R_SHARC_PCRSHORT_V3: u32 = 0x0e; + +/// 24-bit PC-relative address in bits 23:0 of a 48-bit instr +/// +/// Targets: +/// +/// * Type 8a +/// * Type 12a (truncated to 23 bits after relocation) +/// * Type 13a (truncated to 23 bits after relocation) +/// * Type 25a (PC Relative) +pub const R_SHARC_PCRLONG_V3: u32 = 0x0f; + +/// 6-bit absolute address in bits 32:27 of a 48-bit instr +/// +/// Targets: +/// +/// * Type 4a +/// * Type 4b +/// * Type 4d +pub const R_SHARC_DATA6_V3: u32 = 0x10; + +/// 16-bit absolute address in bits 39:24 of a 48-bit instr +/// +/// Targets: +/// +/// * Type 12a +pub const R_SHARC_DATA16_V3: u32 = 0x11; + +/// 6-bit absolute address into bits 16:11 of a 32-bit instr +/// +/// Targets: +/// +/// * Type 4b +pub const R_SHARC_DATA6_VISA_V3: u32 = 0x12; + +/// 7-bit absolute address into bits 6:0 of a 32-bit instr +pub const R_SHARC_DATA7_VISA_V3: u32 = 0x13; + +/// 16-bit absolute address into bits 15:0 of a 32-bit instr +pub const R_SHARC_DATA16_VISA_V3: u32 = 0x14; + +/// 6-bit PC-relative address into bits 16:11 of a Type B +/// +/// Targets: +/// +/// * Type 9b +pub const R_SHARC_PCR6_VISA_V3: u32 = 0x17; + +/// 16-bit absolute address into bits 15:0 of a 16-bit location. +/// +/// Represented with `RelocationEncoding::Generic` +pub const R_SHARC_ADDR_VAR16_V3: u32 = 0x19; + +pub const R_SHARC_CALC_PUSH_ADDR: u32 = 0xe0; +pub const R_SHARC_CALC_PUSH_ADDEND: u32 = 0xe1; +pub const R_SHARC_CALC_ADD: u32 = 0xe2; +pub const R_SHARC_CALC_SUB: u32 = 0xe3; +pub const R_SHARC_CALC_MUL: u32 = 0xe4; +pub const R_SHARC_CALC_DIV: u32 = 0xe5; +pub const R_SHARC_CALC_MOD: u32 = 0xe6; +pub const R_SHARC_CALC_LSHIFT: u32 = 0xe7; +pub const R_SHARC_CALC_RSHIFT: u32 = 0xe8; +pub const R_SHARC_CALC_AND: u32 = 0xe9; +pub const R_SHARC_CALC_OR: u32 = 0xea; +pub const R_SHARC_CALC_XOR: u32 = 0xeb; +pub const R_SHARC_CALC_PUSH_LEN: u32 = 0xec; +pub const R_SHARC_CALC_NOT: u32 = 0xf6; + +// SHARC values for `SectionHeader*::sh_type`. + +/// .adi.attributes +pub const SHT_SHARC_ADI_ATTRIBUTES: u32 = SHT_LOPROC + 0x2; + +// 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 +/// instruction can be relaxed +pub const R_LARCH_RELAX: u32 = 100; +/// Reserved +pub const R_LARCH_DELETE: u32 = 101; +/// Delete some bytes to ensure the instruction at PC + A aligned to +/// `A.next_power_of_two()`-byte boundary +pub const R_LARCH_ALIGN: u32 = 102; +/// 22-bit PC-relative offset with two trailing zeros +pub const R_LARCH_PCREL20_S2: u32 = 103; +/// Reserved +pub const R_LARCH_CFA: u32 = 104; +/// 6-bit in-place addition +pub const R_LARCH_ADD6: u32 = 105; +/// 6-bit in-place subtraction +pub const R_LARCH_SUB6: u32 = 106; +/// LEB128 in-place addition +pub const R_LARCH_ADD_ULEB128: u32 = 107; +/// LEB128 in-place subtraction +pub const R_LARCH_SUB_ULEB128: u32 = 108; +/// 64-bit PC relative +pub const R_LARCH_64_PCREL: u32 = 109; +/// 18..=37 bits of `S + A - PC` into the `pcaddu18i` instruction at `PC`, +/// and 2..=17 bits of `S + A - PC` into the `jirl` instruction at `PC + 4` +pub const R_LARCH_CALL36: u32 = 110; + +// 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/vendor/object/src/endian.rs b/vendor/object/src/endian.rs new file mode 100644 index 0000000..e4a36ba --- /dev/null +++ b/vendor/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/vendor/object/src/lib.rs b/vendor/object/src/lib.rs new file mode 100644 index 0000000..5956e06 --- /dev/null +++ b/vendor/object/src/lib.rs @@ -0,0 +1,99 @@ +//! # `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 the [`pod`] and [`endian`] modules. +//! +//! ## Unified read API +//! +//! The [`read`] module provides a unified read API using the [`read::Object`] trait. +//! There is an implementation of this trait for [`read::File`], which allows reading any +//! file format, as well as implementations for each file format. +//! +//! ## Low level read API +//! +//! The [`read#modules`] submodules define helpers that operate on the raw structs. +//! These can be used instead of the unified API, or in conjunction with it to access +//! details that are not available via the unified API. +//! +//! ## Unified write API +//! +//! The [`mod@write`] module provides a unified write API for relocatable object files +//! using [`write::Object`]. This does not support writing executable files. +//! +//! ## Low level write API +//! +//! The [`mod@write#modules`] submodules define helpers for writing the raw structs. +//! +//! ## Shared definitions +//! +//! The crate provides a number of definitions that are used by both the read and write +//! APIs. These are defined at the top level module, but none of these are the main entry +//! points of the crate. + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![no_std] +#![warn(rust_2018_idioms)] +// Style. +#![allow(clippy::collapsible_if)] +#![allow(clippy::comparison_chain)] +#![allow(clippy::manual_flatten)] +#![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/vendor/object/src/macho.rs b/vendor/object/src/macho.rs new file mode 100644 index 0000000..3cd38e0 --- /dev/null +++ b/vendor/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/vendor/object/src/pe.rs b/vendor/object/src/pe.rs new file mode 100644 index 0000000..64ccf06 --- /dev/null +++ b/vendor/object/src/pe.rs @@ -0,0 +1,3056 @@ +//! 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; +/// ARM64EC ("Emulation Compatible") +pub const IMAGE_FILE_MACHINE_ARM64EC: u16 = 0xA641; +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/vendor/object/src/pod.rs b/vendor/object/src/pod.rs new file mode 100644 index 0000000..8ee7816 --- /dev/null +++ b/vendor/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/vendor/object/src/read/any.rs b/vendor/object/src/read/any.rs new file mode 100644 index 0000000..a14e56d --- /dev/null +++ b/vendor/object/src/read/any.rs @@ -0,0 +1,1328 @@ +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, SubArchitecture}; + +/// 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 that can be any supported file format. +/// +/// 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 sub_architecture(&self) -> Option<SubArchitecture> { +        with_inner!(self, File, |x| x.sub_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 for the loadable segments in 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 loadable segment in a [`File`]. +/// +/// Most functionality is provided by the [`ObjectSegment`] trait implementation. +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 for the sections in 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 in a [`File`]. +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +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 for the COMDAT section groups in 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 in a [`File`]. +/// +/// Most functionality is provided by the [`ObjectComdat`] trait implementation. +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 for the sections in a [`Comdat`]. +#[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 in a [`File`]. +/// +/// Most functionality is provided by the [`ObjectSymbolTable`] trait implementation. +#[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 for the symbols in a [`SymbolTable`]. +#[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 }) +    } +} + +/// An symbol in a [`SymbolTable`]. +/// +/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. +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 for the dynamic relocation entries in a [`File`]. +#[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 for the relocation entries in a [`Section`]. +#[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/vendor/object/src/read/archive.rs b/vendor/object/src/read/archive.rs new file mode 100644 index 0000000..5d4ec4a --- /dev/null +++ b/vendor/object/src/read/archive.rs @@ -0,0 +1,759 @@ +//! Support for archive files. +//! +//! ## Example +//!  ```no_run +//! use object::{Object, ObjectSection}; +//! use std::error::Error; +//! use std::fs; +//! +//! /// Reads an archive and displays the name of each member. +//! fn main() -> Result<(), Box<dyn Error>> { +//! #   #[cfg(feature = "std")] { +//!     let data = fs::read("path/to/binary")?; +//!     let file = object::read::archive::ArchiveFile::parse(&*data)?; +//!     for member in file.members() { +//!         let member = member?; +//!         println!("{}", String::from_utf8_lossy(member.name())); +//!     } +//! #   } +//!     Ok(()) +//! } +//! ``` + +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/vendor/object/src/read/coff/comdat.rs b/vendor/object/src/read/coff/comdat.rs new file mode 100644 index 0000000..90c29be --- /dev/null +++ b/vendor/object/src/read/coff/comdat.rs @@ -0,0 +1,211 @@ +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 for the COMDAT section groups in a [`CoffBigFile`](super::CoffBigFile). +pub type CoffBigComdatIterator<'data, 'file, R = &'data [u8]> = +    CoffComdatIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// An iterator for the COMDAT section groups in 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 in a [`CoffBigFile`](super::CoffBigFile). +/// +/// Most functionality is provided by the [`ObjectComdat`] trait implementation. +pub type CoffBigComdat<'data, 'file, R = &'data [u8]> = +    CoffComdat<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// A COMDAT section group in a [`CoffFile`]. +/// +/// Most functionality is provided by the [`ObjectComdat`] trait implementation. +#[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 for the sections in a COMDAT section group in a [`CoffBigFile`](super::CoffBigFile). +pub type CoffBigComdatSectionIterator<'data, 'file, R = &'data [u8]> = +    CoffComdatSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// An iterator for the sections in a COMDAT section group in 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/vendor/object/src/read/coff/file.rs b/vendor/object/src/read/coff/file.rs new file mode 100644 index 0000000..40b9e70 --- /dev/null +++ b/vendor/object/src/read/coff/file.rs @@ -0,0 +1,381 @@ +use alloc::vec::Vec; +use core::fmt::Debug; + +use crate::read::{ +    self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, ObjectKind, +    ObjectSection, ReadError, ReadRef, Result, SectionIndex, SubArchitecture, 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. +/// +/// This is a file that starts with [`pe::AnonObjectHeaderBigobj`], and corresponds +/// to [`crate::FileKind::CoffBig`]. +/// +/// Most functionality is provided by the [`Object`] trait implementation. +pub type CoffBigFile<'data, R = &'data [u8]> = CoffFile<'data, R, pe::AnonObjectHeaderBigobj>; + +/// A COFF object file. +/// +/// This is a file that starts with [`pe::ImageFileHeader`], and corresponds +/// to [`crate::FileKind::Coff`]. +/// +/// Most functionality is provided by the [`Object`] trait implementation. +#[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 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, +            pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, +            pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, +            _ => Architecture::Unknown, +        } +    } + +    fn sub_architecture(&self) -> Option<SubArchitecture> { +        match self.header.machine() { +            pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), +            _ => None, +        } +    } + +    #[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 a [`pe::AnonObjectHeader`]. +/// +/// 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 [`pe::ImageFileHeader`] and [`pe::AnonObjectHeaderBigobj`]. +#[allow(missing_docs)] +pub trait CoffHeader: Debug + Pod { +    type ImageSymbol: ImageSymbol; +    type ImageSymbolBytes: Debug + Pod; + +    /// Return true if this type is [`pe::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/vendor/object/src/read/coff/import.rs b/vendor/object/src/read/coff/import.rs new file mode 100644 index 0000000..a296ac3 --- /dev/null +++ b/vendor/object/src/read/coff/import.rs @@ -0,0 +1,220 @@ +//! 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, SubArchitecture}; + +/// 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. +/// +/// This is a file that starts with [`pe::ImportObjectHeader`], and corresponds +/// to [`crate::FileKind::CoffImport`]. +#[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 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, +            pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, +            pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, +            _ => Architecture::Unknown, +        } +    } + +    /// Get the sub machine type, if available. +    pub fn sub_architecture(&self) -> Option<SubArchitecture> { +        match self.header.machine.get(LE) { +            pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), +            _ => None, +        } +    } + +    /// 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 [`pe::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/vendor/object/src/read/coff/mod.rs b/vendor/object/src/read/coff/mod.rs new file mode 100644 index 0000000..de397da --- /dev/null +++ b/vendor/object/src/read/coff/mod.rs @@ -0,0 +1,66 @@ +//! Support for reading Windows COFF files. +//! +//! Traits are used to abstract over the difference between COFF object files +//! and COFF bigobj files. The primary trait for this is [`CoffHeader`]. +//! +//! ## High level API +//! +//! [`CoffFile`] implements the [`Object`](crate::read::Object) trait for +//! COFF files. [`CoffFile`] is parameterised by [`CoffHeader`]. +//! The default parameter allows reading regular COFF object files, +//! while the type alias [`CoffBigFile`] allows reading COFF bigobj files. +//! +//! [`ImportFile`] allows reading COFF short imports that are used in import +//! libraries. Currently these are not integrated with the unified read API. +//! +//! ## Low level API +//! +//! The [`CoffHeader`] trait can be directly used to parse both COFF +//! object files (which start with [`pe::ImageFileHeader`]) and COFF bigobj +//! files (which start with [`pe::AnonObjectHeaderBigobj`]). +//! +//! ### Example for low level API +//!  ```no_run +//! use object::pe; +//! use object::read::coff::{CoffHeader, ImageSymbol as _}; +//! use std::error::Error; +//! use std::fs; +//! +//! /// Reads a file and displays the name of each section and symbol. +//! fn main() -> Result<(), Box<dyn Error>> { +//! #   #[cfg(feature = "std")] { +//!     let data = fs::read("path/to/binary")?; +//!     let mut offset = 0; +//!     let header = pe::ImageFileHeader::parse(&*data, &mut offset)?; +//!     let sections = header.sections(&*data, offset)?; +//!     let symbols = header.symbols(&*data)?; +//!     for section in sections.iter() { +//!         println!("{}", String::from_utf8_lossy(section.name(symbols.strings())?)); +//!     } +//!     for (_index, symbol) in symbols.iter() { +//!         println!("{}", String::from_utf8_lossy(symbol.name(symbols.strings())?)); +//!     } +//! #   } +//!     Ok(()) +//! } +//! ``` +#[cfg(doc)] +use crate::pe; + +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/vendor/object/src/read/coff/relocation.rs b/vendor/object/src/read/coff/relocation.rs new file mode 100644 index 0000000..e990944 --- /dev/null +++ b/vendor/object/src/read/coff/relocation.rs @@ -0,0 +1,106 @@ +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 for the relocations in a [`CoffBigSection`](super::CoffBigSection). +pub type CoffBigRelocationIterator<'data, 'file, R = &'data [u8]> = +    CoffRelocationIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// An iterator for the relocations in a [`CoffSection`](super::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 | pe::IMAGE_FILE_MACHINE_ARM64EC => { +                    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/vendor/object/src/read/coff/section.rs b/vendor/object/src/read/coff/section.rs new file mode 100644 index 0000000..84a3fa9 --- /dev/null +++ b/vendor/object/src/read/coff/section.rs @@ -0,0 +1,585 @@ +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. +/// +/// Returned by [`CoffHeader::sections`] and +/// [`ImageNtHeaders::sections`](crate::read::pe::ImageNtHeaders::sections). +#[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 for the loadable sections in a [`CoffBigFile`](super::CoffBigFile). +pub type CoffBigSegmentIterator<'data, 'file, R = &'data [u8]> = +    CoffSegmentIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// An iterator for the loadable sections in 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 in a [`CoffBigFile`](super::CoffBigFile). +/// +/// Most functionality is provided by the [`ObjectSegment`] trait implementation. +pub type CoffBigSegment<'data, 'file, R = &'data [u8]> = +    CoffSegment<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// A loadable section in a [`CoffFile`]. +/// +/// Most functionality is provided by the [`ObjectSegment`] trait implementation. +#[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 for the sections in a [`CoffBigFile`](super::CoffBigFile). +pub type CoffBigSectionIterator<'data, 'file, R = &'data [u8]> = +    CoffSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// An iterator for the sections in 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 in a [`CoffBigFile`](super::CoffBigFile). +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +pub type CoffBigSection<'data, 'file, R = &'data [u8]> = +    CoffSection<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// A section in a [`CoffFile`]. +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +#[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/vendor/object/src/read/coff/symbol.rs b/vendor/object/src/read/coff/symbol.rs new file mode 100644 index 0000000..4f8a0c6 --- /dev/null +++ b/vendor/object/src/read/coff/symbol.rs @@ -0,0 +1,635 @@ +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. +/// +/// Returned by [`CoffHeader::symbols`] and +/// [`ImageNtHeaders::symbols`](crate::read::pe::ImageNtHeaders::symbols). +#[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 in a [`CoffBigFile`](super::CoffBigFile). +pub type CoffBigSymbolTable<'data, 'file, R = &'data [u8]> = +    CoffSymbolTable<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// A symbol table in a [`CoffFile`](super::CoffFile) +/// or [`PeFile`](crate::read::pe::PeFile). +#[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 for the symbols in a [`CoffBigFile`](super::CoffBigFile). +pub type CoffBigSymbolIterator<'data, 'file, R = &'data [u8]> = +    CoffSymbolIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// An iterator for the symbols in a [`CoffFile`](super::CoffFile) +/// or [`PeFile`](crate::read::pe::PeFile). +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 in a [`CoffBigFile`](super::CoffBigFile). +/// +/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. +pub type CoffBigSymbol<'data, 'file, R = &'data [u8]> = +    CoffSymbol<'data, 'file, R, pe::AnonObjectHeaderBigobj>; + +/// A symbol in a [`CoffFile`](super::CoffFile) or [`PeFile`](crate::read::pe::PeFile). +/// +/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. +#[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.has_aux_section() { +                    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 { +                    if self.symbol.value() == 0 { +                        SymbolSection::Undefined +                    } else { +                        SymbolSection::Common +                    } +                } else if self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_SECTION { +                    SymbolSection::Undefined +                } else { +                    SymbolSection::Unknown +                } +            } +            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 [`pe::ImageSymbol`] and [`pe::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 { +        if self.section_number() <= 0 { +            return false; +        } +        match self.storage_class() { +            pe::IMAGE_SYM_CLASS_STATIC => !self.has_aux_section(), +            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.typ() == 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/vendor/object/src/read/elf/attributes.rs b/vendor/object/src/read/elf/attributes.rs new file mode 100644 index 0000000..bf6f35c --- /dev/null +++ b/vendor/object/src/read/elf/attributes.rs @@ -0,0 +1,307 @@ +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 [`AttributesSubsection`]. +/// +/// Returned by [`SectionHeader::attributes`](super::SectionHeader::attributes) +/// and [`SectionHeader::gnu_attributes`](super::SectionHeader::gnu_attributes). +#[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 for the subsections in an [`AttributesSection`]. +#[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 [`AttributesSection`]. +/// +/// A subsection is identified by a vendor name.  It contains a series of +/// [`AttributesSubsubsection`]. +#[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 for the sub-subsections in an [`AttributesSubsection`]. +#[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 [`AttributesSubsection`]. +/// +/// 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 an [`AttributesSubsubsection`]. +#[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 an [`AttributesSubsubsection`]. +/// +/// 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/vendor/object/src/read/elf/comdat.rs b/vendor/object/src/read/elf/comdat.rs new file mode 100644 index 0000000..882d253 --- /dev/null +++ b/vendor/object/src/read/elf/comdat.rs @@ -0,0 +1,162 @@ +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 for the COMDAT section groups in an [`ElfFile32`](super::ElfFile32). +pub type ElfComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfComdatIterator<'data, 'file, elf::FileHeader32<Endian>, R>; +/// An iterator for the COMDAT section groups in an [`ElfFile64`](super::ElfFile64). +pub type ElfComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfComdatIterator<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// An iterator for the COMDAT section groups in 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 in an [`ElfFile32`](super::ElfFile32). +pub type ElfComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfComdat<'data, 'file, elf::FileHeader32<Endian>, R>; +/// A COMDAT section group in an [`ElfFile64`](super::ElfFile64). +pub type ElfComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfComdat<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// A COMDAT section group in an [`ElfFile`]. +/// +/// Most functionality is provided by the [`ObjectComdat`] trait implementation. +#[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 for the sections in a COMDAT section group in an [`ElfFile32`](super::ElfFile32). +pub type ElfComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfComdatSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>; +/// An iterator for the sections in a COMDAT section group in an [`ElfFile64`](super::ElfFile64). +pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfComdatSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// An iterator for the sections in a COMDAT section group in 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/vendor/object/src/read/elf/compression.rs b/vendor/object/src/read/elf/compression.rs new file mode 100644 index 0000000..de2533f --- /dev/null +++ b/vendor/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 [`elf::CompressionHeader32`] and [`elf::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/vendor/object/src/read/elf/dynamic.rs b/vendor/object/src/read/elf/dynamic.rs new file mode 100644 index 0000000..1661434 --- /dev/null +++ b/vendor/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 [`elf::Dyn32`] and [`elf::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/vendor/object/src/read/elf/file.rs b/vendor/object/src/read/elf/file.rs new file mode 100644 index 0000000..14ba568 --- /dev/null +++ b/vendor/object/src/read/elf/file.rs @@ -0,0 +1,916 @@ +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. +/// +/// This is a file that starts with [`elf::FileHeader32`], and corresponds +/// to [`crate::FileKind::Elf32`]. +pub type ElfFile32<'data, Endian = Endianness, R = &'data [u8]> = +    ElfFile<'data, elf::FileHeader32<Endian>, R>; +/// A 64-bit ELF object file. +/// +/// This is a file that starts with [`elf::FileHeader64`], and corresponds +/// to [`crate::FileKind::Elf64`]. +pub type ElfFile64<'data, Endian = Endianness, R = &'data [u8]> = +    ElfFile<'data, elf::FileHeader64<Endian>, R>; + +/// A partially parsed ELF file. +/// +/// Most functionality 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(§ion_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_SHARC, false) => Architecture::Sharc, +            (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, +        }) +    } + +    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) +    } + +    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 [`elf::FileHeader32`] and [`elf::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 [`Self::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/vendor/object/src/read/elf/hash.rs b/vendor/object/src/read/elf/hash.rs new file mode 100644 index 0000000..b0130cc --- /dev/null +++ b/vendor/object/src/read/elf/hash.rs @@ -0,0 +1,224 @@ +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. +/// +/// Returned by [`SectionHeader::hash`](super::SectionHeader::hash). +#[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 an [`elf::SHT_HASH`] section, or from a +    /// segment pointed to via the [`elf::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. +/// +/// Returned by [`SectionHeader::gnu_hash`](super::SectionHeader::gnu_hash). +#[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 an [`elf::SHT_GNU_HASH`] section, or from a +    /// segment pointed to via the [`elf::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 [`elf::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/vendor/object/src/read/elf/mod.rs b/vendor/object/src/read/elf/mod.rs new file mode 100644 index 0000000..66931bd --- /dev/null +++ b/vendor/object/src/read/elf/mod.rs @@ -0,0 +1,78 @@ +//! Support for reading ELF files. +//! +//! Traits are used to abstract over the difference between 32-bit and 64-bit ELF. +//! The primary trait for this is [`FileHeader`]. +//! +//! ## High level API +//! +//! [`ElfFile`] implements the [`Object`](crate::read::Object) trait for ELF files. +//! [`ElfFile`] is parameterised by [`FileHeader`] to allow reading both 32-bit and +//! 64-bit ELF. There are type aliases for these parameters ([`ElfFile32`] and +//! [`ElfFile64`]). +//! +//! ## Low level API +//! +//! The [`FileHeader`] trait can be directly used to parse both [`elf::FileHeader32`] +//! and [`elf::FileHeader64`]. +//! +//! ### Example for low level API +//!  ```no_run +//! use object::elf; +//! use object::read::elf::{FileHeader, Sym}; +//! use std::error::Error; +//! use std::fs; +//! +//! /// Reads a file and displays the name of each symbol. +//! fn main() -> Result<(), Box<dyn Error>> { +//! #   #[cfg(feature = "std")] { +//!     let data = fs::read("path/to/binary")?; +//!     let elf = elf::FileHeader64::<object::Endianness>::parse(&*data)?; +//!     let endian = elf.endian()?; +//!     let sections = elf.sections(endian, &*data)?; +//!     let symbols = sections.symbols(endian, &*data, elf::SHT_SYMTAB)?; +//!     for symbol in symbols.iter() { +//!         let name = symbol.name(endian, symbols.strings())?; +//!         println!("{}", String::from_utf8_lossy(name)); +//!     } +//! #   } +//!     Ok(()) +//! } +//! ``` +#[cfg(doc)] +use crate::elf; + +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/vendor/object/src/read/elf/note.rs b/vendor/object/src/read/elf/note.rs new file mode 100644 index 0000000..e2beef9 --- /dev/null +++ b/vendor/object/src/read/elf/note.rs @@ -0,0 +1,271 @@ +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. +/// +/// Returned [`ProgramHeader::notes`](super::ProgramHeader::notes) +/// and [`SectionHeader::notes`](super::SectionHeader::notes). +#[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 [`elf::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 [`elf::NoteHeader32`] and [`elf::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 for the properties in a [`elf::NT_GNU_PROPERTY_TYPE_0`] note. +/// +/// Returned by [`Note::gnu_properties`]. +#[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 [`elf::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/vendor/object/src/read/elf/relocation.rs b/vendor/object/src/read/elf/relocation.rs new file mode 100644 index 0000000..aac1574 --- /dev/null +++ b/vendor/object/src/read/elf/relocation.rs @@ -0,0 +1,628 @@ +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 for the dynamic relocations in an [`ElfFile32`](super::ElfFile32). +pub type ElfDynamicRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>; +/// An iterator for the dynamic relocations in an [`ElfFile64`](super::ElfFile64). +pub type ElfDynamicRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// An iterator for the dynamic relocations in 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 for the relocations for an [`ElfSection32`](super::ElfSection32). +pub type ElfSectionRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSectionRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>; +/// An iterator for the relocations for an [`ElfSection64`](super::ElfSection64). +pub type ElfSectionRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSectionRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// An iterator for the relocations for an [`ElfSection`](super::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_64_PCREL => (RelocationKind::Relative, 64), +            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_SHARC => match reloc.r_type(endian, false) { +            elf::R_SHARC_ADDR24_V3 => { +                encoding = RelocationEncoding::SharcTypeA; +                (RelocationKind::Absolute, 24) +            } +            elf::R_SHARC_ADDR32_V3 => { +                encoding = RelocationEncoding::SharcTypeA; +                (RelocationKind::Absolute, 32) +            } +            elf::R_SHARC_ADDR_VAR_V3 => { +                encoding = RelocationEncoding::Generic; +                (RelocationKind::Absolute, 32) +            } +            elf::R_SHARC_PCRSHORT_V3 => { +                encoding = RelocationEncoding::SharcTypeA; +                (RelocationKind::Relative, 6) +            } +            elf::R_SHARC_PCRLONG_V3 => { +                encoding = RelocationEncoding::SharcTypeA; +                (RelocationKind::Relative, 24) +            } +            elf::R_SHARC_DATA6_V3 => { +                encoding = RelocationEncoding::SharcTypeA; +                (RelocationKind::Absolute, 6) +            } +            elf::R_SHARC_DATA16_V3 => { +                encoding = RelocationEncoding::SharcTypeA; +                (RelocationKind::Absolute, 16) +            } +            elf::R_SHARC_DATA6_VISA_V3 => { +                encoding = RelocationEncoding::SharcTypeB; +                (RelocationKind::Absolute, 6) +            } +            elf::R_SHARC_DATA7_VISA_V3 => { +                encoding = RelocationEncoding::SharcTypeB; +                (RelocationKind::Absolute, 7) +            } +            elf::R_SHARC_DATA16_VISA_V3 => { +                encoding = RelocationEncoding::SharcTypeB; +                (RelocationKind::Absolute, 16) +            } +            elf::R_SHARC_PCR6_VISA_V3 => { +                encoding = RelocationEncoding::SharcTypeB; +                (RelocationKind::Relative, 16) +            } +            elf::R_SHARC_ADDR_VAR16_V3 => { +                encoding = RelocationEncoding::Generic; +                (RelocationKind::Absolute, 16) +            } +            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 [`elf::Rel32`] and [`elf::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 [`elf::Rela32`] and [`elf::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/vendor/object/src/read/elf/section.rs b/vendor/object/src/read/elf/section.rs new file mode 100644 index 0000000..2b5ae01 --- /dev/null +++ b/vendor/object/src/read/elf/section.rs @@ -0,0 +1,1150 @@ +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. +/// +/// Returned by [`FileHeader::sections`]. +#[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 for the sections in an [`ElfFile32`](super::ElfFile32). +pub type ElfSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>; +/// An iterator for the sections in an [`ElfFile64`](super::ElfFile64). +pub type ElfSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// An iterator for the sections in 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 in an [`ElfFile32`](super::ElfFile32). +pub type ElfSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSection<'data, 'file, elf::FileHeader32<Endian>, R>; +/// A section in an [`ElfFile64`](super::ElfFile64). +pub type ElfSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSection<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// A section in an [`ElfFile`]. +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +#[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 [`elf::SectionHeader32`] and [`elf::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/vendor/object/src/read/elf/segment.rs b/vendor/object/src/read/elf/segment.rs new file mode 100644 index 0000000..957117a --- /dev/null +++ b/vendor/object/src/read/elf/segment.rs @@ -0,0 +1,334 @@ +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 for the segments in an [`ElfFile32`](super::ElfFile32). +pub type ElfSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSegmentIterator<'data, 'file, elf::FileHeader32<Endian>, R>; +/// An iterator for the segments in an [`ElfFile64`](super::ElfFile64). +pub type ElfSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSegmentIterator<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// An iterator for the segments in 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 in an [`ElfFile32`](super::ElfFile32). +pub type ElfSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSegment<'data, 'file, elf::FileHeader32<Endian>, R>; +/// A segment in an [`ElfFile64`](super::ElfFile64). +pub type ElfSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSegment<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// A segment in an [`ElfFile`]. +/// +/// Most functionality is provided by the [`ObjectSegment`] trait implementation. +#[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 [`elf::ProgramHeader32`] and [`elf::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/vendor/object/src/read/elf/symbol.rs b/vendor/object/src/read/elf/symbol.rs new file mode 100644 index 0000000..8ba707f --- /dev/null +++ b/vendor/object/src/read/elf/symbol.rs @@ -0,0 +1,595 @@ +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. +/// +/// Returned by [`SectionTable::symbols`]. +#[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 in an [`ElfFile32`](super::ElfFile32). +pub type ElfSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSymbolTable<'data, 'file, elf::FileHeader32<Endian>, R>; +/// A symbol table in an [`ElfFile32`](super::ElfFile32). +pub type ElfSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSymbolTable<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// A symbol table in an [`ElfFile`](super::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 for the symbols in an [`ElfFile32`](super::ElfFile32). +pub type ElfSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSymbolIterator<'data, 'file, elf::FileHeader32<Endian>, R>; +/// An iterator for the symbols in an [`ElfFile64`](super::ElfFile64). +pub type ElfSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSymbolIterator<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// An iterator for the symbols in an [`ElfFile`](super::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 in an [`ElfFile32`](super::ElfFile32). +pub type ElfSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSymbol<'data, 'file, elf::FileHeader32<Endian>, R>; +/// A symbol in an [`ElfFile64`](super::ElfFile64). +pub type ElfSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    ElfSymbol<'data, 'file, elf::FileHeader64<Endian>, R>; + +/// A symbol in an [`ElfFile`](super::ElfFile). +/// +/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. +#[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::Unknown, +            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 [`elf::Sym32`] and [`elf::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 shndx = self.st_shndx(endian); +        if shndx == elf::SHN_UNDEF || (shndx >= elf::SHN_LORESERVE && shndx != elf::SHN_XINDEX) { +            return false; +        } +        match self.st_type() { +            elf::STT_NOTYPE => self.st_size(endian).into() != 0, +            elf::STT_FUNC | elf::STT_OBJECT => true, +            _ => false, +        } +    } +} + +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/vendor/object/src/read/elf/version.rs b/vendor/object/src/read/elf/version.rs new file mode 100644 index 0000000..28eeed0 --- /dev/null +++ b/vendor/object/src/read/elf/version.rs @@ -0,0 +1,424 @@ +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 [`elf::SHT_GNU_VERDEF`] and [`elf::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 [`elf::SHT_GNU_VERSYM`], [`elf::SHT_GNU_VERDEF`] +/// and [`elf::SHT_GNU_VERNEED`] sections. +/// +/// Returned by [`SectionTable::versions`](super::SectionTable::versions). +#[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 for the entries in an ELF [`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 for the auxiliary records for an entry in an ELF [`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 for the entries in an ELF [`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 for the auxiliary records for an entry in an ELF [`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/vendor/object/src/read/macho/dyld_cache.rs b/vendor/object/src/read/macho/dyld_cache.rs new file mode 100644 index 0000000..0f5dfc5 --- /dev/null +++ b/vendor/object/src/read/macho/dyld_cache.rs @@ -0,0 +1,344 @@ +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/vendor/object/src/read/macho/fat.rs b/vendor/object/src/read/macho/fat.rs new file mode 100644 index 0000000..a481351 --- /dev/null +++ b/vendor/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 [`macho::FatArch32`] and [`macho::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/vendor/object/src/read/macho/file.rs b/vendor/object/src/read/macho/file.rs new file mode 100644 index 0000000..0e04477 --- /dev/null +++ b/vendor/object/src/read/macho/file.rs @@ -0,0 +1,781 @@ +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, SubArchitecture, 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. +/// +/// This is a file that starts with [`macho::MachHeader32`], and corresponds +/// to [`crate::FileKind::MachO32`]. +pub type MachOFile32<'data, Endian = Endianness, R = &'data [u8]> = +    MachOFile<'data, macho::MachHeader32<Endian>, R>; +/// A 64-bit Mach-O object file. +/// +/// This is a file that starts with [`macho::MachHeader64`], and corresponds +/// to [`crate::FileKind::MachO64`]. +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") +    } + +    /// Returns the endianness. +    pub fn endian(&self) -> Mach::Endian { +        self.endian +    } + +    /// Returns the raw data. +    pub fn data(&self) -> R { +        self.data +    } + +    /// Returns the raw Mach-O file header. +    pub fn raw_header(&self) -> &'data Mach { +        self.header +    } + +    /// Return the `LC_BUILD_VERSION` load command if present. +    pub fn build_version(&self) -> Result<Option<&'data macho::BuildVersionCommand<Mach::Endian>>> { +        let mut commands = self +            .header +            .load_commands(self.endian, self.data, self.header_offset)?; +        while let Some(command) = commands.next()? { +            if let Some(build_version) = command.build_version()? { +                return Ok(Some(build_version)); +            } +        } +        Ok(None) +    } +} + +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, +        } +    } + +    fn sub_architecture(&self) -> Option<SubArchitecture> { +        match ( +            self.header.cputype(self.endian), +            self.header.cpusubtype(self.endian), +        ) { +            (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64E) => Some(SubArchitecture::Arm64E), +            _ => None, +        } +    } + +    #[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(§ion_name[1..15]) +            } else { +                Some(§ion_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 for the COMDAT section groups in a [`MachOFile64`]. +pub type MachOComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOComdatIterator<'data, 'file, macho::MachHeader32<Endian>, R>; +/// An iterator for the COMDAT section groups in a [`MachOFile64`]. +pub type MachOComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOComdatIterator<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// An iterator for the COMDAT section groups in a [`MachOFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 in a [`MachOFile32`]. +pub type MachOComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOComdat<'data, 'file, macho::MachHeader32<Endian>, R>; + +/// A COMDAT section group in a [`MachOFile64`]. +pub type MachOComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOComdat<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// A COMDAT section group in a [`MachOFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 for the sections in a COMDAT section group in a [`MachOFile32`]. +pub type MachOComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOComdatSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>; +/// An iterator for the sections in a COMDAT section group in a [`MachOFile64`]. +pub type MachOComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOComdatSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// An iterator for the sections in a COMDAT section group in a [`MachOFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 [`macho::MachHeader32`] and [`macho::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/vendor/object/src/read/macho/load_command.rs b/vendor/object/src/read/macho/load_command.rs new file mode 100644 index 0000000..7225fbd --- /dev/null +++ b/vendor/object/src/read/macho/load_command.rs @@ -0,0 +1,382 @@ +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 for the load commands from 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 [`macho::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 [`macho::LoadCommand`]. +    /// +    /// This is one of the `LC_` constants. +    pub fn cmd(&self) -> u32 { +        self.cmd +    } + +    /// Return the `cmdsize` field of the [`macho::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 [`macho::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 [`macho::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 [`macho::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 [`macho::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 [`macho::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 [`macho::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 [`macho::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 [`macho::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 [`macho::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) +        } +    } + +    /// Try to parse this command as a [`macho::BuildVersionCommand`]. +    pub fn build_version(self) -> Result<Option<&'data macho::BuildVersionCommand<E>>> { +        if self.cmd == macho::LC_BUILD_VERSION { +            Some(self.data()).transpose() +        } else { +            Ok(None) +        } +    } +} + +/// A [`macho::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/vendor/object/src/read/macho/mod.rs b/vendor/object/src/read/macho/mod.rs new file mode 100644 index 0000000..ab51ff3 --- /dev/null +++ b/vendor/object/src/read/macho/mod.rs @@ -0,0 +1,72 @@ +//! Support for reading Mach-O files. +//! +//! Traits are used to abstract over the difference between 32-bit and 64-bit Mach-O +//! files. The primary trait for this is [`MachHeader`]. +//! +//! ## High level API +//! +//! [`MachOFile`] implements the [`Object`](crate::read::Object) trait for Mach-O files. +//! [`MachOFile`] is parameterised by [`MachHeader`] to allow reading both 32-bit and +//! 64-bit Mach-O files. There are type aliases for these parameters ([`MachOFile32`] and +//! [`MachOFile64`]). +//! +//! ## Low level API +//! +//! The [`MachHeader`] trait can be directly used to parse both [`macho::MachHeader32`] +//! and [`macho::MachHeader64`]. Additionally, [`FatHeader`] and the [`FatArch`] trait +//! can be used to iterate images in multi-architecture binaries, and [`DyldCache`] can +//! be used to locate images in a dyld shared cache. +//! +//! ### Example for low level API +//!  ```no_run +//! use object::macho; +//! use object::read::macho::{MachHeader, Nlist}; +//! use std::error::Error; +//! use std::fs; +//! +//! /// Reads a file and displays the name of each symbol. +//! fn main() -> Result<(), Box<dyn Error>> { +//! #   #[cfg(feature = "std")] { +//!     let data = fs::read("path/to/binary")?; +//!     let header = macho::MachHeader64::<object::Endianness>::parse(&*data, 0)?; +//!     let endian = header.endian()?; +//!     let mut commands = header.load_commands(endian, &*data, 0)?; +//!     while let Some(command) = commands.next()? { +//!         if let Some(symtab_command) = command.symtab()? { +//!             let symbols = symtab_command.symbols::<macho::MachHeader64<_>, _>(endian, &*data)?; +//!             for symbol in symbols.iter() { +//!                 let name = symbol.name(endian, symbols.strings())?; +//!                 println!("{}", String::from_utf8_lossy(name)); +//!             } +//!         } +//!     } +//! #   } +//!     Ok(()) +//! } +//! ``` +#[cfg(doc)] +use crate::macho; + +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/vendor/object/src/read/macho/relocation.rs b/vendor/object/src/read/macho/relocation.rs new file mode 100644 index 0000000..709f1a4 --- /dev/null +++ b/vendor/object/src/read/macho/relocation.rs @@ -0,0 +1,158 @@ +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 for the relocations in a [`MachOSection32`](super::MachOSection32). +pub type MachORelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachORelocationIterator<'data, 'file, macho::MachHeader32<Endian>, R>; +/// An iterator for the relocations in a [`MachOSection64`](super::MachOSection64). +pub type MachORelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachORelocationIterator<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// An iterator for the relocations in a [`MachOSection`](super::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> { +        let mut paired_addend = 0; +        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, +                        (macho::ARM64_RELOC_ADDEND, _) => { +                            paired_addend = i64::from(reloc.r_symbolnum) +                                .wrapping_shl(64 - 24) +                                .wrapping_shr(64 - 24); +                            continue; +                        } +                        _ => 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 implicit_addend = paired_addend == 0; +            let mut addend = paired_addend; +            if reloc.r_pcrel { +                // For PC relative relocations on some architectures, the +                // addend does not include the offset required due to the +                // PC being different from the place of the relocation. +                // This differs from other file formats, so adjust the +                // addend here to account for this. +                match cputype { +                    macho::CPU_TYPE_X86 => { +                        addend -= 1 << reloc.r_length; +                    } +                    macho::CPU_TYPE_X86_64 => { +                        addend -= 1 << reloc.r_length; +                        match reloc.r_type { +                            macho::X86_64_RELOC_SIGNED_1 => addend -= 1, +                            macho::X86_64_RELOC_SIGNED_2 => addend -= 2, +                            macho::X86_64_RELOC_SIGNED_4 => addend -= 4, +                            _ => {} +                        } +                    } +                    // TODO: maybe missing support for some architectures and relocations +                    _ => {} +                } +            } +            return Some(( +                reloc.r_address as u64, +                Relocation { +                    kind, +                    encoding, +                    size, +                    target, +                    addend, +                    implicit_addend, +                }, +            )); +        } +    } +} + +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/vendor/object/src/read/macho/section.rs b/vendor/object/src/read/macho/section.rs new file mode 100644 index 0000000..7c79123 --- /dev/null +++ b/vendor/object/src/read/macho/section.rs @@ -0,0 +1,389 @@ +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 for the sections in a [`MachOFile32`](super::MachOFile32). +pub type MachOSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>; +/// An iterator for the sections in a [`MachOFile64`](super::MachOFile64). +pub type MachOSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// An iterator for the sections in 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 in a [`MachOFile32`](super::MachOFile32). +pub type MachOSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSection<'data, 'file, macho::MachHeader32<Endian>, R>; +/// A section in a [`MachOFile64`](super::MachOFile64). +pub type MachOSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSection<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// A section in a [`MachOFile`]. +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +#[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 [`macho::Section32`] and [`macho::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) => §name[..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/vendor/object/src/read/macho/segment.rs b/vendor/object/src/read/macho/segment.rs new file mode 100644 index 0000000..c889ad2 --- /dev/null +++ b/vendor/object/src/read/macho/segment.rs @@ -0,0 +1,303 @@ +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 for the segments in a [`MachOFile32`](super::MachOFile32). +pub type MachOSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSegmentIterator<'data, 'file, macho::MachHeader32<Endian>, R>; +/// An iterator for the segments in a [`MachOFile64`](super::MachOFile64). +pub type MachOSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSegmentIterator<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// An iterator for the segments in 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 in a [`MachOFile32`](super::MachOFile32). +pub type MachOSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSegment<'data, 'file, macho::MachHeader32<Endian>, R>; +/// A segment in a [`MachOFile64`](super::MachOFile64). +pub type MachOSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSegment<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// A segment in a [`MachOFile`]. +/// +/// Most functionality is provided by the [`ObjectSegment`] trait implementation. +#[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 [`macho::SegmentCommand32`] and [`macho::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/vendor/object/src/read/macho/symbol.rs b/vendor/object/src/read/macho/symbol.rs new file mode 100644 index 0000000..434361f --- /dev/null +++ b/vendor/object/src/read/macho/symbol.rs @@ -0,0 +1,492 @@ +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. +/// +/// Returned by [`macho::SymtabCommand::symbols`]. +#[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, +        } +    } +} + +/// A symbol table in a [`MachOFile32`](super::MachOFile32). +pub type MachOSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSymbolTable<'data, 'file, macho::MachHeader32<Endian>, R>; +/// A symbol table in a [`MachOFile64`](super::MachOFile64). +pub type MachOSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSymbolTable<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// A symbol table in 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 for the symbols in a [`MachOFile32`](super::MachOFile32). +pub type MachOSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSymbolIterator<'data, 'file, macho::MachHeader32<Endian>, R>; +/// An iterator for the symbols in a [`MachOFile64`](super::MachOFile64). +pub type MachOSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSymbolIterator<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// An iterator for the symbols in 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 in a [`MachOFile32`](super::MachOFile32). +pub type MachOSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSymbol<'data, 'file, macho::MachHeader32<Endian>, R>; +/// A symbol in a [`MachOFile64`](super::MachOFile64). +pub type MachOSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> = +    MachOSymbol<'data, 'file, macho::MachHeader64<Endian>, R>; + +/// A symbol in a [`MachOFile`]. +/// +/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. +#[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 [`macho::Nlist32`] and [`macho::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_SECT +    } + +    /// 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/vendor/object/src/read/mod.rs b/vendor/object/src/read/mod.rs new file mode 100644 index 0000000..c13e309 --- /dev/null +++ b/vendor/object/src/read/mod.rs @@ -0,0 +1,860 @@ +//! Interface for reading object files. +//! +//! ## Unified read API +//! +//! The [`Object`] trait provides a unified read API for accessing common features of +//! object files, such as sections and symbols. There is an implementation of this +//! trait for [`File`], which allows reading any file format, as well as implementations +//! for each file format: +//! [`ElfFile`](elf::ElfFile), [`MachOFile`](macho::MachOFile), [`CoffFile`](coff::CoffFile), +//! [`PeFile`](pe::PeFile), [`WasmFile`](wasm::WasmFile), [`XcoffFile`](xcoff::XcoffFile). +//! +//! ## Low level read API +//! +//! The submodules for each file format define helpers that operate on the raw structs. +//! These can be used instead of the unified API, or in conjunction with it to access +//! details that are not available via the unified API. +//! +//! See the [submodules](#modules) for examples of the low level read API. +//! +//! ## Naming Convention +//! +//! Types that form part of the unified API for a file format are prefixed with the +//! name of the file format. +//! +//! ## Example for unified read API +//!  ```no_run +//! use object::{Object, ObjectSection}; +//! use std::error::Error; +//! use std::fs; +//! +//! /// Reads a file and displays the name of each section. +//! fn main() -> Result<(), Box<dyn Error>> { +//! #   #[cfg(feature = "std")] { +//!     let data = fs::read("path/to/binary")?; +//!     let file = object::File::parse(&*data)?; +//!     for section in file.sections() { +//!         println!("{}", section.name()?); +//!     } +//! #   } +//!     Ok(()) +//! } +//! ``` + +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. +    /// +    /// See [`archive::ArchiveFile`]. +    #[cfg(feature = "archive")] +    Archive, +    /// A COFF object file. +    /// +    /// See [`coff::CoffFile`]. +    #[cfg(feature = "coff")] +    Coff, +    /// A COFF bigobj object file. +    /// +    /// This supports a larger number of sections. +    /// +    /// See [`coff::CoffBigFile`]. +    #[cfg(feature = "coff")] +    CoffBig, +    /// A Windows short import file. +    /// +    /// See [`coff::ImportFile`]. +    #[cfg(feature = "coff")] +    CoffImport, +    /// A dyld cache file containing Mach-O images. +    /// +    /// See [`macho::DyldCache`] +    #[cfg(feature = "macho")] +    DyldCache, +    /// A 32-bit ELF file. +    /// +    /// See [`elf::ElfFile32`]. +    #[cfg(feature = "elf")] +    Elf32, +    /// A 64-bit ELF file. +    /// +    /// See [`elf::ElfFile64`]. +    #[cfg(feature = "elf")] +    Elf64, +    /// A 32-bit Mach-O file. +    /// +    /// See [`macho::MachOFile32`]. +    #[cfg(feature = "macho")] +    MachO32, +    /// A 64-bit Mach-O file. +    /// +    /// See [`macho::MachOFile64`]. +    #[cfg(feature = "macho")] +    MachO64, +    /// A 32-bit Mach-O fat binary. +    /// +    /// See [`macho::FatHeader::parse_arch32`]. +    #[cfg(feature = "macho")] +    MachOFat32, +    /// A 64-bit Mach-O fat binary. +    /// +    /// See [`macho::FatHeader::parse_arch64`]. +    #[cfg(feature = "macho")] +    MachOFat64, +    /// A 32-bit PE file. +    /// +    /// See [`pe::PeFile32`]. +    #[cfg(feature = "pe")] +    Pe32, +    /// A 64-bit PE file. +    /// +    /// See [`pe::PeFile64`]. +    #[cfg(feature = "pe")] +    Pe64, +    /// A Wasm file. +    /// +    /// See [`wasm::WasmFile`]. +    #[cfg(feature = "wasm")] +    Wasm, +    /// A 32-bit XCOFF file. +    /// +    /// See [`xcoff::XcoffFile32`]. +    #[cfg(feature = "xcoff")] +    Xcoff32, +    /// A 64-bit XCOFF file. +    /// +    /// See [`xcoff::XcoffFile64`]. +    #[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 arm64ec +            | [0x41, 0xa6, ..] +            // 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. +/// +/// Returned by [`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 in a file. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SectionIndex(pub usize); + +/// The index used to identify a symbol in a symbol table. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SymbolIndex(pub usize); + +/// The section where an [`ObjectSymbol`] 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 symbol information. +/// +/// The symbol information depends on the chosen entry type, such as [`SymbolMapName`]. +/// +/// Returned by [`Object::symbol_map`]. +#[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_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 +    } +} + +/// The type used for entries in a [`SymbolMap`] that maps from addresses to 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. +/// +/// Returned by [`Object::object_map`]. +#[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 +    } +} + +/// An [`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. +/// +/// Returned by [`Object::imports`]. +#[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. +/// +/// Returned by [`Object::exports`]. +#[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 from the debug directory in a PE file. +#[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. +/// +/// Returned by [`Object::dynamic_relocations`] or [`ObjectSection::relocations`]. +#[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. +/// +/// Returned by [`ObjectSection::compressed_file_range`]. +#[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. +/// +/// Returned by [`ObjectSection::compressed_data`]. +#[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/vendor/object/src/read/pe/data_directory.rs b/vendor/object/src/read/pe/data_directory.rs new file mode 100644 index 0000000..a17179f --- /dev/null +++ b/vendor/object/src/read/pe/data_directory.rs @@ -0,0 +1,213 @@ +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. +/// +/// Returned by [`ImageNtHeaders::parse`](super::ImageNtHeaders::parse). +#[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/vendor/object/src/read/pe/export.rs b/vendor/object/src/read/pe/export.rs new file mode 100644 index 0000000..1aba844 --- /dev/null +++ b/vendor/object/src/read/pe/export.rs @@ -0,0 +1,333 @@ +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. +/// +/// Returned by [`DataDirectories::export_table`](super::DataDirectories::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/vendor/object/src/read/pe/file.rs b/vendor/object/src/read/pe/file.rs new file mode 100644 index 0000000..5372bdd --- /dev/null +++ b/vendor/object/src/read/pe/file.rs @@ -0,0 +1,1050 @@ +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, SubArchitecture, U32}; + +use super::{ +    DataDirectories, ExportTable, ImageThunkData, ImportTable, PeSection, PeSectionIterator, +    PeSegment, PeSegmentIterator, RichHeaderInfo, SectionTable, +}; + +/// A PE32 (32-bit) image file. +/// +/// This is a file that starts with [`pe::ImageNtHeaders32`], and corresponds +/// to [`crate::FileKind::Pe32`]. +pub type PeFile32<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders32, R>; +/// A PE32+ (64-bit) image file. +/// +/// This is a file that starts with [`pe::ImageNtHeaders64`], and corresponds +/// to [`crate::FileKind::Pe64`]. +pub type PeFile64<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders64, R>; + +/// A PE image file. +/// +/// Most functionality is provided by the [`Object`] trait implementation. +#[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 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, +            pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, +            pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, +            _ => Architecture::Unknown, +        } +    } + +    fn sub_architecture(&self) -> Option<SubArchitecture> { +        match self.nt_headers.file_header().machine.get(LE) { +            pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), +            _ => None, +        } +    } + +    #[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 for the COMDAT section groups in a [`PeFile32`]. +pub type PeComdatIterator32<'data, 'file, R = &'data [u8]> = +    PeComdatIterator<'data, 'file, pe::ImageNtHeaders32, R>; +/// An iterator for the COMDAT section groups in a [`PeFile64`]. +pub type PeComdatIterator64<'data, 'file, R = &'data [u8]> = +    PeComdatIterator<'data, 'file, pe::ImageNtHeaders64, R>; + +/// An iterator for the COMDAT section groups in a [`PeFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 in a [`PeFile32`]. +pub type PeComdat32<'data, 'file, R = &'data [u8]> = +    PeComdat<'data, 'file, pe::ImageNtHeaders32, R>; +/// A COMDAT section group in a [`PeFile64`]. +pub type PeComdat64<'data, 'file, R = &'data [u8]> = +    PeComdat<'data, 'file, pe::ImageNtHeaders64, R>; + +/// A COMDAT section group in a [`PeFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 for the sections in a COMDAT section group in a [`PeFile32`]. +pub type PeComdatSectionIterator32<'data, 'file, R = &'data [u8]> = +    PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>; +/// An iterator for the sections in a COMDAT section group in a [`PeFile64`]. +pub type PeComdatSectionIterator64<'data, 'file, R = &'data [u8]> = +    PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>; + +/// An iterator for the sections in a COMDAT section group in a [`PeFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 its `magic` field. +/// +/// 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 [`pe::ImageNtHeaders32`] and [`pe::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 [`pe::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 [`pe::ImageOptionalHeader32`] and [`pe::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/vendor/object/src/read/pe/import.rs b/vendor/object/src/read/pe/import.rs new file mode 100644 index 0000000..8e9a9a9 --- /dev/null +++ b/vendor/object/src/read/pe/import.rs @@ -0,0 +1,337 @@ +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. +/// +/// Returned by [`DataDirectories::import_table`](super::DataDirectories::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. +/// +/// Returned by +/// [`DataDirectories::delay_load_import_table`](super::DataDirectories::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/vendor/object/src/read/pe/mod.rs b/vendor/object/src/read/pe/mod.rs new file mode 100644 index 0000000..ab6011c --- /dev/null +++ b/vendor/object/src/read/pe/mod.rs @@ -0,0 +1,68 @@ +//! Support for reading PE files. +//! +//! Traits are used to abstract over the difference between PE32 and PE32+. +//! The primary trait for this is [`ImageNtHeaders`]. +//! +//! ## High level API +//! +//! [`PeFile`] implements the [`Object`](crate::read::Object) trait for +//! PE files. [`PeFile`] is parameterised by [`ImageNtHeaders`] to allow +//! reading both PE32 and PE32+. There are type aliases for these parameters +//! ([`PeFile32`] and [`PeFile64`]). +//! +//! ## Low level API +//! +//! The [`ImageNtHeaders`] trait can be directly used to parse both +//! [`pe::ImageNtHeaders32`] and [`pe::ImageNtHeaders64`]. +//! +//! ### Example for low level API +//!  ```no_run +//! use object::pe; +//! use object::read::pe::ImageNtHeaders; +//! use std::error::Error; +//! use std::fs; +//! +//! /// Reads a file and displays the name of each section. +//! fn main() -> Result<(), Box<dyn Error>> { +//! #   #[cfg(feature = "std")] { +//!     let data = fs::read("path/to/binary")?; +//!     let dos_header = pe::ImageDosHeader::parse(&*data)?; +//!     let mut offset = dos_header.nt_headers_offset().into(); +//!     let (nt_headers, data_directories) = pe::ImageNtHeaders64::parse(&*data, &mut offset)?; +//!     let sections = nt_headers.sections(&*data, offset)?; +//!     let symbols = nt_headers.symbols(&*data)?; +//!     for section in sections.iter() { +//!         println!("{}", String::from_utf8_lossy(section.name(symbols.strings())?)); +//!     } +//! #   } +//!     Ok(()) +//! } +//! ``` +#[cfg(doc)] +use crate::pe; + +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/vendor/object/src/read/pe/relocation.rs b/vendor/object/src/read/pe/relocation.rs new file mode 100644 index 0000000..77421b7 --- /dev/null +++ b/vendor/object/src/read/pe/relocation.rs @@ -0,0 +1,92 @@ +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. +/// +/// Returned by [`DataDirectories::relocation_blocks`](super::DataDirectories::relocation_blocks). +#[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/vendor/object/src/read/pe/resource.rs b/vendor/object/src/read/pe/resource.rs new file mode 100644 index 0000000..331da3f --- /dev/null +++ b/vendor/object/src/read/pe/resource.rs @@ -0,0 +1,209 @@ +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. +/// +/// Returned by [`DataDirectories::resource_directory`](super::DataDirectories::resource_directory). +#[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/vendor/object/src/read/pe/rich.rs b/vendor/object/src/read/pe/rich.rs new file mode 100644 index 0000000..33dd039 --- /dev/null +++ b/vendor/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/vendor/object/src/read/pe/section.rs b/vendor/object/src/read/pe/section.rs new file mode 100644 index 0000000..74c9d7f --- /dev/null +++ b/vendor/object/src/read/pe/section.rs @@ -0,0 +1,440 @@ +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 for the loadable sections in a [`PeFile32`](super::PeFile32). +pub type PeSegmentIterator32<'data, 'file, R = &'data [u8]> = +    PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32, R>; +/// An iterator for the loadable sections in a [`PeFile64`](super::PeFile64). +pub type PeSegmentIterator64<'data, 'file, R = &'data [u8]> = +    PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64, R>; + +/// An iterator for the loadable sections in 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 in a [`PeFile32`](super::PeFile32). +pub type PeSegment32<'data, 'file, R = &'data [u8]> = +    PeSegment<'data, 'file, pe::ImageNtHeaders32, R>; +/// A loadable section in a [`PeFile64`](super::PeFile64). +pub type PeSegment64<'data, 'file, R = &'data [u8]> = +    PeSegment<'data, 'file, pe::ImageNtHeaders64, R>; + +/// A loadable section in a [`PeFile`]. +/// +/// Most functionality is provided by the [`ObjectSegment`] trait implementation. +#[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 for the sections in a [`PeFile32`](super::PeFile32). +pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> = +    PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>; +/// An iterator for the sections in a [`PeFile64`](super::PeFile64). +pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> = +    PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>; + +/// An iterator for the sections in 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 in a [`PeFile32`](super::PeFile32). +pub type PeSection32<'data, 'file, R = &'data [u8]> = +    PeSection<'data, 'file, pe::ImageNtHeaders32, R>; +/// A section in a [`PeFile64`](super::PeFile64). +pub type PeSection64<'data, 'file, R = &'data [u8]> = +    PeSection<'data, 'file, pe::ImageNtHeaders64, R>; + +/// A section in a [`PeFile`]. +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +#[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 for the relocations in an [`PeSection`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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/vendor/object/src/read/read_cache.rs b/vendor/object/src/read/read_cache.rs new file mode 100644 index 0000000..d1377f1 --- /dev/null +++ b/vendor/object/src/read/read_cache.rs @@ -0,0 +1,178 @@ +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 +    } +} + +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/vendor/object/src/read/read_ref.rs b/vendor/object/src/read/read_ref.rs new file mode 100644 index 0000000..8b87cba --- /dev/null +++ b/vendor/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/vendor/object/src/read/traits.rs b/vendor/object/src/read/traits.rs new file mode 100644 index 0000000..67105d3 --- /dev/null +++ b/vendor/object/src/read/traits.rs @@ -0,0 +1,551 @@ +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, SubArchitecture, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, +    SymbolMapName, SymbolScope, SymbolSection, +}; +use crate::Endianness; + +/// An object file. +/// +/// This is the primary trait for the unified read API. +pub trait Object<'data: 'file, 'file>: read::private::Sealed { +    /// A loadable segment in the object file. +    type Segment: ObjectSegment<'data>; + +    /// An iterator for the loadable segments in the object file. +    type SegmentIterator: Iterator<Item = Self::Segment>; + +    /// A section in the object file. +    type Section: ObjectSection<'data>; + +    /// An iterator for 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 for 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 for 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 for the 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 sub-architecture type of the file if known. +    /// +    /// A value of `None` has a range of meanings: the file supports all +    /// sub-architectures, the file does not explicitly specify a +    /// sub-architecture, or the sub-architecture is currently unrecognized. +    fn sub_architecture(&self) -> Option<SubArchitecture> { +        None +    } + +    /// 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 for the loadable segments in the file. +    /// +    /// For ELF, this is program headers with type [`PT_LOAD`](crate::elf::PT_LOAD). +    /// For Mach-O, this is load commands with type [`LC_SEGMENT`](crate::macho::LC_SEGMENT) +    /// or [`LC_SEGMENT_64`](crate::macho::LC_SEGMENT_64). +    /// For PE, this is all sections. +    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 for the sections in the file. +    fn sections(&'file self) -> Self::SectionIterator; + +    /// Get an iterator for the COMDAT section groups in the file. +    fn comdats(&'file self) -> Self::ComdatIterator; + +    /// Get the debugging 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 for 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 symbol named `symbol_name`, if the symbol exists. +    fn symbol_by_name(&'file self, symbol_name: &str) -> Option<Self::Symbol> { +        self.symbol_by_name_bytes(symbol_name.as_bytes()) +    } + +    /// Like [`Self::symbol_by_name`], but allows names that are not UTF-8. +    fn symbol_by_name_bytes(&'file self, symbol_name: &[u8]) -> Option<Self::Symbol> { +        self.symbols() +            .find(|sym| sym.name_bytes() == Ok(symbol_name)) +    } + +    /// Get the dynamic linking symbol table, if any. +    /// +    /// Only ELF has a separate dynamic linking symbol table. +    /// Consider using [`Self::exports`] or [`Self::imports`] instead. +    fn dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>; + +    /// Get an iterator for the dynamic linking symbols in the file. +    /// +    /// This may skip over symbols that are malformed or unsupported. +    /// +    /// Only ELF has dynamic linking symbols. +    /// Other file formats will return an empty iterator. +    /// Consider using [`Self::exports`] or [`Self::imports`] instead. +    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()) { +            // Sometimes symbols share addresses. Collect them all then choose the "best". +            let mut all_symbols = Vec::new(); +            for symbol in table.symbols() { +                // Must have an address. +                if !symbol.is_definition() { +                    continue; +                } +                // Must have a name. +                let name = match symbol.name() { +                    Ok(name) => name, +                    _ => continue, +                }; +                if name.is_empty() { +                    continue; +                } + +                // Lower is better. +                let mut priority = 0u32; + +                // Prefer known kind. +                match symbol.kind() { +                    SymbolKind::Text | SymbolKind::Data => {} +                    SymbolKind::Unknown => priority += 1, +                    _ => continue, +                } +                priority *= 2; + +                // Prefer global visibility. +                priority += match symbol.scope() { +                    SymbolScope::Unknown => 3, +                    SymbolScope::Compilation => 2, +                    SymbolScope::Linkage => 1, +                    SymbolScope::Dynamic => 0, +                }; +                priority *= 4; + +                // Prefer later entries (earlier symbol is likely to be less specific). +                let index = !0 - symbol.index().0; + +                // Tuple is ordered for sort. +                all_symbols.push((symbol.address(), priority, index, name)); +            } +            // Unstable sort is okay because tuple includes index. +            all_symbols.sort_unstable(); + +            let mut previous_address = !0; +            for (address, _priority, _index, name) in all_symbols { +                if address != previous_address { +                    symbols.push(SymbolMapName::new(address, name)); +                    previous_address = address; +                } +            } +        } +        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 low level API. +    fn exports(&self) -> Result<Vec<Export<'data>>>; + +    /// Return true if the file contains DWARF debug information sections, false if not. +    fn has_debug_symbols(&self) -> bool; + +    /// The UUID from a Mach-O [`LC_UUID`](crate::macho::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`](crate::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 in an [`Object`]. +/// +/// This trait is part of the unified read API. +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 in an [`Object`]. +/// +/// This trait is part of the unified read API. +pub trait ObjectSection<'data>: read::private::Sealed { +    /// An iterator for 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 in an [`Object`]. +/// +/// This trait is part of the unified read API. +pub trait ObjectComdat<'data>: read::private::Sealed { +    /// An iterator for the sections in the section group. +    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 in an [`Object`]. +/// +/// This trait is part of the unified read API. +pub trait ObjectSymbolTable<'data>: read::private::Sealed { +    /// A symbol table entry. +    type Symbol: ObjectSymbol<'data>; + +    /// An iterator for the symbols in a symbol table. +    type SymbolIterator: Iterator<Item = Self::Symbol>; + +    /// Get an iterator for 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 in an [`Object`]. +/// +/// This trait is part of the unified read API. +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. +    /// +    /// This is primarily used to implement [`Object::symbol_map`]. +    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/vendor/object/src/read/util.rs b/vendor/object/src/read/util.rs new file mode 100644 index 0000000..7d85b27 --- /dev/null +++ b/vendor/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 by most file formats for strings such as section names and symbol names. +#[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/vendor/object/src/read/wasm.rs b/vendor/object/src/read/wasm.rs new file mode 100644 index 0000000..4d034bc --- /dev/null +++ b/vendor/object/src/read/wasm.rs @@ -0,0 +1,966 @@ +//! Support for reading Wasm files. +//! +//! [`WasmFile`] implements the [`Object`] trait for Wasm files. +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 for the segments in a [`WasmFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 in a [`WasmFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 for the sections in 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 in a [`WasmFile`]. +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +#[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 for the COMDAT section groups in a [`WasmFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 in a [`WasmFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 for the sections in a COMDAT section group in a [`WasmFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 in 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 for the symbols in 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 in a [`WasmFile`]. +/// +/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. +#[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.kind == SymbolKind::Data) +            && 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 for the relocations for a [`WasmSection`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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/vendor/object/src/read/xcoff/comdat.rs b/vendor/object/src/read/xcoff/comdat.rs new file mode 100644 index 0000000..03e52bf --- /dev/null +++ b/vendor/object/src/read/xcoff/comdat.rs @@ -0,0 +1,135 @@ +//! 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 for the COMDAT section groups in a [`XcoffFile32`](super::XcoffFile32). +pub type XcoffComdatIterator32<'data, 'file, R = &'data [u8]> = +    XcoffComdatIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator for the COMDAT section groups in a [`XcoffFile64`](super::XcoffFile64). +pub type XcoffComdatIterator64<'data, 'file, R = &'data [u8]> = +    XcoffComdatIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator for the COMDAT section groups in a [`XcoffFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 in a [`XcoffFile32`](super::XcoffFile32). +pub type XcoffComdat32<'data, 'file, R = &'data [u8]> = +    XcoffComdat<'data, 'file, xcoff::FileHeader32, R>; + +/// A COMDAT section group in a [`XcoffFile64`](super::XcoffFile64). +pub type XcoffComdat64<'data, 'file, R = &'data [u8]> = +    XcoffComdat<'data, 'file, xcoff::FileHeader64, R>; + +/// A COMDAT section group in a [`XcoffFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 for the sections in a COMDAT section group in a [`XcoffFile32`](super::XcoffFile32). +pub type XcoffComdatSectionIterator32<'data, 'file, R = &'data [u8]> = +    XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator for the sections in a COMDAT section group in a [`XcoffFile64`](super::XcoffFile64). +pub type XcoffComdatSectionIterator64<'data, 'file, R = &'data [u8]> = +    XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator for the sections in a COMDAT section group in a [`XcoffFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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/vendor/object/src/read/xcoff/file.rs b/vendor/object/src/read/xcoff/file.rs new file mode 100644 index 0000000..70d980a --- /dev/null +++ b/vendor/object/src/read/xcoff/file.rs @@ -0,0 +1,696 @@ +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. +/// +/// This is a file that starts with [`xcoff::FileHeader32`], and corresponds +/// to [`crate::FileKind::Xcoff32`]. +pub type XcoffFile32<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader32, R>; +/// A 64-bit XCOFF object file. +/// +/// This is a file that starts with [`xcoff::FileHeader64`], and corresponds +/// to [`crate::FileKind::Xcoff64`]. +pub type XcoffFile64<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader64, R>; + +/// A partially parsed XCOFF file. +/// +/// Most functionality 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 { +            file: self, +            symbols: self.symbols.iter(), +        } +    } + +    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.iter_none(), +        } +    } + +    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 [`xcoff::FileHeader32`] and [`xcoff::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) +    } +} + +/// A trait for generic access to [`xcoff::AuxHeader32`] and [`xcoff::AuxHeader64`]. +#[allow(missing_docs)] +pub trait AuxHeader: Debug + Pod { +    type Word: Into<u64>; + +    fn o_mflag(&self) -> u16; +    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_algntext(&self) -> u16; +    fn o_algndata(&self) -> u16; +    fn o_modtype(&self) -> u16; +    fn o_cpuflag(&self) -> u8; +    fn o_cputype(&self) -> u8; +    fn o_maxstack(&self) -> Self::Word; +    fn o_maxdata(&self) -> Self::Word; +    fn o_debugger(&self) -> u32; +    fn o_textpsize(&self) -> u8; +    fn o_datapsize(&self) -> u8; +    fn o_stackpsize(&self) -> u8; +    fn o_flags(&self) -> u8; +    fn o_sntdata(&self) -> u16; +    fn o_sntbss(&self) -> u16; +    fn o_x64flags(&self) -> Option<u16>; +} + +impl AuxHeader for xcoff::AuxHeader32 { +    type Word = u32; + +    fn o_mflag(&self) -> u16 { +        self.o_mflag.get(BE) +    } + +    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_algntext(&self) -> u16 { +        self.o_algntext.get(BE) +    } + +    fn o_algndata(&self) -> u16 { +        self.o_algndata.get(BE) +    } + +    fn o_modtype(&self) -> u16 { +        self.o_modtype.get(BE) +    } + +    fn o_cpuflag(&self) -> u8 { +        self.o_cpuflag +    } + +    fn o_cputype(&self) -> u8 { +        self.o_cputype +    } + +    fn o_maxstack(&self) -> Self::Word { +        self.o_maxstack.get(BE) +    } + +    fn o_maxdata(&self) -> Self::Word { +        self.o_maxdata.get(BE) +    } + +    fn o_debugger(&self) -> u32 { +        self.o_debugger.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 +    } + +    fn o_flags(&self) -> u8 { +        self.o_flags +    } + +    fn o_sntdata(&self) -> u16 { +        self.o_sntdata.get(BE) +    } + +    fn o_sntbss(&self) -> u16 { +        self.o_sntbss.get(BE) +    } + +    fn o_x64flags(&self) -> Option<u16> { +        None +    } +} + +impl AuxHeader for xcoff::AuxHeader64 { +    type Word = u64; + +    fn o_mflag(&self) -> u16 { +        self.o_mflag.get(BE) +    } + +    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_algntext(&self) -> u16 { +        self.o_algntext.get(BE) +    } + +    fn o_algndata(&self) -> u16 { +        self.o_algndata.get(BE) +    } + +    fn o_modtype(&self) -> u16 { +        self.o_modtype.get(BE) +    } + +    fn o_cpuflag(&self) -> u8 { +        self.o_cpuflag +    } + +    fn o_cputype(&self) -> u8 { +        self.o_cputype +    } + +    fn o_maxstack(&self) -> Self::Word { +        self.o_maxstack.get(BE) +    } + +    fn o_maxdata(&self) -> Self::Word { +        self.o_maxdata.get(BE) +    } + +    fn o_debugger(&self) -> u32 { +        self.o_debugger.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 +    } + +    fn o_flags(&self) -> u8 { +        self.o_flags +    } + +    fn o_sntdata(&self) -> u16 { +        self.o_sntdata.get(BE) +    } + +    fn o_sntbss(&self) -> u16 { +        self.o_sntbss.get(BE) +    } + +    fn o_x64flags(&self) -> Option<u16> { +        Some(self.o_x64flags.get(BE)) +    } +} diff --git a/vendor/object/src/read/xcoff/mod.rs b/vendor/object/src/read/xcoff/mod.rs new file mode 100644 index 0000000..b75c4da --- /dev/null +++ b/vendor/object/src/read/xcoff/mod.rs @@ -0,0 +1,63 @@ +//! Support for reading AIX XCOFF files. +//! +//! Traits are used to abstract over the difference between 32-bit and 64-bit XCOFF. +//! The primary trait for this is [`FileHeader`]. +//! +//! ## High level API +//! +//! [`XcoffFile`] implements the [`Object`](crate::read::Object) trait for XCOFF files. +//! [`XcoffFile`] is parameterised by [`FileHeader`] to allow reading both 32-bit and +//! 64-bit XCOFF. There are type aliases for these parameters ([`XcoffFile32`] and +//! [`XcoffFile64`]). +//! +//! ## Low level API +//! +//! The [`FileHeader`] trait can be directly used to parse both [`xcoff::FileHeader32`] +//! and [`xcoff::FileHeader64`]. +//! +//! ### Example for low level API +//!  ```no_run +//! use object::xcoff; +//! use object::read::xcoff::{FileHeader, SectionHeader, Symbol}; +//! use std::error::Error; +//! use std::fs; +//! +//! /// Reads a file and displays the name of each section and symbol. +//! fn main() -> Result<(), Box<dyn Error>> { +//! #   #[cfg(feature = "std")] { +//!     let data = fs::read("path/to/binary")?; +//!     let mut offset = 0; +//!     let header = xcoff::FileHeader64::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)?; +//!     for section in sections.iter() { +//!         println!("{}", String::from_utf8_lossy(section.name())); +//!     } +//!     for (_index, symbol) in symbols.iter() { +//!         println!("{}", String::from_utf8_lossy(symbol.name(symbols.strings())?)); +//!     } +//! #   } +//!     Ok(()) +//! } +//! ``` +#[cfg(doc)] +use crate::xcoff; + +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/vendor/object/src/read/xcoff/relocation.rs b/vendor/object/src/read/xcoff/relocation.rs new file mode 100644 index 0000000..a655ccc --- /dev/null +++ b/vendor/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 for the relocations in an [`XcoffSection32`](super::XcoffSection32). +pub type XcoffRelocationIterator32<'data, 'file, R = &'data [u8]> = +    XcoffRelocationIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator for the relocations in an [`XcoffSection64`](super::XcoffSection64). +pub type XcoffRelocationIterator64<'data, 'file, R = &'data [u8]> = +    XcoffRelocationIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator for the relocations in an [`XcoffSection`](super::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 [`xcoff::Rel32`] and [`xcoff::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/vendor/object/src/read/xcoff/section.rs b/vendor/object/src/read/xcoff/section.rs new file mode 100644 index 0000000..8a36bcf --- /dev/null +++ b/vendor/object/src/read/xcoff/section.rs @@ -0,0 +1,431 @@ +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 for the sections in an [`XcoffFile32`](super::XcoffFile32). +pub type XcoffSectionIterator32<'data, 'file, R = &'data [u8]> = +    XcoffSectionIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator for the sections in an [`XcoffFile64`](super::XcoffFile64). +pub type XcoffSectionIterator64<'data, 'file, R = &'data [u8]> = +    XcoffSectionIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator for the sections in 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 in an [`XcoffFile32`](super::XcoffFile32). +pub type XcoffSection32<'data, 'file, R = &'data [u8]> = +    XcoffSection<'data, 'file, xcoff::FileHeader32, R>; +/// A section in an [`XcoffFile64`](super::XcoffFile64). +pub type XcoffSection64<'data, 'file, R = &'data [u8]> = +    XcoffSection<'data, 'file, xcoff::FileHeader64, R>; + +/// A section in an [`XcoffFile`]. +/// +/// Most functionality is provided by the [`ObjectSection`] trait implementation. +#[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. +/// +/// Returned by [`FileHeader::sections`]. +#[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 [`xcoff::SectionHeader32`] and [`xcoff::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) => §name[..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/vendor/object/src/read/xcoff/segment.rs b/vendor/object/src/read/xcoff/segment.rs new file mode 100644 index 0000000..d30d7d8 --- /dev/null +++ b/vendor/object/src/read/xcoff/segment.rs @@ -0,0 +1,117 @@ +//! 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 for the segments in an [`XcoffFile32`](super::XcoffFile32). +pub type XcoffSegmentIterator32<'data, 'file, R = &'data [u8]> = +    XcoffSegmentIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator for the segments in an [`XcoffFile64`](super::XcoffFile64). +pub type XcoffSegmentIterator64<'data, 'file, R = &'data [u8]> = +    XcoffSegmentIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator for the segments in an [`XcoffFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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 in an [`XcoffFile32`](super::XcoffFile32). +pub type XcoffSegment32<'data, 'file, R = &'data [u8]> = +    XcoffSegment<'data, 'file, xcoff::FileHeader32, R>; +/// A segment in an [`XcoffFile64`](super::XcoffFile64). +pub type XcoffSegment64<'data, 'file, R = &'data [u8]> = +    XcoffSegment<'data, 'file, xcoff::FileHeader64, R>; + +/// A loadable section in an [`XcoffFile`]. +/// +/// This is a stub that doesn't implement any functionality. +#[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/vendor/object/src/read/xcoff/symbol.rs b/vendor/object/src/read/xcoff/symbol.rs new file mode 100644 index 0000000..72651c3 --- /dev/null +++ b/vendor/object/src/read/xcoff/symbol.rs @@ -0,0 +1,786 @@ +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. +/// +/// Returned by [`FileHeader::symbols`]. +#[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 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<'table>(&'table self) -> SymbolIterator<'data, 'table, Xcoff, R> { +        SymbolIterator { +            symbols: self, +            index: 0, +        } +    } + +    /// Empty symbol iterator. +    #[inline] +    pub(super) fn iter_none<'table>(&'table self) -> SymbolIterator<'data, 'table, Xcoff, R> { +        SymbolIterator { +            symbols: self, +            index: self.symbols.len(), +        } +    } + +    /// 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() +    } +} + +/// An iterator for symbol entries in an XCOFF file. +/// +/// Yields the index and symbol structure for each symbol. +#[derive(Debug)] +pub struct SymbolIterator<'data, 'table, Xcoff, R = &'data [u8]> +where +    Xcoff: FileHeader, +    R: ReadRef<'data>, +{ +    symbols: &'table SymbolTable<'data, Xcoff, R>, +    index: usize, +} + +impl<'data, 'table, Xcoff: FileHeader, R: ReadRef<'data>> Iterator +    for SymbolIterator<'data, 'table, Xcoff, R> +{ +    type Item = (SymbolIndex, &'data Xcoff::Symbol); + +    fn next(&mut self) -> Option<Self::Item> { +        let index = self.index; +        let symbol = self.symbols.symbol(index).ok()?; +        self.index += 1 + symbol.n_numaux() as usize; +        Some((SymbolIndex(index), symbol)) +    } +} + +/// A symbol table in an [`XcoffFile32`](super::XcoffFile32). +pub type XcoffSymbolTable32<'data, 'file, R = &'data [u8]> = +    XcoffSymbolTable<'data, 'file, xcoff::FileHeader32, R>; +/// A symbol table in an [`XcoffFile64`](super::XcoffFile64). +pub type XcoffSymbolTable64<'data, 'file, R = &'data [u8]> = +    XcoffSymbolTable<'data, 'file, xcoff::FileHeader64, R>; + +/// A symbol table in an [`XcoffFile`]. +#[derive(Debug, Clone, Copy)] +pub struct XcoffSymbolTable<'data, 'file, Xcoff, R = &'data [u8]> +where +    Xcoff: FileHeader, +    R: ReadRef<'data>, +{ +    pub(super) 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.iter(), +        } +    } + +    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 for the symbols in an [`XcoffFile32`](super::XcoffFile32). +pub type XcoffSymbolIterator32<'data, 'file, R = &'data [u8]> = +    XcoffSymbolIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator for the symbols in an [`XcoffFile64`](super::XcoffFile64). +pub type XcoffSymbolIterator64<'data, 'file, R = &'data [u8]> = +    XcoffSymbolIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator for the symbols in an [`XcoffFile`]. +pub struct XcoffSymbolIterator<'data, 'file, Xcoff, R = &'data [u8]> +where +    Xcoff: FileHeader, +    R: ReadRef<'data>, +{ +    pub(super) file: &'file XcoffFile<'data, Xcoff, R>, +    pub(super) symbols: SymbolIterator<'data, 'file, Xcoff, R>, +} + +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, symbol) = self.symbols.next()?; +        Some(XcoffSymbol { +            file: self.file, +            symbols: self.symbols.symbols, +            index, +            symbol, +        }) +    } +} + +/// A symbol in an [`XcoffFile32`](super::XcoffFile32). +pub type XcoffSymbol32<'data, 'file, R = &'data [u8]> = +    XcoffSymbol<'data, 'file, xcoff::FileHeader32, R>; +/// A symbol in an [`XcoffFile64`](super::XcoffFile64). +pub type XcoffSymbol64<'data, 'file, R = &'data [u8]> = +    XcoffSymbol<'data, 'file, xcoff::FileHeader64, R>; + +/// A symbol in an [`XcoffFile`]. +/// +/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. +#[derive(Debug, Clone, Copy)] +pub struct XcoffSymbol<'data, 'file, Xcoff, R = &'data [u8]> +where +    Xcoff: FileHeader, +    R: ReadRef<'data>, +{ +    pub(super) 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(); +                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(); +                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.n_scnum() <= 0 { +            return false; +        } +        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 sym_type = aux_csect.sym_type(); +                sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_LD || sym_type == xcoff::XTY_CM +            } 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 => { +                    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 aux_csect.sym_type() == 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 [`xcoff::Symbol32`] and [`xcoff::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_offset(&self) -> Option<u32>; +    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 +    } + +    fn name_offset(&self) -> Option<u32> { +        Some(self.n_offset.get(BE)) +    } + +    /// 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 +    } + +    fn name_offset(&self) -> Option<u32> { +        if self.n_name[0] == 0 { +            let offset = u32::from_be_bytes(self.n_name[4..8].try_into().unwrap()); +            Some(offset) +        } else { +            None +        } +    } + +    /// Parse the symbol name for XCOFF32. +    fn name<'data, R: ReadRef<'data>>( +        &'data self, +        strings: StringTable<'data, R>, +    ) -> Result<&'data [u8]> { +        if let Some(offset) = self.name_offset() { +            // If the name starts with 0 then the last 4 bytes are a string table offset. +            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 [`xcoff::FileAux32`] and [`xcoff::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>; + +    fn name_offset(&self) -> Option<u32> { +        let x_fname = self.x_fname(); +        if x_fname[0] == 0 { +            Some(u32::from_be_bytes(x_fname[4..8].try_into().unwrap())) +        } else { +            None +        } +    } + +    /// 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]> { +        if let Some(offset) = self.name_offset() { +            // If the name starts with 0 then the last 4 bytes are a string table offset. +            strings +                .get(offset) +                .read_error("Invalid XCOFF symbol name offset") +        } else { +            // The name is inline and padded with nulls. +            let x_fname = self.x_fname(); +            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 [`xcoff::CsectAux32`] and [`xcoff::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_stab(&self) -> Option<u32>; +    fn x_snstab(&self) -> Option<u16>; +    fn x_auxtype(&self) -> Option<u8>; + +    fn alignment(&self) -> u8 { +        self.x_smtyp() >> 3 +    } +    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_stab(&self) -> Option<u32> { +        None +    } + +    fn x_snstab(&self) -> Option<u16> { +        None +    } + +    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_stab(&self) -> Option<u32> { +        Some(self.x_stab.get(BE)) +    } + +    fn x_snstab(&self) -> Option<u16> { +        Some(self.x_snstab.get(BE)) +    } + +    fn x_auxtype(&self) -> Option<u8> { +        None +    } +} diff --git a/vendor/object/src/write/coff/mod.rs b/vendor/object/src/write/coff/mod.rs new file mode 100644 index 0000000..6e0f5ed --- /dev/null +++ b/vendor/object/src/write/coff/mod.rs @@ -0,0 +1,10 @@ +//! Support for writing COFF files. +//! +//! Provides [`Writer`] for low level writing of COFF files. +//! This is also used to provide COFF support for [`write::Object`](crate::write::Object). + +mod object; +pub use self::object::*; + +mod writer; +pub use writer::*; diff --git a/vendor/object/src/write/coff/object.rs b/vendor/object/src/write/coff/object.rs new file mode 100644 index 0000000..5229665 --- /dev/null +++ b/vendor/object/src/write/coff/object.rs @@ -0,0 +1,583 @@ +use alloc::vec::Vec; + +use crate::pe as coff; +use crate::write::coff::writer; +use crate::write::util::*; +use crate::write::*; + +#[derive(Default, Clone, Copy)] +struct SectionOffsets { +    name: writer::Name, +    offset: u32, +    reloc_offset: u32, +    selection: u8, +    associative_section: u32, +} + +#[derive(Default, Clone, Copy)] +struct SymbolOffsets { +    name: writer::Name, +    index: u32, +    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, 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<()> { +        let mut writer = writer::Writer::new(buffer); + +        // Add section strings to strtab. +        let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; +        for (index, section) in self.sections.iter().enumerate() { +            section_offsets[index].name = writer.add_name(§ion.name); +        } + +        // 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 u32 + 1; +                } +            } +        } + +        // Reserve symbol indices and add symbol strings to strtab. +        let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; +        for (index, symbol) in self.symbols.iter().enumerate() { +            symbol_offsets[index].index = writer.reserve_symbol_index(); +            let mut name = &*symbol.name; +            match symbol.kind { +                SymbolKind::File => { +                    // Name goes in auxiliary symbol records. +                    symbol_offsets[index].aux_count = writer.reserve_aux_file_name(&symbol.name); +                    name = b".file"; +                } +                SymbolKind::Section if symbol.section.id().is_some() => { +                    symbol_offsets[index].aux_count = writer.reserve_aux_section(); +                } +                _ => {} +            }; +            symbol_offsets[index].name = writer.add_name(name); +        } + +        // Reserve file ranges. +        writer.reserve_file_header(); +        writer.reserve_section_headers(self.sections.len() as u16); +        for (index, section) in self.sections.iter().enumerate() { +            section_offsets[index].offset = writer.reserve_section(section.data.len()); +            section_offsets[index].reloc_offset = +                writer.reserve_relocations(section.relocations.len()); +        } +        writer.reserve_symtab_strtab(); + +        // Start writing. +        writer.write_file_header(writer::FileHeader { +            machine: match (self.architecture, self.sub_architecture) { +                (Architecture::Arm, None) => coff::IMAGE_FILE_MACHINE_ARMNT, +                (Architecture::Aarch64, None) => coff::IMAGE_FILE_MACHINE_ARM64, +                (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)) => { +                    coff::IMAGE_FILE_MACHINE_ARM64EC +                } +                (Architecture::I386, None) => coff::IMAGE_FILE_MACHINE_I386, +                (Architecture::X86_64, None) => coff::IMAGE_FILE_MACHINE_AMD64, +                _ => { +                    return Err(Error(format!( +                        "unimplemented architecture {:?} with sub-architecture {:?}", +                        self.architecture, self.sub_architecture +                    ))); +                } +            }, +            time_date_stamp: 0, +            characteristics: match self.flags { +                FileFlags::Coff { characteristics } => characteristics, +                _ => 0, +            }, +        })?; + +        // 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 +                    ))); +                } +            }; +            writer.write_section_header(writer::SectionHeader { +                name: section_offsets[index].name, +                size_of_raw_data: section.size as u32, +                pointer_to_raw_data: section_offsets[index].offset, +                pointer_to_relocations: section_offsets[index].reloc_offset, +                pointer_to_linenumbers: 0, +                number_of_relocations: section.relocations.len() as u32, +                number_of_linenumbers: 0, +                characteristics, +            }); +        } + +        // Write section data and relocations. +        for section in &self.sections { +            writer.write_section(§ion.data); + +            if !section.relocations.is_empty() { +                //debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); +                writer.write_relocations_count(section.relocations.len()); +                for reloc in §ion.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 +                            ))); +                        } +                    }; +                    writer.write_relocation(writer::Relocation { +                        virtual_address: reloc.offset as u32, +                        symbol: symbol_offsets[reloc.symbol.0].index, +                        typ, +                    }); +                } +            } +        } + +        // Write symbols. +        for (index, symbol) in self.symbols.iter().enumerate() { +            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 => coff::IMAGE_SYM_CLASS_FILE, +                SymbolKind::Section => { +                    if symbol.section.id().is_some() { +                        coff::IMAGE_SYM_CLASS_STATIC +                    } else { +                        coff::IMAGE_SYM_CLASS_SECTION +                    } +                } +                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 +            }; +            writer.write_symbol(writer::Symbol { +                name: symbol_offsets[index].name, +                value, +                section_number, +                typ, +                storage_class, +                number_of_aux_symbols, +            }); + +            // Write auxiliary symbols. +            match symbol.kind { +                SymbolKind::File => { +                    writer.write_aux_file_name(&symbol.name, number_of_aux_symbols); +                } +                SymbolKind::Section if symbol.section.id().is_some() => { +                    debug_assert_eq!(number_of_aux_symbols, 1); +                    let section_index = symbol.section.id().unwrap().0; +                    let section = &self.sections[section_index]; +                    writer.write_aux_section(writer::AuxSymbolSection { +                        length: section.size as u32, +                        number_of_relocations: section.relocations.len() as u32, +                        number_of_linenumbers: 0, +                        check_sum: checksum(section.data()), +                        number: section_offsets[section_index].associative_section, +                        selection: section_offsets[section_index].selection, +                    }); +                } +                _ => { +                    debug_assert_eq!(number_of_aux_symbols, 0); +                } +            } +        } + +        writer.write_strtab(); + +        debug_assert_eq!(writer.reserved_len(), writer.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/vendor/object/src/write/coff/writer.rs b/vendor/object/src/write/coff/writer.rs new file mode 100644 index 0000000..8c7ada3 --- /dev/null +++ b/vendor/object/src/write/coff/writer.rs @@ -0,0 +1,518 @@ +//! Helper for writing COFF files. +use alloc::string::String; +use alloc::vec::Vec; +use core::mem; + +use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32}; +use crate::pe; +use crate::write::string::{StringId, StringTable}; +use crate::write::util; +use crate::write::{Error, Result, WritableBuffer}; + +/// A helper for writing COFF 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 table +/// - 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 the string table before reserving the file range for the string table. 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> { +    buffer: &'a mut dyn WritableBuffer, +    len: usize, + +    section_num: u16, + +    symtab_offset: u32, +    symtab_num: u32, + +    strtab: StringTable<'a>, +    strtab_len: usize, +    strtab_offset: u32, +    strtab_data: Vec<u8>, +} + +impl<'a> Writer<'a> { +    /// Create a new `Writer`. +    pub fn new(buffer: &'a mut dyn WritableBuffer) -> Self { +        Writer { +            buffer, +            len: 0, + +            section_num: 0, + +            symtab_offset: 0, +            symtab_num: 0, + +            strtab: StringTable::default(), +            strtab_len: 0, +            strtab_offset: 0, +            strtab_data: Vec::new(), +        } +    } + +    /// 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) -> u32 { +        if align_start > 1 { +            self.len = util::align(self.len, align_start); +        } +        let offset = self.len; +        self.len += len; +        offset as u32 +    } + +    /// 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. +    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); +    } + +    /// 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(mem::size_of::<pe::ImageFileHeader>(), 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); + +        // Start writing. +        self.buffer +            .reserve(self.len) +            .map_err(|_| Error(String::from("Cannot allocate buffer")))?; + +        // Write file header. +        let header = pe::ImageFileHeader { +            machine: U16::new(LE, header.machine), +            number_of_sections: U16::new(LE, self.section_num), +            time_date_stamp: U32::new(LE, header.time_date_stamp), +            pointer_to_symbol_table: U32::new(LE, self.symtab_offset), +            number_of_symbols: U32::new(LE, self.symtab_num), +            size_of_optional_header: U16::default(), +            characteristics: U16::new(LE, header.characteristics), +        }; +        self.buffer.write(&header); + +        Ok(()) +    } + +    /// Reserve the range for the section headers. +    pub fn reserve_section_headers(&mut self, section_num: u16) { +        debug_assert_eq!(self.section_num, 0); +        self.section_num = section_num; +        self.reserve( +            section_num as usize * mem::size_of::<pe::ImageSectionHeader>(), +            1, +        ); +    } + +    /// Write a section header. +    pub fn write_section_header(&mut self, section: SectionHeader) { +        let mut coff_section = pe::ImageSectionHeader { +            name: [0; 8], +            virtual_size: U32::default(), +            virtual_address: U32::default(), +            size_of_raw_data: U32::new(LE, section.size_of_raw_data), +            pointer_to_raw_data: U32::new(LE, section.pointer_to_raw_data), +            pointer_to_relocations: U32::new(LE, section.pointer_to_relocations), +            pointer_to_linenumbers: U32::new(LE, section.pointer_to_linenumbers), +            number_of_relocations: if section.number_of_relocations > 0xffff { +                U16::new(LE, 0xffff) +            } else { +                U16::new(LE, section.number_of_relocations as u16) +            }, +            number_of_linenumbers: U16::default(), +            characteristics: U32::new(LE, section.characteristics), +        }; +        match section.name { +            Name::Short(name) => coff_section.name = name, +            Name::Long(str_id) => { +                let mut str_offset = self.strtab.get_offset(str_id); +                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 { +                    debug_assert!(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; +                    } +                } +            } +        } +        self.buffer.write(&coff_section); +    } + +    /// Reserve the range for the section data. +    /// +    /// Returns the aligned offset of the start of the range. +    /// Does nothing and returns 0 if the length is zero. +    pub fn reserve_section(&mut self, len: usize) -> u32 { +        if len == 0 { +            return 0; +        } +        // TODO: not sure what alignment is required here, but this seems to match LLVM +        self.reserve(len, 4) +    } + +    /// Write the alignment bytes prior to section data. +    /// +    /// This is unneeded if you are using `write_section` or `write_section_zeroes` +    /// for the data. +    pub fn write_section_align(&mut self) { +        util::write_align(self.buffer, 4); +    } + +    /// Write the section data. +    /// +    /// Writes alignment bytes prior to the data. +    /// Does nothing if the data is empty. +    pub fn write_section(&mut self, data: &[u8]) { +        if data.is_empty() { +            return; +        } +        self.write_section_align(); +        self.buffer.write_bytes(data); +    } + +    /// Write the section data using zero bytes. +    /// +    /// Writes alignment bytes prior to the data. +    /// Does nothing if the length is zero. +    pub fn write_section_zeroes(&mut self, len: usize) { +        if len == 0 { +            return; +        } +        self.write_section_align(); +        self.buffer.resize(self.buffer.len() + len); +    } + +    /// Reserve a file range for the given number of relocations. +    /// +    /// This will automatically reserve an extra relocation if there are more than 0xffff. +    /// +    /// Returns the offset of the range. +    /// Does nothing and returns 0 if the count is zero. +    pub fn reserve_relocations(&mut self, mut count: usize) -> u32 { +        if count == 0 { +            return 0; +        } +        if count > 0xffff { +            count += 1; +        } +        self.reserve(count * mem::size_of::<pe::ImageRelocation>(), 1) +    } + +    /// Write a relocation containing the count if required. +    /// +    /// This should be called before writing the first relocation for a section. +    pub fn write_relocations_count(&mut self, count: usize) { +        if count > 0xffff { +            let coff_relocation = pe::ImageRelocation { +                virtual_address: U32Bytes::new(LE, count as u32 + 1), +                symbol_table_index: U32Bytes::new(LE, 0), +                typ: U16Bytes::new(LE, 0), +            }; +            self.buffer.write(&coff_relocation); +        } +    } + +    /// Write a relocation. +    pub fn write_relocation(&mut self, reloc: Relocation) { +        let coff_relocation = pe::ImageRelocation { +            virtual_address: U32Bytes::new(LE, reloc.virtual_address), +            symbol_table_index: U32Bytes::new(LE, reloc.symbol), +            typ: U16Bytes::new(LE, reloc.typ), +        }; +        self.buffer.write(&coff_relocation); +    } + +    /// Reserve a symbol table entry. +    /// +    /// This must be called before [`Self::reserve_symtab_strtab`]. +    pub fn reserve_symbol_index(&mut self) -> u32 { +        debug_assert_eq!(self.symtab_offset, 0); +        let index = self.symtab_num; +        self.symtab_num += 1; +        index +    } + +    /// Reserve a number of symbol table entries. +    pub fn reserve_symbol_indices(&mut self, count: u32) { +        debug_assert_eq!(self.symtab_offset, 0); +        self.symtab_num += count; +    } + +    /// Write a symbol table entry. +    pub fn write_symbol(&mut self, symbol: Symbol) { +        let mut coff_symbol = pe::ImageSymbol { +            name: [0; 8], +            value: U32Bytes::new(LE, symbol.value), +            section_number: U16Bytes::new(LE, symbol.section_number), +            typ: U16Bytes::new(LE, symbol.typ), +            storage_class: symbol.storage_class, +            number_of_aux_symbols: symbol.number_of_aux_symbols, +        }; +        match symbol.name { +            Name::Short(name) => coff_symbol.name = name, +            Name::Long(str_id) => { +                let str_offset = self.strtab.get_offset(str_id); +                coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32)); +            } +        } +        self.buffer.write(&coff_symbol); +    } + +    /// Reserve auxiliary symbols for a file name. +    /// +    /// Returns the number of auxiliary symbols required. +    /// +    /// This must be called before [`Self::reserve_symtab_strtab`]. +    pub fn reserve_aux_file_name(&mut self, name: &[u8]) -> u8 { +        debug_assert_eq!(self.symtab_offset, 0); +        let aux_count = (name.len() + pe::IMAGE_SIZEOF_SYMBOL - 1) / pe::IMAGE_SIZEOF_SYMBOL; +        self.symtab_num += aux_count as u32; +        aux_count as u8 +    } + +    /// Write auxiliary symbols for a file name. +    pub fn write_aux_file_name(&mut self, name: &[u8], aux_count: u8) { +        let aux_len = aux_count as usize * pe::IMAGE_SIZEOF_SYMBOL; +        debug_assert!(aux_len >= name.len()); +        let old_len = self.buffer.len(); +        self.buffer.write_bytes(name); +        self.buffer.resize(old_len + aux_len); +    } + +    /// Reserve an auxiliary symbol for a section. +    /// +    /// Returns the number of auxiliary symbols required. +    /// +    /// This must be called before [`Self::reserve_symtab_strtab`]. +    pub fn reserve_aux_section(&mut self) -> u8 { +        debug_assert_eq!(self.symtab_offset, 0); +        self.symtab_num += 1; +        1 +    } + +    /// Write an auxiliary symbol for a section. +    pub fn write_aux_section(&mut self, section: AuxSymbolSection) { +        let aux = pe::ImageAuxSymbolSection { +            length: U32Bytes::new(LE, section.length), +            number_of_relocations: if section.number_of_relocations > 0xffff { +                U16Bytes::new(LE, 0xffff) +            } else { +                U16Bytes::new(LE, section.number_of_relocations as u16) +            }, +            number_of_linenumbers: U16Bytes::new(LE, section.number_of_linenumbers), +            check_sum: U32Bytes::new(LE, section.check_sum), +            number: U16Bytes::new(LE, section.number as u16), +            selection: section.selection, +            reserved: 0, +            high_number: U16Bytes::new(LE, (section.number >> 16) as u16), +        }; +        self.buffer.write(&aux); +    } + +    /// Return the number of reserved symbol table entries. +    pub fn symbol_count(&self) -> u32 { +        self.symtab_num +    } + +    /// Add a string to the string table. +    /// +    /// This must be called before [`Self::reserve_symtab_strtab`]. +    pub fn add_string(&mut self, name: &'a [u8]) -> StringId { +        debug_assert_eq!(self.strtab_offset, 0); +        self.strtab.add(name) +    } + +    /// Add a section or symbol name to the string table if required. +    /// +    /// This must be called before [`Self::reserve_symtab_strtab`]. +    pub fn add_name(&mut self, name: &'a [u8]) -> Name { +        if name.len() > 8 { +            Name::Long(self.add_string(name)) +        } else { +            let mut short_name = [0; 8]; +            short_name[..name.len()].copy_from_slice(name); +            Name::Short(short_name) +        } +    } + +    /// Reserve the range for the symbol table and string table. +    /// +    /// This must be called after functions that reserve symbol +    /// indices or add strings. +    pub fn reserve_symtab_strtab(&mut self) { +        debug_assert_eq!(self.symtab_offset, 0); +        self.symtab_offset = self.reserve(self.symtab_num as usize * pe::IMAGE_SIZEOF_SYMBOL, 1); + +        debug_assert_eq!(self.strtab_offset, 0); +        // First 4 bytes of strtab are the length. +        self.strtab.write(4, &mut self.strtab_data); +        self.strtab_len = self.strtab_data.len() + 4; +        self.strtab_offset = self.reserve(self.strtab_len, 1); +    } + +    /// Write the string table. +    pub fn write_strtab(&mut self) { +        debug_assert_eq!(self.strtab_offset, self.buffer.len() as u32); +        self.buffer +            .write_bytes(&u32::to_le_bytes(self.strtab_len as u32)); +        self.buffer.write_bytes(&self.strtab_data); +    } +} + +/// Shortened and native endian version of [`pe::ImageFileHeader`]. +#[allow(missing_docs)] +#[derive(Debug, Default, Clone)] +pub struct FileHeader { +    pub machine: u16, +    pub time_date_stamp: u32, +    pub characteristics: u16, +} + +/// A section or symbol name. +#[derive(Debug, Clone, Copy)] +pub enum Name { +    /// An inline name. +    Short([u8; 8]), +    /// An id of a string table entry. +    Long(StringId), +} + +impl Default for Name { +    fn default() -> Name { +        Name::Short([0; 8]) +    } +} + +// From isn't useful. +#[allow(clippy::from_over_into)] +impl<'a> Into<Name> for &'a [u8; 8] { +    fn into(self) -> Name { +        Name::Short(*self) +    } +} + +/// Native endian version of [`pe::ImageSectionHeader`]. +#[allow(missing_docs)] +#[derive(Debug, Default, Clone)] +pub struct SectionHeader { +    pub name: Name, +    pub size_of_raw_data: u32, +    pub pointer_to_raw_data: u32, +    pub pointer_to_relocations: u32, +    pub pointer_to_linenumbers: u32, +    /// This will automatically be clamped if there are more than 0xffff. +    pub number_of_relocations: u32, +    pub number_of_linenumbers: u16, +    pub characteristics: u32, +} + +/// Native endian version of [`pe::ImageSymbol`]. +#[allow(missing_docs)] +#[derive(Debug, Default, Clone)] +pub struct Symbol { +    pub name: Name, +    pub value: u32, +    pub section_number: u16, +    pub typ: u16, +    pub storage_class: u8, +    pub number_of_aux_symbols: u8, +} + +/// Native endian version of [`pe::ImageAuxSymbolSection`]. +#[allow(missing_docs)] +#[derive(Debug, Default, Clone)] +pub struct AuxSymbolSection { +    pub length: u32, +    /// This will automatically be clamped if there are more than 0xffff. +    pub number_of_relocations: u32, +    pub number_of_linenumbers: u16, +    pub check_sum: u32, +    pub number: u32, +    pub selection: u8, +} + +/// Native endian version of [`pe::ImageRelocation`]. +#[allow(missing_docs)] +#[derive(Debug, Default, Clone)] +pub struct Relocation { +    pub virtual_address: u32, +    pub symbol: u32, +    pub typ: u16, +} diff --git a/vendor/object/src/write/elf/mod.rs b/vendor/object/src/write/elf/mod.rs new file mode 100644 index 0000000..3a4f371 --- /dev/null +++ b/vendor/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/vendor/object/src/write/elf/object.rs b/vendor/object/src/write/elf/object.rs new file mode 100644 index 0000000..5d7a93e --- /dev/null +++ b/vendor/object/src/write/elf/object.rs @@ -0,0 +1,907 @@ +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::Sharc => true, +            Architecture::Sparc64 => true, +            Architecture::Xtensa => true, +            _ => { +                return Err(Error(format!( +                    "unimplemented architecture {:?}", +                    self.architecture +                ))); +            } +        }) +    } + +    pub(crate) fn elf_fixup_relocation(&mut self, relocation: &mut Relocation) -> Result<i64> { +        // 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(§ion.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(§ion.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, self.sub_architecture) { +            (Architecture::Aarch64, None) => elf::EM_AARCH64, +            (Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64, +            (Architecture::Arm, None) => elf::EM_ARM, +            (Architecture::Avr, None) => elf::EM_AVR, +            (Architecture::Bpf, None) => elf::EM_BPF, +            (Architecture::Csky, None) => elf::EM_CSKY, +            (Architecture::I386, None) => elf::EM_386, +            (Architecture::X86_64, None) => elf::EM_X86_64, +            (Architecture::X86_64_X32, None) => elf::EM_X86_64, +            (Architecture::Hexagon, None) => elf::EM_HEXAGON, +            (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, +            (Architecture::Mips, None) => elf::EM_MIPS, +            (Architecture::Mips64, None) => elf::EM_MIPS, +            (Architecture::Msp430, None) => elf::EM_MSP430, +            (Architecture::PowerPc, None) => elf::EM_PPC, +            (Architecture::PowerPc64, None) => elf::EM_PPC64, +            (Architecture::Riscv32, None) => elf::EM_RISCV, +            (Architecture::Riscv64, None) => elf::EM_RISCV, +            (Architecture::S390x, None) => elf::EM_S390, +            (Architecture::Sbf, None) => elf::EM_SBF, +            (Architecture::Sharc, None) => elf::EM_SHARC, +            (Architecture::Sparc64, None) => elf::EM_SPARCV9, +            (Architecture::Xtensa, None) => elf::EM_XTENSA, +            _ => { +                return Err(Error(format!( +                    "unimplemented architecture {:?} with sub-architecture {:?}", +                    self.architecture, self.sub_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(§ion.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 §ion.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, RelocationEncoding::X86Branch, 32) => { +                                    elf::R_X86_64_PLT32 +                                } +                                (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, _, 64) => elf::R_LARCH_64_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::Sharc => match (reloc.kind, reloc.encoding, reloc.size) { +                            (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 32) => { +                                elf::R_SHARC_ADDR32_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { +                                elf::R_SHARC_ADDR_VAR_V3 +                            } +                            (RelocationKind::Relative, RelocationEncoding::SharcTypeA, 24) => { +                                elf::R_SHARC_PCRLONG_V3 +                            } +                            (RelocationKind::Relative, RelocationEncoding::SharcTypeA, 6) => { +                                elf::R_SHARC_PCRSHORT_V3 +                            } +                            (RelocationKind::Relative, RelocationEncoding::SharcTypeB, 6) => { +                                elf::R_SHARC_PCRSHORT_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { +                                elf::R_SHARC_ADDR_VAR16_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 16) => { +                                elf::R_SHARC_DATA16_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 16) => { +                                elf::R_SHARC_DATA16_VISA_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 24) => { +                                elf::R_SHARC_ADDR24_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 6) => { +                                elf::R_SHARC_DATA6_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 6) => { +                                elf::R_SHARC_DATA6_VISA_V3 +                            } +                            (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 7) => { +                                elf::R_SHARC_DATA7_VISA_V3 +                            } +                            (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/vendor/object/src/write/elf/writer.rs b/vendor/object/src/write/elf/writer.rs new file mode 100644 index 0000000..9750924 --- /dev/null +++ b/vendor/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(§ion); +        } 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(§ion); +        } +    } + +    /// 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/vendor/object/src/write/macho.rs b/vendor/object/src/write/macho.rs new file mode 100644 index 0000000..1c61523 --- /dev/null +++ b/vendor/object/src/write/macho.rs @@ -0,0 +1,1095 @@ +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, +    reloc_count: usize, +} + +#[derive(Default, Clone, Copy)] +struct SymbolOffsets { +    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 the Mach-O CPU subtype. +    /// +    /// Requires `feature = "macho"`. +    #[inline] +    pub fn set_macho_cpu_subtype(&mut self, cpu_subtype: u32) { +        self.macho_cpu_subtype = Some(cpu_subtype); +    } + +    /// 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, relocation: &mut Relocation) -> i64 { +        let relative = match relocation.kind { +            RelocationKind::Relative +            | RelocationKind::GotRelative +            | RelocationKind::PltRelative +            | RelocationKind::MachO { relative: true, .. } => true, +            _ => false, +        }; +        if relative { +            // For PC relative relocations on some architectures, the +            // addend does not include the offset required due to the +            // PC being different from the place of the relocation. +            // This differs from other file formats, so adjust the +            // addend here to account for this. +            let pcrel_offset = match self.architecture { +                Architecture::I386 => 4, +                Architecture::X86_64 => match relocation.kind { +                    RelocationKind::MachO { +                        value: macho::X86_64_RELOC_SIGNED_1, +                        .. +                    } => 5, +                    RelocationKind::MachO { +                        value: macho::X86_64_RELOC_SIGNED_2, +                        .. +                    } => 6, +                    RelocationKind::MachO { +                        value: macho::X86_64_RELOC_SIGNED_4, +                        .. +                    } => 8, +                    _ => 4, +                }, +                // TODO: maybe missing support for some architectures and relocations +                _ => 0, +            }; +            relocation.addend += pcrel_offset; +        } +        // 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; +        } +        // Check for relocations that use an explicit addend. +        if self.architecture == Architecture::Aarch64 { +            if relocation.encoding == RelocationEncoding::AArch64Call { +                return 0; +            } +            if let RelocationKind::MachO { value, .. } = relocation.kind { +                match value { +                    macho::ARM64_RELOC_BRANCH26 +                    | macho::ARM64_RELOC_PAGE21 +                    | macho::ARM64_RELOC_PAGEOFF12 => return 0, +                    _ => {} +                } +            } +        } +        // Signify implicit addend. +        let constant = relocation.addend; +        relocation.addend = 0; +        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; + +        // 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 build version. +        let build_version_offset = offset; +        if let Some(version) = &self.macho_build_version { +            offset += version.cmdsize() as usize; +            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; + +        // Calculate size of dysymtab command. +        let dysymtab_command_offset = offset; +        let dysymtab_command_len = mem::size_of::<macho::DysymtabCommand<Endianness>>(); +        offset += dysymtab_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; +            } +        } + +        // Partition symbols and add symbol strings to strtab. +        let mut strtab = StringTable::default(); +        let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; +        let mut local_symbols = vec![]; +        let mut external_symbols = vec![]; +        let mut undefined_symbols = vec![]; +        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 +                    ))); +                } +            } +            if !symbol.name.is_empty() { +                symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); +            } +            if symbol.is_undefined() { +                undefined_symbols.push(index); +            } else if symbol.is_local() { +                local_symbols.push(index); +            } else { +                external_symbols.push(index); +            } +        } + +        external_symbols.sort_by_key(|index| &*self.symbols[*index].name); +        undefined_symbols.sort_by_key(|index| &*self.symbols[*index].name); + +        // Count symbols. +        let mut nsyms = 0; +        for index in local_symbols +            .iter() +            .copied() +            .chain(external_symbols.iter().copied()) +            .chain(undefined_symbols.iter().copied()) +        { +            symbol_offsets[index].index = nsyms; +            nsyms += 1; +        } + +        // Calculate size of relocations. +        for (index, section) in self.sections.iter().enumerate() { +            let count: usize = section +                .relocations +                .iter() +                .map(|reloc| 1 + usize::from(reloc.addend != 0)) +                .sum(); +            if count != 0 { +                offset = align(offset, pointer_align); +                section_offsets[index].reloc_offset = offset; +                section_offsets[index].reloc_count = count; +                let len = count * mem::size_of::<macho::Relocation<Endianness>>(); +                offset += len; +            } +        } + +        // 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); +        write_align(&mut strtab_data, pointer_align); +        offset += strtab_data.len(); + +        // Start writing. +        buffer +            .reserve(offset) +            .map_err(|_| Error(String::from("Cannot allocate buffer")))?; + +        // Write file header. +        let (cputype, mut cpusubtype) = match (self.architecture, self.sub_architecture) { +            (Architecture::Arm, None) => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL), +            (Architecture::Aarch64, None) => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), +            (Architecture::Aarch64, Some(SubArchitecture::Arm64E)) => { +                (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64E) +            } +            (Architecture::Aarch64_Ilp32, None) => { +                (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8) +            } +            (Architecture::I386, None) => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), +            (Architecture::X86_64, None) => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), +            (Architecture::PowerPc, None) => { +                (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL) +            } +            (Architecture::PowerPc64, None) => { +                (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL) +            } +            _ => { +                return Err(Error(format!( +                    "unimplemented architecture {:?} with sub-architecture {:?}", +                    self.architecture, self.sub_architecture +                ))); +            } +        }; + +        if let Some(cpu_subtype) = self.macho_cpu_subtype { +            cpusubtype = cpu_subtype; +        } + +        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, +            }, +        ); + +        // 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(§ion.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(§ion.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_offsets[index].reloc_count as u32, +                    flags, +                }, +            ); +        } + +        // Write build version. +        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 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 dysymtab command. +        debug_assert_eq!(dysymtab_command_offset, buffer.len()); +        let dysymtab_command = macho::DysymtabCommand { +            cmd: U32::new(endian, macho::LC_DYSYMTAB), +            cmdsize: U32::new(endian, dysymtab_command_len as u32), +            ilocalsym: U32::new(endian, 0), +            nlocalsym: U32::new(endian, local_symbols.len() as u32), +            iextdefsym: U32::new(endian, local_symbols.len() as u32), +            nextdefsym: U32::new(endian, external_symbols.len() as u32), +            iundefsym: U32::new( +                endian, +                local_symbols.len() as u32 + external_symbols.len() as u32, +            ), +            nundefsym: U32::new(endian, undefined_symbols.len() as u32), +            tocoff: U32::default(), +            ntoc: U32::default(), +            modtaboff: U32::default(), +            nmodtab: U32::default(), +            extrefsymoff: U32::default(), +            nextrefsyms: U32::default(), +            indirectsymoff: U32::default(), +            nindirectsyms: U32::default(), +            extreloff: U32::default(), +            nextrel: U32::default(), +            locreloff: U32::default(), +            nlocrel: U32::default(), +        }; +        buffer.write(&dysymtab_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(§ion.data); +            } +        } +        debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len()); + +        // Write relocations. +        for (index, section) in self.sections.iter().enumerate() { +            if !section.relocations.is_empty() { +                write_align(buffer, pointer_align); +                debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); +                for reloc in §ion.relocations { +                    let r_length = match reloc.size { +                        8 => 0, +                        16 => 1, +                        32 => 2, +                        64 => 3, +                        _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))), +                    }; + +                    // Write explicit addend. +                    if reloc.addend != 0 { +                        let r_type = match self.architecture { +                            Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => { +                                macho::ARM64_RELOC_ADDEND +                            } +                            _ => { +                                return Err(Error(format!("unimplemented relocation {:?}", reloc))) +                            } +                        }; + +                        let reloc_info = macho::RelocationInfo { +                            r_address: reloc.offset as u32, +                            r_symbolnum: reloc.addend as u32, +                            r_pcrel: false, +                            r_length, +                            r_extern: false, +                            r_type, +                        }; +                        buffer.write(&reloc_info.relocation(endian)); +                    } + +                    let r_extern; +                    let 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_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) { +                            (RelocationKind::Absolute, RelocationEncoding::Generic) => { +                                (false, macho::X86_64_RELOC_UNSIGNED) +                            } +                            (RelocationKind::Relative, RelocationEncoding::Generic) => { +                                (true, macho::X86_64_RELOC_SIGNED) +                            } +                            (RelocationKind::Relative, RelocationEncoding::X86RipRelative) => { +                                (true, macho::X86_64_RELOC_SIGNED) +                            } +                            (RelocationKind::Relative, RelocationEncoding::X86Branch) => { +                                (true, macho::X86_64_RELOC_BRANCH) +                            } +                            (RelocationKind::PltRelative, RelocationEncoding::X86Branch) => { +                                (true, macho::X86_64_RELOC_BRANCH) +                            } +                            (RelocationKind::GotRelative, RelocationEncoding::Generic) => { +                                (true, macho::X86_64_RELOC_GOT) +                            } +                            ( +                                RelocationKind::GotRelative, +                                RelocationEncoding::X86RipRelativeMovq, +                            ) => (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) { +                                (RelocationKind::Absolute, RelocationEncoding::Generic) => { +                                    (false, macho::ARM64_RELOC_UNSIGNED) +                                } +                                (RelocationKind::Relative, RelocationEncoding::AArch64Call) => { +                                    (true, macho::ARM64_RELOC_BRANCH26) +                                } +                                ( +                                    RelocationKind::MachO { value, relative }, +                                    RelocationEncoding::Generic, +                                ) => (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)); +                } +            } +        } + +        // Write symtab. +        write_align(buffer, pointer_align); +        debug_assert_eq!(symtab_offset, buffer.len()); +        for index in local_symbols +            .iter() +            .copied() +            .chain(external_symbols.iter().copied()) +            .chain(undefined_symbols.iter().copied()) +        { +            let symbol = &self.symbols[index]; +            // 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); + +        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(§ion); +    } + +    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(§ion); +    } + +    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/vendor/object/src/write/mod.rs b/vendor/object/src/write/mod.rs new file mode 100644 index 0000000..cea4d2e --- /dev/null +++ b/vendor/object/src/write/mod.rs @@ -0,0 +1,961 @@ +//! 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, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, +}; + +#[cfg(feature = "coff")] +pub 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, +    sub_architecture: Option<SubArchitecture>, +    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>, +    /// Mach-O CPU subtype. +    #[cfg(feature = "macho")] +    macho_cpu_subtype: Option<u32>, +    #[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, +            sub_architecture: None, +            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_cpu_subtype: 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 sub-architecture. +    #[inline] +    pub fn sub_architecture(&self) -> Option<SubArchitecture> { +        self.sub_architecture +    } + +    /// Specify the sub-architecture. +    pub fn set_sub_architecture(&mut self, sub_architecture: Option<SubArchitecture>) { +        self.sub_architecture = sub_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(§ion) +            .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/vendor/object/src/write/pe.rs b/vendor/object/src/write/pe.rs new file mode 100644 index 0000000..70da3a0 --- /dev/null +++ b/vendor/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(§ion_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/vendor/object/src/write/string.rs b/vendor/object/src/write/string.rs new file mode 100644 index 0000000..b23274a --- /dev/null +++ b/vendor/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/vendor/object/src/write/util.rs b/vendor/object/src/write/util.rs new file mode 100644 index 0000000..f7ee2f4 --- /dev/null +++ b/vendor/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(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/vendor/object/src/write/xcoff.rs b/vendor/object/src/write/xcoff.rs new file mode 100644 index 0000000..fc58886 --- /dev/null +++ b/vendor/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, 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(§ion.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(§ion_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(§ion_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(§ion.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 §ion.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/vendor/object/src/xcoff.rs b/vendor/object/src/xcoff.rs new file mode 100644 index 0000000..dbe5d73 --- /dev/null +++ b/vendor/object/src/xcoff.rs @@ -0,0 +1,905 @@ +//! 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 SSUBTYP_DWINFO: u32 = 0x10000; +pub const SSUBTYP_DWLINE: u32 = 0x20000; +pub const SSUBTYP_DWPBNMS: u32 = 0x30000; +pub const SSUBTYP_DWPBTYP: u32 = 0x40000; +pub const SSUBTYP_DWARNGE: u32 = 0x50000; +pub const SSUBTYP_DWABREV: u32 = 0x60000; +pub const SSUBTYP_DWSTR: u32 = 0x70000; +pub const SSUBTYP_DWRNGES: u32 = 0x80000; +pub const SSUBTYP_DWLOC: u32 = 0x90000; +pub const SSUBTYP_DWFRAME: u32 = 0xA0000; +pub const SSUBTYP_DWMAC: u32 = 0xB0000; + +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, +);  | 
