зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1807630 - Update the object crate to 0.30.0. r=mstange,supply-chain-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D165528
This commit is contained in:
Родитель
5f638aa50c
Коммит
06330c8a21
|
@ -3879,9 +3879,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.28.4"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
|
||||
checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
|
@ -1270,6 +1270,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "1.13.1 -> 1.14.0"
|
||||
|
||||
[[audits.object]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.28.4 -> 0.30.0"
|
||||
|
||||
[[audits.ohttp]]
|
||||
who = "Dana Keeler <dkeeler@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -2,6 +2,93 @@
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.30.0
|
||||
|
||||
Released 2022/11/22.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* The minimum supported rust version for the `read` feature has changed to 1.52.0.
|
||||
[#458](https://github.com/gimli-rs/object/pull/458)
|
||||
|
||||
* The minimum supported rust version for the `write` feature has changed to 1.61.0.
|
||||
|
||||
* Fixed endian handling in `read::elf::SymbolTable::shndx`.
|
||||
[#458](https://github.com/gimli-rs/object/pull/458)
|
||||
|
||||
* Fixed endian handling in `read::pe::ResourceName`.
|
||||
[#458](https://github.com/gimli-rs/object/pull/458)
|
||||
|
||||
* Changed definitions for LoongArch ELF header flags.
|
||||
[#483](https://github.com/gimli-rs/object/pull/483)
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed parsing of multiple debug directory entries in `read::pe::PeFile::pdb_info`.
|
||||
[#451](https://github.com/gimli-rs/object/pull/451)
|
||||
|
||||
* Changed the section name used when writing COFF stub symbols.
|
||||
[#475](https://github.com/gimli-rs/object/pull/475)
|
||||
|
||||
### Added
|
||||
|
||||
* Added `read::pe::DataDirectories::delay_load_import_table`.
|
||||
[#448](https://github.com/gimli-rs/object/pull/448)
|
||||
|
||||
* Added `read::macho::LoadCommandData::raw_data`.
|
||||
[#449](https://github.com/gimli-rs/object/pull/449)
|
||||
|
||||
* Added ELF relocations for LoongArch ps ABI v2.
|
||||
[#450](https://github.com/gimli-rs/object/pull/450)
|
||||
|
||||
* Added PowerPC support for Mach-O.
|
||||
[#460](https://github.com/gimli-rs/object/pull/460)
|
||||
|
||||
* Added support for reading the AIX big archive format.
|
||||
[#462](https://github.com/gimli-rs/object/pull/462)
|
||||
[#467](https://github.com/gimli-rs/object/pull/467)
|
||||
[#473](https://github.com/gimli-rs/object/pull/473)
|
||||
|
||||
* Added support for `RelocationEncoding::AArch64Call` when writing Mach-O files.
|
||||
[#465](https://github.com/gimli-rs/object/pull/465)
|
||||
|
||||
* Added support for `RelocationKind::Relative` when writing RISC-V ELF files.
|
||||
[#470](https://github.com/gimli-rs/object/pull/470)
|
||||
|
||||
* Added Xtensa architecture support for ELF.
|
||||
[#481](https://github.com/gimli-rs/object/pull/481)
|
||||
|
||||
* Added `read::pe::ResourceName::raw_data`.
|
||||
[#487](https://github.com/gimli-rs/object/pull/487)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.29.0
|
||||
|
||||
Released 2022/06/22.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* The `write` feature now has a minimum supported rust version of 1.56.1.
|
||||
[#444](https://github.com/gimli-rs/object/pull/444)
|
||||
|
||||
* Added `os_abi` and `abi_version` fields to `FileFlags::Elf`.
|
||||
[#438](https://github.com/gimli-rs/object/pull/438)
|
||||
[#441](https://github.com/gimli-rs/object/pull/441)
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed handling of empty symbol tables in `read::elf::ElfFile::symbol_table` and
|
||||
`read::elf::ElfFile::dynamic_symbol_table`.
|
||||
[#443](https://github.com/gimli-rs/object/pull/443)
|
||||
|
||||
### Added
|
||||
|
||||
* Added more `ELF_OSABI_*` constants.
|
||||
[#439](https://github.com/gimli-rs/object/pull/439)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.28.4
|
||||
|
||||
Released 2022/05/09.
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "object"
|
||||
version = "0.28.4"
|
||||
version = "0.30.0"
|
||||
exclude = [
|
||||
"/.github",
|
||||
"/testfiles",
|
||||
]
|
||||
description = "A unified interface for reading and writing object file formats."
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"object",
|
||||
"elf",
|
||||
|
@ -27,6 +28,7 @@ keywords = [
|
|||
]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/gimli-rs/object"
|
||||
resolver = "2"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["doc"]
|
||||
|
@ -55,7 +57,7 @@ version = "1"
|
|||
optional = true
|
||||
|
||||
[dependencies.hashbrown]
|
||||
version = "0.11"
|
||||
version = "0.13.1"
|
||||
features = ["ahash"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
@ -124,6 +126,12 @@ rustc-dep-of-std = [
|
|||
]
|
||||
std = ["memchr/std"]
|
||||
unaligned = []
|
||||
unstable = []
|
||||
unstable-all = [
|
||||
"all",
|
||||
"unstable",
|
||||
"xcoff",
|
||||
]
|
||||
wasm = ["wasmparser"]
|
||||
write = [
|
||||
"write_std",
|
||||
|
@ -143,3 +151,4 @@ write_std = [
|
|||
"indexmap/std",
|
||||
"crc32fast/std",
|
||||
]
|
||||
xcoff = []
|
||||
|
|
|
@ -34,6 +34,14 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
See [`crates/examples`](crates/examples) for more examples.
|
||||
|
||||
## Minimum Supported Rust Version (MSRV)
|
||||
|
||||
Changes to MSRV are considered breaking changes. We are conservative about changing the MSRV,
|
||||
but sometimes are required to due to dependencies. The MSRV is:
|
||||
|
||||
* 1.52.0 for the `read` feature and its dependencies.
|
||||
* 1.61.0 for the `write` feature and its dependencies.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
|
|
@ -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,);
|
||||
|
|
|
@ -24,6 +24,7 @@ pub enum Architecture {
|
|||
S390x,
|
||||
Sparc64,
|
||||
Wasm32,
|
||||
Xtensa,
|
||||
}
|
||||
|
||||
impl Architecture {
|
||||
|
@ -52,6 +53,7 @@ impl Architecture {
|
|||
Architecture::S390x => Some(AddressSize::U64),
|
||||
Architecture::Sparc64 => Some(AddressSize::U64),
|
||||
Architecture::Wasm32 => Some(AddressSize::U32),
|
||||
Architecture::Xtensa => Some(AddressSize::U32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +90,7 @@ pub enum BinaryFormat {
|
|||
MachO,
|
||||
Pe,
|
||||
Wasm,
|
||||
Xcoff,
|
||||
}
|
||||
|
||||
/// The kind of a section.
|
||||
|
@ -305,6 +308,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 +348,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.
|
||||
|
@ -353,6 +363,10 @@ pub enum FileFlags {
|
|||
None,
|
||||
/// ELF file flags.
|
||||
Elf {
|
||||
/// `os_abi` field in the ELF file header.
|
||||
os_abi: u8,
|
||||
/// `abi_version` field in the ELF file header.
|
||||
abi_version: u8,
|
||||
/// `e_flags` field in the ELF file header.
|
||||
e_flags: u32,
|
||||
},
|
||||
|
@ -366,6 +380,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.
|
||||
|
@ -416,6 +435,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.
|
||||
|
|
|
@ -162,6 +162,8 @@ pub const ELFOSABI_GNU: u8 = 3;
|
|||
///
|
||||
/// Compatibility alias.
|
||||
pub const ELFOSABI_LINUX: u8 = ELFOSABI_GNU;
|
||||
/// GNU/Hurd.
|
||||
pub const ELFOSABI_HURD: u8 = 4;
|
||||
/// Sun Solaris.
|
||||
pub const ELFOSABI_SOLARIS: u8 = 6;
|
||||
/// IBM AIX.
|
||||
|
@ -176,6 +178,16 @@ pub const ELFOSABI_TRU64: u8 = 10;
|
|||
pub const ELFOSABI_MODESTO: u8 = 11;
|
||||
/// OpenBSD.
|
||||
pub const ELFOSABI_OPENBSD: u8 = 12;
|
||||
/// OpenVMS.
|
||||
pub const ELFOSABI_OPENVMS: u8 = 13;
|
||||
/// Hewlett-Packard Non-Stop Kernel.
|
||||
pub const ELFOSABI_NSK: u8 = 14;
|
||||
/// AROS
|
||||
pub const ELFOSABI_AROS: u8 = 15;
|
||||
/// FenixOS
|
||||
pub const ELFOSABI_FENIXOS: u8 = 16;
|
||||
/// Nuxi CloudABI
|
||||
pub const ELFOSABI_CLOUDABI: u8 = 17;
|
||||
/// ARM EABI.
|
||||
pub const ELFOSABI_ARM_AEABI: u8 = 64;
|
||||
/// ARM.
|
||||
|
@ -6239,18 +6251,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
|
||||
|
@ -6360,6 +6371,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,
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
//!
|
||||
//! /// Reads a file and displays the content of the ".boot" section.
|
||||
//! fn main() -> Result<(), Box<dyn Error>> {
|
||||
//! # #[cfg(feature = "read")] {
|
||||
//! # #[cfg(all(feature = "read", feature = "std"))] {
|
||||
//! let bin_data = fs::read("./multiboot2-binary.elf")?;
|
||||
//! let obj_file = object::File::parse(&*bin_data)?;
|
||||
//! if let Some(section) = obj_file.section_by_name(".boot") {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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;
|
||||
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)
|
||||
}
|
||||
},
|
||||
}
|
||||
let member = ArchiveMember::parse(self.data, &mut self.offset, self.names);
|
||||
if member.is_err() {
|
||||
self.offset = self.len;
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -176,6 +176,7 @@ where
|
|||
// We only support the 64-bit variant s390x here.
|
||||
(elf::EM_S390, true) => Architecture::S390x,
|
||||
(elf::EM_SPARCV9, true) => Architecture::Sparc64,
|
||||
(elf::EM_XTENSA, false) => Architecture::Xtensa,
|
||||
_ => Architecture::Unknown,
|
||||
}
|
||||
}
|
||||
|
@ -264,6 +265,9 @@ where
|
|||
}
|
||||
|
||||
fn symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> {
|
||||
if self.symbols.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(ElfSymbolTable {
|
||||
endian: self.endian,
|
||||
symbols: &self.symbols,
|
||||
|
@ -279,6 +283,9 @@ where
|
|||
}
|
||||
|
||||
fn dynamic_symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> {
|
||||
if self.dynamic_symbols.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(ElfSymbolTable {
|
||||
endian: self.endian,
|
||||
symbols: &self.dynamic_symbols,
|
||||
|
@ -419,6 +426,8 @@ where
|
|||
|
||||
fn flags(&self) -> FileFlags {
|
||||
FileFlags::Elf {
|
||||
os_abi: self.header.e_ident().os_abi,
|
||||
abi_version: self.header.e_ident().abi_version,
|
||||
e_flags: self.header.e_flags(self.endian),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -304,6 +304,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) {
|
||||
|
@ -379,6 +392,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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()))),
|
||||
|
@ -369,7 +369,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,
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
let debug_data_size = data_dir.size.get(LE) as usize;
|
||||
|
||||
let count = debug_data_size / mem::size_of::<pe::ImageDebugDirectory>();
|
||||
let rem = debug_data_size % mem::size_of::<pe::ImageDebugDirectory>();
|
||||
if rem != 0 || count < 1 {
|
||||
return Err(Error("Invalid PE debug dir size"));
|
||||
}
|
||||
|
||||
let debug_dirs = debug_data
|
||||
.read_slice_at::<pe::ImageDebugDirectory>(0, count)
|
||||
.read_error("Invalid PE debug dir size")?;
|
||||
|
||||
if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW {
|
||||
return Ok(None);
|
||||
for debug_dir in debug_dirs {
|
||||
if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW {
|
||||
continue;
|
||||
}
|
||||
|
||||
let info = self
|
||||
.data
|
||||
.read_slice_at::<u8>(
|
||||
debug_dir.pointer_to_raw_data.get(LE) as u64,
|
||||
debug_dir.size_of_data.get(LE) as usize,
|
||||
)
|
||||
.read_error("Invalid CodeView Info address")?;
|
||||
|
||||
let mut info = Bytes(info);
|
||||
|
||||
let sig = info
|
||||
.read_bytes(4)
|
||||
.read_error("Invalid CodeView signature")?;
|
||||
if sig.0 != b"RSDS" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let guid: [u8; 16] = info
|
||||
.read_bytes(16)
|
||||
.read_error("Invalid CodeView GUID")?
|
||||
.0
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let age = info.read::<U32<LE>>().read_error("Invalid CodeView Age")?;
|
||||
|
||||
let path = info
|
||||
.read_string()
|
||||
.read_error("Invalid CodeView file path")?;
|
||||
|
||||
return Ok(Some(CodeView {
|
||||
path: ByteString(path),
|
||||
guid,
|
||||
age: age.get(LE),
|
||||
}));
|
||||
}
|
||||
|
||||
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 guid: [u8; 16] = info
|
||||
.read_bytes(16)
|
||||
.read_error("Invalid CodeView GUID")?
|
||||
.0
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let age = info.read::<U32<LE>>().read_error("Invalid CodeView Age")?;
|
||||
|
||||
let path = info
|
||||
.read_string()
|
||||
.read_error("Invalid CodeView file path")?;
|
||||
|
||||
Ok(Some(CodeView {
|
||||
path: ByteString(path),
|
||||
guid,
|
||||
age: age.get(LE),
|
||||
}))
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn has_debug_symbols(&self) -> bool {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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::*;
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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!();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -84,6 +84,7 @@ impl<'a> Object<'a> {
|
|||
Architecture::Riscv32 => true,
|
||||
Architecture::S390x => true,
|
||||
Architecture::Sparc64 => true,
|
||||
Architecture::Xtensa => true,
|
||||
_ => {
|
||||
return Err(Error(format!(
|
||||
"unimplemented architecture {:?}",
|
||||
|
@ -281,6 +282,7 @@ impl<'a> Object<'a> {
|
|||
Architecture::Riscv64 => elf::EM_RISCV,
|
||||
Architecture::S390x => elf::EM_S390,
|
||||
Architecture::Sparc64 => elf::EM_SPARCV9,
|
||||
Architecture::Xtensa => elf::EM_XTENSA,
|
||||
_ => {
|
||||
return Err(Error(format!(
|
||||
"unimplemented architecture {:?}",
|
||||
|
@ -288,14 +290,19 @@ impl<'a> Object<'a> {
|
|||
)));
|
||||
}
|
||||
};
|
||||
let e_flags = if let FileFlags::Elf { e_flags } = self.flags {
|
||||
e_flags
|
||||
let (os_abi, abi_version, e_flags) = if let FileFlags::Elf {
|
||||
os_abi,
|
||||
abi_version,
|
||||
e_flags,
|
||||
} = self.flags
|
||||
{
|
||||
(os_abi, abi_version, e_flags)
|
||||
} else {
|
||||
0
|
||||
(elf::ELFOSABI_NONE, 0, 0)
|
||||
};
|
||||
writer.write_file_header(&FileHeader {
|
||||
os_abi: elf::ELFOSABI_NONE,
|
||||
abi_version: 0,
|
||||
os_abi,
|
||||
abi_version,
|
||||
e_type,
|
||||
e_machine,
|
||||
e_entry: 0,
|
||||
|
@ -523,6 +530,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)));
|
||||
|
@ -569,6 +595,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!(
|
||||
|
@ -653,6 +682,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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
);
|
|
@ -248,6 +248,7 @@ fn elf_any() {
|
|||
(Architecture::Riscv64, Endianness::Little),
|
||||
(Architecture::S390x, Endianness::Big),
|
||||
(Architecture::Sparc64, Endianness::Big),
|
||||
(Architecture::Xtensa, Endianness::Little),
|
||||
]
|
||||
.iter()
|
||||
.copied()
|
||||
|
|
|
@ -10,7 +10,7 @@ rustc-demangle = "0.1"
|
|||
uuid = "1.0"
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.28"
|
||||
version = "0.30"
|
||||
optional = true
|
||||
default-features = false
|
||||
features = ["std", "read_core", "elf"]
|
||||
|
|
Загрузка…
Ссылка в новой задаче