diff options
Diffstat (limited to '')
33 files changed, 4078 insertions, 128 deletions
diff --git a/vendor/object/src/archive.rs b/vendor/object/src/archive.rs index d4b419beb..6271d0736 100644 --- a/vendor/object/src/archive.rs +++ b/vendor/object/src/archive.rs @@ -8,6 +8,9 @@ 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. @@ -36,4 +39,53 @@ pub struct Header { pub terminator: [u8; 2], } -unsafe_impl_pod!(Header); +/// 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 index 20dde991a..cb009c0f9 100644 --- a/vendor/object/src/common.rs +++ b/vendor/object/src/common.rs @@ -5,6 +5,8 @@ pub enum Architecture { Unknown, Aarch64, + #[allow(non_camel_case_types)] + Aarch64_Ilp32, Arm, Avr, Bpf, @@ -22,8 +24,10 @@ pub enum Architecture { Riscv32, Riscv64, S390x, + Sbf, Sparc64, Wasm32, + Xtensa, } impl Architecture { @@ -34,6 +38,7 @@ impl Architecture { 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), @@ -50,8 +55,10 @@ impl Architecture { Architecture::Riscv32 => Some(AddressSize::U32), Architecture::Riscv64 => Some(AddressSize::U64), Architecture::S390x => Some(AddressSize::U64), + Architecture::Sbf => Some(AddressSize::U64), Architecture::Sparc64 => Some(AddressSize::U64), Architecture::Wasm32 => Some(AddressSize::U32), + Architecture::Xtensa => Some(AddressSize::U32), } } } @@ -88,6 +95,7 @@ pub enum BinaryFormat { MachO, Pe, Wasm, + Xcoff, } /// The kind of a section. @@ -305,6 +313,8 @@ pub enum RelocationKind { }, /// 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. @@ -343,6 +353,11 @@ pub enum RelocationEncoding { /// /// The `RelocationKind` must be PC relative. AArch64Call, + + /// LoongArch branch offset with two trailing zeros. + /// + /// The `RelocationKind` must be PC relative. + LoongArchBranch, } /// File flags that are specific to each file format. @@ -370,6 +385,11 @@ pub enum FileFlags { /// `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. @@ -420,6 +440,11 @@ pub enum SectionFlags { /// `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. diff --git a/vendor/object/src/elf.rs b/vendor/object/src/elf.rs index 9f6577269..ac9742080 100644 --- a/vendor/object/src/elf.rs +++ b/vendor/object/src/elf.rs @@ -576,6 +576,8 @@ pub const EM_BPF: u16 = 247; 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; @@ -6122,6 +6124,14 @@ pub const R_BPF_64_64: u32 = 1; #[allow(missing_docs)] pub const R_BPF_64_32: u32 = 10; +// SBF values `Rel*::r_type`. +/// No reloc +pub const R_SBF_NONE: u32 = 0; +#[allow(missing_docs)] +pub const R_SBF_64_64: u32 = 1; +#[allow(missing_docs)] +pub const R_SBF_64_32: u32 = 10; + // Imagination Meta values `Rel*::r_type`. #[allow(missing_docs)] @@ -6251,18 +6261,17 @@ pub const R_NDS32_TLS_TPOFF: u32 = 102; pub const R_NDS32_TLS_DESC: u32 = 119; // LoongArch values `FileHeader*::e_flags`. -/// Uses 64-bit GPRs and the stack for parameter passing -pub const EF_LARCH_ABI_LP64S: u32 = 0x1; -/// Uses 64-bit GPRs, 32-bit FPRs and the stack for parameter passing -pub const EF_LARCH_ABI_LP64F: u32 = 0x2; -/// Uses 64-bit GPRs, 64-bit FPRs and the stack for parameter passing -pub const EF_LARCH_ABI_LP64D: u32 = 0x3; -/// Uses 32-bit GPRs and the stack for parameter passing -pub const EF_LARCH_ABI_ILP32S: u32 = 0x5; -/// Uses 32-bit GPRs, 32-bit FPRs and the stack for parameter passing -pub const EF_LARCH_ABI_ILP32F: u32 = 0x6; -/// Uses 32-bit GPRs, 64-bit FPRs and the stack for parameter passing -pub const EF_LARCH_ABI_ILP32D: u32 = 0x7; +/// 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 @@ -6372,6 +6381,228 @@ pub const R_LARCH_SUB64: u32 = 56; pub const R_LARCH_GNU_VTINHERIT: u32 = 57; /// GNU C++ vtable member usage pub const R_LARCH_GNU_VTENTRY: u32 = 58; +/// 18-bit PC-relative jump offset with two trailing zeros +pub const R_LARCH_B16: u32 = 64; +/// 23-bit PC-relative jump offset with two trailing zeros +pub const R_LARCH_B21: u32 = 65; +/// 28-bit PC-relative jump offset with two trailing zeros +pub const R_LARCH_B26: u32 = 66; +/// 12..=31 bits of 32/64-bit absolute address +pub const R_LARCH_ABS_HI20: u32 = 67; +/// 0..=11 bits of 32/64-bit absolute address +pub const R_LARCH_ABS_LO12: u32 = 68; +/// 32..=51 bits of 64-bit absolute address +pub const R_LARCH_ABS64_LO20: u32 = 69; +/// 52..=63 bits of 64-bit absolute address +pub const R_LARCH_ABS64_HI12: u32 = 70; +/// The signed 32-bit offset `offs` from `PC & 0xfffff000` to +/// `(S + A + 0x800) & 0xfffff000`, with 12 trailing zeros removed. +/// +/// We define the *PC relative anchor* for `S + A` as `PC + offs` (`offs` +/// is sign-extended to VA bits). +pub const R_LARCH_PCALA_HI20: u32 = 71; +/// Same as R_LARCH_ABS_LO12. 0..=11 bits of the 32/64-bit offset from the +/// [PC relative anchor][R_LARCH_PCALA_HI20]. +pub const R_LARCH_PCALA_LO12: u32 = 72; +/// 32..=51 bits of the 64-bit offset from the +/// [PC relative anchor][R_LARCH_PCALA_HI20]. +pub const R_LARCH_PCALA64_LO20: u32 = 73; +/// 52..=63 bits of the 64-bit offset from the +/// [PC relative anchor][R_LARCH_PCALA_HI20]. +pub const R_LARCH_PCALA64_HI12: u32 = 74; +/// The signed 32-bit offset `offs` from `PC & 0xfffff000` to +/// `(GP + G + 0x800) & 0xfffff000`, with 12 trailing zeros removed. +/// +/// We define the *PC relative anchor* for the GOT entry at `GP + G` as +/// `PC + offs` (`offs` is sign-extended to VA bits). +pub const R_LARCH_GOT_PC_HI20: u32 = 75; +/// 0..=11 bits of the 32/64-bit offset from the +/// [PC relative anchor][R_LARCH_GOT_PC_HI20] to the GOT entry. +pub const R_LARCH_GOT_PC_LO12: u32 = 76; +/// 32..=51 bits of the 64-bit offset from the +/// [PC relative anchor][R_LARCH_GOT_PC_HI20] to the GOT entry. +pub const R_LARCH_GOT64_PC_LO20: u32 = 77; +/// 52..=63 bits of the 64-bit offset from the +/// [PC relative anchor][R_LARCH_GOT_PC_HI20] to the GOT entry. +pub const R_LARCH_GOT64_PC_HI12: u32 = 78; +/// 12..=31 bits of 32/64-bit GOT entry absolute address +pub const R_LARCH_GOT_HI20: u32 = 79; +/// 0..=11 bits of 32/64-bit GOT entry absolute address +pub const R_LARCH_GOT_LO12: u32 = 80; +/// 32..=51 bits of 64-bit GOT entry absolute address +pub const R_LARCH_GOT64_LO20: u32 = 81; +/// 52..=63 bits of 64-bit GOT entry absolute address +pub const R_LARCH_GOT64_HI12: u32 = 82; +/// 12..=31 bits of TLS LE 32/64-bit offset from thread pointer +pub const R_LARCH_TLS_LE_HI20: u32 = 83; +/// 0..=11 bits of TLS LE 32/64-bit offset from thread pointer +pub const R_LARCH_TLS_LE_LO12: u32 = 84; +/// 32..=51 bits of TLS LE 64-bit offset from thread pointer +pub const R_LARCH_TLS_LE64_LO20: u32 = 85; +/// 52..=63 bits of TLS LE 64-bit offset from thread pointer +pub const R_LARCH_TLS_LE64_HI12: u32 = 86; +/// The signed 32-bit offset `offs` from `PC & 0xfffff000` to +/// `(GP + IE + 0x800) & 0xfffff000`, with 12 trailing zeros removed. +/// +/// We define the *PC relative anchor* for the TLS IE GOT entry at +/// `GP + IE` as `PC + offs` (`offs` is sign-extended to VA bits). +pub const R_LARCH_TLS_IE_PC_HI20: u32 = 87; +/// 0..=12 bits of the 32/64-bit offset from the +/// [PC-relative anchor][R_LARCH_TLS_IE_PC_HI20] to the TLS IE GOT entry. +pub const R_LARCH_TLS_IE_PC_LO12: u32 = 88; +/// 32..=51 bits of the 64-bit offset from the +/// [PC-relative anchor][R_LARCH_TLS_IE_PC_HI20] to the TLS IE GOT entry. +pub const R_LARCH_TLS_IE64_PC_LO20: u32 = 89; +/// 52..=63 bits of the 64-bit offset from the +/// [PC-relative anchor][R_LARCH_TLS_IE_PC_HI20] to the TLS IE GOT entry. +pub const R_LARCH_TLS_IE64_PC_HI12: u32 = 90; +/// 12..=31 bits of TLS IE GOT entry 32/64-bit absolute address +pub const R_LARCH_TLS_IE_HI20: u32 = 91; +/// 0..=11 bits of TLS IE GOT entry 32/64-bit absolute address +pub const R_LARCH_TLS_IE_LO12: u32 = 92; +/// 32..=51 bits of TLS IE GOT entry 64-bit absolute address +pub const R_LARCH_TLS_IE64_LO20: u32 = 93; +/// 51..=63 bits of TLS IE GOT entry 64-bit absolute address +pub const R_LARCH_TLS_IE64_HI12: u32 = 94; +/// 12..=31 bits of the offset from `PC` to `GP + GD + 0x800`, where +/// `GP + GD` is a TLS LD GOT entry +pub const R_LARCH_TLS_LD_PC_HI20: u32 = 95; +/// 12..=31 bits of TLS LD GOT entry 32/64-bit absolute address +pub const R_LARCH_TLS_LD_HI20: u32 = 96; +/// 12..=31 bits of the 32/64-bit PC-relative offset to the PC-relative +/// anchor for the TLE GD GOT entry. +pub const R_LARCH_TLS_GD_PC_HI20: u32 = 97; +/// 12..=31 bits of TLS GD GOT entry 32/64-bit absolute address +pub const R_LARCH_TLS_GD_HI20: u32 = 98; +/// 32-bit PC relative +pub const R_LARCH_32_PCREL: u32 = 99; +/// Paired with a normal relocation at the same address to indicate the +/// insturction can be relaxed +pub const R_LARCH_RELAX: u32 = 100; + +// Xtensa values Rel*::r_type`. +#[allow(missing_docs)] +pub const R_XTENSA_NONE: u32 = 0; +#[allow(missing_docs)] +pub const R_XTENSA_32: u32 = 1; +#[allow(missing_docs)] +pub const R_XTENSA_RTLD: u32 = 2; +#[allow(missing_docs)] +pub const R_XTENSA_GLOB_DAT: u32 = 3; +#[allow(missing_docs)] +pub const R_XTENSA_JMP_SLOT: u32 = 4; +#[allow(missing_docs)] +pub const R_XTENSA_RELATIVE: u32 = 5; +#[allow(missing_docs)] +pub const R_XTENSA_PLT: u32 = 6; +#[allow(missing_docs)] +pub const R_XTENSA_OP0: u32 = 8; +#[allow(missing_docs)] +pub const R_XTENSA_OP1: u32 = 9; +#[allow(missing_docs)] +pub const R_XTENSA_OP2: u32 = 10; +#[allow(missing_docs)] +pub const R_XTENSA_ASM_EXPAND: u32 = 11; +#[allow(missing_docs)] +pub const R_XTENSA_ASM_SIMPLIFY: u32 = 12; +#[allow(missing_docs)] +pub const R_XTENSA_32_PCREL: u32 = 14; +#[allow(missing_docs)] +pub const R_XTENSA_GNU_VTINHERIT: u32 = 15; +#[allow(missing_docs)] +pub const R_XTENSA_GNU_VTENTRY: u32 = 16; +#[allow(missing_docs)] +pub const R_XTENSA_DIFF8: u32 = 17; +#[allow(missing_docs)] +pub const R_XTENSA_DIFF16: u32 = 18; +#[allow(missing_docs)] +pub const R_XTENSA_DIFF32: u32 = 19; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT0_OP: u32 = 20; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT1_OP: u32 = 21; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT2_OP: u32 = 22; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT3_OP: u32 = 23; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT4_OP: u32 = 24; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT5_OP: u32 = 25; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT6_OP: u32 = 26; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT7_OP: u32 = 27; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT8_OP: u32 = 28; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT9_OP: u32 = 29; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT10_OP: u32 = 30; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT11_OP: u32 = 31; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT12_OP: u32 = 32; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT13_OP: u32 = 33; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT14_OP: u32 = 34; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT0_ALT: u32 = 35; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT1_ALT: u32 = 36; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT2_ALT: u32 = 37; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT3_ALT: u32 = 38; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT4_ALT: u32 = 39; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT5_ALT: u32 = 40; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT6_ALT: u32 = 41; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT7_ALT: u32 = 42; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT8_ALT: u32 = 43; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT9_ALT: u32 = 44; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT10_ALT: u32 = 45; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT11_ALT: u32 = 46; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT12_ALT: u32 = 47; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT13_ALT: u32 = 48; +#[allow(missing_docs)] +pub const R_XTENSA_SLOT14_ALT: u32 = 49; +#[allow(missing_docs)] +pub const R_XTENSA_TLSDESC_FN: u32 = 50; +#[allow(missing_docs)] +pub const R_XTENSA_TLSDESC_ARG: u32 = 51; +#[allow(missing_docs)] +pub const R_XTENSA_TLS_DTPOFF: u32 = 52; +#[allow(missing_docs)] +pub const R_XTENSA_TLS_TPOFF: u32 = 53; +#[allow(missing_docs)] +pub const R_XTENSA_TLS_FUNC: u32 = 54; +#[allow(missing_docs)] +pub const R_XTENSA_TLS_ARG: u32 = 55; +#[allow(missing_docs)] +pub const R_XTENSA_TLS_CALL: u32 = 56; +#[allow(missing_docs)] +pub const R_XTENSA_PDIFF8: u32 = 57; +#[allow(missing_docs)] +pub const R_XTENSA_PDIFF16: u32 = 58; +#[allow(missing_docs)] +pub const R_XTENSA_PDIFF32: u32 = 59; +#[allow(missing_docs)] +pub const R_XTENSA_NDIFF8: u32 = 60; +#[allow(missing_docs)] +pub const R_XTENSA_NDIFF16: u32 = 61; +#[allow(missing_docs)] +pub const R_XTENSA_NDIFF32: u32 = 62; unsafe_impl_endian_pod!( FileHeader32, diff --git a/vendor/object/src/lib.rs b/vendor/object/src/lib.rs index d50009f38..40f17c017 100644 --- a/vendor/object/src/lib.rs +++ b/vendor/object/src/lib.rs @@ -73,6 +73,9 @@ #[cfg(feature = "cargo-all")] compile_error!("'--all-features' is not supported; use '--features all' instead"); +#[cfg(all(feature = "xcoff", not(feature = "unstable")))] +compile_error!("'xcoff` is an unstable feature; enable 'unstable' as well"); + #[cfg(any(feature = "read_core", feature = "write_core"))] #[allow(unused_imports)] #[macro_use] @@ -110,3 +113,5 @@ pub mod elf; pub mod macho; #[cfg(any(feature = "coff", feature = "pe"))] pub mod pe; +#[cfg(feature = "xcoff")] +pub mod xcoff; diff --git a/vendor/object/src/pe.rs b/vendor/object/src/pe.rs index c89b86caa..00105adac 100644 --- a/vendor/object/src/pe.rs +++ b/vendor/object/src/pe.rs @@ -1977,6 +1977,21 @@ pub struct ImageDelayloadDescriptor { 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; diff --git a/vendor/object/src/pod.rs b/vendor/object/src/pod.rs index 805cf8249..8ee78164f 100644 --- a/vendor/object/src/pod.rs +++ b/vendor/object/src/pod.rs @@ -14,6 +14,7 @@ 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 diff --git a/vendor/object/src/read/any.rs b/vendor/object/src/read/any.rs index 02e76dcdd..c390b21b6 100644 --- a/vendor/object/src/read/any.rs +++ b/vendor/object/src/read/any.rs @@ -12,6 +12,8 @@ use crate::read::macho; 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, @@ -44,6 +46,10 @@ macro_rules! with_inner { $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, } }; } @@ -67,6 +73,10 @@ macro_rules! with_inner_mut { $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, } }; } @@ -91,6 +101,10 @@ macro_rules! map_inner { $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), } }; } @@ -115,6 +129,10 @@ macro_rules! map_inner_option { $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), } }; } @@ -138,6 +156,10 @@ macro_rules! map_inner_option_mut { $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), } }; } @@ -162,6 +184,10 @@ macro_rules! next_inner { $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), } }; } @@ -192,6 +218,10 @@ enum FileInternal<'data, R: ReadRef<'data>> { 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> { @@ -214,6 +244,10 @@ impl<'data, R: ReadRef<'data>> File<'data, R> { FileKind::Pe64 => FileInternal::Pe64(pe::PeFile64::parse(data)?), #[cfg(feature = "coff")] FileKind::Coff => FileInternal::Coff(coff::CoffFile::parse(data)?), + #[cfg(feature = "xcoff")] + FileKind::Xcoff32 => FileInternal::Xcoff32(xcoff::XcoffFile32::parse(data)?), + #[cfg(feature = "xcoff")] + FileKind::Xcoff64 => FileInternal::Xcoff64(xcoff::XcoffFile64::parse(data)?), #[allow(unreachable_patterns)] _ => return Err(Error("Unsupported file format")), }; @@ -250,6 +284,8 @@ impl<'data, R: ReadRef<'data>> File<'data, R> { FileInternal::Pe32(_) | FileInternal::Pe64(_) => BinaryFormat::Pe, #[cfg(feature = "wasm")] FileInternal::Wasm(_) => BinaryFormat::Wasm, + #[cfg(feature = "xcoff")] + FileInternal::Xcoff32(_) | FileInternal::Xcoff64(_) => BinaryFormat::Xcoff, } } } @@ -468,6 +504,10 @@ where 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> { @@ -508,6 +548,10 @@ where 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> { @@ -600,6 +644,10 @@ where 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> { @@ -639,6 +687,10 @@ where 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> { @@ -771,6 +823,10 @@ where 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> { @@ -810,6 +866,10 @@ where 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> { @@ -885,6 +945,10 @@ where 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> { @@ -947,6 +1011,10 @@ where 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> {} @@ -1027,6 +1095,20 @@ where 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> { @@ -1090,6 +1172,10 @@ where 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> { @@ -1240,6 +1326,10 @@ where 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> { diff --git a/vendor/object/src/read/archive.rs b/vendor/object/src/read/archive.rs index 0208878e4..f5aaa9b19 100644 --- a/vendor/object/src/read/archive.rs +++ b/vendor/object/src/read/archive.rs @@ -3,7 +3,7 @@ use core::convert::TryInto; use crate::archive; -use crate::read::{self, Error, ReadError, ReadRef}; +use crate::read::{self, Bytes, Error, ReadError, ReadRef}; /// The kind of archive format. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -23,15 +23,28 @@ pub enum ArchiveKind { 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)] +#[derive(Debug, Clone, Copy)] pub struct ArchiveFile<'data, R: ReadRef<'data> = &'data [u8]> { data: R, - len: u64, - offset: u64, kind: ArchiveKind, + members: Members<'data>, symbols: (u64, u64), names: &'data [u8], } @@ -44,15 +57,23 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> { let magic = data .read_bytes(&mut tail, archive::MAGIC.len() as u64) .read_error("Invalid archive size")?; - if magic != &archive::MAGIC[..] { + + 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, - offset: tail, - len, kind: ArchiveKind::Unknown, + members: Members::Common { + offset: 0, + end_offset: 0, + }, symbols: (0, 0), names: &[], }; @@ -77,7 +98,7 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> { // GNU symbol table (unless we later determine this is COFF). file.kind = ArchiveKind::Gnu; file.symbols = member.file_range(); - file.offset = tail; + members_offset = tail; if tail < len { let member = ArchiveMember::parse(data, &mut tail, &[])?; @@ -85,55 +106,125 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> { // COFF linker member. file.kind = ArchiveKind::Coff; file.symbols = member.file_range(); - file.offset = tail; + 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)?; - file.offset = tail; + members_offset = tail; } } } else if member.name == b"//" { // GNU names table. file.names = member.data(data)?; - file.offset = tail; + members_offset = tail; } } } else if member.name == b"/SYM64/" { // GNU 64-bit symbol table. file.kind = ArchiveKind::Gnu64; file.symbols = member.file_range(); - file.offset = tail; + 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)?; - file.offset = tail; + members_offset = tail; } } } else if member.name == b"//" { // GNU names table. file.kind = ArchiveKind::Gnu; file.names = member.data(data)?; - file.offset = tail; + 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(); - file.offset = tail; + 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(); - file.offset = tail; + 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) } @@ -150,8 +241,7 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> { pub fn members(&self) -> ArchiveMemberIterator<'data, R> { ArchiveMemberIterator { data: self.data, - offset: self.offset, - len: self.len, + members: self.members, names: self.names, } } @@ -161,8 +251,7 @@ impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> { #[derive(Debug)] pub struct ArchiveMemberIterator<'data, R: ReadRef<'data> = &'data [u8]> { data: R, - offset: u64, - len: u64, + members: Members<'data>, names: &'data [u8], } @@ -170,28 +259,55 @@ impl<'data, R: ReadRef<'data>> Iterator for ArchiveMemberIterator<'data, R> { type Item = read::Result<ArchiveMember<'data>>; fn next(&mut self) -> Option<Self::Item> { - if self.offset >= self.len { - return None; - } - let member = ArchiveMember::parse(self.data, &mut self.offset, self.names); - if member.is_err() { - self.offset = self.len; + 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) + } + }, } - 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: &'data archive::Header, + header: MemberHeader<'data>, name: &'data [u8], offset: u64, size: u64, } impl<'data> ArchiveMember<'data> { - /// Parse the archive member header, name, and file 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>>( @@ -217,11 +333,11 @@ impl<'data> ArchiveMember<'data> { *offset = offset.saturating_add(1); } - let name = if header.name[0] == b'/' && (header.name[1] as char).is_digit(10) { + 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_digit(10) { + } 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")? @@ -236,17 +352,81 @@ impl<'data> ArchiveMember<'data> { }; Ok(ArchiveMember { - header, + header: MemberHeader::Common(header), name, offset: file_offset, size: file_size, }) } - /// Return the raw header. + /// 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) -> &'data archive::Header { - self.header + 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. @@ -260,25 +440,37 @@ impl<'data> ArchiveMember<'data> { /// Parse the file modification timestamp from the header. #[inline] pub fn date(&self) -> Option<u64> { - parse_u64_digits(&self.header.date, 10) + 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> { - parse_u64_digits(&self.header.uid, 10) + 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> { - parse_u64_digits(&self.header.gid, 10) + 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> { - parse_u64_digits(&self.header.mode, 8) + 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. @@ -442,6 +634,19 @@ mod tests { 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] @@ -499,4 +704,36 @@ mod tests { 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/symbol.rs b/vendor/object/src/read/coff/symbol.rs index c954c8a29..217e38fca 100644 --- a/vendor/object/src/read/coff/symbol.rs +++ b/vendor/object/src/read/coff/symbol.rs @@ -325,6 +325,14 @@ where pub(crate) symbol: &'data pe::ImageSymbol, } +impl<'data, 'file, R: ReadRef<'data>> CoffSymbol<'data, 'file, R> { + #[inline] + /// Get the raw `ImageSymbol` struct. + pub fn raw_symbol(&self) -> &'data pe::ImageSymbol { + self.symbol + } +} + impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for CoffSymbol<'data, 'file, R> {} impl<'data, 'file, R: ReadRef<'data>> ObjectSymbol<'data> for CoffSymbol<'data, 'file, R> { diff --git a/vendor/object/src/read/elf/comdat.rs b/vendor/object/src/read/elf/comdat.rs index c9f0076f9..7cee85bb4 100644 --- a/vendor/object/src/read/elf/comdat.rs +++ b/vendor/object/src/read/elf/comdat.rs @@ -34,7 +34,7 @@ where type Item = ElfComdat<'data, 'file, Elf, R>; fn next(&mut self) -> Option<Self::Item> { - while let Some((_index, section)) = self.iter.next() { + for (_index, section) in self.iter.by_ref() { if let Some(comdat) = ElfComdat::parse(self.file, section) { return Some(comdat); } diff --git a/vendor/object/src/read/elf/file.rs b/vendor/object/src/read/elf/file.rs index e1f76a38c..259da7906 100644 --- a/vendor/object/src/read/elf/file.rs +++ b/vendor/object/src/read/elf/file.rs @@ -156,7 +156,8 @@ where self.header.e_machine(self.endian), self.header.is_class_64(), ) { - (elf::EM_AARCH64, _) => Architecture::Aarch64, + (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, @@ -175,7 +176,9 @@ where // This is either s390 or s390x, depending on the ELF class. // We only support the 64-bit variant s390x here. (elf::EM_S390, true) => Architecture::S390x, + (elf::EM_SBF, _) => Architecture::Sbf, (elf::EM_SPARCV9, true) => Architecture::Sparc64, + (elf::EM_XTENSA, false) => Architecture::Xtensa, _ => Architecture::Unknown, } } diff --git a/vendor/object/src/read/elf/relocation.rs b/vendor/object/src/read/elf/relocation.rs index 557b80efc..8443dbc75 100644 --- a/vendor/object/src/read/elf/relocation.rs +++ b/vendor/object/src/read/elf/relocation.rs @@ -240,19 +240,28 @@ fn parse_relocation<Elf: FileHeader>( let mut encoding = RelocationEncoding::Generic; let is_mips64el = header.is_mips64el(endian); let (kind, size) = match header.e_machine(endian) { - elf::EM_AARCH64 => 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) + 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), + } } - 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), @@ -304,6 +313,19 @@ fn parse_relocation<Elf: FileHeader>( elf::EM_LOONGARCH => match reloc.r_type(endian, false) { elf::R_LARCH_32 => (RelocationKind::Absolute, 32), elf::R_LARCH_64 => (RelocationKind::Absolute, 64), + elf::R_LARCH_32_PCREL => (RelocationKind::Relative, 32), + elf::R_LARCH_B16 => { + encoding = RelocationEncoding::LoongArchBranch; + (RelocationKind::Relative, 16) + } + elf::R_LARCH_B21 => { + encoding = RelocationEncoding::LoongArchBranch; + (RelocationKind::Relative, 21) + } + elf::R_LARCH_B26 => { + encoding = RelocationEncoding::LoongArchBranch; + (RelocationKind::Relative, 26) + } r_type => (RelocationKind::Elf(r_type), 0), }, elf::EM_MIPS => match reloc.r_type(endian, is_mips64el) { @@ -372,6 +394,11 @@ fn parse_relocation<Elf: FileHeader>( } r_type => (RelocationKind::Elf(r_type), 0), }, + elf::EM_SBF => match reloc.r_type(endian, false) { + elf::R_SBF_64_64 => (RelocationKind::Absolute, 64), + elf::R_SBF_64_32 => (RelocationKind::Absolute, 32), + r_type => (RelocationKind::Elf(r_type), 0), + }, elf::EM_SPARC | elf::EM_SPARC32PLUS | elf::EM_SPARCV9 => { match reloc.r_type(endian, false) { elf::R_SPARC_32 | elf::R_SPARC_UA32 => (RelocationKind::Absolute, 32), @@ -379,6 +406,11 @@ fn parse_relocation<Elf: FileHeader>( 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; diff --git a/vendor/object/src/read/elf/segment.rs b/vendor/object/src/read/elf/segment.rs index 874ea92b8..445893c8d 100644 --- a/vendor/object/src/read/elf/segment.rs +++ b/vendor/object/src/read/elf/segment.rs @@ -34,7 +34,7 @@ where type Item = ElfSegment<'data, 'file, Elf, R>; fn next(&mut self) -> Option<Self::Item> { - while let Some(segment) = self.iter.next() { + for segment in self.iter.by_ref() { if segment.p_type(self.file.endian) == elf::PT_LOAD { return Some(ElfSegment { file: self.file, diff --git a/vendor/object/src/read/elf/symbol.rs b/vendor/object/src/read/elf/symbol.rs index f52eff20e..5d8d29f27 100644 --- a/vendor/object/src/read/elf/symbol.rs +++ b/vendor/object/src/read/elf/symbol.rs @@ -4,7 +4,6 @@ use core::fmt::Debug; use core::slice; use core::str; -use crate::elf; use crate::endian::{self, Endianness}; use crate::pod::Pod; use crate::read::util::StringTable; @@ -12,6 +11,7 @@ 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}; @@ -28,7 +28,7 @@ where shndx_section: SectionIndex, symbols: &'data [Elf::Sym], strings: StringTable<'data, R>, - shndx: &'data [u32], + shndx: &'data [U32<Elf::Endian>], } impl<'data, Elf: FileHeader, R: ReadRef<'data>> Default for SymbolTable<'data, Elf, R> { @@ -145,8 +145,8 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> { /// Return the extended section index for the given symbol if present. #[inline] - pub fn shndx(&self, index: usize) -> Option<u32> { - self.shndx.get(index).copied() + 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. @@ -161,7 +161,7 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> { match symbol.st_shndx(endian) { elf::SHN_UNDEF => Ok(None), elf::SHN_XINDEX => self - .shndx(index) + .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()))), @@ -349,8 +349,9 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> fn kind(&self) -> SymbolKind { match self.symbol.st_type() { elf::STT_NOTYPE if self.index.0 == 0 => SymbolKind::Null, + elf::STT_NOTYPE => SymbolKind::Label, elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data, - elf::STT_FUNC => SymbolKind::Text, + elf::STT_FUNC | elf::STT_GNU_IFUNC => SymbolKind::Text, elf::STT_SECTION => SymbolKind::Section, elf::STT_FILE => SymbolKind::File, elf::STT_TLS => SymbolKind::Tls, @@ -369,7 +370,7 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> } } elf::SHN_COMMON => SymbolSection::Common, - elf::SHN_XINDEX => match self.symbols.shndx(self.index.0) { + elf::SHN_XINDEX => match self.symbols.shndx(self.endian, self.index.0) { Some(index) => SymbolSection::Section(SectionIndex(index as usize)), None => SymbolSection::Unknown, }, diff --git a/vendor/object/src/read/macho/fat.rs b/vendor/object/src/read/macho/fat.rs index 6fc649f31..d4301b7e1 100644 --- a/vendor/object/src/read/macho/fat.rs +++ b/vendor/object/src/read/macho/fat.rs @@ -57,6 +57,8 @@ pub trait FatArch: Pod { 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, } } diff --git a/vendor/object/src/read/macho/file.rs b/vendor/object/src/read/macho/file.rs index e028de3b9..ab8c05757 100644 --- a/vendor/object/src/read/macho/file.rs +++ b/vendor/object/src/read/macho/file.rs @@ -195,6 +195,8 @@ where 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, } } diff --git a/vendor/object/src/read/macho/load_command.rs b/vendor/object/src/read/macho/load_command.rs index 29fab6e0e..10daf4ed1 100644 --- a/vendor/object/src/read/macho/load_command.rs +++ b/vendor/object/src/read/macho/load_command.rs @@ -77,6 +77,11 @@ impl<'data, E: Endian> LoadCommandData<'data, E> { .read_error("Invalid Mach-O command size") } + /// Raw bytes of this LoadCommand structure. + pub fn raw_data(&self) -> &'data [u8] { + self.data.0 + } + /// Parse a load command string value. /// /// Strings used by load commands are specified by offsets that are diff --git a/vendor/object/src/read/mod.rs b/vendor/object/src/read/mod.rs index 41d344111..91a5c05a5 100644 --- a/vendor/object/src/read/mod.rs +++ b/vendor/object/src/read/mod.rs @@ -22,7 +22,8 @@ pub use util::*; feature = "elf", feature = "macho", feature = "pe", - feature = "wasm" + feature = "wasm", + feature = "xcoff" ))] mod any; #[cfg(any( @@ -30,7 +31,8 @@ mod any; feature = "elf", feature = "macho", feature = "pe", - feature = "wasm" + feature = "wasm", + feature = "xcoff" ))] pub use any::*; @@ -49,12 +51,15 @@ pub mod macho; #[cfg(feature = "pe")] pub mod pe; -mod traits; -pub use traits::*; - #[cfg(feature = "wasm")] pub mod wasm; +#[cfg(feature = "xcoff")] +pub mod xcoff; + +mod traits; +pub use traits::*; + mod private { pub trait Sealed {} } @@ -176,6 +181,12 @@ pub enum FileKind { /// A Wasm file. #[cfg(feature = "wasm")] Wasm, + /// A 32-bit XCOFF file. + #[cfg(feature = "xcoff")] + Xcoff32, + /// A 64-bit XCOFF file. + #[cfg(feature = "xcoff")] + Xcoff64, } impl FileKind { @@ -236,6 +247,10 @@ impl FileKind { | [0x4c, 0x01, ..] // COFF x86-64 | [0x64, 0x86, ..] => FileKind::Coff, + #[cfg(feature = "xcoff")] + [0x01, 0xDF, ..] => FileKind::Xcoff32, + #[cfg(feature = "xcoff")] + [0x01, 0xF7, ..] => FileKind::Xcoff64, _ => return Err(Error("Unknown file magic")), }; Ok(kind) diff --git a/vendor/object/src/read/pe/data_directory.rs b/vendor/object/src/read/pe/data_directory.rs index 8c1955355..f5d98774e 100644 --- a/vendor/object/src/read/pe/data_directory.rs +++ b/vendor/object/src/read/pe/data_directory.rs @@ -3,7 +3,10 @@ use core::slice; use crate::read::{Error, ReadError, ReadRef, Result}; use crate::{pe, LittleEndian as LE}; -use super::{ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectory, SectionTable}; +use super::{ + DelayLoadImportTable, ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectory, + SectionTable, +}; /// The table of data directories in a PE file. #[derive(Debug, Clone, Copy)] @@ -105,6 +108,29 @@ impl<'data> DataDirectories<'data> { 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. diff --git a/vendor/object/src/read/pe/file.rs b/vendor/object/src/read/pe/file.rs index 15b42074a..8dd85131a 100644 --- a/vendor/object/src/read/pe/file.rs +++ b/vendor/object/src/read/pe/file.rs @@ -304,49 +304,60 @@ where None => return Ok(None), }; let debug_data = data_dir.data(self.data, &self.common.sections).map(Bytes)?; - let debug_dir = debug_data - .read_at::<pe::ImageDebugDirectory>(0) - .read_error("Invalid PE debug dir size")?; + let debug_data_size = data_dir.size.get(LE) as usize; - if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW { - return Ok(None); + 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 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" { - return Ok(None); - } + 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 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 age = info.read::<U32<LE>>().read_error("Invalid CodeView Age")?; - let path = info - .read_string() - .read_error("Invalid CodeView file path")?; + let path = info + .read_string() + .read_error("Invalid CodeView file path")?; - Ok(Some(CodeView { - path: ByteString(path), - guid, - age: age.get(LE), - })) + return Ok(Some(CodeView { + path: ByteString(path), + guid, + age: age.get(LE), + })); + } + Ok(None) } fn has_debug_symbols(&self) -> bool { diff --git a/vendor/object/src/read/pe/import.rs b/vendor/object/src/read/pe/import.rs index 809a96286..a5535dc36 100644 --- a/vendor/object/src/read/pe/import.rs +++ b/vendor/object/src/read/pe/import.rs @@ -216,3 +216,117 @@ impl ImageThunkData for pe::ImageThunkData32 { self.0.get(LE) & 0x7fff_ffff } } + +/// Information for parsing a PE delay-load import table. +#[derive(Debug, Clone)] +pub struct DelayLoadImportTable<'data> { + section_data: Bytes<'data>, + section_address: u32, + import_address: u32, +} + +impl<'data> DelayLoadImportTable<'data> { + /// Create a new delay load import table parser. + /// + /// The import descriptors start at `import_address`. + /// This table works in the same way the import table does: descriptors will be + /// parsed until a null entry. + /// + /// `section_data` should be from the section containing `import_address`, and + /// `section_address` should be the address of that section. Pointers within the + /// descriptors and thunks may point to anywhere within the section data. + pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self { + DelayLoadImportTable { + section_data: Bytes(section_data), + section_address, + import_address, + } + } + + /// Return an iterator for the import descriptors. + pub fn descriptors(&self) -> Result<DelayLoadDescriptorIterator<'data>> { + let offset = self.import_address.wrapping_sub(self.section_address); + let mut data = self.section_data; + data.skip(offset as usize) + .read_error("Invalid PE delay-load import descriptor address")?; + Ok(DelayLoadDescriptorIterator { data }) + } + + /// Return a library name given its address. + /// + /// This address may be from [`pe::ImageDelayloadDescriptor::dll_name_rva`]. + pub fn name(&self, address: u32) -> Result<&'data [u8]> { + self.section_data + .read_string_at(address.wrapping_sub(self.section_address) as usize) + .read_error("Invalid PE import descriptor name") + } + + /// Return a list of thunks given its address. + /// + /// This address may be from the INT, i.e. from + /// [`pe::ImageDelayloadDescriptor::import_name_table_rva`]. + /// + /// Please note that others RVA values from [`pe::ImageDelayloadDescriptor`] are used + /// by the delay loader at runtime to store values, and thus do not point inside the same + /// section as the INT. Calling this function on those addresses will fail. + pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> { + let offset = address.wrapping_sub(self.section_address); + let mut data = self.section_data; + data.skip(offset as usize) + .read_error("Invalid PE delay load import thunk table address")?; + Ok(ImportThunkList { data }) + } + + /// Parse a thunk. + pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> { + if thunk.is_ordinal() { + Ok(Import::Ordinal(thunk.ordinal())) + } else { + let (hint, name) = self.hint_name(thunk.address())?; + Ok(Import::Name(hint, name)) + } + } + + /// Return the hint and name at the given address. + /// + /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`]. + /// + /// The hint is an index into the export name pointer table in the target library. + pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> { + let offset = address.wrapping_sub(self.section_address); + let mut data = self.section_data; + data.skip(offset as usize) + .read_error("Invalid PE delay load import thunk address")?; + let hint = data + .read::<U16Bytes<LE>>() + .read_error("Missing PE delay load import thunk hint")? + .get(LE); + let name = data + .read_string() + .read_error("Missing PE delay load import thunk name")?; + Ok((hint, name)) + } +} + +/// A fallible iterator for the descriptors in the delay-load data directory. +#[derive(Debug, Clone)] +pub struct DelayLoadDescriptorIterator<'data> { + data: Bytes<'data>, +} + +impl<'data> DelayLoadDescriptorIterator<'data> { + /// Return the next descriptor. + /// + /// Returns `Ok(None)` when a null descriptor is found. + pub fn next(&mut self) -> Result<Option<&'data pe::ImageDelayloadDescriptor>> { + let import_desc = self + .data + .read::<pe::ImageDelayloadDescriptor>() + .read_error("Missing PE null delay-load import descriptor")?; + if import_desc.is_null() { + Ok(None) + } else { + Ok(Some(import_desc)) + } + } +} diff --git a/vendor/object/src/read/pe/resource.rs b/vendor/object/src/read/pe/resource.rs index bfbb609f5..e667f0d98 100644 --- a/vendor/object/src/read/pe/resource.rs +++ b/vendor/object/src/read/pe/resource.rs @@ -1,7 +1,8 @@ use alloc::string::String; +use core::char; use crate::read::{ReadError, ReadRef, Result}; -use crate::{pe, LittleEndian as LE, U16}; +use crate::{pe, LittleEndian as LE, U16Bytes}; /// The `.rsrc` section of a PE file. #[derive(Debug, Clone, Copy)] @@ -17,7 +18,7 @@ impl<'data> ResourceDirectory<'data> { /// Parses the root resource directory. pub fn root(&self) -> Result<ResourceDirectoryTable<'data>> { - ResourceDirectoryTable::parse(&self.data, 0) + ResourceDirectoryTable::parse(self.data, 0) } } @@ -92,13 +93,13 @@ impl pe::ImageResourceDirectoryEntry { ) -> Result<ResourceDirectoryEntryData<'data>> { if self.is_table() { ResourceDirectoryTable::parse(section.data, self.data_offset()) - .map(|t| ResourceDirectoryEntryData::Table(t)) + .map(ResourceDirectoryEntryData::Table) } else { section .data .read_at::<pe::ImageResourceDataEntry>(self.data_offset().into()) .read_error("Invalid resource entry") - .map(|d| ResourceDirectoryEntryData::Data(d)) + .map(ResourceDirectoryEntryData::Data) } } } @@ -143,22 +144,33 @@ pub struct ResourceName { impl ResourceName { /// Converts to a `String`. pub fn to_string_lossy(&self, directory: ResourceDirectory) -> Result<String> { - let d = self.data(directory)?; - Ok(String::from_utf16_lossy(d)) + 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 [u16]> { + pub fn data<'data>( + &self, + directory: ResourceDirectory<'data>, + ) -> Result<&'data [U16Bytes<LE>]> { let mut offset = u64::from(self.offset); let len = directory .data - .read::<U16<LE>>(&mut offset) + .read::<U16Bytes<LE>>(&mut offset) .read_error("Invalid resource name offset")?; directory .data - .read_slice::<u16>(&mut offset, len.get(LE).into()) + .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. diff --git a/vendor/object/src/read/xcoff/comdat.rs b/vendor/object/src/read/xcoff/comdat.rs new file mode 100644 index 000000000..eeed2f54d --- /dev/null +++ b/vendor/object/src/read/xcoff/comdat.rs @@ -0,0 +1,130 @@ +//! XCOFF doesn't support the COMDAT section. + +use core::fmt::Debug; + +use crate::xcoff; + +use crate::read::{self, ComdatKind, ObjectComdat, ReadRef, Result, SectionIndex, SymbolIndex}; + +use super::{FileHeader, XcoffFile}; + +/// An iterator over the COMDAT section groups of a `XcoffFile32`. +pub type XcoffComdatIterator32<'data, 'file, R = &'data [u8]> = + XcoffComdatIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator over the COMDAT section groups of a `XcoffFile64`. +pub type XcoffComdatIterator64<'data, 'file, R = &'data [u8]> = + XcoffComdatIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator over the COMDAT section groups of a `XcoffFile`. +#[derive(Debug)] +pub struct XcoffComdatIterator<'data, 'file, Xcoff, R = &'data [u8]> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + #[allow(unused)] + pub(crate) file: &'file XcoffFile<'data, Xcoff, R>, +} + +impl<'data, 'file, Xcoff, R> Iterator for XcoffComdatIterator<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + type Item = XcoffComdat<'data, 'file, Xcoff, R>; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + None + } +} + +/// A COMDAT section group of a `XcoffFile32`. +pub type XcoffComdat32<'data, 'file, R = &'data [u8]> = + XcoffComdat<'data, 'file, xcoff::FileHeader32, R>; + +/// A COMDAT section group of a `XcoffFile64`. +pub type XcoffComdat64<'data, 'file, R = &'data [u8]> = + XcoffComdat<'data, 'file, xcoff::FileHeader64, R>; + +/// A COMDAT section group of a `XcoffFile`. +#[derive(Debug)] +pub struct XcoffComdat<'data, 'file, Xcoff, R = &'data [u8]> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + #[allow(unused)] + file: &'file XcoffFile<'data, Xcoff, R>, +} + +impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffComdat<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ +} + +impl<'data, 'file, Xcoff, R> ObjectComdat<'data> for XcoffComdat<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + type SectionIterator = XcoffComdatSectionIterator<'data, 'file, Xcoff, R>; + + #[inline] + fn kind(&self) -> ComdatKind { + unreachable!(); + } + + #[inline] + fn symbol(&self) -> SymbolIndex { + unreachable!(); + } + + #[inline] + fn name_bytes(&self) -> Result<&[u8]> { + unreachable!(); + } + + #[inline] + fn name(&self) -> Result<&str> { + unreachable!(); + } + + #[inline] + fn sections(&self) -> Self::SectionIterator { + unreachable!(); + } +} + +/// An iterator over the sections in a COMDAT section group of a `XcoffFile32`. +pub type XcoffComdatSectionIterator32<'data, 'file, R = &'data [u8]> = + XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator over the sections in a COMDAT section group of a `XcoffFile64`. +pub type XcoffComdatSectionIterator64<'data, 'file, R = &'data [u8]> = + XcoffComdatSectionIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator over the sections in a COMDAT section group of a `XcoffFile`. +#[derive(Debug)] +pub struct XcoffComdatSectionIterator<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + 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 000000000..bac9e7075 --- /dev/null +++ b/vendor/object/src/read/xcoff/file.rs @@ -0,0 +1,629 @@ +use core::fmt::Debug; +use core::mem; + +use alloc::vec::Vec; + +use crate::read::{self, Error, NoDynamicRelocationIterator, Object, ReadError, ReadRef, Result}; + +use crate::{ + xcoff, Architecture, BigEndian as BE, FileFlags, ObjectKind, ObjectSection, Pod, SectionIndex, + SymbolIndex, +}; + +use super::{ + CsectAux, FileAux, SectionHeader, SectionTable, Symbol, SymbolTable, XcoffComdat, + XcoffComdatIterator, XcoffSection, XcoffSectionIterator, XcoffSegment, XcoffSegmentIterator, + XcoffSymbol, XcoffSymbolIterator, XcoffSymbolTable, +}; + +/// A 32-bit XCOFF object file. +pub type XcoffFile32<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader32, R>; +/// A 64-bit XCOFF object file. +pub type XcoffFile64<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader64, R>; + +/// A partially parsed XCOFF file. +/// +/// Most of the functionality of this type is provided by the `Object` trait implementation. +#[derive(Debug)] +pub struct XcoffFile<'data, Xcoff, R = &'data [u8]> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + pub(super) data: R, + pub(super) header: &'data Xcoff, + pub(super) aux_header: Option<&'data Xcoff::AuxHeader>, + pub(super) sections: SectionTable<'data, Xcoff>, + pub(super) symbols: SymbolTable<'data, Xcoff, R>, +} + +impl<'data, Xcoff, R> XcoffFile<'data, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + /// Parse the raw XCOFF file data. + pub fn parse(data: R) -> Result<Self> { + let mut offset = 0; + let header = Xcoff::parse(data, &mut offset)?; + let aux_header = header.aux_header(data, &mut offset)?; + let sections = header.sections(data, &mut offset)?; + let symbols = header.symbols(data)?; + + Ok(XcoffFile { + data, + header, + aux_header, + sections, + symbols, + }) + } + + /// Returns the raw data. + pub fn data(&self) -> R { + self.data + } + + /// Returns the raw XCOFF file header. + pub fn raw_header(&self) -> &'data Xcoff { + self.header + } +} + +impl<'data, Xcoff, R> read::private::Sealed for XcoffFile<'data, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ +} + +impl<'data, 'file, Xcoff, R> Object<'data, 'file> for XcoffFile<'data, Xcoff, R> +where + 'data: 'file, + Xcoff: FileHeader, + R: 'file + ReadRef<'data>, +{ + type Segment = XcoffSegment<'data, 'file, Xcoff, R>; + type SegmentIterator = XcoffSegmentIterator<'data, 'file, Xcoff, R>; + type Section = XcoffSection<'data, 'file, Xcoff, R>; + type SectionIterator = XcoffSectionIterator<'data, 'file, Xcoff, R>; + type Comdat = XcoffComdat<'data, 'file, Xcoff, R>; + type ComdatIterator = XcoffComdatIterator<'data, 'file, Xcoff, R>; + type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>; + type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>; + type SymbolTable = XcoffSymbolTable<'data, 'file, Xcoff, R>; + type DynamicRelocationIterator = NoDynamicRelocationIterator; + + fn architecture(&self) -> crate::Architecture { + if self.is_64() { + Architecture::PowerPc64 + } else { + Architecture::PowerPc + } + } + + fn is_little_endian(&self) -> bool { + false + } + + fn is_64(&self) -> bool { + self.header.is_type_64() + } + + fn kind(&self) -> ObjectKind { + let flags = self.header.f_flags(); + if flags & xcoff::F_EXEC != 0 { + ObjectKind::Executable + } else if flags & xcoff::F_SHROBJ != 0 { + ObjectKind::Dynamic + } else if flags & xcoff::F_RELFLG == 0 { + ObjectKind::Relocatable + } else { + ObjectKind::Unknown + } + } + + fn segments(&'file self) -> XcoffSegmentIterator<'data, 'file, Xcoff, R> { + XcoffSegmentIterator { file: self } + } + + fn section_by_name_bytes( + &'file self, + section_name: &[u8], + ) -> Option<XcoffSection<'data, 'file, Xcoff, R>> { + self.sections() + .find(|section| section.name_bytes() == Ok(section_name)) + } + + fn section_by_index( + &'file self, + index: SectionIndex, + ) -> Result<XcoffSection<'data, 'file, Xcoff, R>> { + let section = self.sections.section(index)?; + Ok(XcoffSection { + file: self, + section, + index, + }) + } + + fn sections(&'file self) -> XcoffSectionIterator<'data, 'file, Xcoff, R> { + XcoffSectionIterator { + file: self, + iter: self.sections.iter().enumerate(), + } + } + + fn comdats(&'file self) -> XcoffComdatIterator<'data, 'file, Xcoff, R> { + XcoffComdatIterator { file: self } + } + + fn symbol_table(&'file self) -> Option<XcoffSymbolTable<'data, 'file, Xcoff, R>> { + if self.symbols.is_empty() { + return None; + } + Some(XcoffSymbolTable { + symbols: &self.symbols, + file: self, + }) + } + + fn symbol_by_index( + &'file self, + index: SymbolIndex, + ) -> Result<XcoffSymbol<'data, 'file, Xcoff, R>> { + let symbol = self.symbols.symbol(index.0)?; + Ok(XcoffSymbol { + symbols: &self.symbols, + index, + symbol, + file: self, + }) + } + + fn symbols(&'file self) -> XcoffSymbolIterator<'data, 'file, Xcoff, R> { + XcoffSymbolIterator { + symbols: &self.symbols, + index: 0, + file: self, + } + } + + fn dynamic_symbol_table(&'file self) -> Option<XcoffSymbolTable<'data, 'file, Xcoff, R>> { + None + } + + fn dynamic_symbols(&'file self) -> XcoffSymbolIterator<'data, 'file, Xcoff, R> { + // TODO: return the symbols in the STYP_LOADER section. + XcoffSymbolIterator { + file: self, + symbols: &self.symbols, + // Hack: don't return any. + index: self.symbols.len(), + } + } + + fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator> { + // TODO: return the relocations in the STYP_LOADER section. + None + } + + fn imports(&self) -> Result<alloc::vec::Vec<crate::Import<'data>>> { + // TODO: return the imports in the STYP_LOADER section. + Ok(Vec::new()) + } + + fn exports(&self) -> Result<alloc::vec::Vec<crate::Export<'data>>> { + // TODO: return the exports in the STYP_LOADER section. + Ok(Vec::new()) + } + + fn has_debug_symbols(&self) -> bool { + self.section_by_name(".debug").is_some() || self.section_by_name(".dwinfo").is_some() + } + + fn relative_address_base(&'file self) -> u64 { + 0 + } + + fn entry(&'file self) -> u64 { + if let Some(aux_header) = self.aux_header { + aux_header.o_entry().into() + } else { + 0 + } + } + + fn flags(&self) -> FileFlags { + FileFlags::Xcoff { + f_flags: self.header.f_flags(), + } + } +} + +/// A trait for generic access to `FileHeader32` and `FileHeader64`. +#[allow(missing_docs)] +pub trait FileHeader: Debug + Pod { + type Word: Into<u64>; + type AuxHeader: AuxHeader<Word = Self::Word>; + type SectionHeader: SectionHeader<Word = Self::Word>; + type Symbol: Symbol<Word = Self::Word>; + type FileAux: FileAux; + type CsectAux: CsectAux; + + /// Return true if this type is a 64-bit header. + fn is_type_64(&self) -> bool; + + fn f_magic(&self) -> u16; + fn f_nscns(&self) -> u16; + fn f_timdat(&self) -> u32; + fn f_symptr(&self) -> Self::Word; + fn f_nsyms(&self) -> u32; + fn f_opthdr(&self) -> u16; + fn f_flags(&self) -> u16; + + // Provided methods. + + /// Read the file header. + /// + /// Also checks that the magic field in the file header is a supported format. + fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> Result<&'data Self> { + let header = data + .read::<Self>(offset) + .read_error("Invalid XCOFF header size or alignment")?; + if !header.is_supported() { + return Err(Error("Unsupported XCOFF header")); + } + Ok(header) + } + + fn is_supported(&self) -> bool { + (self.is_type_64() && self.f_magic() == xcoff::MAGIC_64) + || (!self.is_type_64() && self.f_magic() == xcoff::MAGIC_32) + } + + /// Read the auxiliary file header. + fn aux_header<'data, R: ReadRef<'data>>( + &self, + data: R, + offset: &mut u64, + ) -> Result<Option<&'data Self::AuxHeader>> { + let aux_header_size = self.f_opthdr(); + if self.f_flags() & xcoff::F_EXEC == 0 { + // No auxiliary header is required for an object file that is not an executable. + // TODO: Some AIX programs generate auxiliary headers for 32-bit object files + // that end after the data_start field. + *offset += u64::from(aux_header_size); + return Ok(None); + } + // Executables, however, must have auxiliary headers that include the + // full structure definitions. + if aux_header_size != mem::size_of::<Self::AuxHeader>() as u16 { + *offset += u64::from(aux_header_size); + return Ok(None); + } + let aux_header = data + .read::<Self::AuxHeader>(offset) + .read_error("Invalid XCOFF auxiliary header size")?; + Ok(Some(aux_header)) + } + + /// Read the section table. + #[inline] + fn sections<'data, R: ReadRef<'data>>( + &self, + data: R, + offset: &mut u64, + ) -> Result<SectionTable<'data, Self>> { + SectionTable::parse(self, data, offset) + } + + /// Return the symbol table. + #[inline] + fn symbols<'data, R: ReadRef<'data>>(&self, data: R) -> Result<SymbolTable<'data, Self, R>> { + SymbolTable::parse(*self, data) + } +} + +impl FileHeader for xcoff::FileHeader32 { + type Word = u32; + type AuxHeader = xcoff::AuxHeader32; + type SectionHeader = xcoff::SectionHeader32; + type Symbol = xcoff::Symbol32; + type FileAux = xcoff::FileAux32; + type CsectAux = xcoff::CsectAux32; + + fn is_type_64(&self) -> bool { + false + } + + fn f_magic(&self) -> u16 { + self.f_magic.get(BE) + } + + fn f_nscns(&self) -> u16 { + self.f_nscns.get(BE) + } + + fn f_timdat(&self) -> u32 { + self.f_timdat.get(BE) + } + + fn f_symptr(&self) -> Self::Word { + self.f_symptr.get(BE) + } + + fn f_nsyms(&self) -> u32 { + self.f_nsyms.get(BE) + } + + fn f_opthdr(&self) -> u16 { + self.f_opthdr.get(BE) + } + + fn f_flags(&self) -> u16 { + self.f_flags.get(BE) + } +} + +impl FileHeader for xcoff::FileHeader64 { + type Word = u64; + type AuxHeader = xcoff::AuxHeader64; + type SectionHeader = xcoff::SectionHeader64; + type Symbol = xcoff::Symbol64; + type FileAux = xcoff::FileAux64; + type CsectAux = xcoff::CsectAux64; + + fn is_type_64(&self) -> bool { + true + } + + fn f_magic(&self) -> u16 { + self.f_magic.get(BE) + } + + fn f_nscns(&self) -> u16 { + self.f_nscns.get(BE) + } + + fn f_timdat(&self) -> u32 { + self.f_timdat.get(BE) + } + + fn f_symptr(&self) -> Self::Word { + self.f_symptr.get(BE) + } + + fn f_nsyms(&self) -> u32 { + self.f_nsyms.get(BE) + } + + fn f_opthdr(&self) -> u16 { + self.f_opthdr.get(BE) + } + + fn f_flags(&self) -> u16 { + self.f_flags.get(BE) + } +} + +#[allow(missing_docs)] +pub trait AuxHeader: Debug + Pod { + type Word: Into<u64>; + + fn o_vstamp(&self) -> u16; + fn o_tsize(&self) -> Self::Word; + fn o_dsize(&self) -> Self::Word; + fn o_bsize(&self) -> Self::Word; + fn o_entry(&self) -> Self::Word; + fn o_text_start(&self) -> Self::Word; + fn o_data_start(&self) -> Self::Word; + fn o_toc(&self) -> Self::Word; + fn o_snentry(&self) -> u16; + fn o_sntext(&self) -> u16; + fn o_sndata(&self) -> u16; + fn o_sntoc(&self) -> u16; + fn o_snloader(&self) -> u16; + fn o_snbss(&self) -> u16; + fn o_sntdata(&self) -> u16; + fn o_sntbss(&self) -> u16; + fn o_algntext(&self) -> u16; + fn o_algndata(&self) -> u16; + fn o_maxstack(&self) -> Self::Word; + fn o_maxdata(&self) -> Self::Word; + fn o_textpsize(&self) -> u8; + fn o_datapsize(&self) -> u8; + fn o_stackpsize(&self) -> u8; +} + +impl AuxHeader for xcoff::AuxHeader32 { + type Word = u32; + + fn o_vstamp(&self) -> u16 { + self.o_vstamp.get(BE) + } + + fn o_tsize(&self) -> Self::Word { + self.o_tsize.get(BE) + } + + fn o_dsize(&self) -> Self::Word { + self.o_dsize.get(BE) + } + + fn o_bsize(&self) -> Self::Word { + self.o_bsize.get(BE) + } + + fn o_entry(&self) -> Self::Word { + self.o_entry.get(BE) + } + + fn o_text_start(&self) -> Self::Word { + self.o_text_start.get(BE) + } + + fn o_data_start(&self) -> Self::Word { + self.o_data_start.get(BE) + } + + fn o_toc(&self) -> Self::Word { + self.o_toc.get(BE) + } + + fn o_snentry(&self) -> u16 { + self.o_snentry.get(BE) + } + + fn o_sntext(&self) -> u16 { + self.o_sntext.get(BE) + } + + fn o_sndata(&self) -> u16 { + self.o_sndata.get(BE) + } + + fn o_sntoc(&self) -> u16 { + self.o_sntoc.get(BE) + } + + fn o_snloader(&self) -> u16 { + self.o_snloader.get(BE) + } + + fn o_snbss(&self) -> u16 { + self.o_snbss.get(BE) + } + + fn o_sntdata(&self) -> u16 { + self.o_sntdata.get(BE) + } + + fn o_sntbss(&self) -> u16 { + self.o_sntbss.get(BE) + } + + fn o_algntext(&self) -> u16 { + self.o_algntext.get(BE) + } + + fn o_algndata(&self) -> u16 { + self.o_algndata.get(BE) + } + + fn o_maxstack(&self) -> Self::Word { + self.o_maxstack.get(BE) + } + + fn o_maxdata(&self) -> Self::Word { + self.o_maxdata.get(BE) + } + + fn o_textpsize(&self) -> u8 { + self.o_textpsize + } + + fn o_datapsize(&self) -> u8 { + self.o_datapsize + } + + fn o_stackpsize(&self) -> u8 { + self.o_stackpsize + } +} + +impl AuxHeader for xcoff::AuxHeader64 { + type Word = u64; + + fn o_vstamp(&self) -> u16 { + self.o_vstamp.get(BE) + } + + fn o_tsize(&self) -> Self::Word { + self.o_tsize.get(BE) + } + + fn o_dsize(&self) -> Self::Word { + self.o_dsize.get(BE) + } + + fn o_bsize(&self) -> Self::Word { + self.o_bsize.get(BE) + } + + fn o_entry(&self) -> Self::Word { + self.o_entry.get(BE) + } + + fn o_text_start(&self) -> Self::Word { + self.o_text_start.get(BE) + } + + fn o_data_start(&self) -> Self::Word { + self.o_data_start.get(BE) + } + + fn o_toc(&self) -> Self::Word { + self.o_toc.get(BE) + } + + fn o_snentry(&self) -> u16 { + self.o_snentry.get(BE) + } + + fn o_sntext(&self) -> u16 { + self.o_sntext.get(BE) + } + + fn o_sndata(&self) -> u16 { + self.o_sndata.get(BE) + } + + fn o_sntoc(&self) -> u16 { + self.o_sntoc.get(BE) + } + + fn o_snloader(&self) -> u16 { + self.o_snloader.get(BE) + } + + fn o_snbss(&self) -> u16 { + self.o_snbss.get(BE) + } + + fn o_sntdata(&self) -> u16 { + self.o_sntdata.get(BE) + } + + fn o_sntbss(&self) -> u16 { + self.o_sntbss.get(BE) + } + + fn o_algntext(&self) -> u16 { + self.o_algntext.get(BE) + } + + fn o_algndata(&self) -> u16 { + self.o_algndata.get(BE) + } + + fn o_maxstack(&self) -> Self::Word { + self.o_maxstack.get(BE) + } + + fn o_maxdata(&self) -> Self::Word { + self.o_maxdata.get(BE) + } + + fn o_textpsize(&self) -> u8 { + self.o_textpsize + } + + fn o_datapsize(&self) -> u8 { + self.o_datapsize + } + + fn o_stackpsize(&self) -> u8 { + self.o_stackpsize + } +} diff --git a/vendor/object/src/read/xcoff/mod.rs b/vendor/object/src/read/xcoff/mod.rs new file mode 100644 index 000000000..136e31073 --- /dev/null +++ b/vendor/object/src/read/xcoff/mod.rs @@ -0,0 +1,21 @@ +//! Support for reading AIX XCOFF files. +//! +//! Provides `XcoffFile` and related types which implement the `Object` trait. + +mod file; +pub use file::*; + +mod section; +pub use section::*; + +mod symbol; +pub use symbol::*; + +mod relocation; +pub use relocation::*; + +mod comdat; +pub use comdat::*; + +mod segment; +pub use segment::*; diff --git a/vendor/object/src/read/xcoff/relocation.rs b/vendor/object/src/read/xcoff/relocation.rs new file mode 100644 index 000000000..8107a2e82 --- /dev/null +++ b/vendor/object/src/read/xcoff/relocation.rs @@ -0,0 +1,128 @@ +use alloc::fmt; +use core::fmt::Debug; +use core::slice; + +use crate::pod::Pod; +use crate::{xcoff, BigEndian as BE, Relocation}; + +use crate::read::{ReadRef, RelocationEncoding, RelocationKind, RelocationTarget, SymbolIndex}; + +use super::{FileHeader, SectionHeader, XcoffFile}; + +/// An iterator over the relocations in a `XcoffSection32`. +pub type XcoffRelocationIterator32<'data, 'file, R = &'data [u8]> = + XcoffRelocationIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator over the relocations in a `XcoffSection64`. +pub type XcoffRelocationIterator64<'data, 'file, R = &'data [u8]> = + XcoffRelocationIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator over the relocations in a `XcoffSection`. +pub struct XcoffRelocationIterator<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + #[allow(unused)] + pub(super) file: &'file XcoffFile<'data, Xcoff, R>, + pub(super) relocations: + slice::Iter<'data, <<Xcoff as FileHeader>::SectionHeader as SectionHeader>::Rel>, +} + +impl<'data, 'file, Xcoff, R> Iterator for XcoffRelocationIterator<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + type Item = (u64, Relocation); + + fn next(&mut self) -> Option<Self::Item> { + self.relocations.next().map(|relocation| { + let encoding = RelocationEncoding::Generic; + let (kind, addend) = match relocation.r_rtype() { + xcoff::R_POS + | xcoff::R_RL + | xcoff::R_RLA + | xcoff::R_BA + | xcoff::R_RBA + | xcoff::R_TLS => (RelocationKind::Absolute, 0), + xcoff::R_REL | xcoff::R_BR | xcoff::R_RBR => (RelocationKind::Relative, -4), + xcoff::R_TOC | xcoff::R_TOCL | xcoff::R_TOCU => (RelocationKind::Got, 0), + r_type => (RelocationKind::Xcoff(r_type), 0), + }; + let size = (relocation.r_rsize() & 0x3F) + 1; + let target = RelocationTarget::Symbol(SymbolIndex(relocation.r_symndx() as usize)); + ( + relocation.r_vaddr().into(), + Relocation { + kind, + encoding, + size, + target, + addend, + implicit_addend: true, + }, + ) + }) + } +} + +impl<'data, 'file, Xcoff, R> fmt::Debug for XcoffRelocationIterator<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("XcoffRelocationIterator").finish() + } +} + +/// A trait for generic access to `Rel32` and `Rel64`. +#[allow(missing_docs)] +pub trait Rel: Debug + Pod { + type Word: Into<u64>; + fn r_vaddr(&self) -> Self::Word; + fn r_symndx(&self) -> u32; + fn r_rsize(&self) -> u8; + fn r_rtype(&self) -> u8; +} + +impl Rel for xcoff::Rel32 { + type Word = u32; + + fn r_vaddr(&self) -> Self::Word { + self.r_vaddr.get(BE) + } + + fn r_symndx(&self) -> u32 { + self.r_symndx.get(BE) + } + + fn r_rsize(&self) -> u8 { + self.r_rsize + } + + fn r_rtype(&self) -> u8 { + self.r_rtype + } +} + +impl Rel for xcoff::Rel64 { + type Word = u64; + + fn r_vaddr(&self) -> Self::Word { + self.r_vaddr.get(BE) + } + + fn r_symndx(&self) -> u32 { + self.r_symndx.get(BE) + } + + fn r_rsize(&self) -> u8 { + self.r_rsize + } + + fn r_rtype(&self) -> u8 { + self.r_rtype + } +} diff --git a/vendor/object/src/read/xcoff/section.rs b/vendor/object/src/read/xcoff/section.rs new file mode 100644 index 000000000..0944e10c8 --- /dev/null +++ b/vendor/object/src/read/xcoff/section.rs @@ -0,0 +1,426 @@ +use core::fmt::Debug; +use core::{iter, result, slice, str}; + +use crate::{ + xcoff, BigEndian as BE, CompressedData, CompressedFileRange, Pod, SectionFlags, SectionKind, +}; + +use crate::read::{self, Error, ObjectSection, ReadError, ReadRef, Result, SectionIndex}; + +use super::{AuxHeader, FileHeader, Rel, XcoffFile, XcoffRelocationIterator}; + +/// An iterator over the sections of an `XcoffFile32`. +pub type XcoffSectionIterator32<'data, 'file, R = &'data [u8]> = + XcoffSectionIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator over the sections of an `XcoffFile64`. +pub type XcoffSectionIterator64<'data, 'file, R = &'data [u8]> = + XcoffSectionIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator over the sections of an `XcoffFile`. +#[derive(Debug)] +pub struct XcoffSectionIterator<'data, 'file, Xcoff, R = &'data [u8]> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + pub(super) file: &'file XcoffFile<'data, Xcoff, R>, + pub(super) iter: iter::Enumerate<slice::Iter<'data, Xcoff::SectionHeader>>, +} + +impl<'data, 'file, Xcoff, R> Iterator for XcoffSectionIterator<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + type Item = XcoffSection<'data, 'file, Xcoff, R>; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().map(|(index, section)| XcoffSection { + index: SectionIndex(index), + file: self.file, + section, + }) + } +} + +/// A section of an `XcoffFile32`. +pub type XcoffSection32<'data, 'file, R = &'data [u8]> = + XcoffSection<'data, 'file, xcoff::FileHeader32, R>; +/// A section of an `XcoffFile64`. +pub type XcoffSection64<'data, 'file, R = &'data [u8]> = + XcoffSection<'data, 'file, xcoff::FileHeader64, R>; + +/// A section of an `XcoffFile`. +#[derive(Debug)] +pub struct XcoffSection<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + pub(super) file: &'file XcoffFile<'data, Xcoff, R>, + pub(super) section: &'data Xcoff::SectionHeader, + pub(super) index: SectionIndex, +} + +impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> XcoffSection<'data, 'file, Xcoff, R> { + fn bytes(&self) -> Result<&'data [u8]> { + self.section + .data(self.file.data) + .read_error("Invalid XCOFF section offset or size") + } +} + +impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffSection<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ +} + +impl<'data, 'file, Xcoff, R> ObjectSection<'data> for XcoffSection<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + type RelocationIterator = XcoffRelocationIterator<'data, 'file, Xcoff, R>; + + fn index(&self) -> SectionIndex { + self.index + } + + fn address(&self) -> u64 { + self.section.s_paddr().into() + } + + fn size(&self) -> u64 { + self.section.s_size().into() + } + + fn align(&self) -> u64 { + // The default section alignment is 4. + if let Some(aux_header) = self.file.aux_header { + match self.kind() { + SectionKind::Text => aux_header.o_algntext().into(), + SectionKind::Data => aux_header.o_algndata().into(), + _ => 4, + } + } else { + 4 + } + } + + fn file_range(&self) -> Option<(u64, u64)> { + self.section.file_range() + } + + fn data(&self) -> Result<&'data [u8]> { + self.bytes() + } + + fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { + Ok(read::util::data_range( + self.bytes()?, + self.address(), + address, + size, + )) + } + + fn compressed_file_range(&self) -> Result<CompressedFileRange> { + Ok(CompressedFileRange::none(self.file_range())) + } + + fn compressed_data(&self) -> Result<CompressedData<'data>> { + self.data().map(CompressedData::none) + } + + fn name_bytes(&self) -> read::Result<&[u8]> { + Ok(self.section.name()) + } + + fn name(&self) -> read::Result<&str> { + let name = self.name_bytes()?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 XCOFF section name") + } + + fn segment_name_bytes(&self) -> Result<Option<&[u8]>> { + Ok(None) + } + + fn segment_name(&self) -> Result<Option<&str>> { + Ok(None) + } + + fn kind(&self) -> SectionKind { + let section_type = self.section.s_flags() as u16; + if section_type & xcoff::STYP_TEXT != 0 { + SectionKind::Text + } else if section_type & xcoff::STYP_DATA != 0 { + SectionKind::Data + } else if section_type & xcoff::STYP_TDATA != 0 { + SectionKind::Tls + } else if section_type & xcoff::STYP_BSS != 0 { + SectionKind::UninitializedData + } else if section_type & xcoff::STYP_TBSS != 0 { + SectionKind::UninitializedTls + } else if section_type & (xcoff::STYP_DEBUG | xcoff::STYP_DWARF) != 0 { + SectionKind::Debug + } else if section_type & (xcoff::STYP_LOADER | xcoff::STYP_OVRFLO) != 0 { + SectionKind::Metadata + } else if section_type + & (xcoff::STYP_INFO | xcoff::STYP_EXCEPT | xcoff::STYP_PAD | xcoff::STYP_TYPCHK) + != 0 + { + SectionKind::Other + } else { + SectionKind::Unknown + } + } + + fn relocations(&self) -> Self::RelocationIterator { + let rel = self.section.relocations(self.file.data).unwrap_or(&[]); + XcoffRelocationIterator { + file: self.file, + relocations: rel.iter(), + } + } + + fn flags(&self) -> SectionFlags { + SectionFlags::Xcoff { + s_flags: self.section.s_flags(), + } + } + + fn uncompressed_data(&self) -> Result<alloc::borrow::Cow<'data, [u8]>> { + self.compressed_data()?.decompress() + } +} + +/// The table of section headers in an XCOFF file. +#[derive(Debug, Clone, Copy)] +pub struct SectionTable<'data, Xcoff: FileHeader> { + sections: &'data [Xcoff::SectionHeader], +} + +impl<'data, Xcoff> Default for SectionTable<'data, Xcoff> +where + Xcoff: FileHeader, +{ + fn default() -> Self { + Self { sections: &[] } + } +} + +impl<'data, Xcoff> SectionTable<'data, Xcoff> +where + Xcoff: FileHeader, +{ + /// Parse the section table. + /// + /// `data` must be the entire file data. + /// `offset` must be after the optional file header. + pub fn parse<R: ReadRef<'data>>(header: &Xcoff, data: R, offset: &mut u64) -> Result<Self> { + let section_num = header.f_nscns(); + if section_num == 0 { + return Ok(SectionTable::default()); + } + let sections = data + .read_slice(offset, section_num as usize) + .read_error("Invalid XCOFF section headers")?; + Ok(SectionTable { sections }) + } + + /// Iterate over the section headers. + #[inline] + pub fn iter(&self) -> slice::Iter<'data, Xcoff::SectionHeader> { + self.sections.iter() + } + + /// Return true if the section table is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.sections.is_empty() + } + + /// The number of section headers. + #[inline] + pub fn len(&self) -> usize { + self.sections.len() + } + + /// Return the section header at the given index. + pub fn section(&self, index: SectionIndex) -> read::Result<&'data Xcoff::SectionHeader> { + self.sections + .get(index.0) + .read_error("Invalid XCOFF section index") + } +} + +/// A trait for generic access to `SectionHeader32` and `SectionHeader64`. +#[allow(missing_docs)] +pub trait SectionHeader: Debug + Pod { + type Word: Into<u64>; + type HalfWord: Into<u32>; + type Xcoff: FileHeader<SectionHeader = Self, Word = Self::Word>; + type Rel: Rel<Word = Self::Word>; + + fn s_name(&self) -> &[u8; 8]; + fn s_paddr(&self) -> Self::Word; + fn s_vaddr(&self) -> Self::Word; + fn s_size(&self) -> Self::Word; + fn s_scnptr(&self) -> Self::Word; + fn s_relptr(&self) -> Self::Word; + fn s_lnnoptr(&self) -> Self::Word; + fn s_nreloc(&self) -> Self::HalfWord; + fn s_nlnno(&self) -> Self::HalfWord; + fn s_flags(&self) -> u32; + + /// Return the section name. + fn name(&self) -> &[u8] { + let sectname = &self.s_name()[..]; + match memchr::memchr(b'\0', sectname) { + Some(end) => §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 000000000..49969438d --- /dev/null +++ b/vendor/object/src/read/xcoff/segment.rs @@ -0,0 +1,115 @@ +//! TODO: Support the segment for XCOFF when auxiliary file header and loader section is ready. + +use core::fmt::Debug; +use core::str; + +use crate::read::{self, ObjectSegment, ReadRef, Result}; +use crate::xcoff; + +use super::{FileHeader, XcoffFile}; + +/// An iterator over the segments of an `XcoffFile32`. +pub type XcoffSegmentIterator32<'data, 'file, R = &'data [u8]> = + XcoffSegmentIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator over the segments of an `XcoffFile64`. +pub type XcoffSegmentIterator64<'data, 'file, R = &'data [u8]> = + XcoffSegmentIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator over the segments of an `XcoffFile`. +#[derive(Debug)] +pub struct XcoffSegmentIterator<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + #[allow(unused)] + pub(super) file: &'file XcoffFile<'data, Xcoff, R>, +} + +impl<'data, 'file, Xcoff, R> Iterator for XcoffSegmentIterator<'data, 'file, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + type Item = XcoffSegment<'data, 'file, Xcoff, R>; + + fn next(&mut self) -> Option<Self::Item> { + None + } +} + +/// A segment of an `XcoffFile32`. +pub type XcoffSegment32<'data, 'file, R = &'data [u8]> = + XcoffSegment<'data, 'file, xcoff::FileHeader32, R>; +/// A segment of an `XcoffFile64`. +pub type XcoffSegment64<'data, 'file, R = &'data [u8]> = + XcoffSegment<'data, 'file, xcoff::FileHeader64, R>; + +/// A loadable section of an `XcoffFile`. +#[derive(Debug)] +pub struct XcoffSegment<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + 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 000000000..6738ad171 --- /dev/null +++ b/vendor/object/src/read/xcoff/symbol.rs @@ -0,0 +1,634 @@ +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::Pod; +use crate::read::util::StringTable; +use crate::{bytes_of, xcoff, Object, ObjectSection, SectionKind}; + +use crate::read::{ + self, Bytes, Error, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex, + SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, +}; + +use super::{FileHeader, XcoffFile}; + +/// A table of symbol entries in an XCOFF file. +/// +/// Also includes the string table used for the symbol names. +#[derive(Debug)] +pub struct SymbolTable<'data, Xcoff, R = &'data [u8]> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + symbols: &'data [xcoff::SymbolBytes], + strings: StringTable<'data, R>, + header: PhantomData<Xcoff>, +} + +impl<'data, Xcoff, R> Default for SymbolTable<'data, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + fn default() -> Self { + Self { + symbols: &[], + strings: StringTable::default(), + header: PhantomData, + } + } +} + +impl<'data, Xcoff, R> SymbolTable<'data, Xcoff, R> +where + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + /// Parse the symbol table. + pub fn parse(header: Xcoff, data: R) -> Result<Self> { + let mut offset = header.f_symptr().into(); + let (symbols, strings) = if offset != 0 { + let symbols = data + .read_slice(&mut offset, header.f_nsyms() as usize) + .read_error("Invalid XCOFF symbol table offset or size")?; + + // Parse the string table. + // Note: don't update data when reading length; the length includes itself. + let length = data + .read_at::<U32Bytes<_>>(offset) + .read_error("Missing XCOFF string table")? + .get(BE); + let str_end = offset + .checked_add(length as u64) + .read_error("Invalid XCOFF string table length")?; + let strings = StringTable::new(data, offset, str_end); + + (symbols, strings) + } else { + (&[][..], StringTable::default()) + }; + + Ok(SymbolTable { + symbols, + strings, + header: PhantomData, + }) + } + + /// Return the symbol entry at the given index and offset. + pub fn get<T: Pod>(&self, index: usize, offset: usize) -> Result<&'data T> { + let entry = index + .checked_add(offset) + .and_then(|x| self.symbols.get(x)) + .read_error("Invalid XCOFF symbol index")?; + let bytes = bytes_of(entry); + Bytes(bytes).read().read_error("Invalid XCOFF symbol data") + } + + /// Return the symbol at the given index. + pub fn symbol(&self, index: usize) -> Result<&'data Xcoff::Symbol> { + self.get::<Xcoff::Symbol>(index, 0) + } + + /// Return the file auxiliary symbol. + pub fn aux_file(&self, index: usize) -> Result<&'data Xcoff::FileAux> { + debug_assert!(self.symbol(index)?.has_aux_file()); + let aux_file = self.get::<Xcoff::FileAux>(index, 1)?; + if let Some(aux_type) = aux_file.x_auxtype() { + if aux_type != xcoff::AUX_FILE { + return Err(Error("Invalid index for file auxiliary symbol.")); + } + } + Ok(aux_file) + } + + /// Return the csect auxiliary symbol. + pub fn aux_csect(&self, index: usize, offset: usize) -> Result<&'data Xcoff::CsectAux> { + debug_assert!(self.symbol(index)?.has_aux_csect()); + let aux_csect = self.get::<Xcoff::CsectAux>(index, offset)?; + if let Some(aux_type) = aux_csect.x_auxtype() { + if aux_type != xcoff::AUX_CSECT { + return Err(Error("Invalid index/offset for csect auxiliary symbol.")); + } + } + Ok(aux_csect) + } + + /// Return true if the symbol table is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.symbols.is_empty() + } + + /// The number of symbol table entries. + /// + /// This includes auxiliary symbol table entries. + #[inline] + pub fn len(&self) -> usize { + self.symbols.len() + } +} + +/// A symbol table of an `XcoffFile32`. +pub type XcoffSymbolTable32<'data, 'file, R = &'data [u8]> = + XcoffSymbolTable<'data, 'file, xcoff::FileHeader32, R>; +/// A symbol table of an `XcoffFile64`. +pub type XcoffSymbolTable64<'data, 'file, R = &'data [u8]> = + XcoffSymbolTable<'data, 'file, xcoff::FileHeader64, R>; + +/// A symbol table of an `XcoffFile`. +#[derive(Debug, Clone, Copy)] +pub struct XcoffSymbolTable<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + pub(crate) file: &'file XcoffFile<'data, Xcoff, R>, + pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, +} + +impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed + for XcoffSymbolTable<'data, 'file, Xcoff, R> +{ +} + +impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data> + for XcoffSymbolTable<'data, 'file, Xcoff, R> +{ + type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>; + type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>; + + fn symbols(&self) -> Self::SymbolIterator { + XcoffSymbolIterator { + file: self.file, + symbols: self.symbols, + index: 0, + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> { + let symbol = self.symbols.symbol(index.0)?; + Ok(XcoffSymbol { + file: self.file, + symbols: self.symbols, + index, + symbol, + }) + } +} + +/// An iterator over the symbols of an `XcoffFile32`. +pub type XcoffSymbolIterator32<'data, 'file, R = &'data [u8]> = + XcoffSymbolIterator<'data, 'file, xcoff::FileHeader32, R>; +/// An iterator over the symbols of an `XcoffFile64`. +pub type XcoffSymbolIterator64<'data, 'file, R = &'data [u8]> = + XcoffSymbolIterator<'data, 'file, xcoff::FileHeader64, R>; + +/// An iterator over the symbols of an `XcoffFile`. +pub struct XcoffSymbolIterator<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + pub(crate) file: &'file XcoffFile<'data, Xcoff, R>, + pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, + pub(super) index: usize, +} + +impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> fmt::Debug + for XcoffSymbolIterator<'data, 'file, Xcoff, R> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("XcoffSymbolIterator").finish() + } +} + +impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> Iterator + for XcoffSymbolIterator<'data, 'file, Xcoff, R> +{ + type Item = XcoffSymbol<'data, 'file, Xcoff, R>; + + fn next(&mut self) -> Option<Self::Item> { + let index = self.index; + let symbol = self.symbols.symbol(index).ok()?; + // TODO: skip over the auxiliary symbols for now. + self.index += 1 + symbol.n_numaux() as usize; + Some(XcoffSymbol { + file: self.file, + symbols: self.symbols, + index: SymbolIndex(index), + symbol, + }) + } +} + +/// A symbol of an `XcoffFile32`. +pub type XcoffSymbol32<'data, 'file, R = &'data [u8]> = + XcoffSymbol<'data, 'file, xcoff::FileHeader32, R>; +/// A symbol of an `XcoffFile64`. +pub type XcoffSymbol64<'data, 'file, R = &'data [u8]> = + XcoffSymbol<'data, 'file, xcoff::FileHeader64, R>; + +/// A symbol of an `XcoffFile`. +#[derive(Debug, Clone, Copy)] +pub struct XcoffSymbol<'data, 'file, Xcoff, R = &'data [u8]> +where + 'data: 'file, + Xcoff: FileHeader, + R: ReadRef<'data>, +{ + pub(crate) file: &'file XcoffFile<'data, Xcoff, R>, + pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, + pub(super) index: SymbolIndex, + pub(super) symbol: &'data Xcoff::Symbol, +} + +impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed + for XcoffSymbol<'data, 'file, Xcoff, R> +{ +} + +impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> + for XcoffSymbol<'data, 'file, Xcoff, R> +{ + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + fn name_bytes(&self) -> Result<&'data [u8]> { + 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 => self.symbol.n_value().into(), + _ => 0, + } + } + + #[inline] + fn size(&self) -> u64 { + if self.symbol.has_aux_csect() { + // XCOFF32 must have the csect auxiliary entry as the last auxiliary entry. + // XCOFF64 doesn't require this, but conventionally does. + if let Ok(aux_csect) = self + .file + .symbols + .aux_csect(self.index.0, self.symbol.n_numaux() as usize) + { + let sym_type = aux_csect.sym_type() & 0x07; + if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM { + aux_csect.x_scnlen() + } else { + 0 + } + } else { + 0 + } + } else { + 0 + } + } + + fn kind(&self) -> SymbolKind { + match self.symbol.n_sclass() { + xcoff::C_FILE => SymbolKind::File, + xcoff::C_NULL => SymbolKind::Null, + _ => self + .file + .section_by_index(SectionIndex((self.symbol.n_scnum() - 1) as usize)) + .map(|section| match section.kind() { + SectionKind::Data | SectionKind::UninitializedData => SymbolKind::Data, + SectionKind::UninitializedTls | SectionKind::Tls => SymbolKind::Tls, + SectionKind::Text => SymbolKind::Text, + _ => SymbolKind::Unknown, + }) + .unwrap_or(SymbolKind::Unknown), + } + } + + fn section(&self) -> SymbolSection { + match self.symbol.n_scnum() { + xcoff::N_ABS => SymbolSection::Absolute, + xcoff::N_UNDEF => SymbolSection::Undefined, + xcoff::N_DEBUG => SymbolSection::None, + index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)), + _ => SymbolSection::Unknown, + } + } + + #[inline] + fn is_undefined(&self) -> bool { + self.symbol.is_undefined() + } + + /// Return true if the symbol is a definition of a function or data object. + #[inline] + fn is_definition(&self) -> bool { + if self.symbol.has_aux_csect() { + if let Ok(aux_csect) = self + .symbols + .aux_csect(self.index.0, self.symbol.n_numaux() as usize) + { + let smclas = aux_csect.x_smclas(); + self.symbol.n_scnum() != xcoff::N_UNDEF + && (smclas == xcoff::XMC_PR + || smclas == xcoff::XMC_RW + || smclas == xcoff::XMC_RO) + } else { + false + } + } else { + false + } + } + + #[inline] + fn is_common(&self) -> bool { + self.symbol.n_sclass() == xcoff::C_EXT && self.symbol.n_scnum() == xcoff::N_UNDEF + } + + #[inline] + fn is_weak(&self) -> bool { + self.symbol.n_sclass() == xcoff::C_WEAKEXT + } + + fn scope(&self) -> SymbolScope { + if self.symbol.n_scnum() == xcoff::N_UNDEF { + SymbolScope::Unknown + } else { + match self.symbol.n_sclass() { + xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => { + let visibility = self.symbol.n_type() & xcoff::SYM_V_MASK; + if visibility == xcoff::SYM_V_HIDDEN { + SymbolScope::Linkage + } else { + SymbolScope::Dynamic + } + } + _ => SymbolScope::Compilation, + } + } + } + + #[inline] + fn is_global(&self) -> bool { + match self.symbol.n_sclass() { + xcoff::C_EXT | xcoff::C_WEAKEXT => true, + _ => false, + } + } + + #[inline] + fn is_local(&self) -> bool { + !self.is_global() + } + + #[inline] + fn flags(&self) -> SymbolFlags<SectionIndex> { + SymbolFlags::None + } +} + +/// A trait for generic access to `Symbol32` and `Symbol64`. +#[allow(missing_docs)] +pub trait Symbol: Debug + Pod { + type Word: Into<u64>; + + fn n_value(&self) -> Self::Word; + fn n_scnum(&self) -> i16; + fn n_type(&self) -> u16; + fn n_sclass(&self) -> u8; + fn n_numaux(&self) -> u8; + + fn name<'data, R: ReadRef<'data>>( + &'data self, + strings: StringTable<'data, R>, + ) -> Result<&'data [u8]>; + + /// Return true if the symbol is undefined. + #[inline] + fn is_undefined(&self) -> bool { + let n_sclass = self.n_sclass(); + (n_sclass == xcoff::C_EXT || n_sclass == xcoff::C_WEAKEXT) + && self.n_scnum() == xcoff::N_UNDEF + } + + /// Return true if the symbol has file auxiliary entry. + fn has_aux_file(&self) -> bool { + self.n_numaux() > 0 && self.n_sclass() == xcoff::C_FILE + } + + /// Return true if the symbol has csect auxiliary entry. + /// + /// A csect auxiliary entry is required for each symbol table entry that has + /// a storage class value of C_EXT, C_WEAKEXT, or C_HIDEXT. + fn has_aux_csect(&self) -> bool { + let sclass = self.n_sclass(); + self.n_numaux() > 0 + && (sclass == xcoff::C_EXT || sclass == xcoff::C_WEAKEXT || sclass == xcoff::C_HIDEXT) + } +} + +impl Symbol for xcoff::Symbol64 { + type Word = u64; + + fn n_value(&self) -> Self::Word { + self.n_value.get(BE) + } + + fn n_scnum(&self) -> i16 { + self.n_scnum.get(BE) + } + + fn n_type(&self) -> u16 { + self.n_type.get(BE) + } + + fn n_sclass(&self) -> u8 { + self.n_sclass + } + + fn n_numaux(&self) -> u8 { + self.n_numaux + } + + /// Parse the symbol name for XCOFF64. + fn name<'data, R: ReadRef<'data>>( + &'data self, + strings: StringTable<'data, R>, + ) -> Result<&'data [u8]> { + strings + .get(self.n_offset.get(BE)) + .read_error("Invalid XCOFF symbol name offset") + } +} + +impl Symbol for xcoff::Symbol32 { + type Word = u32; + + fn n_value(&self) -> Self::Word { + self.n_value.get(BE) + } + + fn n_scnum(&self) -> i16 { + self.n_scnum.get(BE) + } + + fn n_type(&self) -> u16 { + self.n_type.get(BE) + } + + fn n_sclass(&self) -> u8 { + self.n_sclass + } + + fn n_numaux(&self) -> u8 { + self.n_numaux + } + + /// Parse the symbol name for XCOFF32. + fn name<'data, R: ReadRef<'data>>( + &'data self, + strings: StringTable<'data, R>, + ) -> Result<&'data [u8]> { + if self.n_name[0] == 0 { + // If the name starts with 0 then the last 4 bytes are a string table offset. + let offset = u32::from_be_bytes(self.n_name[4..8].try_into().unwrap()); + strings + .get(offset) + .read_error("Invalid XCOFF symbol name offset") + } else { + // The name is inline and padded with nulls. + Ok(match memchr::memchr(b'\0', &self.n_name) { + Some(end) => &self.n_name[..end], + None => &self.n_name, + }) + } + } +} + +/// A trait for generic access to `FileAux32` and `FileAux64`. +#[allow(missing_docs)] +pub trait FileAux: Debug + Pod { + fn x_fname(&self) -> &[u8; 8]; + fn x_ftype(&self) -> u8; + fn x_auxtype(&self) -> Option<u8>; +} + +impl FileAux for xcoff::FileAux64 { + fn x_fname(&self) -> &[u8; 8] { + &self.x_fname + } + + fn x_ftype(&self) -> u8 { + self.x_ftype + } + + fn x_auxtype(&self) -> Option<u8> { + Some(self.x_auxtype) + } +} + +impl FileAux for xcoff::FileAux32 { + fn x_fname(&self) -> &[u8; 8] { + &self.x_fname + } + + fn x_ftype(&self) -> u8 { + self.x_ftype + } + + fn x_auxtype(&self) -> Option<u8> { + None + } +} + +/// A trait for generic access to `CsectAux32` and `CsectAux64`. +#[allow(missing_docs)] +pub trait CsectAux: Debug + Pod { + fn x_scnlen(&self) -> u64; + fn x_parmhash(&self) -> u32; + fn x_snhash(&self) -> u16; + fn x_smtyp(&self) -> u8; + fn x_smclas(&self) -> u8; + fn x_auxtype(&self) -> Option<u8>; + + fn sym_type(&self) -> u8 { + self.x_smtyp() & 0x07 + } +} + +impl CsectAux for xcoff::CsectAux64 { + fn x_scnlen(&self) -> u64 { + self.x_scnlen_lo.get(BE) as u64 | ((self.x_scnlen_hi.get(BE) as u64) << 32) + } + + fn x_parmhash(&self) -> u32 { + self.x_parmhash.get(BE) + } + + fn x_snhash(&self) -> u16 { + self.x_snhash.get(BE) + } + + fn x_smtyp(&self) -> u8 { + self.x_smtyp + } + + fn x_smclas(&self) -> u8 { + self.x_smclas + } + + fn x_auxtype(&self) -> Option<u8> { + Some(self.x_auxtype) + } +} + +impl CsectAux for xcoff::CsectAux32 { + fn x_scnlen(&self) -> u64 { + self.x_scnlen.get(BE) as u64 + } + + fn x_parmhash(&self) -> u32 { + self.x_parmhash.get(BE) + } + + fn x_snhash(&self) -> u16 { + self.x_snhash.get(BE) + } + + fn x_smtyp(&self) -> u8 { + self.x_smtyp + } + + fn x_smclas(&self) -> u8 { + self.x_smclas + } + + fn x_auxtype(&self) -> Option<u8> { + None + } +} diff --git a/vendor/object/src/write/coff.rs b/vendor/object/src/write/coff.rs index 6647b9611..c7489d3d6 100644 --- a/vendor/object/src/write/coff.rs +++ b/vendor/object/src/write/coff.rs @@ -117,8 +117,7 @@ impl<'a> Object<'a> { } let stub_size = self.architecture.address_size().unwrap().bytes(); - let mut name = b".rdata$.refptr.".to_vec(); - name.extend_from_slice(&self.symbols[symbol_id.0].name); + 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)); diff --git a/vendor/object/src/write/elf/object.rs b/vendor/object/src/write/elf/object.rs index 8c1fa4717..068ada6bd 100644 --- a/vendor/object/src/write/elf/object.rs +++ b/vendor/object/src/write/elf/object.rs @@ -67,6 +67,7 @@ impl<'a> Object<'a> { 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, @@ -83,7 +84,9 @@ impl<'a> Object<'a> { Architecture::Riscv64 => true, Architecture::Riscv32 => true, Architecture::S390x => true, + Architecture::Sbf => false, Architecture::Sparc64 => true, + Architecture::Xtensa => true, _ => { return Err(Error(format!( "unimplemented architecture {:?}", @@ -264,6 +267,7 @@ impl<'a> Object<'a> { let e_type = elf::ET_REL; let e_machine = match self.architecture { Architecture::Aarch64 => elf::EM_AARCH64, + Architecture::Aarch64_Ilp32 => elf::EM_AARCH64, Architecture::Arm => elf::EM_ARM, Architecture::Avr => elf::EM_AVR, Architecture::Bpf => elf::EM_BPF, @@ -280,7 +284,9 @@ impl<'a> Object<'a> { Architecture::Riscv32 => elf::EM_RISCV, Architecture::Riscv64 => elf::EM_RISCV, Architecture::S390x => elf::EM_S390, + Architecture::Sbf => elf::EM_SBF, Architecture::Sparc64 => elf::EM_SPARCV9, + Architecture::Xtensa => elf::EM_XTENSA, _ => { return Err(Error(format!( "unimplemented architecture {:?}", @@ -450,6 +456,20 @@ impl<'a> Object<'a> { 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, @@ -528,6 +548,25 @@ impl<'a> Object<'a> { { (RelocationKind::Absolute, _, 32) => elf::R_LARCH_32, (RelocationKind::Absolute, _, 64) => elf::R_LARCH_64, + (RelocationKind::Relative, _, 32) => elf::R_LARCH_32_PCREL, + (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 16) + | ( + RelocationKind::PltRelative, + RelocationEncoding::LoongArchBranch, + 16, + ) => elf::R_LARCH_B16, + (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 21) + | ( + RelocationKind::PltRelative, + RelocationEncoding::LoongArchBranch, + 21, + ) => elf::R_LARCH_B21, + (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 26) + | ( + RelocationKind::PltRelative, + RelocationEncoding::LoongArchBranch, + 26, + ) => elf::R_LARCH_B26, (RelocationKind::Elf(x), _, _) => x, _ => { return Err(Error(format!("unimplemented relocation {:?}", reloc))); @@ -574,6 +613,9 @@ impl<'a> Object<'a> { 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!( @@ -649,6 +691,14 @@ impl<'a> Object<'a> { return Err(Error(format!("unimplemented relocation {:?}", reloc))); } }, + Architecture::Sbf => match (reloc.kind, reloc.encoding, reloc.size) { + (RelocationKind::Absolute, _, 64) => elf::R_SBF_64_64, + (RelocationKind::Absolute, _, 32) => elf::R_SBF_64_32, + (RelocationKind::Elf(x), _, _) => x, + _ => { + return Err(Error(format!("unimplemented relocation {:?}", reloc))); + } + }, Architecture::Sparc64 => match (reloc.kind, reloc.encoding, reloc.size) { // TODO: use R_SPARC_32/R_SPARC_64 if aligned. (RelocationKind::Absolute, _, 32) => elf::R_SPARC_UA32, @@ -658,6 +708,16 @@ impl<'a> Object<'a> { 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 diff --git a/vendor/object/src/write/macho.rs b/vendor/object/src/write/macho.rs index f689dec51..8ef722fae 100644 --- a/vendor/object/src/write/macho.rs +++ b/vendor/object/src/write/macho.rs @@ -175,11 +175,17 @@ impl<'a> Object<'a> { pub(crate) fn macho_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 { let constant = match relocation.kind { + // AArch64Call relocations have special handling for the addend, so don't adjust it + RelocationKind::Relative if relocation.encoding == RelocationEncoding::AArch64Call => 0, RelocationKind::Relative | RelocationKind::GotRelative | RelocationKind::PltRelative => relocation.addend + 4, _ => relocation.addend, }; + // Aarch64 relocs of these sizes act as if they are double-word length + if self.architecture == Architecture::Aarch64 && matches!(relocation.size, 12 | 21 | 26) { + relocation.size = 32; + } relocation.addend -= constant; constant } @@ -326,6 +332,8 @@ impl<'a> Object<'a> { Architecture::Aarch64 => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), Architecture::I386 => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), Architecture::X86_64 => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), + Architecture::PowerPc => (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL), + Architecture::PowerPc64 => (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL), _ => { return Err(Error(format!( "unimplemented architecture {:?}", @@ -532,7 +540,7 @@ impl<'a> Object<'a> { debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); for reloc in §ion.relocations { let r_extern; - let r_symbolnum; + let mut r_symbolnum; let symbol = &self.symbols[reloc.symbol.0]; if symbol.kind == SymbolKind::Section { r_symbolnum = section_offsets[symbol.section.id().unwrap().0].index as u32; @@ -588,6 +596,26 @@ impl<'a> Object<'a> { (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { (false, macho::ARM64_RELOC_UNSIGNED) } + (RelocationKind::Relative, RelocationEncoding::AArch64Call, 0) => { + (true, macho::ARM64_RELOC_BRANCH26) + } + // Non-zero addend, so we have to encode the addend separately + (RelocationKind::Relative, RelocationEncoding::AArch64Call, value) => { + // first emit the BR26 relocation + let reloc_info = macho::RelocationInfo { + r_address: reloc.offset as u32, + r_symbolnum, + r_pcrel: true, + r_length, + r_extern: true, + r_type: macho::ARM64_RELOC_BRANCH26, + }; + buffer.write(&reloc_info.relocation(endian)); + + // set up a separate relocation for the addend + r_symbolnum = value as u32; + (false, macho::ARM64_RELOC_ADDEND) + } ( RelocationKind::MachO { value, relative }, RelocationEncoding::Generic, diff --git a/vendor/object/src/xcoff.rs b/vendor/object/src/xcoff.rs new file mode 100644 index 000000000..4724f8ef8 --- /dev/null +++ b/vendor/object/src/xcoff.rs @@ -0,0 +1,893 @@ +//! XCOFF definitions +//! +//! These definitions are independent of read/write support, although we do implement +//! some traits useful for those. +//! +//! This module is the equivalent of /usr/include/xcoff.h, and is based heavily on it. + +#![allow(missing_docs)] + +use crate::endian::{BigEndian as BE, I16, U16, U32, U64}; +use crate::pod::Pod; + +/// The header at the start of every 32-bit XCOFF file. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FileHeader32 { + /// Magic number. Must be 0x01DF. + pub f_magic: U16<BE>, + /// Number of sections. + pub f_nscns: U16<BE>, + /// Time and date of file creation. + pub f_timdat: U32<BE>, + /// Byte offset to symbol table start. + pub f_symptr: U32<BE>, + /// Number of entries in symbol table. + pub f_nsyms: U32<BE>, + /// Number of bytes in optional header + pub f_opthdr: U16<BE>, + /// Extra flags. + pub f_flags: U16<BE>, +} + +/// The header at the start of every 64-bit XCOFF file. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FileHeader64 { + /// Magic number. Must be 0x01F7. + pub f_magic: U16<BE>, + /// Number of sections. + pub f_nscns: U16<BE>, + /// Time and date of file creation + pub f_timdat: U32<BE>, + /// Byte offset to symbol table start. + pub f_symptr: U64<BE>, + /// Number of bytes in optional header + pub f_opthdr: U16<BE>, + /// Extra flags. + pub f_flags: U16<BE>, + /// Number of entries in symbol table. + pub f_nsyms: U32<BE>, +} + +// Values for `f_magic`. +// +/// the 64-bit mach magic number +pub const MAGIC_64: u16 = 0x01F7; +/// the 32-bit mach magic number +pub const MAGIC_32: u16 = 0x01DF; + +// Values for `f_flags`. +// +/// Indicates that the relocation information for binding has been removed from +/// the file. +pub const F_RELFLG: u16 = 0x0001; +/// Indicates that the file is executable. No unresolved external references exist. +pub const F_EXEC: u16 = 0x0002; +/// Indicates that line numbers have been stripped from the file by a utility program. +pub const F_LNNO: u16 = 0x0004; +/// Indicates that the file was profiled with the fdpr command. +pub const F_FDPR_PROF: u16 = 0x0010; +/// Indicates that the file was reordered with the fdpr command. +pub const F_FDPR_OPTI: u16 = 0x0020; +/// Indicates that the file uses Very Large Program Support. +pub const F_DSA: u16 = 0x0040; +/// Indicates that one of the members of the auxiliary header specifying the +/// medium page sizes is non-zero. +pub const F_VARPG: u16 = 0x0100; +/// Indicates the file is dynamically loadable and executable. External references +/// are resolved by way of imports, and the file might contain exports and loader +/// relocation. +pub const F_DYNLOAD: u16 = 0x1000; +/// Indicates the file is a shared object (shared library). The file is separately +/// loadable. That is, it is not normally bound with other objects, and its loader +/// exports symbols are used as automatic import symbols for other object files. +pub const F_SHROBJ: u16 = 0x2000; +/// If the object file is a member of an archive, it can be loaded by the system +/// loader, but the member is ignored by the binder. If the object file is not in +/// an archive, this flag has no effect. +pub const F_LOADONLY: u16 = 0x4000; + +/// The auxiliary header immediately following file header. If the value of the +/// f_opthdr field in the file header is 0, the auxiliary header does not exist. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct AuxHeader32 { + /// Flags. + pub o_mflag: U16<BE>, + /// Version. + pub o_vstamp: U16<BE>, + /// Text size in bytes. + pub o_tsize: U32<BE>, + /// Initialized data size in bytes. + pub o_dsize: U32<BE>, + /// Uninitialized data size in bytes. + pub o_bsize: U32<BE>, + /// Entry point descriptor (virtual address). + pub o_entry: U32<BE>, + /// Base address of text (virtual address). + pub o_text_start: U32<BE>, + /// Base address of data (virtual address). + pub o_data_start: U32<BE>, + /// Address of TOC anchor. + pub o_toc: U32<BE>, + /// Section number for entry point. + pub o_snentry: U16<BE>, + /// Section number for .text. + pub o_sntext: U16<BE>, + /// Section number for .data. + pub o_sndata: U16<BE>, + /// Section number for TOC. + pub o_sntoc: U16<BE>, + /// Section number for loader data. + pub o_snloader: U16<BE>, + /// Section number for .bss. + pub o_snbss: U16<BE>, + /// Maximum alignment for .text. + pub o_algntext: U16<BE>, + /// Maximum alignment for .data. + pub o_algndata: U16<BE>, + /// Module type field. + pub o_modtype: U16<BE>, + /// Bit flags - cpu types of objects. + pub o_cpuflag: u8, + /// Reserved for CPU type. + pub o_cputype: u8, + /// Maximum stack size allowed (bytes). + pub o_maxstack: U32<BE>, + /// Maximum data size allowed (bytes). + pub o_maxdata: U32<BE>, + /// Reserved for debuggers. + pub o_debugger: U32<BE>, + /// Requested text page size. + pub o_textpsize: u8, + /// Requested data page size. + pub o_datapsize: u8, + /// Requested stack page size. + pub o_stackpsize: u8, + /// Flags and thread-local storage alignment. + pub o_flags: u8, + /// Section number for .tdata. + pub o_sntdata: U16<BE>, + /// Section number for .tbss. + pub o_sntbss: U16<BE>, +} + +/// The auxiliary header immediately following file header. If the value of the +/// f_opthdr field in the file header is 0, the auxiliary header does not exist. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct AuxHeader64 { + /// Flags. + pub o_mflag: U16<BE>, + /// Version. + pub o_vstamp: U16<BE>, + /// Reserved for debuggers. + pub o_debugger: U32<BE>, + /// Base address of text (virtual address). + pub o_text_start: U64<BE>, + /// Base address of data (virtual address). + pub o_data_start: U64<BE>, + /// Address of TOC anchor. + pub o_toc: U64<BE>, + /// Section number for entry point. + pub o_snentry: U16<BE>, + /// Section number for .text. + pub o_sntext: U16<BE>, + /// Section number for .data. + pub o_sndata: U16<BE>, + /// Section number for TOC. + pub o_sntoc: U16<BE>, + /// Section number for loader data. + pub o_snloader: U16<BE>, + /// Section number for .bss. + pub o_snbss: U16<BE>, + /// Maximum alignment for .text. + pub o_algntext: U16<BE>, + /// Maximum alignment for .data. + pub o_algndata: U16<BE>, + /// Module type field. + pub o_modtype: U16<BE>, + /// Bit flags - cpu types of objects. + pub o_cpuflag: u8, + /// Reserved for CPU type. + pub o_cputype: u8, + /// Requested text page size. + pub o_textpsize: u8, + /// Requested data page size. + pub o_datapsize: u8, + /// Requested stack page size. + pub o_stackpsize: u8, + /// Flags and thread-local storage alignment. + pub o_flags: u8, + /// Text size in bytes. + pub o_tsize: U64<BE>, + /// Initialized data size in bytes. + pub o_dsize: U64<BE>, + /// Uninitialized data size in bytes. + pub o_bsize: U64<BE>, + /// Entry point descriptor (virtual address). + pub o_entry: U64<BE>, + /// Maximum stack size allowed (bytes). + pub o_maxstack: U64<BE>, + /// Maximum data size allowed (bytes). + pub o_maxdata: U64<BE>, + /// Section number for .tdata. + pub o_sntdata: U16<BE>, + /// Section number for .tbss. + pub o_sntbss: U16<BE>, + /// XCOFF64 flags. + pub o_x64flags: U16<BE>, + /// Reserved. + pub o_resv3a: U16<BE>, + /// Reserved. + pub o_resv3: [U32<BE>; 2], +} + +/// Some AIX programs generate auxiliary headers for 32-bit object files that +/// end after the data_start field. +pub const AOUTHSZ_SHORT: u16 = 28; + +/// Section header. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SectionHeader32 { + /// Section name. + pub s_name: [u8; 8], + /// Physical address. + pub s_paddr: U32<BE>, + /// Virtual address (same as physical address). + pub s_vaddr: U32<BE>, + /// Section size. + pub s_size: U32<BE>, + /// Offset in file to raw data for section. + pub s_scnptr: U32<BE>, + /// Offset in file to relocation entries for section. + pub s_relptr: U32<BE>, + /// Offset in file to line number entries for section. + pub s_lnnoptr: U32<BE>, + /// Number of relocation entries. + pub s_nreloc: U16<BE>, + /// Number of line number entries. + pub s_nlnno: U16<BE>, + /// Flags to define the section type. + pub s_flags: U32<BE>, +} + +/// Section header. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SectionHeader64 { + /// Section name. + pub s_name: [u8; 8], + /// Physical address. + pub s_paddr: U64<BE>, + /// Virtual address (same as physical address). + pub s_vaddr: U64<BE>, + /// Section size. + pub s_size: U64<BE>, + /// Offset in file to raw data for section. + pub s_scnptr: U64<BE>, + /// Offset in file to relocation entries for section. + pub s_relptr: U64<BE>, + /// Offset in file to line number entries for section. + pub s_lnnoptr: U64<BE>, + /// Number of relocation entries. + pub s_nreloc: U32<BE>, + /// Number of line number entries. + pub s_nlnno: U32<BE>, + /// Flags to define the section type. + pub s_flags: U32<BE>, + /// Reserved. + pub s_reserve: U32<BE>, +} + +// Values for `s_flags`. +// +/// "regular" section +pub const STYP_REG: u16 = 0x00; +/// Specifies a pad section. A section of this type is used to provide alignment +/// padding between sections within an XCOFF executable object file. This section +/// header type is obsolete since padding is allowed in an XCOFF file without a +/// corresponding pad section header. +pub const STYP_PAD: u16 = 0x08; +/// Specifies a DWARF debugging section, which provide source file and symbol +/// information for the symbolic debugger. +pub const STYP_DWARF: u16 = 0x10; +/// Specifies an executable text (code) section. A section of this type contains +/// the executable instructions of a program. +pub const STYP_TEXT: u16 = 0x20; +/// Specifies an initialized data section. A section of this type contains the +/// initialized data and the TOC of a program. +pub const STYP_DATA: u16 = 0x40; +/// Specifies an uninitialized data section. A section header of this type +/// defines the uninitialized data of a program. +pub const STYP_BSS: u16 = 0x80; +/// Specifies an exception section. A section of this type provides information +/// to identify the reason that a trap or exception occurred within an executable +/// object program. +pub const STYP_EXCEPT: u16 = 0x0100; +/// Specifies a comment section. A section of this type provides comments or data +/// to special processing utility programs. +pub const STYP_INFO: u16 = 0x0200; +/// Specifies an initialized thread-local data section. +pub const STYP_TDATA: u16 = 0x0400; +/// Specifies an uninitialized thread-local data section. +pub const STYP_TBSS: u16 = 0x0800; +/// Specifies a loader section. A section of this type contains object file +/// information for the system loader to load an XCOFF executable. The information +/// includes imported symbols, exported symbols, relocation data, type-check +/// information, and shared object names. +pub const STYP_LOADER: u16 = 0x1000; +/// Specifies a debug section. A section of this type contains stabstring +/// information used by the symbolic debugger. +pub const STYP_DEBUG: u16 = 0x2000; +/// Specifies a type-check section. A section of this type contains +/// parameter/argument type-check strings used by the binder. +pub const STYP_TYPCHK: u16 = 0x4000; +/// Specifies a relocation or line-number field overflow section. A section +/// header of this type contains the count of relocation entries and line +/// number entries for some other section. This section header is required +/// when either of the counts exceeds 65,534. +pub const STYP_OVRFLO: u16 = 0x8000; + +pub const SIZEOF_SYMBOL: usize = 18; + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SymbolBytes(pub [u8; SIZEOF_SYMBOL]); + +/// Symbol table entry. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Symbol32 { + /// Symbol name. + /// + /// If first 4 bytes are 0, then second 4 bytes are offset into string table. + pub n_name: [u8; 8], + /// Symbol value; storage class-dependent. + pub n_value: U32<BE>, + /// Section number of symbol. + pub n_scnum: I16<BE>, + /// Basic and derived type specification. + pub n_type: U16<BE>, + /// Storage class of symbol. + pub n_sclass: u8, + /// Number of auxiliary entries. + pub n_numaux: u8, +} + +/// Symbol table entry. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Symbol64 { + /// Symbol value; storage class-dependent. + pub n_value: U64<BE>, + /// Offset of the name in string table or .debug section. + pub n_offset: U32<BE>, + /// Section number of symbol. + pub n_scnum: I16<BE>, + /// Basic and derived type specification. + pub n_type: U16<BE>, + /// Storage class of symbol. + pub n_sclass: u8, + /// Number of auxiliary entries. + pub n_numaux: u8, +} + +// Values for `n_scnum`. +// +/// A special symbolic debugging symbol. +pub const N_DEBUG: i16 = -2; +/// An absolute symbol. The symbol has a value but is not relocatable. +pub const N_ABS: i16 = -1; +/// An undefined external symbol. +pub const N_UNDEF: i16 = 0; + +// Vlaues for `n_type`. +// +/// Values for visibility as they would appear when encoded in the high 4 bits +/// of the 16-bit unsigned n_type field of symbol table entries. Valid for +/// 32-bit XCOFF only when the o_vstamp in the auxiliary header is greater than 1. +pub const SYM_V_MASK: u16 = 0xF000; +pub const SYM_V_INTERNAL: u16 = 0x1000; +pub const SYM_V_HIDDEN: u16 = 0x2000; +pub const SYM_V_PROTECTED: u16 = 0x3000; +pub const SYM_V_EXPORTED: u16 = 0x4000; + +// Values for `n_sclass`. +// +// Storage classes used for symbolic debugging symbols. +// +/// Source file name and compiler information. +pub const C_FILE: u8 = 103; +/// Beginning of include file. +pub const C_BINCL: u8 = 108; +/// Ending of include file. +pub const C_EINCL: u8 = 109; +/// Global variable. +pub const C_GSYM: u8 = 128; +/// Statically allocated symbol. +pub const C_STSYM: u8 = 133; +/// Beginning of common block. +pub const C_BCOMM: u8 = 135; +/// End of common block. +pub const C_ECOMM: u8 = 137; +/// Alternate entry. +pub const C_ENTRY: u8 = 141; +/// Beginning of static block. +pub const C_BSTAT: u8 = 143; +/// End of static block. +pub const C_ESTAT: u8 = 144; +/// Global thread-local variable. +pub const C_GTLS: u8 = 145; +/// Static thread-local variable. +pub const C_STTLS: u8 = 146; +/// DWARF section symbol. +pub const C_DWARF: u8 = 112; +// +// Storage classes used for absolute symbols. +// +/// Automatic variable allocated on stack. +pub const C_LSYM: u8 = 129; +/// Argument to subroutine allocated on stack. +pub const C_PSYM: u8 = 130; +/// Register variable. +pub const C_RSYM: u8 = 131; +/// Argument to function or procedure stored in register. +pub const C_RPSYM: u8 = 132; +/// Local member of common block. +pub const C_ECOML: u8 = 136; +/// Function or procedure. +pub const C_FUN: u8 = 142; +// +// Storage classes used for undefined external symbols or symbols of general sections. +// +/// External symbol. +pub const C_EXT: u8 = 2; +/// Weak external symbol. +pub const C_WEAKEXT: u8 = 111; +// +// Storage classes used for symbols of general sections. +// +/// Symbol table entry marked for deletion. +pub const C_NULL: u8 = 0; +/// Static. +pub const C_STAT: u8 = 3; +/// Beginning or end of inner block. +pub const C_BLOCK: u8 = 100; +/// Beginning or end of function. +pub const C_FCN: u8 = 101; +/// Un-named external symbol. +pub const C_HIDEXT: u8 = 107; +/// Comment string in .info section. +pub const C_INFO: u8 = 110; +/// Declaration of object (type). +pub const C_DECL: u8 = 140; +// +// Storage classes - Obsolete/Undocumented. +// +/// Automatic variable. +pub const C_AUTO: u8 = 1; +/// Register variable. +pub const C_REG: u8 = 4; +/// External definition. +pub const C_EXTDEF: u8 = 5; +/// Label. +pub const C_LABEL: u8 = 6; +/// Undefined label. +pub const C_ULABEL: u8 = 7; +/// Member of structure. +pub const C_MOS: u8 = 8; +/// Function argument. +pub const C_ARG: u8 = 9; +/// Structure tag. +pub const C_STRTAG: u8 = 10; +/// Member of union. +pub const C_MOU: u8 = 11; +/// Union tag. +pub const C_UNTAG: u8 = 12; +/// Type definition. +pub const C_TPDEF: u8 = 13; +/// Undefined static. +pub const C_USTATIC: u8 = 14; +/// Enumeration tag. +pub const C_ENTAG: u8 = 15; +/// Member of enumeration. +pub const C_MOE: u8 = 16; +/// Register parameter. +pub const C_REGPARM: u8 = 17; +/// Bit field. +pub const C_FIELD: u8 = 18; +/// End of structure. +pub const C_EOS: u8 = 102; +/// Duplicate tag. +pub const C_ALIAS: u8 = 105; +/// Special storage class for external. +pub const C_HIDDEN: u8 = 106; +/// Physical end of function. +pub const C_EFCN: u8 = 255; +/// Reserved. +pub const C_TCSYM: u8 = 134; + +/// File Auxiliary Entry for C_FILE Symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FileAux32 { + /// The source file name or compiler-related string. + /// + /// If first 4 bytes are 0, then second 4 bytes are offset into string table. + pub x_fname: [u8; 8], + /// Pad size for file name. + pub x_fpad: [u8; 6], + /// The source-file string type. + pub x_ftype: u8, + /// Reserved. + pub x_freserve: [u8; 3], +} + +/// File Auxiliary Entry for C_FILE Symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FileAux64 { + /// The source file name or compiler-related string. + /// + /// If first 4 bytes are 0, then second 4 bytes are offset into string table. + pub x_fname: [u8; 8], + /// Pad size for file name. + pub x_fpad: [u8; 6], + /// The source-file string type. + pub x_ftype: u8, + /// Reserved. + pub x_freserve: [u8; 2], + /// Specifies the type of auxiliary entry. Contains _AUX_FILE for this auxiliary entry. + pub x_auxtype: u8, +} + +// Values for `x_ftype`. +// +/// Specifies the source-file name. +pub const XFT_FN: u8 = 0; +/// Specifies the compiler time stamp. +pub const XFT_CT: u8 = 1; +/// Specifies the compiler version number. +pub const XFT_CV: u8 = 2; +/// Specifies compiler-defined information. +pub const XFT_CD: u8 = 128; + +/// Csect auxiliary entry for C_EXT, C_WEAKEXT, and C_HIDEXT symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct CsectAux32 { + /// Section length. + pub x_scnlen: U32<BE>, + /// Offset of parameter type-check hash in .typchk section. + pub x_parmhash: U32<BE>, + /// .typchk section number. + pub x_snhash: U16<BE>, + /// Symbol alignment and type. + pub x_smtyp: u8, + /// Storage mapping class. + pub x_smclas: u8, + /// Reserved. + pub x_stab: U32<BE>, + /// x_snstab. + pub x_snstab: U16<BE>, +} + +/// Csect auxiliary entry for C_EXT, C_WEAKEXT, and C_HIDEXT symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct CsectAux64 { + /// Low 4 bytes of section length. + pub x_scnlen_lo: U32<BE>, + /// Offset of parameter type-check hash in .typchk section. + pub x_parmhash: U32<BE>, + /// .typchk section number. + pub x_snhash: U16<BE>, + /// Symbol alignment and type. + pub x_smtyp: u8, + /// Storage mapping class. + pub x_smclas: u8, + /// High 4 bytes of section length. + pub x_scnlen_hi: U32<BE>, + /// Reserved. + pub pad: u8, + /// Contains _AUX_CSECT; indicates type of auxiliary entry. + pub x_auxtype: u8, +} + +// Values for `x_smtyp`. +// +/// External reference. +pub const XTY_ER: u8 = 0; +/// Csect definition for initialized storage. +pub const XTY_SD: u8 = 1; +/// Defines an entry point to an initialized csect. +pub const XTY_LD: u8 = 2; +/// Common csect definition. For uninitialized storage. +pub const XTY_CM: u8 = 3; + +// Values for `x_smclas`. +// +// READ ONLY CLASSES +// +/// Program Code +pub const XMC_PR: u8 = 0; +/// Read Only Constant +pub const XMC_RO: u8 = 1; +/// Debug Dictionary Table +pub const XMC_DB: u8 = 2; +/// Global Linkage (Interfile Interface Code) +pub const XMC_GL: u8 = 6; +/// Extended Operation (Pseudo Machine Instruction) +pub const XMC_XO: u8 = 7; +/// Supervisor Call (32-bit process only) +pub const XMC_SV: u8 = 8; +/// Supervisor Call for 64-bit process +pub const XMC_SV64: u8 = 17; +/// Supervisor Call for both 32- and 64-bit processes +pub const XMC_SV3264: u8 = 18; +/// Traceback Index csect +pub const XMC_TI: u8 = 12; +/// Traceback Table csect +pub const XMC_TB: u8 = 13; +// +// READ WRITE CLASSES +// +/// Read Write Data +pub const XMC_RW: u8 = 5; +/// TOC Anchor for TOC Addressability +pub const XMC_TC0: u8 = 15; +/// General TOC item +pub const XMC_TC: u8 = 3; +/// Scalar data item in the TOC +pub const XMC_TD: u8 = 16; +/// Descriptor csect +pub const XMC_DS: u8 = 10; +/// Unclassified - Treated as Read Write +pub const XMC_UA: u8 = 4; +/// BSS class (uninitialized static internal) +pub const XMC_BS: u8 = 9; +/// Un-named Fortran Common +pub const XMC_UC: u8 = 11; +/// Initialized thread-local variable +pub const XMC_TL: u8 = 20; +/// Uninitialized thread-local variable +pub const XMC_UL: u8 = 21; +/// Symbol mapped at the end of TOC +pub const XMC_TE: u8 = 22; + +/// Function auxiliary entry. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FunAux32 { + /// File offset to exception table entry. + pub x_exptr: U32<BE>, + /// Size of function in bytes. + pub x_fsize: U32<BE>, + /// File pointer to line number + pub x_lnnoptr: U32<BE>, + /// Symbol table index of next entry beyond this function. + pub x_endndx: U32<BE>, + /// Pad + pub pad: U16<BE>, +} + +/// Function auxiliary entry. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FunAux64 { + /// File pointer to line number + pub x_lnnoptr: U64<BE>, + /// Size of function in bytes. + pub x_fsize: U32<BE>, + /// Symbol table index of next entry beyond this function. + pub x_endndx: U32<BE>, + /// Pad + pub pad: u8, + /// Contains _AUX_FCN; Type of auxiliary entry. + pub x_auxtype: u8, +} + +/// Exception auxiliary entry. (XCOFF64 only) +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct ExpAux { + /// File offset to exception table entry. + pub x_exptr: U64<BE>, + /// Size of function in bytes. + pub x_fsize: U32<BE>, + /// Symbol table index of next entry beyond this function. + pub x_endndx: U32<BE>, + /// Pad + pub pad: u8, + /// Contains _AUX_EXCEPT; Type of auxiliary entry + pub x_auxtype: u8, +} + +/// Block auxiliary entry for the C_BLOCK and C_FCN Symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct BlockAux32 { + /// Reserved. + pub pad: [u8; 2], + /// High-order 2 bytes of the source line number. + pub x_lnnohi: U16<BE>, + /// Low-order 2 bytes of the source line number. + pub x_lnnolo: U16<BE>, + /// Reserved. + pub pad2: [u8; 12], +} + +/// Block auxiliary entry for the C_BLOCK and C_FCN Symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct BlockAux64 { + /// Source line number. + pub x_lnno: U32<BE>, + /// Reserved. + pub pad: [u8; 13], + /// Contains _AUX_SYM; Type of auxiliary entry. + pub x_auxtype: u8, +} + +/// Section auxiliary entry for the C_STAT Symbol. (XCOFF32 Only) +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct StatAux { + /// Section length. + pub x_scnlen: U32<BE>, + /// Number of relocation entries. + pub x_nreloc: U16<BE>, + /// Number of line numbers. + pub x_nlinno: U16<BE>, + /// Reserved. + pub pad: [u8; 10], +} + +/// Section auxiliary entry Format for C_DWARF symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DwarfAux32 { + /// Length of portion of section represented by symbol. + pub x_scnlen: U32<BE>, + /// Reserved. + pub pad: [u8; 4], + /// Number of relocation entries in section. + pub x_nreloc: U32<BE>, + /// Reserved. + pub pad2: [u8; 6], +} + +/// Section auxiliary entry Format for C_DWARF symbols. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DwarfAux64 { + /// Length of portion of section represented by symbol. + pub x_scnlen: U64<BE>, + /// Number of relocation entries in section. + pub x_nreloc: U64<BE>, + /// Reserved. + pub pad: u8, + /// Contains _AUX_SECT; Type of Auxillary 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, +); |