diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/goblin/src/elf | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/goblin/src/elf')
-rw-r--r-- | third_party/rust/goblin/src/elf/compression_header.rs | 275 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/constants_header.rs | 563 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/constants_relocation.rs | 1417 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/dynamic.rs | 807 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/gnu_hash.rs | 220 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/header.rs | 630 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/mod.rs | 566 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/note.rs | 305 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/program_header.rs | 427 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/reloc.rs | 518 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/section_header.rs | 581 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/sym.rs | 607 | ||||
-rw-r--r-- | third_party/rust/goblin/src/elf/symver.rs | 880 |
13 files changed, 7796 insertions, 0 deletions
diff --git a/third_party/rust/goblin/src/elf/compression_header.rs b/third_party/rust/goblin/src/elf/compression_header.rs new file mode 100644 index 0000000000..1dd7aa1362 --- /dev/null +++ b/third_party/rust/goblin/src/elf/compression_header.rs @@ -0,0 +1,275 @@ +macro_rules! elf_compression_header { + () => { + use plain; + // Declare that this is a plain type. + unsafe impl plain::Plain for CompressionHeader {} + + impl ::core::fmt::Debug for CompressionHeader { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.debug_struct("CompressionHeader") + .field("ch_type", &self.ch_type) + .field("ch_size", &format_args!("0x{:x}", self.ch_size)) + .field("ch_addralign", &format_args!("0x{:x}", self.ch_addralign)) + .finish() + } + } + }; +} + +/// ZLIB/DEFLATE algorithm. +pub const ELFCOMPRESS_ZLIB: u32 = 1; +/// Start of OS-specific. +pub const ELFCOMPRESS_LOOS: u32 = 0x6000_0000; +/// End of OS-specific. +pub const ELFCOMPRESS_HIOS: u32 = 0x6fff_ffff; +/// Start of processor-specific. +pub const ELFCOMPRESS_LOPROC: u32 = 0x7000_0000; +/// End of processor-specific. +pub const ELFCOMPRESS_HIPROC: u32 = 0x7fff_ffff; + +macro_rules! elf_compression_header_std_impl { + ($size:ty) => { + #[cfg(test)] + mod tests { + use super::*; + #[test] + fn size_of() { + assert_eq!(::std::mem::size_of::<CompressionHeader>(), SIZEOF_CHDR); + } + } + + if_alloc! { + use crate::elf::compression_header::CompressionHeader as ElfCompressionHeader; + + use plain::Plain; + + if_std! { + use crate::error::Result; + + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + } + + impl From<CompressionHeader> for ElfCompressionHeader { + fn from(ch: CompressionHeader) -> Self { + ElfCompressionHeader { + ch_type: ch.ch_type, + ch_size: u64::from(ch.ch_size), + ch_addralign: u64::from(ch.ch_addralign), + } + } + } + + impl CompressionHeader { + pub fn from_bytes(bytes: &[u8]) -> CompressionHeader { + let mut chdr = CompressionHeader::default(); + chdr.copy_from_bytes(bytes).expect("buffer is too short for header"); + chdr + } + + #[cfg(feature = "std")] + pub fn from_fd(fd: &mut File, offset: u64) -> Result<CompressionHeader> { + let mut chdr = CompressionHeader::default(); + fd.seek(Start(offset))?; + unsafe { + fd.read_exact(plain::as_mut_bytes(&mut chdr))?; + } + Ok(chdr) + } + } + } // end if_alloc + }; +} + +#[cfg(feature = "alloc")] +use scroll::{Pread, Pwrite, SizeWith}; + +pub mod compression_header32 { + pub use crate::elf::compression_header::*; + + #[repr(C)] + #[derive(Copy, Clone, Eq, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// The compression header is used at the start of SHF_COMPRESSED sections + pub struct CompressionHeader { + /// Compression format + pub ch_type: u32, + /// Uncompressed data size + pub ch_size: u32, + /// Uncompressed data alignment + pub ch_addralign: u32, + } + + elf_compression_header!(); + + pub const SIZEOF_CHDR: usize = 12; + + elf_compression_header_std_impl!(u32); + + if_alloc! { + impl From<ElfCompressionHeader> for CompressionHeader { + fn from(ch: ElfCompressionHeader) -> Self { + CompressionHeader { + ch_type: ch.ch_type, + ch_size: ch.ch_size as u32, + ch_addralign: ch.ch_addralign as u32, + } + } + } + } +} + +pub mod compression_header64 { + pub use crate::elf::compression_header::*; + + #[repr(C)] + #[derive(Copy, Clone, Eq, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// The compression header is used at the start of SHF_COMPRESSED sections + pub struct CompressionHeader { + /// Compression format + pub ch_type: u32, + pub ch_reserved: u32, + /// Uncompressed data size + pub ch_size: u64, + /// Uncompressed data alignment + pub ch_addralign: u64, + } + + elf_compression_header!(); + + pub const SIZEOF_CHDR: usize = 24; + + elf_compression_header_std_impl!(u64); + + if_alloc! { + impl From<ElfCompressionHeader> for CompressionHeader { + fn from(ch: ElfCompressionHeader) -> Self { + CompressionHeader { + ch_type: ch.ch_type, + ch_reserved: 0, + ch_size: ch.ch_size as u64, + ch_addralign: ch.ch_addralign as u64, + } + } + } + } +} + +/////////////////////////////// +// Std/analysis/Unified Structs +/////////////////////////////// + +if_alloc! { + #[cfg(feature = "endian_fd")] + use crate::error; + use core::fmt; + use core::result; + use scroll::ctx; + use crate::container::{Container, Ctx}; + + #[derive(Default, PartialEq, Clone)] + /// A unified CompressionHeader - convertable to and from 32-bit and 64-bit variants + pub struct CompressionHeader { + /// Compression format + pub ch_type: u32, + /// Uncompressed data size + pub ch_size: u64, + /// Uncompressed data alignment + pub ch_addralign: u64, + } + + impl CompressionHeader { + /// Return the size of the underlying compression header, given a `container` + #[inline] + pub fn size(ctx: Ctx) -> usize { + use scroll::ctx::SizeWith; + Self::size_with(&ctx) + } + pub fn new() -> Self { + CompressionHeader { + ch_type: 0, + ch_size: 0, + ch_addralign: 2 << 8, + } + } + /// Parse a compression header from `bytes` at `offset`, using the given `ctx` + #[cfg(feature = "endian_fd")] + pub fn parse(bytes: &[u8], mut offset: usize, ctx: Ctx) -> error::Result<CompressionHeader> { + use scroll::Pread; + bytes.gread_with(&mut offset, ctx) + } + } + + impl fmt::Debug for CompressionHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("CompressionHeader") + .field("ch_type", &self.ch_type) + .field("ch_size", &format_args!("0x{:x}", self.ch_size)) + .field("ch_addralign", &format_args!("0x{:x}", self.ch_addralign)) + .finish() + } + } + + impl ctx::SizeWith<Ctx> for CompressionHeader { + fn size_with( &Ctx { container, .. }: &Ctx) -> usize { + match container { + Container::Little => { + compression_header32::SIZEOF_CHDR + }, + Container::Big => { + compression_header64::SIZEOF_CHDR + }, + } + } + } + + impl<'a> ctx::TryFromCtx<'a, Ctx> for CompressionHeader { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], Ctx {container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> { + use scroll::Pread; + let res = match container { + Container::Little => { + (bytes.pread_with::<compression_header32::CompressionHeader>(0, le)?.into(), compression_header32::SIZEOF_CHDR) + }, + Container::Big => { + (bytes.pread_with::<compression_header64::CompressionHeader>(0, le)?.into(), compression_header64::SIZEOF_CHDR) + } + }; + Ok(res) + } + } + + impl ctx::TryIntoCtx<Ctx> for CompressionHeader { + type Error = crate::error::Error; + fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> { + use scroll::Pwrite; + match container { + Container::Little => { + let chdr: compression_header32::CompressionHeader = self.into(); + Ok(bytes.pwrite_with(chdr, 0, le)?) + }, + Container::Big => { + let chdr: compression_header64::CompressionHeader = self.into(); + Ok(bytes.pwrite_with(chdr, 0, le)?) + } + } + } + } + impl ctx::IntoCtx<Ctx> for CompressionHeader { + fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) { + use scroll::Pwrite; + match container { + Container::Little => { + let chdr: compression_header32::CompressionHeader = self.into(); + bytes.pwrite_with(chdr, 0, le).unwrap(); + }, + Container::Big => { + let chdr: compression_header64::CompressionHeader = self.into(); + bytes.pwrite_with(chdr, 0, le).unwrap(); + } + } + } + } +} // end if_alloc diff --git a/third_party/rust/goblin/src/elf/constants_header.rs b/third_party/rust/goblin/src/elf/constants_header.rs new file mode 100644 index 0000000000..9b19c84c2c --- /dev/null +++ b/third_party/rust/goblin/src/elf/constants_header.rs @@ -0,0 +1,563 @@ +// sweet emacs regexp +// pub const \([[:word:]|_]*\)[[:space:]]*\([[:digit:]]+\)[[:space:]]*/\*\(.*\) \*/ +// \\\\3 C-q C-j pub const \1: u32 = \2; + +/// TODO: use Enum with explicit discriminant and get debug printer for free? + +/// No machine +pub const EM_NONE: u16 = 0; +/// AT&T WE 32100 +pub const EM_M32: u16 = 1; +/// SUN SPARC +pub const EM_SPARC: u16 = 2; +/// Intel 80386 +pub const EM_386: u16 = 3; +/// Motorola m68k family +pub const EM_68K: u16 = 4; +/// Motorola m88k family +pub const EM_88K: u16 = 5; +/// Intel MCU +pub const EM_IAMCU: u16 = 6; +/// Intel 80860 +pub const EM_860: u16 = 7; +/// MIPS R3000 big-endian +pub const EM_MIPS: u16 = 8; +/// IBM System/370 +pub const EM_S370: u16 = 9; +/// MIPS R3000 little-endian +pub const EM_MIPS_RS3_LE: u16 = 10; +// reserved 11-14 +/// HPPA +pub const EM_PARISC: u16 = 15; +// reserved 16 +/// Fujitsu VPP500 +pub const EM_VPP500: u16 = 17; +/// Sun's "v8plus" +pub const EM_SPARC32PLUS: u16 = 18; +/// Intel 80960 +pub const EM_960: u16 = 19; +/// PowerPC +pub const EM_PPC: u16 = 20; +/// PowerPC 64-bit +pub const EM_PPC64: u16 = 21; +/// IBM S390 +pub const EM_S390: u16 = 22; +/// IBM SPU/SPC +pub const EM_SPU: u16 = 23; +// reserved 24-35 +/// NEC V800 series +pub const EM_V800: u16 = 36; +/// Fujitsu FR20 +pub const EM_FR20: u16 = 37; +/// TRW RH-32 +pub const EM_RH32: u16 = 38; +/// Motorola RCE +pub const EM_RCE: u16 = 39; +/// ARM +pub const EM_ARM: u16 = 40; +/// Digital Alpha +pub const EM_FAKE_ALPHA: u16 = 41; +/// Hitachi SH +pub const EM_SH: u16 = 42; +/// SPARC v9 64-bit +pub const EM_SPARCV9: u16 = 43; +/// Siemens Tricore +pub const EM_TRICORE: u16 = 44; +/// Argonaut RISC Core +pub const EM_ARC: u16 = 45; +/// Hitachi H8/300 +pub const EM_H8_300: u16 = 46; +/// Hitachi H8/300H +pub const EM_H8_300H: u16 = 47; +/// Hitachi H8S +pub const EM_H8S: u16 = 48; +/// Hitachi H8/500 +pub const EM_H8_500: u16 = 49; +/// Intel Merced +pub const EM_IA_64: u16 = 50; +/// Stanford MIPS-X +pub const EM_MIPS_X: u16 = 51; +/// Motorola Coldfire +pub const EM_COLDFIRE: u16 = 52; +/// Motorola M68HC12 +pub const EM_68HC12: u16 = 53; +/// Fujitsu MMA Multimedia Accelerator +pub const EM_MMA: u16 = 54; +/// Siemens PCP +pub const EM_PCP: u16 = 55; +/// Sony nCPU embeeded RISC +pub const EM_NCPU: u16 = 56; +/// Denso NDR1 microprocessor +pub const EM_NDR1: u16 = 57; +/// Motorola Start*Core processor +pub const EM_STARCORE: u16 = 58; +/// Toyota ME16 processor +pub const EM_ME16: u16 = 59; +/// STMicroelectronic ST100 processor +pub const EM_ST100: u16 = 60; +/// Advanced Logic Corp. Tinyj emb.fam +pub const EM_TINYJ: u16 = 61; +/// AMD x86-64 architecture +pub const EM_X86_64: u16 = 62; +/// Sony DSP Processor +pub const EM_PDSP: u16 = 63; +/// Digital PDP-10 +pub const EM_PDP10: u16 = 64; +/// Digital PDP-11 +pub const EM_PDP11: u16 = 65; +/// Siemens FX66 microcontroller +pub const EM_FX66: u16 = 66; +/// STMicroelectronics ST9+ 8/16 mc +pub const EM_ST9PLUS: u16 = 67; +/// STmicroelectronics ST7 8 bit mc +pub const EM_ST7: u16 = 68; +/// Motorola MC68HC16 microcontroller +pub const EM_68HC16: u16 = 69; +/// Motorola MC68HC11 microcontroller +pub const EM_68HC11: u16 = 70; +/// Motorola MC68HC08 microcontroller +pub const EM_68HC08: u16 = 71; +/// Motorola MC68HC05 microcontroller +pub const EM_68HC05: u16 = 72; +/// Silicon Graphics SVx +pub const EM_SVX: u16 = 73; +/// STMicroelectronics ST19 8 bit mc +pub const EM_ST19: u16 = 74; +/// Digital VAX +pub const EM_VAX: u16 = 75; +/// Axis Communications 32-bit emb.proc +pub const EM_CRIS: u16 = 76; +/// Infineon Technologies 32-bit emb.proc +pub const EM_JAVELIN: u16 = 77; +/// Element 14 64-bit DSP Processor +pub const EM_FIREPATH: u16 = 78; +/// LSI Logic 16-bit DSP Processor +pub const EM_ZSP: u16 = 79; +/// Donald Knuth's educational 64-bit proc +pub const EM_MMIX: u16 = 80; +/// Harvard University machine-independent object files +pub const EM_HUANY: u16 = 81; +/// SiTera Prism +pub const EM_PRISM: u16 = 82; +/// Atmel AVR 8-bit microcontroller +pub const EM_AVR: u16 = 83; +/// Fujitsu FR30 +pub const EM_FR30: u16 = 84; +/// Mitsubishi D10V +pub const EM_D10V: u16 = 85; +/// Mitsubishi D30V +pub const EM_D30V: u16 = 86; +/// NEC v850 +pub const EM_V850: u16 = 87; +/// Mitsubishi M32R +pub const EM_M32R: u16 = 88; +/// Matsushita MN10300 +pub const EM_MN10300: u16 = 89; +/// Matsushita MN10200 +pub const EM_MN10200: u16 = 90; +/// picoJava +pub const EM_PJ: u16 = 91; +/// OpenRISC 32-bit embedded processor +pub const EM_OPENRISC: u16 = 92; +/// ARC International ARCompact +pub const EM_ARC_COMPACT: u16 = 93; +/// Tensilica Xtensa Architecture +pub const EM_XTENSA: u16 = 94; +/// Alphamosaic VideoCore +pub const EM_VIDEOCORE: u16 = 95; +/// Thompson Multimedia General Purpose Proc +pub const EM_TMM_GPP: u16 = 96; +/// National Semi. 32000 +pub const EM_NS32K: u16 = 97; +/// Tenor Network TPC +pub const EM_TPC: u16 = 98; +/// Trebia SNP 1000 +pub const EM_SNP1K: u16 = 99; +/// STMicroelectronics ST200 +pub const EM_ST200: u16 = 100; +/// Ubicom IP2xxx +pub const EM_IP2K: u16 = 101; +/// MAX processor +pub const EM_MAX: u16 = 102; +/// National Semi. CompactRISC +pub const EM_CR: u16 = 103; +/// Fujitsu F2MC16 +pub const EM_F2MC16: u16 = 104; +/// Texas Instruments msp430 +pub const EM_MSP430: u16 = 105; +/// Analog Devices Blackfin DSP +pub const EM_BLACKFIN: u16 = 106; +/// Seiko Epson S1C33 family +pub const EM_SE_C33: u16 = 107; +/// Sharp embedded microprocessor +pub const EM_SEP: u16 = 108; +/// Arca RISC +pub const EM_ARCA: u16 = 109; +/// PKU-Unity & MPRC Peking Uni. mc series +pub const EM_UNICORE: u16 = 110; +/// eXcess configurable cpu +pub const EM_EXCESS: u16 = 111; +/// Icera Semi. Deep Execution Processor +pub const EM_DXP: u16 = 112; +/// Altera Nios II +pub const EM_ALTERA_NIOS2: u16 = 113; +/// National Semi. CompactRISC CRX +pub const EM_CRX: u16 = 114; +/// Motorola XGATE +pub const EM_XGATE: u16 = 115; +/// Infineon C16x/XC16x +pub const EM_C166: u16 = 116; +/// Renesas M16C +pub const EM_M16C: u16 = 117; +/// Microchip Technology dsPIC30F +pub const EM_DSPIC30F: u16 = 118; +/// Freescale Communication Engine RISC +pub const EM_CE: u16 = 119; +/// Renesas M32C +pub const EM_M32C: u16 = 120; +// reserved 121-130 +/// Altium TSK3000 +pub const EM_TSK3000: u16 = 131; +/// Freescale RS08 +pub const EM_RS08: u16 = 132; +/// Analog Devices SHARC family +pub const EM_SHARC: u16 = 133; +/// Cyan Technology eCOG2 +pub const EM_ECOG2: u16 = 134; +/// Sunplus S+core7 RISC +pub const EM_SCORE7: u16 = 135; +/// New Japan Radio (NJR) 24-bit DSP +pub const EM_DSP24: u16 = 136; +/// Broadcom VideoCore III +pub const EM_VIDEOCORE3: u16 = 137; +/// RISC for Lattice FPGA +pub const EM_LATTICEMICO32: u16 = 138; +/// Seiko Epson C17 +pub const EM_SE_C17: u16 = 139; +/// Texas Instruments TMS320C6000 DSP +pub const EM_TI_C6000: u16 = 140; +/// Texas Instruments TMS320C2000 DSP +pub const EM_TI_C2000: u16 = 141; +/// Texas Instruments TMS320C55x DSP +pub const EM_TI_C5500: u16 = 142; +/// Texas Instruments App. Specific RISC +pub const EM_TI_ARP32: u16 = 143; +/// Texas Instruments Prog. Realtime Unit +pub const EM_TI_PRU: u16 = 144; +// reserved 145-159 +/// STMicroelectronics 64bit VLIW DSP +pub const EM_MMDSP_PLUS: u16 = 160; +/// Cypress M8C +pub const EM_CYPRESS_M8C: u16 = 161; +/// Renesas R32C +pub const EM_R32C: u16 = 162; +/// NXP Semi. TriMedia +pub const EM_TRIMEDIA: u16 = 163; +/// QUALCOMM DSP6 +pub const EM_QDSP6: u16 = 164; +/// Intel 8051 and variants +pub const EM_8051: u16 = 165; +/// STMicroelectronics STxP7x +pub const EM_STXP7X: u16 = 166; +/// Andes Tech. compact code emb. RISC +pub const EM_NDS32: u16 = 167; +/// Cyan Technology eCOG1X +pub const EM_ECOG1X: u16 = 168; +/// Dallas Semi. MAXQ30 mc +pub const EM_MAXQ30: u16 = 169; +/// New Japan Radio (NJR) 16-bit DSP +pub const EM_XIMO16: u16 = 170; +/// M2000 Reconfigurable RISC +pub const EM_MANIK: u16 = 171; +/// Cray NV2 vector architecture +pub const EM_CRAYNV2: u16 = 172; +/// Renesas RX +pub const EM_RX: u16 = 173; +/// Imagination Tech. META +pub const EM_METAG: u16 = 174; +/// MCST Elbrus +pub const EM_MCST_ELBRUS: u16 = 175; +/// Cyan Technology eCOG16 +pub const EM_ECOG16: u16 = 176; +/// National Semi. CompactRISC CR16 +pub const EM_CR16: u16 = 177; +/// Freescale Extended Time Processing Unit +pub const EM_ETPU: u16 = 178; +/// Infineon Tech. SLE9X +pub const EM_SLE9X: u16 = 179; +/// Intel L10M +pub const EM_L10M: u16 = 180; +/// Intel K10M +pub const EM_K10M: u16 = 181; +// reserved 182 +/// ARM AARCH64 +pub const EM_AARCH64: u16 = 183; +// reserved 184 +/// Amtel 32-bit microprocessor +pub const EM_AVR32: u16 = 185; +/// STMicroelectronics STM8 +pub const EM_STM8: u16 = 186; +/// Tileta TILE64 +pub const EM_TILE64: u16 = 187; +/// Tilera TILEPro +pub const EM_TILEPRO: u16 = 188; +/// Xilinx MicroBlaze +pub const EM_MICROBLAZE: u16 = 189; +/// NVIDIA CUDA +pub const EM_CUDA: u16 = 190; +/// Tilera TILE-Gx +pub const EM_TILEGX: u16 = 191; +/// CloudShield +pub const EM_CLOUDSHIELD: u16 = 192; +/// KIPO-KAIST Core-A 1st gen. +pub const EM_COREA_1ST: u16 = 193; +/// KIPO-KAIST Core-A 2nd gen. +pub const EM_COREA_2ND: u16 = 194; +/// Synopsys ARCompact V2 +pub const EM_ARC_COMPACT2: u16 = 195; +/// Open8 RISC +pub const EM_OPEN8: u16 = 196; +/// Renesas RL78 +pub const EM_RL78: u16 = 197; +/// Broadcom VideoCore V +pub const EM_VIDEOCORE5: u16 = 198; +/// Renesas 78KOR +pub const EM_78KOR: u16 = 199; +/// Freescale 56800EX DSC +pub const EM_56800EX: u16 = 200; +/// Beyond BA1 +pub const EM_BA1: u16 = 201; +/// Beyond BA2 +pub const EM_BA2: u16 = 202; +/// XMOS xCORE +pub const EM_XCORE: u16 = 203; +/// Microchip 8-bit PIC(r) +pub const EM_MCHP_PIC: u16 = 204; +/// Intel Graphics Technology +pub const EM_INTELGT: u16 = 205; +// reserved 206-209 +/// KM211 KM32 +pub const EM_KM32: u16 = 210; +/// KM211 KMX32 +pub const EM_KMX32: u16 = 211; +/// KM211 KMX16 +pub const EM_EMX16: u16 = 212; +/// KM211 KMX8 +pub const EM_EMX8: u16 = 213; +/// KM211 KVARC +pub const EM_KVARC: u16 = 214; +/// Paneve CDP +pub const EM_CDP: u16 = 215; +/// Cognitive Smart Memory Processor +pub const EM_COGE: u16 = 216; +/// Bluechip CoolEngine +pub const EM_COOL: u16 = 217; +/// Nanoradio Optimized RISC +pub const EM_NORC: u16 = 218; +/// CSR Kalimba +pub const EM_CSR_KALIMBA: u16 = 219; +/// Zilog Z80 +pub const EM_Z80: u16 = 220; +/// Controls and Data Services VISIUMcore +pub const EM_VISIUM: u16 = 221; +/// FTDI Chip FT32 +pub const EM_FT32: u16 = 222; +/// Moxie processor +pub const EM_MOXIE: u16 = 223; +/// AMD GPU +pub const EM_AMDGPU: u16 = 224; +// reserved 225-242 +/// RISC-V +pub const EM_RISCV: u16 = 243; + +/// Linux BPF -- in-kernel virtual machine +pub const EM_BPF: u16 = 247; + +/// C-SKY +pub const EM_CSKY: u16 = 252; + +pub const EM_NUM: u16 = 248; + +/// Convert machine to str representation +pub fn machine_to_str (machine: u16) -> &'static str { + match machine { + EM_M32 => "M32", + EM_SPARC => "SPARC", + EM_386 => "386", + EM_68K => "68K", + EM_88K => "88K", + EM_IAMCU => "IAMCU", + EM_860 => "860", + EM_MIPS => "MIPS", + EM_S370 => "S370", + EM_MIPS_RS3_LE => "MIPS_RS3_LE", + EM_PARISC => "PARISC", + EM_VPP500 => "VPP500", + EM_SPARC32PLUS => "SPARC32PLUS", + EM_960 => "960", + EM_PPC => "PPC", + EM_PPC64 => "PPC64", + EM_S390 => "S390", + EM_SPU => "SPU", + EM_V800 => "V800", + EM_FR20 => "FR20", + EM_RH32 => "RH32", + EM_RCE => "RCE", + EM_ARM => "ARM", + EM_FAKE_ALPHA => "FAKE_ALPHA", + EM_SH => "SH", + EM_SPARCV9 => "SPARCV9", + EM_TRICORE => "TRICORE", + EM_ARC => "ARC", + EM_H8_300 => "H8_300", + EM_H8_300H => "H8_300H", + EM_H8S => "H8S", + EM_H8_500 => "H8_500", + EM_IA_64 => "IA_64", + EM_MIPS_X => "MIPS_X", + EM_COLDFIRE => "COLDFIRE", + EM_68HC12 => "68HC12", + EM_MMA => "MMA", + EM_PCP => "PCP", + EM_NCPU => "NCPU", + EM_NDR1 => "NDR1", + EM_STARCORE => "STARCORE", + EM_ME16 => "ME16", + EM_ST100 => "ST100", + EM_TINYJ => "TINYJ", + EM_X86_64 => "X86_64", + EM_PDSP => "PDSP", + EM_PDP10 => "PDP10", + EM_PDP11 => "PDP11", + EM_FX66 => "FX66", + EM_ST9PLUS => "ST9PLUS", + EM_ST7 => "ST7", + EM_68HC16 => "68HC16", + EM_68HC11 => "68HC11", + EM_68HC08 => "68HC08", + EM_68HC05 => "68HC05", + EM_SVX => "SVX", + EM_ST19 => "ST19", + EM_VAX => "VAX", + EM_CRIS => "CRIS", + EM_JAVELIN => "JAVELIN", + EM_FIREPATH => "FIREPATH", + EM_ZSP => "ZSP", + EM_MMIX => "MMIX", + EM_HUANY => "HUANY", + EM_PRISM => "PRISM", + EM_AVR => "AVR", + EM_FR30 => "FR30", + EM_D10V => "D10V", + EM_D30V => "D30V", + EM_V850 => "V850", + EM_M32R => "M32R", + EM_MN10300 => "MN10300", + EM_MN10200 => "MN10200", + EM_PJ => "PJ", + EM_OPENRISC => "OPENRISC", + EM_ARC_COMPACT => "ARC_COMPACT", + EM_XTENSA => "XTENSA", + EM_VIDEOCORE => "VIDEOCORE", + EM_TMM_GPP => "TMM_GPP", + EM_NS32K => "NS32K", + EM_TPC => "TPC", + EM_SNP1K => "SNP1K", + EM_ST200 => "ST200", + EM_IP2K => "IP2K", + EM_MAX => "MAX", + EM_CR => "CR", + EM_F2MC16 => "F2MC16", + EM_MSP430 => "MSP430", + EM_BLACKFIN => "BLACKFIN", + EM_SE_C33 => "SE_C33", + EM_SEP => "SEP", + EM_ARCA => "ARCA", + EM_UNICORE => "UNICORE", + EM_EXCESS => "EXCESS", + EM_DXP => "DXP", + EM_ALTERA_NIOS2 => "ALTERA_NIOS2", + EM_CRX => "CRX", + EM_XGATE => "XGATE", + EM_C166 => "C166", + EM_M16C => "M16C", + EM_DSPIC30F => "DSPIC30F", + EM_CE => "CE", + EM_M32C => "M32C", + EM_TSK3000 => "TSK3000", + EM_RS08 => "RS08", + EM_SHARC => "SHARC", + EM_ECOG2 => "ECOG2", + EM_SCORE7 => "SCORE7", + EM_DSP24 => "DSP24", + EM_VIDEOCORE3 => "VIDEOCORE3", + EM_LATTICEMICO32 => "LATTICEMICO32", + EM_SE_C17 => "SE_C17", + EM_TI_C6000 => "TI_C6000", + EM_TI_C2000 => "TI_C2000", + EM_TI_C5500 => "TI_C5500", + EM_TI_ARP32 => "TI_ARP32", + EM_TI_PRU => "TI_PRU", + EM_MMDSP_PLUS => "MMDSP_PLUS", + EM_CYPRESS_M8C => "CYPRESS_M8C", + EM_R32C => "R32C", + EM_TRIMEDIA => "TRIMEDIA", + EM_QDSP6 => "QDSP6", + EM_8051 => "8051", + EM_STXP7X => "STXP7X", + EM_NDS32 => "NDS32", + EM_ECOG1X => "ECOG1X", + EM_MAXQ30 => "MAXQ30", + EM_XIMO16 => "XIMO16", + EM_MANIK => "MANIK", + EM_CRAYNV2 => "CRAYNV2", + EM_RX => "RX", + EM_METAG => "METAG", + EM_MCST_ELBRUS => "MCST_ELBRUS", + EM_ECOG16 => "ECOG16", + EM_CR16 => "CR16", + EM_ETPU => "ETPU", + EM_SLE9X => "SLE9X", + EM_L10M => "L10M", + EM_K10M => "K10M", + EM_AARCH64 => "AARCH64", + EM_AVR32 => "AVR32", + EM_STM8 => "STM8", + EM_TILE64 => "TILE64", + EM_TILEPRO => "TILEPRO", + EM_MICROBLAZE => "MICROBLAZE", + EM_CUDA => "CUDA", + EM_TILEGX => "TILEGX", + EM_CLOUDSHIELD => "CLOUDSHIELD", + EM_COREA_1ST => "COREA_1ST", + EM_COREA_2ND => "COREA_2ND", + EM_ARC_COMPACT2 => "ARC_COMPACT2", + EM_OPEN8 => "OPEN8", + EM_RL78 => "RL78", + EM_VIDEOCORE5 => "VIDEOCORE5", + EM_78KOR => "78KOR", + EM_56800EX => "56800EX", + EM_BA1 => "BA1", + EM_BA2 => "BA2", + EM_XCORE => "XCORE", + EM_MCHP_PIC => "MCHP_PIC", + EM_KM32 => "KM32", + EM_KMX32 => "KMX32", + EM_EMX16 => "EMX16", + EM_EMX8 => "EMX8", + EM_KVARC => "KVARC", + EM_CDP => "CDP", + EM_COGE => "COGE", + EM_COOL => "COOL", + EM_NORC => "NORC", + EM_CSR_KALIMBA => "CSR_KALIMBA", + EM_Z80 => "Z80", + EM_VISIUM => "VISIUM", + EM_FT32 => "FT32", + EM_MOXIE => "MOXIE", + EM_AMDGPU => "AMDGPU", + EM_RISCV => "RISCV", + EM_BPF => "BPF", + _val => "EM_UNKNOWN", + } +} diff --git a/third_party/rust/goblin/src/elf/constants_relocation.rs b/third_party/rust/goblin/src/elf/constants_relocation.rs new file mode 100644 index 0000000000..6339de5434 --- /dev/null +++ b/third_party/rust/goblin/src/elf/constants_relocation.rs @@ -0,0 +1,1417 @@ +// x86_64 relocations +/// No reloc. +pub const R_X86_64_NONE: u32 = 0; +/// Direct 64 bit. +pub const R_X86_64_64: u32 = 1; +/// PC relative 32 bit signed. +pub const R_X86_64_PC32: u32 = 2; +/// 32 bit GOT entry. +pub const R_X86_64_GOT32: u32 = 3; +/// 32 bit PLT address. +pub const R_X86_64_PLT32: u32 = 4; +/// Copy symbol at runtime. +pub const R_X86_64_COPY: u32 = 5; +/// Create GOT entry. +pub const R_X86_64_GLOB_DAT: u32 = 6; +/// Create PLT entry. +pub const R_X86_64_JUMP_SLOT: u32 = 7; +/// Adjust by program base. +pub const R_X86_64_RELATIVE: u32 = 8; +/// 32 bit signed PC relative offset to GOT. +pub const R_X86_64_GOTPCREL: u32 = 9; +/// Direct 32 bit zero extended. +pub const R_X86_64_32: u32 = 10; +/// Direct 32 bit sign extended. +pub const R_X86_64_32S: u32 = 11; +/// Direct 16 bit zero extended. +pub const R_X86_64_16: u32 = 12; +/// 16 bit sign extended pc relative. +pub const R_X86_64_PC16: u32 = 13; +/// Direct 8 bit sign extended. +pub const R_X86_64_8: u32 = 14; +/// 8 bit sign extended pc relative. +pub const R_X86_64_PC8: u32 = 15; +/// ID of module containing symbol. +pub const R_X86_64_DTPMOD64: u32 = 16; +/// Offset in module's TLS block. +pub const R_X86_64_DTPOFF64: u32 = 17; +/// Offset in initial TLS block. +pub const R_X86_64_TPOFF64: u32 = 18; +/// 32 bit signed PC relative offset to two GOT entries for GD symbol. +pub const R_X86_64_TLSGD: u32 = 19; +/// 32 bit signed PC relative offset to two GOT entries for LD symbol. +pub const R_X86_64_TLSLD: u32 = 20; +/// Offset in TLS block. +pub const R_X86_64_DTPOFF32: u32 = 21; +/// 32 bit signed PC relative offset to GOT entry for IE symbol. +pub const R_X86_64_GOTTPOFF: u32 = 22; +/// Offset in initial TLS block. +pub const R_X86_64_TPOFF32: u32 = 23; +/// PC relative 64 bit. +pub const R_X86_64_PC64: u32 = 24; +/// 64 bit offset to GOT. +pub const R_X86_64_GOTOFF64: u32 = 25; +/// 32 bit signed pc relative offset to GOT. +pub const R_X86_64_GOTPC32: u32 = 26; +/// 64-bit GOT entry offset. +pub const R_X86_64_GOT64: u32 = 27; +/// 64-bit PC relative offset to GOT entry. +pub const R_X86_64_GOTPCREL64: u32 = 28; +/// 64-bit PC relative offset to GOT. +pub const R_X86_64_GOTPC64: u32 = 29; +/// like GOT64, says PLT entry needed. +pub const R_X86_64_GOTPLT64: u32 = 30; +/// 64-bit GOT relative offset to PLT entry. +pub const R_X86_64_PLTOFF64: u32 = 31; +/// Size of symbol plus 32-bit addend. +pub const R_X86_64_SIZE32: u32 = 32; +/// Size of symbol plus 64-bit addend. +pub const R_X86_64_SIZE64: u32 = 33; +/// GOT offset for TLS descriptor.. +pub const R_X86_64_GOTPC32_TLSDESC: u32 = 34; +/// Marker for call through TLS descriptor.. +pub const R_X86_64_TLSDESC_CALL: u32 = 35; +/// TLS descriptor.. +pub const R_X86_64_TLSDESC: u32 = 36; +/// Adjust indirectly by program base. +pub const R_X86_64_IRELATIVE: u32 = 37; +/// 64-bit adjust by program base. +pub const R_X86_64_RELATIVE64: u32 = 38; +///Load from 32 bit signed pc relative offset to GOT entry without REX prefix, relaxable. +pub const R_X86_64_GOTPCRELX: u32 = 41; +/// Load from 32 bit signed pc relative offset to GOT entry with REX prefix, relaxable. +pub const R_X86_64_REX_GOTPCRELX: u32 = 42; +pub const R_X86_64_NUM: u32 = 43; + +// Intel 80386 specific definitions + +// i386 relocs +/// No reloc +pub const R_386_NONE: u32 = 0; +/// Direct 32 bit +pub const R_386_32: u32 = 1; +/// PC relative 32 bit +pub const R_386_PC32: u32 = 2; +/// 32 bit GOT entry +pub const R_386_GOT32: u32 = 3; +/// 32 bit PLT address +pub const R_386_PLT32: u32 = 4; +/// Copy symbol at runtime +pub const R_386_COPY: u32 = 5; +/// Create GOT entry +pub const R_386_GLOB_DAT: u32 = 6; +/// Create PLT entry +pub const R_386_JMP_SLOT: u32 = 7; +/// Adjust by program base +pub const R_386_RELATIVE: u32 = 8; +/// 32 bit offset to GOT +pub const R_386_GOTOFF: u32 = 9; +/// 32 bit PC relative offset to GOT +pub const R_386_GOTPC: u32 = 10; +pub const R_386_32PLT: u32 = 11; +/// Offset in static TLS block +pub const R_386_TLS_TPOFF: u32 = 14; +/// Address of GOT entry for static TLS block offset +pub const R_386_TLS_IE: u32 = 15; +/// GOT entry for static TLS block offset +pub const R_386_TLS_GOTIE: u32 = 16; +/// Offset relative to static TLS block +pub const R_386_TLS_LE: u32 = 17; +/// Direct 32 bit for GNU version of general dynamic thread local data +pub const R_386_TLS_GD: u32 = 18; +/// Direct 32 bit for GNU version of local dynamic thread local data in LE code +pub const R_386_TLS_LDM: u32 = 19; +pub const R_386_16: u32 = 20; +pub const R_386_PC16: u32 = 21; +pub const R_386_8: u32 = 22; +pub const R_386_PC8: u32 = 23; +/// Direct 32 bit for general dynamic thread local data +pub const R_386_TLS_GD_32: u32 = 24; +/// Tag for pushl in GD TLS code +pub const R_386_TLS_GD_PUSH: u32 = 25; +/// Relocation for call to __tls_get_addr() +pub const R_386_TLS_GD_CALL: u32 = 26; +/// Tag for popl in GD TLS code +pub const R_386_TLS_GD_POP: u32 = 27; +/// Direct 32 bit for local dynamic thread local data in LE code +pub const R_386_TLS_LDM_32: u32 = 28; +/// Tag for pushl in LDM TLS code +pub const R_386_TLS_LDM_PUSH: u32 = 29; +/// Relocation for call to __tls_get_addr() in LDM code +pub const R_386_TLS_LDM_CALL: u32 = 30; +/// Tag for popl in LDM TLS code +pub const R_386_TLS_LDM_POP: u32 = 31; +/// Offset relative to TLS block +pub const R_386_TLS_LDO_32: u32 = 32; +/// GOT entry for negated static TLS block offset +pub const R_386_TLS_IE_32: u32 = 33; +/// Negated offset relative to static TLS block +pub const R_386_TLS_LE_32: u32 = 34; +/// ID of module containing symbol +pub const R_386_TLS_DTPMOD32: u32 = 35; +/// Offset in TLS block +pub const R_386_TLS_DTPOFF32: u32 = 36; +/// Negated offset in static TLS block +pub const R_386_TLS_TPOFF32: u32 = 37; +/// 32-bit symbol size +pub const R_386_SIZE32: u32 = 38; +/// GOT offset for TLS descriptor. +pub const R_386_TLS_GOTDESC: u32 = 39; +/// Marker of call through TLS descriptor for relaxation +pub const R_386_TLS_DESC_CALL: u32 = 40; +/// TLS descriptor containing pointer to code and to argument, returning the TLS offset for the symbol +pub const R_386_TLS_DESC: u32 = 41; +/// Adjust indirectly by program base +pub const R_386_IRELATIVE: u32 = 42; +/// Load from 32 bit GOT entry, relaxable +pub const R_386_GOT32X: u32 = 43; +/// Keep this the last entry +pub const R_386_NUM: u32 = 44; + +// AArch64 relocs +/// No relocation +pub const R_AARCH64_NONE: u32 = 0; + +// ILP32 AArch64 relocs +/// Direct 32 bit +pub const R_AARCH64_P32_ABS32: u32 = 1; +/// Copy symbol at runtime +pub const R_AARCH64_P32_COPY: u32 = 180; +/// Create GOT entry +pub const R_AARCH64_P32_GLOB_DAT: u32 = 181; +/// Create PLT entry +pub const R_AARCH64_P32_JUMP_SLOT: u32 = 182; +/// Adjust by program base +pub const R_AARCH64_P32_RELATIVE: u32 = 183; +/// Module number, 32 bit +pub const R_AARCH64_P32_TLS_DTPMOD: u32 = 184; +/// Module-relative offset, 32 bit +pub const R_AARCH64_P32_TLS_DTPREL: u32 = 185; +/// TP-relative offset, 32 bit +pub const R_AARCH64_P32_TLS_TPREL: u32 = 186; +/// TLS Descriptor +pub const R_AARCH64_P32_TLSDESC: u32 = 187; +/// STT_GNU_IFUNC relocation +pub const R_AARCH64_P32_IRELATIVE: u32 = 188; + +// LP64 AArch64 relocs +/// Direct 64 bit +pub const R_AARCH64_ABS64: u32 = 257; +/// Direct 32 bit +pub const R_AARCH64_ABS32: u32 = 258; +/// Direct 16-bit +pub const R_AARCH64_ABS16: u32 = 259; +/// PC-relative 64-bit +pub const R_AARCH64_PREL64: u32 = 260; +/// PC-relative 32-bit +pub const R_AARCH64_PREL32: u32 = 261; +/// PC-relative 16-bit +pub const R_AARCH64_PREL16: u32 = 262; +/// Dir. MOVZ imm. from bits 15:0 +pub const R_AARCH64_MOVW_UABS_G0: u32 = 263; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_UABS_G0_NC: u32 = 264; +/// Dir. MOVZ imm. from bits 31:16 +pub const R_AARCH64_MOVW_UABS_G1: u32 = 265; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_UABS_G1_NC: u32 = 266; +/// Dir. MOVZ imm. from bits 47:32 +pub const R_AARCH64_MOVW_UABS_G2: u32 = 267; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_UABS_G2_NC: u32 = 268; +/// Dir. MOV{K,Z} imm. from 63:48 +pub const R_AARCH64_MOVW_UABS_G3: u32 = 269; +/// Dir. MOV{N,Z} imm. from 15:0 +pub const R_AARCH64_MOVW_SABS_G0: u32 = 270; +/// Dir. MOV{N,Z} imm. from 31:16 +pub const R_AARCH64_MOVW_SABS_G1: u32 = 271; +/// Dir. MOV{N,Z} imm. from 47:32 +pub const R_AARCH64_MOVW_SABS_G2: u32 = 272; +/// PC-rel. LD imm. from bits 20:2 +pub const R_AARCH64_LD_PREL_LO19: u32 = 273; +/// PC-rel. ADR imm. from bits 20:0 +pub const R_AARCH64_ADR_PREL_LO21: u32 = 274; +/// Page-rel. ADRP imm. from 32:12 +pub const R_AARCH64_ADR_PREL_PG_HI21: u32 = 275; +/// Likewise; no overflow check +pub const R_AARCH64_ADR_PREL_PG_HI21_NC: u32 = 276; +/// Dir. ADD imm. from bits 11:0 +pub const R_AARCH64_ADD_ABS_LO12_NC: u32 = 277; +/// Likewise for LD/ST; no check. +pub const R_AARCH64_LDST8_ABS_LO12_NC: u32 = 278; +/// PC-rel. TBZ/TBNZ imm. from 15:2 +pub const R_AARCH64_TSTBR14: u32 = 279; +/// PC-rel. cond. br. imm. from 20:2. +pub const R_AARCH64_CONDBR19: u32 = 280; +/// PC-rel. B imm. from bits 27:2 +pub const R_AARCH64_JUMP26: u32 = 282; +/// Likewise for CALL +pub const R_AARCH64_CALL26: u32 = 283; +/// Dir. ADD imm. from bits 11:1 +pub const R_AARCH64_LDST16_ABS_LO12_NC: u32 = 284; +/// Likewise for bits 11:2 +pub const R_AARCH64_LDST32_ABS_LO12_NC: u32 = 285; +/// Likewise for bits 11:3 +pub const R_AARCH64_LDST64_ABS_LO12_NC: u32 = 286; +/// PC-rel. MOV{N,Z} imm. from 15:0 +pub const R_AARCH64_MOVW_PREL_G0: u32 = 287; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_PREL_G0_NC: u32 = 288; +/// PC-rel. MOV{N,Z} imm. from 31:16. +pub const R_AARCH64_MOVW_PREL_G1: u32 = 289; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_PREL_G1_NC: u32 = 290; +/// PC-rel. MOV{N,Z} imm. from 47:32. +pub const R_AARCH64_MOVW_PREL_G2: u32 = 291; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_PREL_G2_NC: u32 = 292; +/// PC-rel. MOV{N,Z} imm. from 63:48. +pub const R_AARCH64_MOVW_PREL_G3: u32 = 293; +/// Dir. ADD imm. from bits 11:4 +pub const R_AARCH64_LDST128_ABS_LO12_NC: u32 = 299; +/// GOT-rel. off. MOV{N,Z} imm. 15:0. +pub const R_AARCH64_MOVW_GOTOFF_G0: u32 = 300; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_GOTOFF_G0_NC: u32 = 301; +/// GOT-rel. o. MOV{N,Z} imm. 31:16 +pub const R_AARCH64_MOVW_GOTOFF_G1: u32 = 302; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_GOTOFF_G1_NC: u32 = 303; +/// GOT-rel. o. MOV{N,Z} imm. 47:32 +pub const R_AARCH64_MOVW_GOTOFF_G2: u32 = 304; +/// Likewise for MOVK; no check +pub const R_AARCH64_MOVW_GOTOFF_G2_NC: u32 = 305; +/// GOT-rel. o. MOV{N,Z} imm. 63:48 +pub const R_AARCH64_MOVW_GOTOFF_G3: u32 = 306; +/// GOT-relative 64-bit +pub const R_AARCH64_GOTREL64: u32 = 307; +/// GOT-relative 32-bit +pub const R_AARCH64_GOTREL32: u32 = 308; +/// PC-rel. GOT off. load imm. 20:2 +pub const R_AARCH64_GOT_LD_PREL19: u32 = 309; +/// GOT-rel. off. LD/ST imm. 14:3 +pub const R_AARCH64_LD64_GOTOFF_LO15: u32 = 310; +/// P-page-rel. GOT off. ADRP 32:12 +pub const R_AARCH64_ADR_GOT_PAGE: u32 = 311; +/// Dir. GOT off. LD/ST imm. 11:3 +pub const R_AARCH64_LD64_GOT_LO12_NC: u32 = 312; +/// GOT-page-rel. GOT off. LD/ST 14:3 +pub const R_AARCH64_LD64_GOTPAGE_LO15: u32 = 313; +/// PC-relative ADR imm. 20:0 +pub const R_AARCH64_TLSGD_ADR_PREL21: u32 = 512; +/// page-rel. ADRP imm. 32:12 +pub const R_AARCH64_TLSGD_ADR_PAGE21: u32 = 513; +/// direct ADD imm. from 11:0 +pub const R_AARCH64_TLSGD_ADD_LO12_NC: u32 = 514; +/// GOT-rel. MOV{N,Z} 31:16 +pub const R_AARCH64_TLSGD_MOVW_G1: u32 = 515; +/// GOT-rel. MOVK imm. 15:0 +pub const R_AARCH64_TLSGD_MOVW_G0_NC: u32 = 516; +/// Like 512; local dynamic model +pub const R_AARCH64_TLSLD_ADR_PREL21: u32 = 517; +/// Like 513; local dynamic model +pub const R_AARCH64_TLSLD_ADR_PAGE21: u32 = 518; +/// Like 514; local dynamic model +pub const R_AARCH64_TLSLD_ADD_LO12_NC: u32 = 519; +/// Like 515; local dynamic model +pub const R_AARCH64_TLSLD_MOVW_G1: u32 = 520; +/// Like 516; local dynamic model +pub const R_AARCH64_TLSLD_MOVW_G0_NC: u32 = 521; +/// TLS PC-rel. load imm. 20:2 +pub const R_AARCH64_TLSLD_LD_PREL19: u32 = 522; +/// TLS DTP-rel. MOV{N,Z} 47:32 +pub const R_AARCH64_TLSLD_MOVW_DTPREL_G2: u32 = 523; +/// TLS DTP-rel. MOV{N,Z} 31:16 +pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1: u32 = 524; +/// Likewise; MOVK; no check +pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: u32 = 525; +/// TLS DTP-rel. MOV{N,Z} 15:0 +pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0: u32 = 526; +/// Likewise; MOVK; no check +pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: u32 = 527; +/// DTP-rel. ADD imm. from 23:12. +pub const R_AARCH64_TLSLD_ADD_DTPREL_HI12: u32 = 528; +/// DTP-rel. ADD imm. from 11:0 +pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12: u32 = 529; +/// Likewise; no ovfl. check +pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: u32 = 530; +/// DTP-rel. LD/ST imm. 11:0 +pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12: u32 = 531; +/// Likewise; no check +pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: u32 = 532; +/// DTP-rel. LD/ST imm. 11:1 +pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12: u32 = 533; +/// Likewise; no check +pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: u32 = 534; +/// DTP-rel. LD/ST imm. 11:2 +pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12: u32 = 535; +/// Likewise; no check +pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: u32 = 536; +/// DTP-rel. LD/ST imm. 11:3 +pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12: u32 = 537; +/// Likewise; no check +pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: u32 = 538; +/// GOT-rel. MOV{N,Z} 31:16 +pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G1: u32 = 539; +/// GOT-rel. MOVK 15:0 +pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: u32 = 540; +/// Page-rel. ADRP 32:12 +pub const R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: u32 = 541; +/// Direct LD off. 11:3 +pub const R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: u32 = 542; +/// PC-rel. load imm. 20:2 +pub const R_AARCH64_TLSIE_LD_GOTTPREL_PREL19: u32 = 543; +/// TLS TP-rel. MOV{N,Z} 47:32 +pub const R_AARCH64_TLSLE_MOVW_TPREL_G2: u32 = 544; +/// TLS TP-rel. MOV{N,Z} 31:16 +pub const R_AARCH64_TLSLE_MOVW_TPREL_G1: u32 = 545; +/// Likewise; MOVK; no check +pub const R_AARCH64_TLSLE_MOVW_TPREL_G1_NC: u32 = 546; +/// TLS TP-rel. MOV{N,Z} 15:0 +pub const R_AARCH64_TLSLE_MOVW_TPREL_G0: u32 = 547; +/// Likewise; MOVK; no check +pub const R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: u32 = 548; +/// TP-rel. ADD imm. 23:12 +pub const R_AARCH64_TLSLE_ADD_TPREL_HI12: u32 = 549; +/// TP-rel. ADD imm. 11:0 +pub const R_AARCH64_TLSLE_ADD_TPREL_LO12: u32 = 550; +/// Likewise; no ovfl. check +pub const R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: u32 = 551; +/// TP-rel. LD/ST off. 11:0 +pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12: u32 = 552; +/// Likewise; no ovfl. check. +pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: u32 = 553; +/// TP-rel. LD/ST off. 11:1 +pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12: u32 = 554; +/// Likewise; no check +pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: u32 = 555; +/// TP-rel. LD/ST off. 11:2 +pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12: u32 = 556; +/// Likewise; no check +pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: u32 = 557; +/// TP-rel. LD/ST off. 11:3 +pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12: u32 = 558; +/// Likewise; no check +pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: u32 = 559; +/// PC-rel. load immediate 20:2 +pub const R_AARCH64_TLSDESC_LD_PREL19: u32 = 560; +/// PC-rel. ADR immediate 20:0 +pub const R_AARCH64_TLSDESC_ADR_PREL21: u32 = 561; +/// Page-rel. ADRP imm. 32:12 +pub const R_AARCH64_TLSDESC_ADR_PAGE21: u32 = 562; +/// Direct LD off. from 11:3 +pub const R_AARCH64_TLSDESC_LD64_LO12: u32 = 563; +/// Direct ADD imm. from 11:0 +pub const R_AARCH64_TLSDESC_ADD_LO12: u32 = 564; +/// GOT-rel. MOV{N,Z} imm. 31:16 +pub const R_AARCH64_TLSDESC_OFF_G1: u32 = 565; +/// GOT-rel. MOVK imm. 15:0; no ck +pub const R_AARCH64_TLSDESC_OFF_G0_NC: u32 = 566; +/// Relax LDR +pub const R_AARCH64_TLSDESC_LDR: u32 = 567; +/// Relax ADD +pub const R_AARCH64_TLSDESC_ADD: u32 = 568; +/// Relax BLR +pub const R_AARCH64_TLSDESC_CALL: u32 = 569; +/// TP-rel. LD/ST off. 11:4 +pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: u32 = 570; +/// Likewise; no check +pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: u32 = 571; +/// DTP-rel. LD/ST imm. 11:4. +pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: u32 = 572; +/// Likewise; no check +pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: u32 = 573; +/// Copy symbol at runtime +pub const R_AARCH64_COPY: u32 = 1024; +/// Create GOT entry +pub const R_AARCH64_GLOB_DAT: u32 = 1025; +/// Create PLT entry +pub const R_AARCH64_JUMP_SLOT: u32 = 1026; +/// Adjust by program base +pub const R_AARCH64_RELATIVE: u32 = 1027; +/// Module number, 64 bit +pub const R_AARCH64_TLS_DTPMOD: u32 = 1028; +/// Module-relative offset, 64 bit +pub const R_AARCH64_TLS_DTPREL: u32 = 1029; +/// TP-relative offset, 64 bit +pub const R_AARCH64_TLS_TPREL: u32 = 1030; +/// TLS Descriptor +pub const R_AARCH64_TLSDESC: u32 = 1031; +/// STT_GNU_IFUNC relocation +pub const R_AARCH64_IRELATIVE: u32 = 1032; + +// ARM relocs +/// No reloc +pub const R_ARM_NONE: u32 = 0; +/// Deprecated PC relative 26 bit branch +pub const R_ARM_PC24: u32 = 1; +/// Direct 32 bit +pub const R_ARM_ABS32: u32 = 2; +/// PC relative 32 bit +pub const R_ARM_REL32: u32 = 3; +pub const R_ARM_PC13: u32 = 4; +/// Direct 16 bit +pub const R_ARM_ABS16: u32 = 5; +/// Direct 12 bit +pub const R_ARM_ABS12: u32 = 6; +/// Direct & 0x7C (LDR, STR) +pub const R_ARM_THM_ABS5: u32 = 7; +/// Direct 8 bit +pub const R_ARM_ABS8: u32 = 8; +pub const R_ARM_SBREL32: u32 = 9; +/// PC relative 24 bit (Thumb32 BL) +pub const R_ARM_THM_PC22: u32 = 10; +/// PC relative & 0x3FC(Thumb16 LDR, ADD, ADR). +pub const R_ARM_THM_PC8: u32 = 11; +pub const R_ARM_AMP_VCALL9: u32 = 12; +/// Obsolete static relocation +pub const R_ARM_SWI24: u32 = 13; +/// Dynamic relocation +pub const R_ARM_TLS_DESC: u32 = 13; +/// Reserved +pub const R_ARM_THM_SWI8: u32 = 14; +/// Reserved +pub const R_ARM_XPC25: u32 = 15; +/// Reserved +pub const R_ARM_THM_XPC22: u32 = 16; +/// ID of module containing symbol +pub const R_ARM_TLS_DTPMOD32: u32 = 17; +/// Offset in TLS block +pub const R_ARM_TLS_DTPOFF32: u32 = 18; +/// Offset in static TLS block +pub const R_ARM_TLS_TPOFF32: u32 = 19; +/// Copy symbol at runtime +pub const R_ARM_COPY: u32 = 20; +/// Create GOT entry +pub const R_ARM_GLOB_DAT: u32 = 21; +/// Create PLT entry +pub const R_ARM_JUMP_SLOT: u32 = 22; +/// Adjust by program base +pub const R_ARM_RELATIVE: u32 = 23; +/// 32 bit offset to GOT +pub const R_ARM_GOTOFF: u32 = 24; +/// 32 bit PC relative offset to GOT +pub const R_ARM_GOTPC: u32 = 25; +/// 32 bit GOT entry +pub const R_ARM_GOT32: u32 = 26; +/// Deprecated, 32 bit PLT address +pub const R_ARM_PLT32: u32 = 27; +/// PC relative 24 bit (BL, BLX) +pub const R_ARM_CALL: u32 = 28; +/// PC relative 24 bit (B, BL<cond>) +pub const R_ARM_JUMP24: u32 = 29; +/// PC relative 24 bit (Thumb32 B.W) +pub const R_ARM_THM_JUMP24: u32 = 30; +/// Adjust by program base +pub const R_ARM_BASE_ABS: u32 = 31; +/// Obsolete +pub const R_ARM_ALU_PCREL_7_0: u32 = 32; +/// Obsolete +pub const R_ARM_ALU_PCREL_15_8: u32 = 33; +/// Obsolete +pub const R_ARM_ALU_PCREL_23_15: u32 = 34; +/// Deprecated, prog. base relative +pub const R_ARM_LDR_SBREL_11_0: u32 = 35; +/// Deprecated, prog. base relative +pub const R_ARM_ALU_SBREL_19_12: u32 = 36; +/// Deprecated, prog. base relative +pub const R_ARM_ALU_SBREL_27_20: u32 = 37; +pub const R_ARM_TARGET1: u32 = 38; +/// Program base relative +pub const R_ARM_SBREL31: u32 = 39; +pub const R_ARM_V4BX: u32 = 40; +pub const R_ARM_TARGET2: u32 = 41; +/// 32 bit PC relative +pub const R_ARM_PREL31: u32 = 42; +/// Direct 16-bit (MOVW) +pub const R_ARM_MOVW_ABS_NC: u32 = 43; +/// Direct high 16-bit (MOVT) +pub const R_ARM_MOVT_ABS: u32 = 44; +/// PC relative 16-bit (MOVW) +pub const R_ARM_MOVW_PREL_NC: u32 = 45; +/// PC relative (MOVT) +pub const R_ARM_MOVT_PREL: u32 = 46; +/// Direct 16 bit (Thumb32 MOVW) +pub const R_ARM_THM_MOVW_ABS_NC: u32 = 47; +/// Direct high 16 bit (Thumb32 MOVT) +pub const R_ARM_THM_MOVT_ABS: u32 = 48; +/// PC relative 16 bit (Thumb32 MOVW) +pub const R_ARM_THM_MOVW_PREL_NC: u32 = 49; +/// PC relative high 16 bit (Thumb32 MOVT) +pub const R_ARM_THM_MOVT_PREL: u32 = 50; +/// PC relative 20 bit (Thumb32 B<cond>.W) +pub const R_ARM_THM_JUMP19: u32 = 51; +/// PC relative X & 0x7E (Thumb16 CBZ, CBNZ) +pub const R_ARM_THM_JUMP6: u32 = 52; +/// PC relative 12 bit (Thumb32 ADR.W) +pub const R_ARM_THM_ALU_PREL_11_0: u32 = 53; +/// PC relative 12 bit (Thumb32 LDR{D,SB,H,SH}) +pub const R_ARM_THM_PC12: u32 = 54; +/// Direct 32-bit +pub const R_ARM_ABS32_NOI: u32 = 55; +/// PC relative 32-bit +pub const R_ARM_REL32_NOI: u32 = 56; +/// PC relative (ADD, SUB) +pub const R_ARM_ALU_PC_G0_NC: u32 = 57; +/// PC relative (ADD, SUB) +pub const R_ARM_ALU_PC_G0: u32 = 58; +/// PC relative (ADD, SUB) +pub const R_ARM_ALU_PC_G1_NC: u32 = 59; +/// PC relative (ADD, SUB) +pub const R_ARM_ALU_PC_G1: u32 = 60; +/// PC relative (ADD, SUB) +pub const R_ARM_ALU_PC_G2: u32 = 61; +/// PC relative (LDR,STR,LDRB,STRB) +pub const R_ARM_LDR_PC_G1: u32 = 62; +/// PC relative (LDR,STR,LDRB,STRB) +pub const R_ARM_LDR_PC_G2: u32 = 63; +/// PC relative (STR{D,H},LDR{D,SB,H,SH}) +pub const R_ARM_LDRS_PC_G0: u32 = 64; +/// PC relative (STR{D,H},LDR{D,SB,H,SH}) +pub const R_ARM_LDRS_PC_G1: u32 = 65; +/// PC relative (STR{D,H},LDR{D,SB,H,SH}) +pub const R_ARM_LDRS_PC_G2: u32 = 66; +/// PC relative (LDC, STC) +pub const R_ARM_LDC_PC_G0: u32 = 67; +/// PC relative (LDC, STC) +pub const R_ARM_LDC_PC_G1: u32 = 68; +/// PC relative (LDC, STC) +pub const R_ARM_LDC_PC_G2: u32 = 69; +/// Program base relative (ADD,SUB) +pub const R_ARM_ALU_SB_G0_NC: u32 = 70; +/// Program base relative (ADD,SUB) +pub const R_ARM_ALU_SB_G0: u32 = 71; +/// Program base relative (ADD,SUB) +pub const R_ARM_ALU_SB_G1_NC: u32 = 72; +/// Program base relative (ADD,SUB) +pub const R_ARM_ALU_SB_G1: u32 = 73; +/// Program base relative (ADD,SUB) +pub const R_ARM_ALU_SB_G2: u32 = 74; +/// Program base relative (LDR,STR, LDRB, STRB) +pub const R_ARM_LDR_SB_G0: u32 = 75; +/// Program base relative (LDR, STR, LDRB, STRB) +pub const R_ARM_LDR_SB_G1: u32 = 76; +/// Program base relative (LDR, STR, LDRB, STRB) +pub const R_ARM_LDR_SB_G2: u32 = 77; +/// Program base relative (LDR, STR, LDRB, STRB) +pub const R_ARM_LDRS_SB_G0: u32 = 78; +/// Program base relative (LDR, STR, LDRB, STRB) +pub const R_ARM_LDRS_SB_G1: u32 = 79; +/// Program base relative (LDR, STR, LDRB, STRB) +pub const R_ARM_LDRS_SB_G2: u32 = 80; +/// Program base relative (LDC,STC) +pub const R_ARM_LDC_SB_G0: u32 = 81; +/// Program base relative (LDC,STC) +pub const R_ARM_LDC_SB_G1: u32 = 82; +/// Program base relative (LDC,STC) +pub const R_ARM_LDC_SB_G2: u32 = 83; +/// Program base relative 16 bit (MOVW) +pub const R_ARM_MOVW_BREL_NC: u32 = 84; +/// Program base relative high 16 bit (MOVT) +pub const R_ARM_MOVT_BREL: u32 = 85; +/// Program base relative 16 bit (MOVW) +pub const R_ARM_MOVW_BREL: u32 = 86; +/// Program base relative 16 bit (Thumb32 MOVW) +pub const R_ARM_THM_MOVW_BREL_NC: u32 = 87; +/// Program base relative high 16 bit (Thumb32 MOVT) +pub const R_ARM_THM_MOVT_BREL: u32 = 88; +/// Program base relative 16 bit (Thumb32 MOVW) +pub const R_ARM_THM_MOVW_BREL: u32 = 89; +pub const R_ARM_TLS_GOTDESC: u32 = 90; +pub const R_ARM_TLS_CALL: u32 = 91; +/// TLS relaxation +pub const R_ARM_TLS_DESCSEQ: u32 = 92; +pub const R_ARM_THM_TLS_CALL: u32 = 93; +pub const R_ARM_PLT32_ABS: u32 = 94; +/// GOT entry +pub const R_ARM_GOT_ABS: u32 = 95; +/// PC relative GOT entry +pub const R_ARM_GOT_PREL: u32 = 96; +/// GOT entry relative to GOT origin (LDR) +pub const R_ARM_GOT_BREL12: u32 = 97; +/// 12 bit, GOT entry relative to GOT origin (LDR, STR) +pub const R_ARM_GOTOFF12: u32 = 98; +pub const R_ARM_GOTRELAX: u32 = 99; +pub const R_ARM_GNU_VTENTRY: u32 = 100; +pub const R_ARM_GNU_VTINHERIT: u32 = 101; +/// PC relative & 0xFFE (Thumb16 B) +pub const R_ARM_THM_PC11: u32 = 102; +/// PC relative & 0x1FE (Thumb16 B/B<cond>) +pub const R_ARM_THM_PC9: u32 = 103; +/// PC-rel 32 bit for global dynamic thread local data +pub const R_ARM_TLS_GD32: u32 = 104; +/// PC-rel 32 bit for local dynamic thread local data +pub const R_ARM_TLS_LDM32: u32 = 105; +/// 32 bit offset relative to TLS block +pub const R_ARM_TLS_LDO32: u32 = 106; +/// PC-rel 32 bit for GOT entry of static TLS block offset +pub const R_ARM_TLS_IE32: u32 = 107; +/// 32 bit offset relative to static TLS block +pub const R_ARM_TLS_LE32: u32 = 108; +/// 12 bit relative to TLS block (LDR, STR) +pub const R_ARM_TLS_LDO12: u32 = 109; +/// 12 bit relative to static TLS block (LDR, STR) +pub const R_ARM_TLS_LE12: u32 = 110; +/// 12 bit GOT entry relative to GOT origin (LDR) +pub const R_ARM_TLS_IE12GP: u32 = 111; +/// Obsolete +pub const R_ARM_ME_TOO: u32 = 128; +pub const R_ARM_THM_TLS_DESCSEQ: u32 = 129; +pub const R_ARM_THM_TLS_DESCSEQ16: u32 = 129; +pub const R_ARM_THM_TLS_DESCSEQ32: u32 = 130; +/// GOT entry relative to GOT origin, 12 bit (Thumb32 LDR) +pub const R_ARM_THM_GOT_BREL12: u32 = 131; +pub const R_ARM_IRELATIVE: u32 = 160; +pub const R_ARM_RXPC25: u32 = 249; +pub const R_ARM_RSBREL32: u32 = 250; +pub const R_ARM_THM_RPC22: u32 = 251; +pub const R_ARM_RREL32: u32 = 252; +pub const R_ARM_RABS22: u32 = 253; +pub const R_ARM_RPC24: u32 = 254; +pub const R_ARM_RBASE: u32 = 255; +/// Keep this the last entry +pub const R_ARM_NUM: u32 = 256; + +/////////////////// +// OpenRisc +/////////////////// +pub const R_OR1K_NONE: u32 = 0; +pub const R_OR1K_32: u32 = 1; +pub const R_OR1K_16: u32 = 2; +pub const R_OR1K_8: u32 = 3; +pub const R_OR1K_LO_16_IN_INSN: u32 = 4; +pub const R_OR1K_HI_16_IN_INSN: u32 = 5; +pub const R_OR1K_INSN_REL_26: u32 = 6; +pub const R_OR1K_GNU_VTENTRY: u32 = 7; +pub const R_OR1K_GNU_VTINHERIT: u32 = 8; +pub const R_OR1K_32_PCREL: u32 = 9; +pub const R_OR1K_16_PCREL: u32 = 10; +pub const R_OR1K_8_PCREL: u32 = 11; +pub const R_OR1K_GOTPC_HI16: u32 = 12; +pub const R_OR1K_GOTPC_LO16: u32 = 13; +pub const R_OR1K_GOT16: u32 = 14; +pub const R_OR1K_PLT26: u32 = 15; +pub const R_OR1K_GOTOFF_HI16: u32 = 16; +pub const R_OR1K_GOTOFF_LO16: u32 = 17; +pub const R_OR1K_COPY: u32 = 18; +pub const R_OR1K_GLOB_DAT: u32 = 19; +pub const R_OR1K_JMP_SLOT: u32 = 20; +pub const R_OR1K_RELATIVE: u32 = 21; +pub const R_OR1K_TLS_GD_HI16: u32 = 22; +pub const R_OR1K_TLS_GD_LO16: u32 = 23; +pub const R_OR1K_TLS_LDM_HI16: u32 = 24; +pub const R_OR1K_TLS_LDM_LO16: u32 = 25; +pub const R_OR1K_TLS_LDO_HI16: u32 = 26; +pub const R_OR1K_TLS_LDO_LO16: u32 = 27; +pub const R_OR1K_TLS_IE_HI16: u32 = 28; +pub const R_OR1K_TLS_IE_LO16: u32 = 29; +pub const R_OR1K_TLS_LE_HI16: u32 = 30; +pub const R_OR1K_TLS_LE_LO16: u32 = 31; +pub const R_OR1K_TLS_TPOFF: u32 = 32; +pub const R_OR1K_TLS_DTPOFF: u32 = 33; +pub const R_OR1K_TLS_DTPMOD: u32 = 34; +pub const R_OR1K_NUM: u32 = 35; + +///////////////////// +// MIPS +///////////////////// +/// No reloc +pub const R_MIPS_NONE: u32 = 0; +/// Direct 16 bit +pub const R_MIPS_16: u32 = 1; +/// Direct 32 bit +pub const R_MIPS_32: u32 = 2; +/// PC relative 32 bit +pub const R_MIPS_REL32: u32 = 3; +/// Direct 26 bit shifted +pub const R_MIPS_26: u32 = 4; +/// High 16 bit +pub const R_MIPS_HI16: u32 = 5; +/// Low 16 bit +pub const R_MIPS_LO16: u32 = 6; +/// GP relative 16 bit +pub const R_MIPS_GPREL16: u32 = 7; +/// 16 bit literal entry +pub const R_MIPS_LITERAL: u32 = 8; +/// 16 bit GOT entry +pub const R_MIPS_GOT16: u32 = 9; +/// PC relative 16 bit +pub const R_MIPS_PC16: u32 = 10; +/// 16 bit GOT entry for function +pub const R_MIPS_CALL16: u32 = 11; +/// GP relative 32 bit +pub const R_MIPS_GPREL32: u32 = 12; +pub const R_MIPS_SHIFT5: u32 = 16; +pub const R_MIPS_SHIFT6: u32 = 17; +pub const R_MIPS_64: u32 = 18; +pub const R_MIPS_GOT_DISP: u32 = 19; +pub const R_MIPS_GOT_PAGE: u32 = 20; +pub const R_MIPS_GOT_OFST: u32 = 21; +pub const R_MIPS_GOT_HI16: u32 = 22; +pub const R_MIPS_GOT_LO16: u32 = 23; +pub const R_MIPS_SUB: u32 = 24; +pub const R_MIPS_INSERT_A: u32 = 25; +pub const R_MIPS_INSERT_B: u32 = 26; +pub const R_MIPS_DELETE: u32 = 27; +pub const R_MIPS_HIGHER: u32 = 28; +pub const R_MIPS_HIGHEST: u32 = 29; +pub const R_MIPS_CALL_HI16: u32 = 30; +pub const R_MIPS_CALL_LO16: u32 = 31; +pub const R_MIPS_SCN_DISP: u32 = 32; +pub const R_MIPS_REL16: u32 = 33; +pub const R_MIPS_ADD_IMMEDIATE: u32 = 34; +pub const R_MIPS_PJUMP: u32 = 35; +pub const R_MIPS_RELGOT: u32 = 36; +pub const R_MIPS_JALR: u32 = 37; +/// Module number 32 bit +pub const R_MIPS_TLS_DTPMOD32: u32 = 38; +/// Module-relative offset 32 bit +pub const R_MIPS_TLS_DTPREL32: u32 = 39; +/// Module number 64 bit +pub const R_MIPS_TLS_DTPMOD64: u32 = 40; +/// Module-relative offset 64 bit +pub const R_MIPS_TLS_DTPREL64: u32 = 41; +/// 16 bit GOT offset for GD +pub const R_MIPS_TLS_GD: u32 = 42; +/// 16 bit GOT offset for LDM +pub const R_MIPS_TLS_LDM: u32 = 43; +/// Module-relative offset, high 16 bits +pub const R_MIPS_TLS_DTPREL_HI16: u32 = 44; +/// Module-relative offset, low 16 bits +pub const R_MIPS_TLS_DTPREL_LO16: u32 = 45; +/// 16 bit GOT offset for IE +pub const R_MIPS_TLS_GOTTPREL: u32 = 46; +/// TP-relative offset, 32 bit6 +pub const R_MIPS_TLS_TPREL32: u32 = 47; +/// TP-relative offset, 64 bit +pub const R_MIPS_TLS_TPREL64: u32 = 48; +/// TP-relative offset, high 16 bits +pub const R_MIPS_TLS_TPREL_HI16: u32 = 49; +/// TP-relative offset, low 16 bits +pub const R_MIPS_TLS_TPREL_LO16: u32 = 50; +pub const R_MIPS_GLOB_DAT: u32 = 51; +pub const R_MIPS_COPY: u32 = 126; +pub const R_MIPS_JUMP_SLOT: u32 = 127; +pub const R_MIPS_NUM: u32 = 128; + +/////////////////// +// RISC-V +// See https://github.com/riscv/riscv-elf-psabi-doc +/////////////////// +/// None +pub const R_RISCV_NONE: u32 = 0; +/// Runtime relocation: word32 = S + A +pub const R_RISCV_32: u32 = 1; +/// Runtime relocation: word64 = S + A +pub const R_RISCV_64: u32 = 2; +/// Runtime relocation: word32,64 = B + A +pub const R_RISCV_RELATIVE: u32 = 3; +/// Runtime relocation: must be in executable, not allowed in shared library +pub const R_RISCV_COPY: u32 = 4; +/// Runtime relocation: word32,64 = S; handled by PLT unless LD_BIND_NOW +pub const R_RISCV_JUMP_SLOT: u32 = 5; +/// TLS relocation: word32 = S->TLSINDEX +pub const R_RISCV_TLS_DTPMOD32: u32 = 6; +/// TLS relocation: word64 = S->TLSINDEX +pub const R_RISCV_TLS_DTPMOD64: u32 = 7; +/// TLS relocation: word32 = TLS + S + A - TLS_TP_OFFSET +pub const R_RISCV_TLS_DTPREL32: u32 = 8; +/// TLS relocation: word64 = TLS + S + A - TLS_TP_OFFSET +pub const R_RISCV_TLS_DTPREL64: u32 = 9; +/// TLS relocation: word32 = TLS + S + A + S_TLS_OFFSET - TLS_DTV_OFFSET +pub const R_RISCV_TLS_TPREL32: u32 = 10; +/// TLS relocation: word64 = TLS + S + A + S_TLS_OFFSET - TLS_DTV_OFFSET +pub const R_RISCV_TLS_TPREL64: u32 = 11; +/// PC-relative branch (SB-Type) +pub const R_RISCV_BRANCH: u32 = 16; +/// PC-relative jump (UJ-Type) +pub const R_RISCV_JAL: u32 = 17; +/// PC-relative call: MACRO call,tail (auipc+jalr pair) +pub const R_RISCV_CALL: u32 = 18; +/// PC-relative call (PLT): MACRO call,tail (auipc+jalr pair) PIC +pub const R_RISCV_CALL_PLT: u32 = 19; +/// PC-relative GOT reference: MACRO la +pub const R_RISCV_GOT_HI20: u32 = 20; +/// PC-relative TLS IE GOT offset: MACRO la.tls.ie +pub const R_RISCV_TLS_GOT_HI20: u32 = 21; +/// PC-relative TLS GD reference: MACRO la.tls.gd +pub const R_RISCV_TLS_GD_HI20: u32 = 22; +/// PC-relative reference: %pcrel_hi(symbol) (U-Type) +pub const R_RISCV_PCREL_HI20: u32 = 23; +/// PC-relative reference: %pcrel_lo(symbol) (I-Type) +pub const R_RISCV_PCREL_LO12_I: u32 = 24; +/// PC-relative reference: %pcrel_lo(symbol) (S-Type) +pub const R_RISCV_PCREL_LO12_S: u32 = 25; +/// Absolute address: %hi(symbol) (U-Type) +pub const R_RISCV_HI20: u32 = 26; +/// Absolute address: %lo(symbol) (I-Type) +pub const R_RISCV_LO12_I: u32 = 27; +/// Absolute address: %lo(symbol) (S-Type) +pub const R_RISCV_LO12_S: u32 = 28; +/// TLS LE thread offset: %tprel_hi(symbol) (U-Type) +pub const R_RISCV_TPREL_HI20: u32 = 29; +/// TLS LE thread offset: %tprel_lo(symbol) (I-Type) +pub const R_RISCV_TPREL_LO12_I: u32 = 30; +/// TLS LE thread offset: %tprel_lo(symbol) (S-Type) +pub const R_RISCV_TPREL_LO12_S: u32 = 31; +/// TLS LE thread usage: %tprel_add(symbol) +pub const R_RISCV_TPREL_ADD: u32 = 32; +/// 8-bit label addition: word8 = S + A +pub const R_RISCV_ADD8: u32 = 33; +/// 16-bit label addition: word16 = S + A +pub const R_RISCV_ADD16: u32 = 34; +/// 32-bit label addition: word32 = S + A +pub const R_RISCV_ADD32: u32 = 35; +/// 64-bit label addition: word64 = S + A +pub const R_RISCV_ADD64: u32 = 36; +/// 8-bit label subtraction: word8 = S - A +pub const R_RISCV_SUB8: u32 = 37; +/// 16-bit label subtraction: word16 = S - A +pub const R_RISCV_SUB16: u32 = 38; +/// 32-bit label subtraction: word32 = S - A +pub const R_RISCV_SUB32: u32 = 39; +/// 64-bit label subtraction: word64 = S - A +pub const R_RISCV_SUB64: u32 = 40; +/// GNU C++ vtable hierarchy +pub const R_RISCV_GNU_VTINHERIT: u32 = 41; +/// GNU C++ vtable member usage +pub const R_RISCV_GNU_VTENTRY: u32 = 42; +/// Alignment statement +pub const R_RISCV_ALIGN: u32 = 43; +/// PC-relative branch offset (CB-Type) +pub const R_RISCV_RVC_BRANCH: u32 = 44; +/// PC-relative jump offset (CJ-Type) +pub const R_RISCV_RVC_JUMP: u32 = 45; +/// Absolute address (CI-Type) +pub const R_RISCV_RVC_LUI: u32 = 46; +/// GP-relative reference (I-Type) +pub const R_RISCV_GPREL_I: u32 = 47; +/// GP-relative reference (S-Type) +pub const R_RISCV_GPREL_S: u32 = 48; +/// TP-relative TLS LE load (I-Type) +pub const R_RISCV_TPREL_I: u32 = 49; +/// TP-relative TLS LE store (S-Type) +pub const R_RISCV_TPREL_S: u32 = 50; +/// Instruction pair can be relaxed +pub const R_RISCV_RELAX: u32 = 51; +/// Local label subtraction +pub const R_RISCV_SUB6: u32 = 52; +/// Local label subtraction +pub const R_RISCV_SET6: u32 = 53; +/// Local label subtraction +pub const R_RISCV_SET8: u32 = 54; +/// Local label subtraction +pub const R_RISCV_SET16: u32 = 55; +/// Local label subtraction +pub const R_RISCV_SET32: u32 = 56; + +#[inline] +pub fn r_to_str(typ: u32, machine: u16) -> &'static str { + use crate::elf::header::*; + match machine { + // x86 + EM_386 => { match typ { + R_386_NONE => "386_NONE", + R_386_32 => "386_32", + R_386_PC32 => "386_PC32", + R_386_GOT32 => "386_GOT32", + R_386_PLT32 => "386_PLT32", + R_386_COPY => "386_COPY", + R_386_GLOB_DAT => "386_GLOB_DAT", + R_386_JMP_SLOT => "386_JMP_SLOT", + R_386_RELATIVE => "386_RELATIVE", + R_386_GOTOFF => "386_GOTOFF", + R_386_GOTPC => "386_GOTPC", + R_386_32PLT => "386_32PLT", + R_386_TLS_TPOFF => "386_TLS_TPOFF", + R_386_TLS_IE => "386_TLS_IE", + R_386_TLS_GOTIE => "386_TLS_GOTIE", + R_386_TLS_LE => "386_TLS_LE", + R_386_TLS_GD => "386_TLS_GD", + R_386_TLS_LDM => "386_TLS_LDM", + R_386_16 => "386_16", + R_386_PC16 => "386_PC16", + R_386_8 => "386_8", + R_386_PC8 => "386_PC8", + R_386_TLS_GD_32 => "386_TLS_GD_32", + R_386_TLS_GD_PUSH => "386_TLS_GD_PUSH", + R_386_TLS_GD_CALL => "386_TLS_GD_CALL", + R_386_TLS_GD_POP => "386_TLS_GD_POP", + R_386_TLS_LDM_32 => "386_TLS_LDM_32", + R_386_TLS_LDM_PUSH => "386_TLS_LDM_PUSH", + R_386_TLS_LDM_CALL => "386_TLS_LDM_CALL", + R_386_TLS_LDM_POP => "386_TLS_LDM_POP", + R_386_TLS_LDO_32 => "386_TLS_LDO_32", + R_386_TLS_IE_32 => "386_TLS_IE_32", + R_386_TLS_LE_32 => "386_TLS_LE_32", + R_386_TLS_DTPMOD32 => "386_TLS_DTPMOD32", + R_386_TLS_DTPOFF32 => "386_TLS_DTPOFF32", + R_386_TLS_TPOFF32 => "386_TLS_TPOFF32", + R_386_SIZE32 => "386_SIZE32", + R_386_TLS_GOTDESC => "386_TLS_GOTDESC", + R_386_TLS_DESC_CALL => "386_TLS_DESC_CALL", + R_386_TLS_DESC => "386_TLS_DESC", + R_386_IRELATIVE => "386_IRELATIVE", + R_386_GOT32X => "386_GOT32X", + _ => "R_UNKNOWN_386", + }}, + EM_X86_64 => { match typ { + R_X86_64_64 => "X86_64_64", + R_X86_64_PC32 => "X86_64_PC32", + R_X86_64_GOT32 => "X86_64_GOT32", + R_X86_64_PLT32 => "X86_64_PLT32", + R_X86_64_COPY => "X86_64_COPY", + R_X86_64_GLOB_DAT => "X86_64_GLOB_DAT", + R_X86_64_JUMP_SLOT => "X86_64_JUMP_SLOT", + R_X86_64_RELATIVE => "X86_64_RELATIVE", + R_X86_64_GOTPCREL => "X86_64_GOTPCREL", + R_X86_64_32 => "X86_64_32", + R_X86_64_32S => "X86_64_32S", + R_X86_64_16 => "X86_64_16", + R_X86_64_PC16 => "X86_64_PC16", + R_X86_64_8 => "X86_64_8", + R_X86_64_PC8 => "X86_64_PC8", + R_X86_64_DTPMOD64 => "X86_64_DTPMOD64", + R_X86_64_DTPOFF64 => "X86_64_DTPOFF64", + R_X86_64_TPOFF64 => "X86_64_TPOFF64", + R_X86_64_TLSGD => "X86_64_TLSGD", + R_X86_64_TLSLD => "X86_64_TLSLD", + R_X86_64_DTPOFF32 => "X86_64_DTPOFF32", + R_X86_64_GOTTPOFF => "X86_64_GOTTPOFF", + R_X86_64_TPOFF32 => "X86_64_TPOFF32", + R_X86_64_PC64 => "X86_64_PC64", + R_X86_64_GOTOFF64 => "X86_64_GOTOFF64", + R_X86_64_GOTPC32 => "X86_64_GOTPC32", + R_X86_64_GOT64 => "X86_64_GOT64", + R_X86_64_GOTPCREL64 => "X86_64_GOTPCREL64", + R_X86_64_GOTPC64 => "X86_64_GOTPC64", + R_X86_64_GOTPLT64 => "X86_64_GOTPLT64", + R_X86_64_PLTOFF64 => "X86_64_PLTOFF64", + R_X86_64_SIZE32 => "X86_64_SIZE32", + R_X86_64_SIZE64 => "X86_64_SIZE64", + R_X86_64_GOTPC32_TLSDESC => "X86_64_GOTPC32_TLSDESC", + R_X86_64_TLSDESC_CALL => "X86_64_TLSDESC_CALL", + R_X86_64_TLSDESC => "X86_64_TLSDESC", + R_X86_64_IRELATIVE => "X86_64_IRELATIVE", + R_X86_64_RELATIVE64 => "X86_64_RELATIVE64", + R_X86_64_GOTPCRELX => "R_X86_64_GOTPCRELX", + R_X86_64_REX_GOTPCRELX => "R_X86_64_REX_GOTPCRELX", + _ => "R_UNKNOWN_X86_64", + }}, + // openrisc + EM_OPENRISC => { match typ { + R_OR1K_NONE => "OR1K_NONE", + R_OR1K_32 => "OR1K_32", + R_OR1K_16 => "OR1K_16", + R_OR1K_8 => "OR1K_8", + R_OR1K_LO_16_IN_INSN => "OR1K_LO_16_IN_INSN", + R_OR1K_HI_16_IN_INSN => "OR1K_HI_16_IN_INSN", + R_OR1K_INSN_REL_26 => "OR1K_INSN_REL_26", + R_OR1K_GNU_VTENTRY => "OR1K_GNU_VTENTRY", + R_OR1K_GNU_VTINHERIT => "OR1K_GNU_VTINHERIT", + R_OR1K_32_PCREL => "OR1K_32_PCREL", + R_OR1K_16_PCREL => "OR1K_16_PCREL", + R_OR1K_8_PCREL => "OR1K_8_PCREL", + R_OR1K_GOTPC_HI16 => "OR1K_GOTPC_HI16", + R_OR1K_GOTPC_LO16 => "OR1K_GOTPC_LO16", + R_OR1K_GOT16 => "OR1K_GOT16", + R_OR1K_PLT26 => "OR1K_PLT26", + R_OR1K_GOTOFF_HI16 => "OR1K_GOTOFF_HI16", + R_OR1K_GOTOFF_LO16 => "OR1K_GOTOFF_LO16", + R_OR1K_COPY => "OR1K_COPY", + R_OR1K_GLOB_DAT => "OR1K_GLOB_DAT", + R_OR1K_JMP_SLOT => "OR1K_JMP_SLOT", + R_OR1K_RELATIVE => "OR1K_RELATIVE", + R_OR1K_TLS_GD_HI16 => "OR1K_TLS_GD_HI16", + R_OR1K_TLS_GD_LO16 => "OR1K_TLS_GD_LO16", + R_OR1K_TLS_LDM_HI16 => "OR1K_TLS_LDM_HI16", + R_OR1K_TLS_LDM_LO16 => "OR1K_TLS_LDM_LO16", + R_OR1K_TLS_LDO_HI16 => "OR1K_TLS_LDO_HI16", + R_OR1K_TLS_LDO_LO16 => "OR1K_TLS_LDO_LO16", + R_OR1K_TLS_IE_HI16 => "OR1K_TLS_IE_HI16", + R_OR1K_TLS_IE_LO16 => "OR1K_TLS_IE_LO16", + R_OR1K_TLS_LE_HI16 => "OR1K_TLS_LE_HI16", + R_OR1K_TLS_LE_LO16 => "OR1K_TLS_LE_LO16", + R_OR1K_TLS_TPOFF => "OR1K_TLS_TPOFF", + R_OR1K_TLS_DTPOFF => "OR1K_TLS_DTPOFF", + R_OR1K_TLS_DTPMOD => "OR1K_TLS_DTPMOD", + _ => "R_UNKNOWN_OR1K", + }}, + // arm64 + EM_AARCH64 => { match typ { + R_AARCH64_P32_ABS32 => "AARCH64_P32_ABS32", + R_AARCH64_P32_COPY => "AARCH64_P32_COPY", + R_AARCH64_P32_GLOB_DAT => "AARCH64_P32_GLOB_DAT", + R_AARCH64_P32_JUMP_SLOT => "AARCH64_P32_JUMP_SLOT", + R_AARCH64_P32_RELATIVE => "AARCH64_P32_RELATIVE", + R_AARCH64_P32_TLS_DTPMOD => "AARCH64_P32_TLS_DTPMOD", + R_AARCH64_P32_TLS_DTPREL => "AARCH64_P32_TLS_DTPREL", + R_AARCH64_P32_TLS_TPREL => "AARCH64_P32_TLS_TPREL", + R_AARCH64_P32_TLSDESC => "AARCH64_P32_TLSDESC", + R_AARCH64_P32_IRELATIVE => "AARCH64_P32_IRELATIVE", + R_AARCH64_ABS64 => "AARCH64_ABS64", + R_AARCH64_ABS32 => "AARCH64_ABS32", + R_AARCH64_ABS16 => "AARCH64_ABS16", + R_AARCH64_PREL64 => "AARCH64_PREL64", + R_AARCH64_PREL32 => "AARCH64_PREL32", + R_AARCH64_PREL16 => "AARCH64_PREL16", + R_AARCH64_MOVW_UABS_G0 => "AARCH64_MOVW_UABS_G0", + R_AARCH64_MOVW_UABS_G0_NC => "AARCH64_MOVW_UABS_G0_NC", + R_AARCH64_MOVW_UABS_G1 => "AARCH64_MOVW_UABS_G1", + R_AARCH64_MOVW_UABS_G1_NC => "AARCH64_MOVW_UABS_G1_NC", + R_AARCH64_MOVW_UABS_G2 => "AARCH64_MOVW_UABS_G2", + R_AARCH64_MOVW_UABS_G2_NC => "AARCH64_MOVW_UABS_G2_NC", + R_AARCH64_MOVW_UABS_G3 => "AARCH64_MOVW_UABS_G3", + R_AARCH64_MOVW_SABS_G0 => "AARCH64_MOVW_SABS_G0", + R_AARCH64_MOVW_SABS_G1 => "AARCH64_MOVW_SABS_G1", + R_AARCH64_MOVW_SABS_G2 => "AARCH64_MOVW_SABS_G2", + R_AARCH64_LD_PREL_LO19 => "AARCH64_LD_PREL_LO19", + R_AARCH64_ADR_PREL_LO21 => "AARCH64_ADR_PREL_LO21", + R_AARCH64_ADR_PREL_PG_HI21 => "AARCH64_ADR_PREL_PG_HI21", + R_AARCH64_ADR_PREL_PG_HI21_NC => "AARCH64_ADR_PREL_PG_HI21_NC", + R_AARCH64_ADD_ABS_LO12_NC => "AARCH64_ADD_ABS_LO12_NC", + R_AARCH64_LDST8_ABS_LO12_NC => "AARCH64_LDST8_ABS_LO12_NC", + R_AARCH64_TSTBR14 => "AARCH64_TSTBR14", + R_AARCH64_CONDBR19 => "AARCH64_CONDBR19", + R_AARCH64_JUMP26 => "AARCH64_JUMP26", + R_AARCH64_CALL26 => "AARCH64_CALL26", + R_AARCH64_LDST16_ABS_LO12_NC => "AARCH64_LDST16_ABS_LO12_NC", + R_AARCH64_LDST32_ABS_LO12_NC => "AARCH64_LDST32_ABS_LO12_NC", + R_AARCH64_LDST64_ABS_LO12_NC => "AARCH64_LDST64_ABS_LO12_NC", + R_AARCH64_MOVW_PREL_G0 => "AARCH64_MOVW_PREL_G0", + R_AARCH64_MOVW_PREL_G0_NC => "AARCH64_MOVW_PREL_G0_NC", + R_AARCH64_MOVW_PREL_G1 => "AARCH64_MOVW_PREL_G1", + R_AARCH64_MOVW_PREL_G1_NC => "AARCH64_MOVW_PREL_G1_NC", + R_AARCH64_MOVW_PREL_G2 => "AARCH64_MOVW_PREL_G2", + R_AARCH64_MOVW_PREL_G2_NC => "AARCH64_MOVW_PREL_G2_NC", + R_AARCH64_MOVW_PREL_G3 => "AARCH64_MOVW_PREL_G3", + R_AARCH64_LDST128_ABS_LO12_NC => "AARCH64_LDST128_ABS_LO12_NC", + R_AARCH64_MOVW_GOTOFF_G0 => "AARCH64_MOVW_GOTOFF_G0", + R_AARCH64_MOVW_GOTOFF_G0_NC => "AARCH64_MOVW_GOTOFF_G0_NC", + R_AARCH64_MOVW_GOTOFF_G1 => "AARCH64_MOVW_GOTOFF_G1", + R_AARCH64_MOVW_GOTOFF_G1_NC => "AARCH64_MOVW_GOTOFF_G1_NC", + R_AARCH64_MOVW_GOTOFF_G2 => "AARCH64_MOVW_GOTOFF_G2", + R_AARCH64_MOVW_GOTOFF_G2_NC => "AARCH64_MOVW_GOTOFF_G2_NC", + R_AARCH64_MOVW_GOTOFF_G3 => "AARCH64_MOVW_GOTOFF_G3", + R_AARCH64_GOTREL64 => "AARCH64_GOTREL64", + R_AARCH64_GOTREL32 => "AARCH64_GOTREL32", + R_AARCH64_GOT_LD_PREL19 => "AARCH64_GOT_LD_PREL19", + R_AARCH64_LD64_GOTOFF_LO15 => "AARCH64_LD64_GOTOFF_LO15", + R_AARCH64_ADR_GOT_PAGE => "AARCH64_ADR_GOT_PAGE", + R_AARCH64_LD64_GOT_LO12_NC => "AARCH64_LD64_GOT_LO12_NC", + R_AARCH64_LD64_GOTPAGE_LO15 => "AARCH64_LD64_GOTPAGE_LO15", + R_AARCH64_TLSGD_ADR_PREL21 => "AARCH64_TLSGD_ADR_PREL21", + R_AARCH64_TLSGD_ADR_PAGE21 => "AARCH64_TLSGD_ADR_PAGE21", + R_AARCH64_TLSGD_ADD_LO12_NC => "AARCH64_TLSGD_ADD_LO12_NC", + R_AARCH64_TLSGD_MOVW_G1 => "AARCH64_TLSGD_MOVW_G1", + R_AARCH64_TLSGD_MOVW_G0_NC => "AARCH64_TLSGD_MOVW_G0_NC", + R_AARCH64_TLSLD_ADR_PREL21 => "AARCH64_TLSLD_ADR_PREL21", + R_AARCH64_TLSLD_ADR_PAGE21 => "AARCH64_TLSLD_ADR_PAGE21", + R_AARCH64_TLSLD_ADD_LO12_NC => "AARCH64_TLSLD_ADD_LO12_NC", + R_AARCH64_TLSLD_MOVW_G1 => "AARCH64_TLSLD_MOVW_G1", + R_AARCH64_TLSLD_MOVW_G0_NC => "AARCH64_TLSLD_MOVW_G0_NC", + R_AARCH64_TLSLD_LD_PREL19 => "AARCH64_TLSLD_LD_PREL19", + R_AARCH64_TLSLD_MOVW_DTPREL_G2 => "AARCH64_TLSLD_MOVW_DTPREL_G2", + R_AARCH64_TLSLD_MOVW_DTPREL_G1 => "AARCH64_TLSLD_MOVW_DTPREL_G1", + R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC => "AARCH64_TLSLD_MOVW_DTPREL_G1_NC", + R_AARCH64_TLSLD_MOVW_DTPREL_G0 => "AARCH64_TLSLD_MOVW_DTPREL_G0", + R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC => "AARCH64_TLSLD_MOVW_DTPREL_G0_NC", + R_AARCH64_TLSLD_ADD_DTPREL_HI12 => "AARCH64_TLSLD_ADD_DTPREL_HI12", + R_AARCH64_TLSLD_ADD_DTPREL_LO12 => "AARCH64_TLSLD_ADD_DTPREL_LO12", + R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC => "AARCH64_TLSLD_ADD_DTPREL_LO12_NC", + R_AARCH64_TLSLD_LDST8_DTPREL_LO12 => "AARCH64_TLSLD_LDST8_DTPREL_LO12", + R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC => "AARCH64_TLSLD_LDST8_DTPREL_LO12_NC", + R_AARCH64_TLSLD_LDST16_DTPREL_LO12 => "AARCH64_TLSLD_LDST16_DTPREL_LO12", + R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC => "AARCH64_TLSLD_LDST16_DTPREL_LO12_NC", + R_AARCH64_TLSLD_LDST32_DTPREL_LO12 => "AARCH64_TLSLD_LDST32_DTPREL_LO12", + R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC => "AARCH64_TLSLD_LDST32_DTPREL_LO12_NC", + R_AARCH64_TLSLD_LDST64_DTPREL_LO12 => "AARCH64_TLSLD_LDST64_DTPREL_LO12", + R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC => "AARCH64_TLSLD_LDST64_DTPREL_LO12_NC", + R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 => "AARCH64_TLSIE_MOVW_GOTTPREL_G1", + R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC => "AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC", + R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 => "AARCH64_TLSIE_ADR_GOTTPREL_PAGE21", + R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC => "AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", + R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 => "AARCH64_TLSIE_LD_GOTTPREL_PREL19", + R_AARCH64_TLSLE_MOVW_TPREL_G2 => "AARCH64_TLSLE_MOVW_TPREL_G2", + R_AARCH64_TLSLE_MOVW_TPREL_G1 => "AARCH64_TLSLE_MOVW_TPREL_G1", + R_AARCH64_TLSLE_MOVW_TPREL_G1_NC => "AARCH64_TLSLE_MOVW_TPREL_G1_NC", + R_AARCH64_TLSLE_MOVW_TPREL_G0 => "AARCH64_TLSLE_MOVW_TPREL_G0", + R_AARCH64_TLSLE_MOVW_TPREL_G0_NC => "AARCH64_TLSLE_MOVW_TPREL_G0_NC", + R_AARCH64_TLSLE_ADD_TPREL_HI12 => "AARCH64_TLSLE_ADD_TPREL_HI12", + R_AARCH64_TLSLE_ADD_TPREL_LO12 => "AARCH64_TLSLE_ADD_TPREL_LO12", + R_AARCH64_TLSLE_ADD_TPREL_LO12_NC => "AARCH64_TLSLE_ADD_TPREL_LO12_NC", + R_AARCH64_TLSLE_LDST8_TPREL_LO12 => "AARCH64_TLSLE_LDST8_TPREL_LO12", + R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC => "AARCH64_TLSLE_LDST8_TPREL_LO12_NC", + R_AARCH64_TLSLE_LDST16_TPREL_LO12 => "AARCH64_TLSLE_LDST16_TPREL_LO12", + R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC => "AARCH64_TLSLE_LDST16_TPREL_LO12_NC", + R_AARCH64_TLSLE_LDST32_TPREL_LO12 => "AARCH64_TLSLE_LDST32_TPREL_LO12", + R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC => "AARCH64_TLSLE_LDST32_TPREL_LO12_NC", + R_AARCH64_TLSLE_LDST64_TPREL_LO12 => "AARCH64_TLSLE_LDST64_TPREL_LO12", + R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC => "AARCH64_TLSLE_LDST64_TPREL_LO12_NC", + R_AARCH64_TLSDESC_LD_PREL19 => "AARCH64_TLSDESC_LD_PREL19", + R_AARCH64_TLSDESC_ADR_PREL21 => "AARCH64_TLSDESC_ADR_PREL21", + R_AARCH64_TLSDESC_ADR_PAGE21 => "AARCH64_TLSDESC_ADR_PAGE21", + R_AARCH64_TLSDESC_LD64_LO12 => "AARCH64_TLSDESC_LD64_LO12", + R_AARCH64_TLSDESC_ADD_LO12 => "AARCH64_TLSDESC_ADD_LO12", + R_AARCH64_TLSDESC_OFF_G1 => "AARCH64_TLSDESC_OFF_G1", + R_AARCH64_TLSDESC_OFF_G0_NC => "AARCH64_TLSDESC_OFF_G0_NC", + R_AARCH64_TLSDESC_LDR => "AARCH64_TLSDESC_LDR", + R_AARCH64_TLSDESC_ADD => "AARCH64_TLSDESC_ADD", + R_AARCH64_TLSDESC_CALL => "AARCH64_TLSDESC_CALL", + R_AARCH64_TLSLE_LDST128_TPREL_LO12 => "AARCH64_TLSLE_LDST128_TPREL_LO12", + R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC => "AARCH64_TLSLE_LDST128_TPREL_LO12_NC", + R_AARCH64_TLSLD_LDST128_DTPREL_LO12 => "AARCH64_TLSLD_LDST128_DTPREL_LO12", + R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC => "AARCH64_TLSLD_LDST128_DTPREL_LO12_NC", + R_AARCH64_COPY => "AARCH64_COPY", + R_AARCH64_GLOB_DAT => "AARCH64_GLOB_DAT", + R_AARCH64_JUMP_SLOT => "AARCH64_JUMP_SLOT", + R_AARCH64_RELATIVE => "AARCH64_RELATIVE", + R_AARCH64_TLS_DTPMOD => "AARCH64_TLS_DTPMOD", + R_AARCH64_TLS_DTPREL => "AARCH64_TLS_DTPREL", + R_AARCH64_TLS_TPREL => "AARCH64_TLS_TPREL", + R_AARCH64_TLSDESC => "AARCH64_TLSDESC", + R_AARCH64_IRELATIVE => "AARCH64_IRELATIVE", + _ => "R_UNKNOWN_AARCH64", + }}, + // arm + EM_ARM => { match typ { + R_ARM_PC24 => "ARM_PC24", + R_ARM_ABS32 => "ARM_ABS32", + R_ARM_REL32 => "ARM_REL32", + R_ARM_PC13 => "ARM_PC13", + R_ARM_ABS16 => "ARM_ABS16", + R_ARM_ABS12 => "ARM_ABS12", + R_ARM_THM_ABS5 => "ARM_THM_ABS5", + R_ARM_ABS8 => "ARM_ABS8", + R_ARM_SBREL32 => "ARM_SBREL32", + R_ARM_THM_PC22 => "ARM_THM_PC22", + R_ARM_THM_PC8 => "ARM_THM_PC8", + R_ARM_AMP_VCALL9 => "ARM_AMP_VCALL9", + R_ARM_TLS_DESC => "ARM_TLS_DESC", + R_ARM_THM_SWI8 => "ARM_THM_SWI8", + R_ARM_XPC25 => "ARM_XPC25", + R_ARM_THM_XPC22 => "ARM_THM_XPC22", + R_ARM_TLS_DTPMOD32 => "ARM_TLS_DTPMOD32", + R_ARM_TLS_DTPOFF32 => "ARM_TLS_DTPOFF32", + R_ARM_TLS_TPOFF32 => "ARM_TLS_TPOFF32", + R_ARM_COPY => "ARM_COPY", + R_ARM_GLOB_DAT => "ARM_GLOB_DAT", + R_ARM_JUMP_SLOT => "ARM_JUMP_SLOT", + R_ARM_RELATIVE => "ARM_RELATIVE", + R_ARM_GOTOFF => "ARM_GOTOFF", + R_ARM_GOTPC => "ARM_GOTPC", + R_ARM_GOT32 => "ARM_GOT32", + R_ARM_PLT32 => "ARM_PLT32", + R_ARM_CALL => "ARM_CALL", + R_ARM_JUMP24 => "ARM_JUMP24", + R_ARM_THM_JUMP24 => "ARM_THM_JUMP24", + R_ARM_BASE_ABS => "ARM_BASE_ABS", + R_ARM_ALU_PCREL_7_0 => "ARM_ALU_PCREL_7_0", + R_ARM_ALU_PCREL_15_8 => "ARM_ALU_PCREL_15_8", + R_ARM_ALU_PCREL_23_15 => "ARM_ALU_PCREL_23_15", + R_ARM_LDR_SBREL_11_0 => "ARM_LDR_SBREL_11_0", + R_ARM_ALU_SBREL_19_12 => "ARM_ALU_SBREL_19_12", + R_ARM_ALU_SBREL_27_20 => "ARM_ALU_SBREL_27_20", + R_ARM_TARGET1 => "ARM_TARGET1", + R_ARM_SBREL31 => "ARM_SBREL31", + R_ARM_V4BX => "ARM_V4BX", + R_ARM_TARGET2 => "ARM_TARGET2", + R_ARM_PREL31 => "ARM_PREL31", + R_ARM_MOVW_ABS_NC => "ARM_MOVW_ABS_NC", + R_ARM_MOVT_ABS => "ARM_MOVT_ABS", + R_ARM_MOVW_PREL_NC => "ARM_MOVW_PREL_NC", + R_ARM_MOVT_PREL => "ARM_MOVT_PREL", + R_ARM_THM_MOVW_ABS_NC => "ARM_THM_MOVW_ABS_NC", + R_ARM_THM_MOVT_ABS => "ARM_THM_MOVT_ABS", + R_ARM_THM_MOVW_PREL_NC => "ARM_THM_MOVW_PREL_NC", + R_ARM_THM_MOVT_PREL => "ARM_THM_MOVT_PREL", + R_ARM_THM_JUMP19 => "ARM_THM_JUMP19", + R_ARM_THM_JUMP6 => "ARM_THM_JUMP6", + R_ARM_THM_ALU_PREL_11_0 => "ARM_THM_ALU_PREL_11_0", + R_ARM_THM_PC12 => "ARM_THM_PC12", + R_ARM_ABS32_NOI => "ARM_ABS32_NOI", + R_ARM_REL32_NOI => "ARM_REL32_NOI", + R_ARM_ALU_PC_G0_NC => "ARM_ALU_PC_G0_NC", + R_ARM_ALU_PC_G0 => "ARM_ALU_PC_G0", + R_ARM_ALU_PC_G1_NC => "ARM_ALU_PC_G1_NC", + R_ARM_ALU_PC_G1 => "ARM_ALU_PC_G1", + R_ARM_ALU_PC_G2 => "ARM_ALU_PC_G2", + R_ARM_LDR_PC_G1 => "ARM_LDR_PC_G1", + R_ARM_LDR_PC_G2 => "ARM_LDR_PC_G2", + R_ARM_LDRS_PC_G0 => "ARM_LDRS_PC_G0", + R_ARM_LDRS_PC_G1 => "ARM_LDRS_PC_G1", + R_ARM_LDRS_PC_G2 => "ARM_LDRS_PC_G2", + R_ARM_LDC_PC_G0 => "ARM_LDC_PC_G0", + R_ARM_LDC_PC_G1 => "ARM_LDC_PC_G1", + R_ARM_LDC_PC_G2 => "ARM_LDC_PC_G2", + R_ARM_ALU_SB_G0_NC => "ARM_ALU_SB_G0_NC", + R_ARM_ALU_SB_G0 => "ARM_ALU_SB_G0", + R_ARM_ALU_SB_G1_NC => "ARM_ALU_SB_G1_NC", + R_ARM_ALU_SB_G1 => "ARM_ALU_SB_G1", + R_ARM_ALU_SB_G2 => "ARM_ALU_SB_G2", + R_ARM_LDR_SB_G0 => "ARM_LDR_SB_G0", + R_ARM_LDR_SB_G1 => "ARM_LDR_SB_G1", + R_ARM_LDR_SB_G2 => "ARM_LDR_SB_G2", + R_ARM_LDRS_SB_G0 => "ARM_LDRS_SB_G0", + R_ARM_LDRS_SB_G1 => "ARM_LDRS_SB_G1", + R_ARM_LDRS_SB_G2 => "ARM_LDRS_SB_G2", + R_ARM_LDC_SB_G0 => "ARM_LDC_SB_G0", + R_ARM_LDC_SB_G1 => "ARM_LDC_SB_G1", + R_ARM_LDC_SB_G2 => "ARM_LDC_SB_G2", + R_ARM_MOVW_BREL_NC => "ARM_MOVW_BREL_NC", + R_ARM_MOVT_BREL => "ARM_MOVT_BREL", + R_ARM_MOVW_BREL => "ARM_MOVW_BREL", + R_ARM_THM_MOVW_BREL_NC => "ARM_THM_MOVW_BREL_NC", + R_ARM_THM_MOVT_BREL => "ARM_THM_MOVT_BREL", + R_ARM_THM_MOVW_BREL => "ARM_THM_MOVW_BREL", + R_ARM_TLS_GOTDESC => "ARM_TLS_GOTDESC", + R_ARM_TLS_CALL => "ARM_TLS_CALL", + R_ARM_TLS_DESCSEQ => "ARM_TLS_DESCSEQ", + R_ARM_THM_TLS_CALL => "ARM_THM_TLS_CALL", + R_ARM_PLT32_ABS => "ARM_PLT32_ABS", + R_ARM_GOT_ABS => "ARM_GOT_ABS", + R_ARM_GOT_PREL => "ARM_GOT_PREL", + R_ARM_GOT_BREL12 => "ARM_GOT_BREL12", + R_ARM_GOTOFF12 => "ARM_GOTOFF12", + R_ARM_GOTRELAX => "ARM_GOTRELAX", + R_ARM_GNU_VTENTRY => "ARM_GNU_VTENTRY", + R_ARM_GNU_VTINHERIT => "ARM_GNU_VTINHERIT", + R_ARM_THM_PC11 => "ARM_THM_PC11", + R_ARM_THM_PC9 => "ARM_THM_PC9", + R_ARM_TLS_GD32 => "ARM_TLS_GD32", + R_ARM_TLS_LDM32 => "ARM_TLS_LDM32", + R_ARM_TLS_LDO32 => "ARM_TLS_LDO32", + R_ARM_TLS_IE32 => "ARM_TLS_IE32", + R_ARM_TLS_LE32 => "ARM_TLS_LE32", + R_ARM_TLS_LDO12 => "ARM_TLS_LDO12", + R_ARM_TLS_LE12 => "ARM_TLS_LE12", + R_ARM_TLS_IE12GP => "ARM_TLS_IE12GP", + R_ARM_ME_TOO => "ARM_ME_TOO", + R_ARM_THM_TLS_DESCSEQ16 => "ARM_THM_TLS_DESCSEQ16", + R_ARM_THM_TLS_DESCSEQ32 => "ARM_THM_TLS_DESCSEQ32", + R_ARM_THM_GOT_BREL12 => "ARM_THM_GOT_BREL12", + R_ARM_IRELATIVE => "ARM_IRELATIVE", + R_ARM_RXPC25 => "ARM_RXPC25", + R_ARM_RSBREL32 => "ARM_RSBREL32", + R_ARM_THM_RPC22 => "ARM_THM_RPC22", + R_ARM_RREL32 => "ARM_RREL32", + R_ARM_RABS22 => "ARM_RABS22", + R_ARM_RPC24 => "ARM_RPC24", + R_ARM_RBASE => "ARM_RBASE", + _ => "R_UNKNOWN_ARM", + }}, + // MIPS + EM_MIPS | EM_MIPS_RS3_LE | EM_MIPS_X => { match typ { + R_MIPS_NONE => "R_MIPS_NONE", + R_MIPS_16 => "R_MIPS_16", + R_MIPS_32 => "R_MIPS_32", + R_MIPS_REL32 => "R_MIPS_REL32", + R_MIPS_26 => "R_MIPS_26", + R_MIPS_HI16 => "R_MIPS_HI16", + R_MIPS_LO16 => "R_MIPS_LO16", + R_MIPS_GPREL16 => "R_MIPS_GPREL16", + R_MIPS_LITERAL => "R_MIPS_LITERAL", + R_MIPS_GOT16 => "R_MIPS_GOT16", + R_MIPS_PC16 => "R_MIPS_PC16", + R_MIPS_CALL16 => "R_MIPS_CALL16", + R_MIPS_GPREL32 => "R_MIPS_GPREL32", + R_MIPS_SHIFT5 => "R_MIPS_SHIFT5", + R_MIPS_SHIFT6 => "R_MIPS_SHIFT6", + R_MIPS_64 => "R_MIPS_64", + R_MIPS_GOT_DISP => "R_MIPS_GOT_DISP", + R_MIPS_GOT_PAGE => "R_MIPS_GOT_PAGE", + R_MIPS_GOT_OFST => "R_MIPS_GOT_OFST", + R_MIPS_GOT_HI16 => "R_MIPS_GOT_HI16", + R_MIPS_GOT_LO16 => "R_MIPS_GOT_LO16", + R_MIPS_SUB => "R_MIPS_SUB", + R_MIPS_INSERT_A => "R_MIPS_INSERT_A", + R_MIPS_INSERT_B => "R_MIPS_INSERT_B", + R_MIPS_DELETE => "R_MIPS_DELETE", + R_MIPS_HIGHER => "R_MIPS_HIGHER", + R_MIPS_HIGHEST => "R_MIPS_HIGHEST", + R_MIPS_CALL_HI16 => "R_MIPS_CALL_HI16", + R_MIPS_CALL_LO16 => "R_MIPS_CALL_LO16", + R_MIPS_SCN_DISP => "R_MIPS_SCN_DISP", + R_MIPS_REL16 => "R_MIPS_REL16", + R_MIPS_ADD_IMMEDIATE => "R_MIPS_ADD_IMMEDIATE", + R_MIPS_PJUMP => "R_MIPS_PJUMP", + R_MIPS_RELGOT => "R_MIPS_RELGOT", + R_MIPS_JALR => "R_MIPS_JALR", + R_MIPS_TLS_DTPMOD32 => "R_MIPS_TLS_DTPMOD32", + R_MIPS_TLS_DTPREL32 => "R_MIPS_TLS_DTPREL32", + R_MIPS_TLS_DTPMOD64 => "R_MIPS_TLS_DTPMOD64", + R_MIPS_TLS_DTPREL64 => "R_MIPS_TLS_DTPREL64", + R_MIPS_TLS_GD => "R_MIPS_TLS_GD", + R_MIPS_TLS_LDM => "R_MIPS_TLS_LDM", + R_MIPS_TLS_DTPREL_HI16 => "R_MIPS_TLS_DTPREL_HI16", + R_MIPS_TLS_DTPREL_LO16 => "R_MIPS_TLS_DTPREL_LO16", + R_MIPS_TLS_GOTTPREL => "R_MIPS_TLS_GOTTPREL", + R_MIPS_TLS_TPREL32 => "R_MIPS_TLS_TPREL32", + R_MIPS_TLS_TPREL64 => "R_MIPS_TLS_TPREL64", + R_MIPS_TLS_TPREL_HI16 => "R_MIPS_TLS_TPREL_HI16", + R_MIPS_TLS_TPREL_LO16 => "R_MIPS_TLS_TPREL_LO16", + R_MIPS_GLOB_DAT => "R_MIPS_GLOB_DAT", + R_MIPS_COPY => "R_MIPS_COPY", + R_MIPS_JUMP_SLOT => "R_MIPS_JUMP_SLOT", + _ => "R_UNKNOWN_MIPS", + }}, + // RISC-V + EM_RISCV => { match typ { + R_RISCV_NONE => "R_RISCV_NONE", + R_RISCV_32 => "R_RISCV_32", + R_RISCV_64 => "R_RISCV_64", + R_RISCV_RELATIVE => "R_RISCV_RELATIVE", + R_RISCV_COPY => "R_RISCV_COPY", + R_RISCV_JUMP_SLOT => "R_RISCV_JUMP_SLOT", + R_RISCV_TLS_DTPMOD32 => "R_RISCV_TLS_DTPMOD32", + R_RISCV_TLS_DTPMOD64 => "R_RISCV_TLS_DTPMOD64", + R_RISCV_TLS_DTPREL32 => "R_RISCV_TLS_DTPREL32", + R_RISCV_TLS_DTPREL64 => "R_RISCV_TLS_DTPREL64", + R_RISCV_TLS_TPREL32 => "R_RISCV_TLS_TPREL32", + R_RISCV_TLS_TPREL64 => "R_RISCV_TLS_TPREL64", + R_RISCV_BRANCH => "R_RISCV_BRANCH", + R_RISCV_JAL => "R_RISCV_JAL", + R_RISCV_CALL => "R_RISCV_CALL", + R_RISCV_CALL_PLT => "R_RISCV_CALL_PLT", + R_RISCV_GOT_HI20 => "R_RISCV_GOT_HI20", + R_RISCV_TLS_GOT_HI20 => "R_RISCV_TLS_GOT_HI20", + R_RISCV_TLS_GD_HI20 => "R_RISCV_TLS_GD_HI20", + R_RISCV_PCREL_HI20 => "R_RISCV_PCREL_HI20", + R_RISCV_PCREL_LO12_I => "R_RISCV_PCREL_LO12_I", + R_RISCV_PCREL_LO12_S => "R_RISCV_PCREL_LO12_S", + R_RISCV_HI20 => "R_RISCV_HI20", + R_RISCV_LO12_I => "R_RISCV_LO12_I", + R_RISCV_LO12_S => "R_RISCV_LO12_S", + R_RISCV_TPREL_HI20 => "R_RISCV_TPREL_HI20", + R_RISCV_TPREL_LO12_I => "R_RISCV_TPREL_LO12_I", + R_RISCV_TPREL_LO12_S => "R_RISCV_TPREL_LO12_S", + R_RISCV_TPREL_ADD => "R_RISCV_TPREL_ADD", + R_RISCV_ADD8 => "R_RISCV_ADD8", + R_RISCV_ADD16 => "R_RISCV_ADD16", + R_RISCV_ADD32 => "R_RISCV_ADD32", + R_RISCV_ADD64 => "R_RISCV_ADD64", + R_RISCV_SUB8 => "R_RISCV_SUB8", + R_RISCV_SUB16 => "R_RISCV_SUB16", + R_RISCV_SUB32 => "R_RISCV_SUB32", + R_RISCV_SUB64 => "R_RISCV_SUB64", + R_RISCV_GNU_VTINHERIT => "R_RISCV_GNU_VTINHERIT", + R_RISCV_GNU_VTENTRY => "R_RISCV_GNU_VTENTRY", + R_RISCV_ALIGN => "R_RISCV_ALIGN", + R_RISCV_RVC_BRANCH => "R_RISCV_RVC_BRANCH", + R_RISCV_RVC_JUMP => "R_RISCV_RVC_JUMP", + R_RISCV_RVC_LUI => "R_RISCV_RVC_LUI", + R_RISCV_GPREL_I => "R_RISCV_GPREL_I", + R_RISCV_GPREL_S => "R_RISCV_GPREL_S", + R_RISCV_TPREL_I => "R_RISCV_TPREL_I", + R_RISCV_TPREL_S => "R_RISCV_TPREL_S", + R_RISCV_RELAX => "R_RISCV_RELAX", + R_RISCV_SUB6 => "R_RISCV_SUB6", + R_RISCV_SET6 => "R_RISCV_SET6", + R_RISCV_SET8 => "R_RISCV_SET8", + R_RISCV_SET16 => "R_RISCV_SET16", + R_RISCV_SET32 => "R_RISCV_SET32", + _ => "R_UNKNOWN_RISCV", + }}, + _ => "R_UNKNOWN", + } +} diff --git a/third_party/rust/goblin/src/elf/dynamic.rs b/third_party/rust/goblin/src/elf/dynamic.rs new file mode 100644 index 0000000000..c410469c6a --- /dev/null +++ b/third_party/rust/goblin/src/elf/dynamic.rs @@ -0,0 +1,807 @@ +macro_rules! elf_dyn { + ($size:ty) => { + // XXX: Do not import scroll traits here. + // See: https://github.com/rust-lang/rust/issues/65090#issuecomment-538668155 + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Default)] + #[cfg_attr( + feature = "alloc", + derive(scroll::Pread, scroll::Pwrite, scroll::SizeWith) + )] + /// An entry in the dynamic array + pub struct Dyn { + /// Dynamic entry type + pub d_tag: $size, + /// Integer value + pub d_val: $size, + } + + use plain; + unsafe impl plain::Plain for Dyn {} + }; +} + +// TODO: figure out what's the best, most friendly + safe API choice here - u32s or u64s +// remember that DT_TAG is "pointer sized"/used as address sometimes Original rationale: I +// decided to use u64 instead of u32 due to pattern matching use case seems safer to cast the +// elf32's d_tag from u32 -> u64 at runtime instead of casting the elf64's d_tag from u64 -> +// u32 at runtime + +/// Marks end of dynamic section +pub const DT_NULL: u64 = 0; +/// Name of needed library +pub const DT_NEEDED: u64 = 1; +/// Size in bytes of PLT relocs +pub const DT_PLTRELSZ: u64 = 2; +/// Processor defined value +pub const DT_PLTGOT: u64 = 3; +/// Address of symbol hash table +pub const DT_HASH: u64 = 4; +/// Address of string table +pub const DT_STRTAB: u64 = 5; +/// Address of symbol table +pub const DT_SYMTAB: u64 = 6; +/// Address of Rela relocs +pub const DT_RELA: u64 = 7; +/// Total size of Rela relocs +pub const DT_RELASZ: u64 = 8; +/// Size of one Rela reloc +pub const DT_RELAENT: u64 = 9; +/// Size of string table +pub const DT_STRSZ: u64 = 10; +/// Size of one symbol table entry +pub const DT_SYMENT: u64 = 11; +/// Address of init function +pub const DT_INIT: u64 = 12; +/// Address of termination function +pub const DT_FINI: u64 = 13; +/// Name of shared object +pub const DT_SONAME: u64 = 14; +/// Library search path (deprecated) +pub const DT_RPATH: u64 = 15; +/// Start symbol search here +pub const DT_SYMBOLIC: u64 = 16; +/// Address of Rel relocs +pub const DT_REL: u64 = 17; +/// Total size of Rel relocs +pub const DT_RELSZ: u64 = 18; +/// Size of one Rel reloc +pub const DT_RELENT: u64 = 19; +/// Type of reloc in PLT +pub const DT_PLTREL: u64 = 20; +/// For debugging; unspecified +pub const DT_DEBUG: u64 = 21; +/// Reloc might modify .text +pub const DT_TEXTREL: u64 = 22; +/// Address of PLT relocs +pub const DT_JMPREL: u64 = 23; +/// Process relocations of object +pub const DT_BIND_NOW: u64 = 24; +/// Array with addresses of init fct +pub const DT_INIT_ARRAY: u64 = 25; +/// Array with addresses of fini fct +pub const DT_FINI_ARRAY: u64 = 26; +/// Size in bytes of DT_INIT_ARRAY +pub const DT_INIT_ARRAYSZ: u64 = 27; +/// Size in bytes of DT_FINI_ARRAY +pub const DT_FINI_ARRAYSZ: u64 = 28; +/// Library search path +pub const DT_RUNPATH: u64 = 29; +/// Flags for the object being loaded +pub const DT_FLAGS: u64 = 30; +/// Start of encoded range +pub const DT_ENCODING: u64 = 32; +/// Array with addresses of preinit fct +pub const DT_PREINIT_ARRAY: u64 = 32; +/// size in bytes of DT_PREINIT_ARRAY +pub const DT_PREINIT_ARRAYSZ: u64 = 33; +/// Number used +pub const DT_NUM: u64 = 34; +/// Start of OS-specific +pub const DT_LOOS: u64 = 0x6000_000d; +/// End of OS-specific +pub const DT_HIOS: u64 = 0x6fff_f000; +/// Start of processor-specific +pub const DT_LOPROC: u64 = 0x7000_0000; +/// End of processor-specific +pub const DT_HIPROC: u64 = 0x7fff_ffff; +// Most used by any processor +// pub const DT_PROCNUM: u64 = DT_MIPS_NUM; + +/// DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the +/// Dyn.d_un.d_ptr field of the Elf*_Dyn structure. +/// +/// If any adjustment is made to the ELF object after it has been +/// built these entries will need to be adjusted. +pub const DT_ADDRRNGLO: u64 = 0x6fff_fe00; +/// GNU-style hash table +pub const DT_GNU_HASH: u64 = 0x6fff_fef5; +/// +pub const DT_TLSDESC_PLT: u64 = 0x6fff_fef6; +/// +pub const DT_TLSDESC_GOT: u64 = 0x6fff_fef7; +/// Start of conflict section +pub const DT_GNU_CONFLICT: u64 = 0x6fff_fef8; +/// Library list +pub const DT_GNU_LIBLIST: u64 = 0x6fff_fef9; +/// Configuration information +pub const DT_CONFIG: u64 = 0x6fff_fefa; +/// Dependency auditing +pub const DT_DEPAUDIT: u64 = 0x6fff_fefb; +/// Object auditing +pub const DT_AUDIT: u64 = 0x6fff_fefc; +/// PLT padding +pub const DT_PLTPAD: u64 = 0x6fff_fefd; +/// Move table +pub const DT_MOVETAB: u64 = 0x6fff_fefe; +/// Syminfo table +pub const DT_SYMINFO: u64 = 0x6fff_feff; +/// +pub const DT_ADDRRNGHI: u64 = 0x6fff_feff; + +//DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +pub const DT_ADDRNUM: u64 = 11; + +/// The versioning entry types. The next are defined as part of the GNU extension +pub const DT_VERSYM: u64 = 0x6fff_fff0; +pub const DT_RELACOUNT: u64 = 0x6fff_fff9; +pub const DT_RELCOUNT: u64 = 0x6fff_fffa; +/// State flags, see DF_1_* below +pub const DT_FLAGS_1: u64 = 0x6fff_fffb; +/// Address of version definition table +pub const DT_VERDEF: u64 = 0x6fff_fffc; +/// Number of version definitions +pub const DT_VERDEFNUM: u64 = 0x6fff_fffd; +/// Address of table with needed versions +pub const DT_VERNEED: u64 = 0x6fff_fffe; +/// Number of needed versions +pub const DT_VERNEEDNUM: u64 = 0x6fff_ffff; + +/// Converts a tag to its string representation. +#[inline] +pub fn tag_to_str(tag: u64) -> &'static str { + match tag { + DT_NULL => "DT_NULL", + DT_NEEDED => "DT_NEEDED", + DT_PLTRELSZ => "DT_PLTRELSZ", + DT_PLTGOT => "DT_PLTGOT", + DT_HASH => "DT_HASH", + DT_STRTAB => "DT_STRTAB", + DT_SYMTAB => "DT_SYMTAB", + DT_RELA => "DT_RELA", + DT_RELASZ => "DT_RELASZ", + DT_RELAENT => "DT_RELAENT", + DT_STRSZ => "DT_STRSZ", + DT_SYMENT => "DT_SYMENT", + DT_INIT => "DT_INIT", + DT_FINI => "DT_FINI", + DT_SONAME => "DT_SONAME", + DT_RPATH => "DT_RPATH", + DT_SYMBOLIC => "DT_SYMBOLIC", + DT_REL => "DT_REL", + DT_RELSZ => "DT_RELSZ", + DT_RELENT => "DT_RELENT", + DT_PLTREL => "DT_PLTREL", + DT_DEBUG => "DT_DEBUG", + DT_TEXTREL => "DT_TEXTREL", + DT_JMPREL => "DT_JMPREL", + DT_BIND_NOW => "DT_BIND_NOW", + DT_INIT_ARRAY => "DT_INIT_ARRAY", + DT_FINI_ARRAY => "DT_FINI_ARRAY", + DT_INIT_ARRAYSZ => "DT_INIT_ARRAYSZ", + DT_FINI_ARRAYSZ => "DT_FINI_ARRAYSZ", + DT_RUNPATH => "DT_RUNPATH", + DT_FLAGS => "DT_FLAGS", + DT_PREINIT_ARRAY => "DT_PREINIT_ARRAY", + DT_PREINIT_ARRAYSZ => "DT_PREINIT_ARRAYSZ", + DT_NUM => "DT_NUM", + DT_LOOS => "DT_LOOS", + DT_HIOS => "DT_HIOS", + DT_LOPROC => "DT_LOPROC", + DT_HIPROC => "DT_HIPROC", + DT_VERSYM => "DT_VERSYM", + DT_RELACOUNT => "DT_RELACOUNT", + DT_RELCOUNT => "DT_RELCOUNT", + DT_GNU_HASH => "DT_GNU_HASH", + DT_VERDEF => "DT_VERDEF", + DT_VERDEFNUM => "DT_VERDEFNUM", + DT_VERNEED => "DT_VERNEED", + DT_VERNEEDNUM => "DT_VERNEEDNUM", + DT_FLAGS_1 => "DT_FLAGS_1", + _ => "UNKNOWN_TAG", + } +} + +// Values of `d_un.d_val` in the DT_FLAGS entry +/// Object may use DF_ORIGIN. +pub const DF_ORIGIN: u64 = 0x0000_0001; +/// Symbol resolutions starts here. +pub const DF_SYMBOLIC: u64 = 0x0000_0002; +/// Object contains text relocations. +pub const DF_TEXTREL: u64 = 0x0000_0004; +/// No lazy binding for this object. +pub const DF_BIND_NOW: u64 = 0x0000_0008; +/// Module uses the static TLS model. +pub const DF_STATIC_TLS: u64 = 0x0000_0010; + +pub fn df_tag_to_str(tag: u64) -> &'static str { + match tag { + DF_ORIGIN => "DF_ORIGIN", + DF_SYMBOLIC => "DF_SYMBOLIC", + DF_TEXTREL => "DF_TEXTREL", + DF_BIND_NOW => "DF_BIND_NOW", + DF_STATIC_TLS => "DF_STATIC_TLS", + _ => "UNKNOWN_TAG", + } +} + +/// === State flags === +/// selectable in the `d_un.d_val` element of the DT_FLAGS_1 entry in the dynamic section. +/// +/// Set RTLD_NOW for this object. +pub const DF_1_NOW: u64 = 0x0000_0001; +/// Set RTLD_GLOBAL for this object. +pub const DF_1_GLOBAL: u64 = 0x0000_0002; +/// Set RTLD_GROUP for this object. +pub const DF_1_GROUP: u64 = 0x0000_0004; +/// Set RTLD_NODELETE for this object. +pub const DF_1_NODELETE: u64 = 0x0000_0008; +/// Trigger filtee loading at runtime. +pub const DF_1_LOADFLTR: u64 = 0x0000_0010; +/// Set RTLD_INITFIRST for this object. +pub const DF_1_INITFIRST: u64 = 0x0000_0020; +/// Set RTLD_NOOPEN for this object. +pub const DF_1_NOOPEN: u64 = 0x0000_0040; +/// $ORIGIN must be handled. +pub const DF_1_ORIGIN: u64 = 0x0000_0080; +/// Direct binding enabled. +pub const DF_1_DIRECT: u64 = 0x0000_0100; +pub const DF_1_TRANS: u64 = 0x0000_0200; +/// Object is used to interpose. +pub const DF_1_INTERPOSE: u64 = 0x0000_0400; +/// Ignore default lib search path. +pub const DF_1_NODEFLIB: u64 = 0x0000_0800; +/// Object can't be dldump'ed. +pub const DF_1_NODUMP: u64 = 0x0000_1000; +/// Configuration alternative created. +pub const DF_1_CONFALT: u64 = 0x0000_2000; +/// Filtee terminates filters search. +pub const DF_1_ENDFILTEE: u64 = 0x0000_4000; +/// Disp reloc applied at build time. +pub const DF_1_DISPRELDNE: u64 = 0x0000_8000; +/// Disp reloc applied at run-time. +pub const DF_1_DISPRELPND: u64 = 0x0001_0000; +/// Object has no-direct binding. +pub const DF_1_NODIRECT: u64 = 0x0002_0000; +pub const DF_1_IGNMULDEF: u64 = 0x0004_0000; +pub const DF_1_NOKSYMS: u64 = 0x0008_0000; +pub const DF_1_NOHDR: u64 = 0x0010_0000; +/// Object is modified after built. +pub const DF_1_EDITED: u64 = 0x0020_0000; +pub const DF_1_NORELOC: u64 = 0x0040_0000; +/// Object has individual interposers. +pub const DF_1_SYMINTPOSE: u64 = 0x0080_0000; +/// Global auditing required. +pub const DF_1_GLOBAUDIT: u64 = 0x0100_0000; +/// Singleton dyn are used. +pub const DF_1_SINGLETON: u64 = 0x0200_0000; +/// Object is a Position Independent Executable (PIE). +pub const DF_1_PIE: u64 = 0x0800_0000; + +pub fn df_1_tag_to_str(tag: u64) -> &'static str { + match tag { + DF_1_NOW => "DF_1_NOW", + DF_1_GLOBAL => "DF_1_GLOBAL", + DF_1_GROUP => "DF_1_GROUP", + DF_1_NODELETE => "DF_1_NODELETE", + DF_1_LOADFLTR => "DF_1_LOADFLTR", + DF_1_INITFIRST => "DF_1_INITFIRST", + DF_1_NOOPEN => "DF_1_NOOPEN", + DF_1_ORIGIN => "DF_1_ORIGIN", + DF_1_DIRECT => "DF_1_DIRECT", + DF_1_TRANS => "DF_1_TRANS", + DF_1_INTERPOSE => "DF_1_INTERPOSE", + DF_1_NODEFLIB => "DF_1_NODEFLIB", + DF_1_NODUMP => "DF_1_NODUMP", + DF_1_CONFALT => "DF_1_CONFALT", + DF_1_ENDFILTEE => "DF_1_ENDFILTEE", + DF_1_DISPRELDNE => "DF_1_DISPRELDNE", + DF_1_DISPRELPND => "DF_1_DISPRELPND", + DF_1_NODIRECT => "DF_1_NODIRECT", + DF_1_IGNMULDEF => "DF_1_IGNMULDEF", + DF_1_NOKSYMS => "DF_1_NOKSYMS", + DF_1_NOHDR => "DF_1_NOHDR", + DF_1_EDITED => "DF_1_EDITED", + DF_1_NORELOC => "DF_1_NORELOC", + DF_1_SYMINTPOSE => "DF_1_SYMINTPOSE", + DF_1_GLOBAUDIT => "DF_1_GLOBAUDIT", + DF_1_SINGLETON => "DF_1_SINGLETON", + DF_1_PIE => "DF_1_PIE", + _ => "UNKNOWN_TAG", + } +} + +if_alloc! { + use core::fmt; + use scroll::ctx; + use core::result; + use crate::container::{Ctx, Container}; + use crate::strtab::Strtab; + use alloc::vec::Vec; + + #[derive(Default, PartialEq, Clone)] + pub struct Dyn { + pub d_tag: u64, + pub d_val: u64, + } + + impl Dyn { + #[inline] + pub fn size(container: Container) -> usize { + use scroll::ctx::SizeWith; + Self::size_with(&Ctx::from(container)) + } + } + + impl fmt::Debug for Dyn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Dyn") + .field("d_tag", &tag_to_str(self.d_tag)) + .field("d_val", &format_args!("0x{:x}", self.d_val)) + .finish() + } + } + + impl ctx::SizeWith<Ctx> for Dyn { + fn size_with(&Ctx { container, .. }: &Ctx) -> usize { + match container { + Container::Little => { + dyn32::SIZEOF_DYN + }, + Container::Big => { + dyn64::SIZEOF_DYN + }, + } + } + } + + impl<'a> ctx::TryFromCtx<'a, Ctx> for Dyn { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> { + use scroll::Pread; + let dynamic = match container { + Container::Little => { + (bytes.pread_with::<dyn32::Dyn>(0, le)?.into(), dyn32::SIZEOF_DYN) + }, + Container::Big => { + (bytes.pread_with::<dyn64::Dyn>(0, le)?.into(), dyn64::SIZEOF_DYN) + } + }; + Ok(dynamic) + } + } + + impl ctx::TryIntoCtx<Ctx> for Dyn { + type Error = crate::error::Error; + fn try_into_ctx(self, bytes: &mut [u8], Ctx { container, le}: Ctx) -> result::Result<usize, Self::Error> { + use scroll::Pwrite; + match container { + Container::Little => { + let dynamic: dyn32::Dyn = self.into(); + Ok(bytes.pwrite_with(dynamic, 0, le)?) + }, + Container::Big => { + let dynamic: dyn64::Dyn = self.into(); + Ok(bytes.pwrite_with(dynamic, 0, le)?) + } + } + } + } + + #[derive(Debug)] + pub struct Dynamic { + pub dyns: Vec<Dyn>, + pub info: DynamicInfo, + } + + impl Dynamic { + #[cfg(feature = "endian_fd")] + /// Returns a vector of dynamic entries from the underlying byte `bytes`, with `endianness`, using the provided `phdrs` + pub fn parse(bytes: &[u8], phdrs: &[crate::elf::program_header::ProgramHeader], ctx: Ctx) -> crate::error::Result<Option<Self>> { + use scroll::ctx::SizeWith; + use scroll::Pread; + use crate::elf::program_header; + for phdr in phdrs { + if phdr.p_type == program_header::PT_DYNAMIC { + let offset = phdr.p_offset as usize; + let filesz = phdr.p_filesz as usize; + // Ensure offset and filesz are valid. + let bytes = if filesz > 0 { + bytes + .pread_with::<&[u8]>(offset, filesz) + .map_err(|_| crate::error::Error::Malformed(format!("Invalid PT_DYNAMIC size (offset {:#x}, filesz {:#x})", + offset, filesz)))? + } else { + &[] + }; + let size = Dyn::size_with(&ctx); + // the validity of `count` was implicitly checked by reading `bytes`. + let count = filesz / size; + let mut dyns = Vec::with_capacity(count); + let mut offset = 0; + for _ in 0..count { + let dynamic = bytes.gread_with::<Dyn>(&mut offset, ctx)?; + let tag = dynamic.d_tag; + dyns.push(dynamic); + if tag == DT_NULL { break } + } + let mut info = DynamicInfo::default(); + for dynamic in &dyns { + info.update(phdrs, dynamic); + } + return Ok(Some(Dynamic { dyns: dyns, info: info, })); + } + } + Ok(None) + } + + pub fn get_libraries<'a>(&self, strtab: &Strtab<'a>) -> Vec<&'a str> { + use log::warn; + let count = self.info.needed_count.min(self.dyns.len()); + let mut needed = Vec::with_capacity(count); + for dynamic in &self.dyns { + if dynamic.d_tag as u64 == DT_NEEDED { + if let Some(lib) = strtab.get_at(dynamic.d_val as usize) { + needed.push(lib) + } else { + warn!("Invalid DT_NEEDED {}", dynamic.d_val) + } + } + } + needed + } + } +} + +macro_rules! elf_dyn_std_impl { + ($size:ident, $phdr:ty) => { + + #[cfg(test)] + mod tests { + use super::*; + #[test] + fn size_of() { + assert_eq!(::std::mem::size_of::<Dyn>(), SIZEOF_DYN); + } + } + + if_alloc! { + use core::fmt; + use core::slice; + use alloc::vec::Vec; + + use crate::elf::program_header::{PT_DYNAMIC}; + use crate::strtab::Strtab; + + use crate::elf::dynamic::Dyn as ElfDyn; + + if_std! { + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + use crate::error::Result; + } + + impl From<ElfDyn> for Dyn { + fn from(dynamic: ElfDyn) -> Self { + Dyn { + d_tag: dynamic.d_tag as $size, + d_val: dynamic.d_val as $size, + } + } + } + impl From<Dyn> for ElfDyn { + fn from(dynamic: Dyn) -> Self { + ElfDyn { + d_tag: u64::from(dynamic.d_tag), + d_val: u64::from(dynamic.d_val), + } + } + } + + impl fmt::Debug for Dyn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Dyn") + .field("d_tag", &tag_to_str(u64::from(self.d_tag))) + .field("d_val", &format_args!("0x{:x}", self.d_val)) + .finish() + } + } + + /// Returns a vector of dynamic entries from the given fd and program headers + #[cfg(feature = "std")] + pub fn from_fd(mut fd: &File, phdrs: &[$phdr]) -> Result<Option<Vec<Dyn>>> { + for phdr in phdrs { + if phdr.p_type == PT_DYNAMIC { + // FIXME: validate filesz before allocating + let filesz = phdr.p_filesz as usize; + let dync = filesz / SIZEOF_DYN; + let mut dyns = vec![Dyn::default(); dync]; + fd.seek(Start(u64::from(phdr.p_offset)))?; + unsafe { + fd.read_exact(plain::as_mut_bytes(&mut *dyns))?; + } + dyns.dedup(); + return Ok(Some(dyns)); + } + } + Ok(None) + } + + /// Given a bias and a memory address (typically for a _correctly_ mmap'd binary in memory), returns the `_DYNAMIC` array as a slice of that memory + pub unsafe fn from_raw<'a>(bias: usize, vaddr: usize) -> &'a [Dyn] { + let dynp = vaddr.wrapping_add(bias) as *const Dyn; + let mut idx = 0; + while u64::from((*dynp.offset(idx)).d_tag) != DT_NULL { + idx += 1; + } + slice::from_raw_parts(dynp, idx as usize) + } + + // TODO: these bare functions have always seemed awkward, but not sure where they should go... + /// Maybe gets and returns the dynamic array with the same lifetime as the [phdrs], using the provided bias with wrapping addition. + /// If the bias is wrong, it will either segfault or give you incorrect values, beware + pub unsafe fn from_phdrs(bias: usize, phdrs: &[$phdr]) -> Option<&[Dyn]> { + for phdr in phdrs { + // FIXME: change to casting to u64 similar to DT_*? + if phdr.p_type as u32 == PT_DYNAMIC { + return Some(from_raw(bias, phdr.p_vaddr as usize)); + } + } + None + } + + /// Gets the needed libraries from the `_DYNAMIC` array, with the str slices lifetime tied to the dynamic array/strtab's lifetime(s) + pub unsafe fn get_needed<'a>(dyns: &[Dyn], strtab: *const Strtab<'a>, count: usize) -> Vec<&'a str> { + let mut needed = Vec::with_capacity(count.min(dyns.len())); + for dynamic in dyns { + if u64::from(dynamic.d_tag) == DT_NEEDED { + let lib = &(*strtab)[dynamic.d_val as usize]; + needed.push(lib); + } + } + needed + } + } + }; +} + +macro_rules! elf_dynamic_info_std_impl { + ($size:ident, $phdr:ty) => { + /// Convert a virtual memory address to a file offset + fn vm_to_offset(phdrs: &[$phdr], address: $size) -> Option<$size> { + for ph in phdrs { + if ph.p_type == crate::elf::program_header::PT_LOAD && address >= ph.p_vaddr { + let offset = address - ph.p_vaddr; + if offset < ph.p_memsz { + return ph.p_offset.checked_add(offset); + } + } + } + None + } + + /// Important dynamic linking info generated via a single pass through the `_DYNAMIC` array + #[derive(Default, PartialEq)] + pub struct DynamicInfo { + pub rela: usize, + pub relasz: usize, + pub relaent: $size, + pub relacount: usize, + pub rel: usize, + pub relsz: usize, + pub relent: $size, + pub relcount: usize, + pub gnu_hash: Option<$size>, + pub hash: Option<$size>, + pub strtab: usize, + pub strsz: usize, + pub symtab: usize, + pub syment: usize, + pub pltgot: Option<$size>, + pub pltrelsz: usize, + pub pltrel: $size, + pub jmprel: usize, + pub verdef: $size, + pub verdefnum: $size, + pub verneed: $size, + pub verneednum: $size, + pub versym: $size, + pub init: $size, + pub fini: $size, + pub init_array: $size, + pub init_arraysz: usize, + pub fini_array: $size, + pub fini_arraysz: usize, + pub needed_count: usize, + pub flags: $size, + pub flags_1: $size, + pub soname: usize, + pub textrel: bool, + } + + impl DynamicInfo { + #[inline] + pub fn update(&mut self, phdrs: &[$phdr], dynamic: &Dyn) { + match u64::from(dynamic.d_tag) { + DT_RELA => self.rela = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize, // .rela.dyn + DT_RELASZ => self.relasz = dynamic.d_val as usize, + DT_RELAENT => self.relaent = dynamic.d_val as _, + DT_RELACOUNT => self.relacount = dynamic.d_val as usize, + DT_REL => self.rel = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize, // .rel.dyn + DT_RELSZ => self.relsz = dynamic.d_val as usize, + DT_RELENT => self.relent = dynamic.d_val as _, + DT_RELCOUNT => self.relcount = dynamic.d_val as usize, + DT_GNU_HASH => self.gnu_hash = vm_to_offset(phdrs, dynamic.d_val), + DT_HASH => self.hash = vm_to_offset(phdrs, dynamic.d_val), + DT_STRTAB => { + self.strtab = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize + } + DT_STRSZ => self.strsz = dynamic.d_val as usize, + DT_SYMTAB => { + self.symtab = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize + } + DT_SYMENT => self.syment = dynamic.d_val as usize, + DT_PLTGOT => self.pltgot = vm_to_offset(phdrs, dynamic.d_val), + DT_PLTRELSZ => self.pltrelsz = dynamic.d_val as usize, + DT_PLTREL => self.pltrel = dynamic.d_val as _, + DT_JMPREL => { + self.jmprel = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) as usize + } // .rela.plt + DT_VERDEF => self.verdef = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), + DT_VERDEFNUM => self.verdefnum = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), + DT_VERNEED => self.verneed = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), + DT_VERNEEDNUM => self.verneednum = dynamic.d_val as _, + DT_VERSYM => self.versym = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), + DT_INIT => self.init = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), + DT_FINI => self.fini = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0), + DT_INIT_ARRAY => { + self.init_array = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) + } + DT_INIT_ARRAYSZ => self.init_arraysz = dynamic.d_val as _, + DT_FINI_ARRAY => { + self.fini_array = vm_to_offset(phdrs, dynamic.d_val).unwrap_or(0) + } + DT_FINI_ARRAYSZ => self.fini_arraysz = dynamic.d_val as _, + DT_NEEDED => self.needed_count += 1, + DT_FLAGS => self.flags = dynamic.d_val as _, + DT_FLAGS_1 => self.flags_1 = dynamic.d_val as _, + DT_SONAME => self.soname = dynamic.d_val as _, + DT_TEXTREL => self.textrel = true, + _ => (), + } + } + pub fn new(dynamic: &[Dyn], phdrs: &[$phdr]) -> DynamicInfo { + let mut info = DynamicInfo::default(); + for dyna in dynamic { + info.update(phdrs, &dyna); + } + info + } + } + + if_alloc! { + impl fmt::Debug for DynamicInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let gnu_hash = self.gnu_hash.unwrap_or(0); + let hash = self.hash.unwrap_or(0); + let pltgot = self.pltgot.unwrap_or(0); + + let flags: Vec<&'static str> = [DF_ORIGIN, DF_SYMBOLIC, DF_TEXTREL, DF_BIND_NOW, DF_STATIC_TLS,][..] + .iter() + .filter(|f| (self.flags as u64 & *f) != 0) + .map(|f| df_tag_to_str(*f)) + .collect(); + + let flags_1: Vec<&'static str> = [ + DF_1_NOW, + DF_1_GLOBAL, + DF_1_GROUP, + DF_1_NODELETE, + DF_1_LOADFLTR, + DF_1_INITFIRST, + DF_1_NOOPEN, + DF_1_ORIGIN, + DF_1_DIRECT, + DF_1_TRANS, + DF_1_INTERPOSE, + DF_1_NODEFLIB, + DF_1_NODUMP, + DF_1_CONFALT, + DF_1_ENDFILTEE, + DF_1_DISPRELDNE, + DF_1_DISPRELPND, + DF_1_NODIRECT, + DF_1_IGNMULDEF, + DF_1_NOKSYMS, + DF_1_NOHDR, + DF_1_EDITED, + DF_1_NORELOC, + DF_1_SYMINTPOSE, + DF_1_GLOBAUDIT, + DF_1_SINGLETON, + DF_1_PIE, + ][..] + .iter() + .filter(|f| (self.flags_1 as u64 & *f) != 0) + .map(|f| df_1_tag_to_str(*f)) + .collect(); + + f.debug_struct("DynamicInfo") + .field("rela", &format_args!("0x{:x}", self.rela)) + .field("relasz", &self.relasz) + .field("relaent", &self.relaent) + .field("relacount", &self.relacount) + .field("gnu_hash", &format_args!("0x{:x}", gnu_hash)) + .field("hash", &format_args!("0x{:x}", hash)) + .field("strtab", &format_args!("0x{:x}", self.strtab)) + .field("strsz", &self.strsz) + .field("symtab", &format_args!("0x{:x}", self.symtab)) + .field("syment", &self.syment) + .field("pltgot", &format_args!("0x{:x}", pltgot)) + .field("pltrelsz", &self.pltrelsz) + .field("pltrel", &self.pltrel) + .field("jmprel", &format_args!("0x{:x}", self.jmprel)) + .field("verdef", &format_args!("0x{:x}", self.verdef)) + .field("verdefnum", &self.verdefnum) + .field("verneed", &format_args!("0x{:x}", self.verneed)) + .field("verneednum", &self.verneednum) + .field("versym", &format_args!("0x{:x}", self.versym)) + .field("init", &format_args!("0x{:x}", self.init)) + .field("fini", &format_args!("0x{:x}", self.fini)) + .field("init_array", &format_args!("{:#x}", self.init_array)) + .field("init_arraysz", &self.init_arraysz) + .field("needed_count", &self.needed_count) + .field("flags", &format_args!("{:#0width$x} {:?}", self.flags, flags, width = core::mem::size_of_val(&self.flags))) + .field("flags_1", &format_args!("{:#0width$x} {:?}", self.flags_1, flags_1, width = core::mem::size_of_val(&self.flags_1))) + .field("soname", &self.soname) + .field("textrel", &self.textrel) + .finish() + } + } + } + }; +} + +if_alloc! { + elf_dynamic_info_std_impl!(u64, crate::elf::program_header::ProgramHeader); +} + +pub mod dyn32 { + pub use crate::elf::dynamic::*; + + elf_dyn!(u32); + + pub const SIZEOF_DYN: usize = 8; + + elf_dyn_std_impl!(u32, crate::elf32::program_header::ProgramHeader); + elf_dynamic_info_std_impl!( + u32, + crate::elf::program_header::program_header32::ProgramHeader + ); +} + +pub mod dyn64 { + pub use crate::elf::dynamic::*; + + elf_dyn!(u64); + + pub const SIZEOF_DYN: usize = 16; + + elf_dyn_std_impl!(u64, crate::elf64::program_header::ProgramHeader); + elf_dynamic_info_std_impl!( + u64, + crate::elf::program_header::program_header64::ProgramHeader + ); +} diff --git a/third_party/rust/goblin/src/elf/gnu_hash.rs b/third_party/rust/goblin/src/elf/gnu_hash.rs new file mode 100644 index 0000000000..d785382c26 --- /dev/null +++ b/third_party/rust/goblin/src/elf/gnu_hash.rs @@ -0,0 +1,220 @@ +//! A Gnu Hash table as 4 sections: +//! +//! 1. Header +//! 2. Bloom Filter +//! 3. Hash Buckets +//! 4. Chains +//! +//! The header has is an array of four `u32`s: +//! +//! 1. nbuckets +//! 2. symndx +//! 3. maskwords +//! 4. shift2 +//! +//! See more: +//! * http://www.linker-aliens.org/blogs/ali/entry/gnu_hash_elf_sections +//! or https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2 +//! * https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/ + +/// GNU hash function: accepts a symbol name and returns a value that may be +/// used to compute a bucket index. +/// +/// Consequently, if the hashing function returns the value `x` for some name, +/// `buckets[x % nbuckets]` gives an index, `y`, into both the symbol table +/// and the chain table. +pub fn hash(symbol: &str) -> u32 { + const HASH_SEED: u32 = 5381; + symbol.bytes().fold(HASH_SEED, |hash, b| { + hash.wrapping_mul(33).wrapping_add(u32::from(b)) + }) +} + +#[cfg(test)] +mod tests { + use super::hash; + #[test] + fn test_hash() { + assert_eq!(hash(""), 0x0000_1505); + assert_eq!(hash("printf"), 0x156b_2bb8); + assert_eq!(hash("exit"), 0x7c96_7e3f); + assert_eq!(hash("syscall"), 0xbac2_12a0); + assert_eq!(hash("flapenguin.me"), 0x8ae9_f18e); + } +} + +macro_rules! elf_gnu_hash_impl { + ($IntTy:ty) => { + use crate::elf::sym::Sym; + use crate::strtab::Strtab; + use core::fmt; + use core::mem; + use core::slice; + + const INT_SIZE: usize = mem::size_of::<$IntTy>(); + const U32_SIZE: usize = mem::size_of::<u32>(); + /// Size of a bits mask in bloom filter + const ELFCLASS_BITS: u32 = INT_SIZE as u32 * 8; + + /// A better hash table for the ELF used by GNU systems in GNU-compatible software. + pub struct GnuHash<'a> { + /// Index of the first symbol in the `.dynsym` table which is accessible with + /// the hash table + symindex: u32, + /// Shift count used in the bloom filter + shift2: u32, + /// 2 bit bloom filter on `chains` + // Either 32 or 64-bit depending on the class of object + bloom_filter: &'a [$IntTy], + /// GNU hash table bucket array; indexes start at 0. This array holds symbol + /// table indexes and contains the index of hashes in `chains` + buckets: &'a [u32], + /// Hash values; indexes start at 0. This array holds symbol table indexes. + chains: &'a [u32], // => chains[dynsyms.len() - symindex] + dynsyms: &'a [Sym], + } + + impl fmt::Debug for GnuHash<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("GnuHash") + .field("nbuckets", &self.buckets.len()) + .field("symindex", &self.symindex) + .field("maskwords", &(self.bloom_filter.len() - 1)) + .field("shift2", &self.shift2) + .field("bloom_filter", &self.bloom_filter.as_ptr()) + .field("bucket", &self.buckets.as_ptr()) + .field("chains", &self.chains.as_ptr()) + .finish() + } + } + + impl<'a> GnuHash<'a> { + /// Initialize a GnuHash from a pointer to `.hash` (or `.gnu.hash`) section + /// and total number of dynamic symbols. + /// # Safety + /// + /// This function creates a `GnuHash` directly from a raw pointer + pub unsafe fn from_raw_table( + hashtab: &'a [u8], + dynsyms: &'a [Sym], + ) -> Result<Self, &'static str> { + if hashtab.as_ptr() as usize % INT_SIZE != 0 { + return Err("hashtab is not aligned with 64-bit"); + } + + if hashtab.len() <= 16 { + return Err("failed to read in number of buckets"); + } + + let [nbuckets, symindex, maskwords, shift2] = + (hashtab.as_ptr() as *const u32 as *const [u32; 4]).read(); + + if !maskwords.is_power_of_two() { + return Err("maskwords must be a power of two"); + } + + let hashtab = &hashtab[16..]; + { + // SAFETY: Condition to check for an overflow + // size_of(chains) + size_of(buckets) + size_of(bloom_filter) == size_of(hashtab) + + if dynsyms.len() <= symindex as usize { + return Err("symindex must be smaller than dynsyms.len()"); + } + let chains_size = (dynsyms.len() - symindex as usize).checked_mul(U32_SIZE); + let buckets_size = (nbuckets as usize).checked_mul(U32_SIZE); + let bloom_size = (maskwords as usize).checked_mul(INT_SIZE); + + let total_size = match (chains_size, buckets_size, bloom_size) { + (Some(a), Some(b), Some(c)) => { + a.checked_add(b).and_then(|t| t.checked_add(c)) + } + _ => None, + }; + match total_size { + Some(size) if size == hashtab.len() => {} + _ => return Err("index out of bound or non-complete hash section"), + } + } + + let bloom_filter_ptr = hashtab.as_ptr() as *const $IntTy; + let buckets_ptr = bloom_filter_ptr.add(maskwords as usize) as *const u32; + let chains_ptr = buckets_ptr.add(nbuckets as usize); + let bloom_filter = slice::from_raw_parts(bloom_filter_ptr, maskwords as usize); + let buckets = slice::from_raw_parts(buckets_ptr, nbuckets as usize); + let chains = slice::from_raw_parts(chains_ptr, dynsyms.len() - symindex as usize); + Ok(Self { + symindex, + shift2, + bloom_filter, + buckets, + chains, + dynsyms, + }) + } + + /// Locate the hash chain, and corresponding hash value element. + #[cold] + fn lookup(&self, symbol: &str, hash: u32, dynstrtab: &Strtab) -> Option<&'a Sym> { + const MASK_LOWEST_BIT: u32 = 0xffff_fffe; + let bucket = self.buckets[hash as usize % self.buckets.len()]; + + // Empty hash chain, symbol not present + if bucket < self.symindex { + return None; + } + // Walk the chain until the symbol is found or the chain is exhausted. + let chain_idx = bucket - self.symindex; + let hash = hash & MASK_LOWEST_BIT; + let chains = &self.chains.get((chain_idx as usize)..)?; + let dynsyms = &self.dynsyms.get((bucket as usize)..)?; + for (hash2, symb) in chains.iter().zip(dynsyms.iter()) { + if (hash == (hash2 & MASK_LOWEST_BIT)) + && (symbol == &dynstrtab[symb.st_name as usize]) + { + return Some(symb); + } + // Chain ends with an element with the lowest bit set to 1. + if hash2 & 1 == 1 { + break; + } + } + None + } + + /// Check if symbol maybe is in the hash table, or definitely not in it. + #[inline] + fn check_maybe_match(&self, hash: u32) -> bool { + const MASK: u32 = ELFCLASS_BITS - 1; + let hash2 = hash >> self.shift2; + // `x & (N - 1)` is equivalent to `x % N` iff `N = 2^y`. + let bitmask: $IntTy = 1 << (hash & (MASK)) | 1 << (hash2 & MASK); + let bloom_idx = (hash / ELFCLASS_BITS) & (self.bloom_filter.len() as u32 - 1); + let bitmask_word = self.bloom_filter[bloom_idx as usize]; + (bitmask_word & bitmask) == bitmask + } + + /// Given a symbol, a hash of that symbol, a dynamic string table and + /// a `dynstrtab` to cross-reference names, maybe returns a Sym. + pub fn find(&self, symbol: &str, dynstrtab: &Strtab) -> Option<&'a Sym> { + let hash = self::hash(symbol); + self.find_with_hash(symbol, hash, dynstrtab) + } + + /// This function will not check if the passed `hash` is really + /// the hash of `symbol` + pub fn find_with_hash( + &self, + symbol: &str, + hash: u32, + dynstrtab: &Strtab, + ) -> Option<&'a Sym> { + if self.check_maybe_match(hash) { + self.lookup(symbol, hash, dynstrtab) + } else { + None + } + } + } + }; +} diff --git a/third_party/rust/goblin/src/elf/header.rs b/third_party/rust/goblin/src/elf/header.rs new file mode 100644 index 0000000000..2c05e8ffc6 --- /dev/null +++ b/third_party/rust/goblin/src/elf/header.rs @@ -0,0 +1,630 @@ +include!("constants_header.rs"); + +macro_rules! elf_header { + ($size:ident) => { + use core::fmt; + + #[repr(C)] + #[derive(Clone, Copy, Default, PartialEq)] + pub struct Header { + /// Magic number and other info + pub e_ident: [u8; SIZEOF_IDENT], + /// Object file type + pub e_type: u16, + /// Architecture + pub e_machine: u16, + /// Object file version + pub e_version: u32, + /// Entry point virtual address + pub e_entry: $size, + /// Program header table file offset + pub e_phoff: $size, + /// Section header table file offset + pub e_shoff: $size, + /// Processor-specific flags + pub e_flags: u32, + /// ELF header size in bytes + pub e_ehsize: u16, + /// Program header table entry size + pub e_phentsize: u16, + /// Program header table entry count + pub e_phnum: u16, + /// Section header table entry size + pub e_shentsize: u16, + /// Section header table entry count + pub e_shnum: u16, + /// Section header string table index + pub e_shstrndx: u16, + } + + use plain; + // Declare that this is a plain type. + unsafe impl plain::Plain for Header {} + + impl Header { + /// Returns the corresponding ELF header from the given byte array. + pub fn from_bytes(bytes: &[u8; SIZEOF_EHDR]) -> &Header { + // FIXME: Length is ensured correct because it's encoded in the type, + // but it can still panic due to invalid alignment. + plain::from_bytes(bytes).unwrap() + } + } + impl fmt::Debug for Header { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Header") + .field("e_ident", &format_args!("{:?}", self.e_ident)) + .field("e_type", &et_to_str(self.e_type)) + .field("e_machine", &format_args!("0x{:x}", self.e_machine)) + .field("e_version", &format_args!("0x{:x}", self.e_version)) + .field("e_entry", &format_args!("0x{:x}", self.e_entry)) + .field("e_phoff", &format_args!("0x{:x}", self.e_phoff)) + .field("e_shoff", &format_args!("0x{:x}", self.e_shoff)) + .field("e_flags", &format_args!("{:x}", self.e_flags)) + .field("e_ehsize", &self.e_ehsize) + .field("e_phentsize", &self.e_phentsize) + .field("e_phnum", &self.e_phnum) + .field("e_shentsize", &self.e_shentsize) + .field("e_shnum", &self.e_shnum) + .field("e_shstrndx", &self.e_shstrndx) + .finish() + } + } + }; +} + +/// No file type. +pub const ET_NONE: u16 = 0; +/// Relocatable file. +pub const ET_REL: u16 = 1; +/// Executable file. +pub const ET_EXEC: u16 = 2; +/// Shared object file. +pub const ET_DYN: u16 = 3; +/// Core file. +pub const ET_CORE: u16 = 4; +/// Number of defined types. +pub const ET_NUM: u16 = 5; +/// OS-specific range start +pub const ET_LOOS: u16 = 0xfe00; +/// OS-specific range end +pub const ET_HIOS: u16 = 0xfeff; +/// Processor-specific range start +pub const ET_LOPROC: u16 = 0xff00; +/// Processor-specific range end +pub const ET_HIPROC: u16 = 0xffff; + +/// The ELF magic number. +pub const ELFMAG: &[u8; 4] = b"\x7FELF"; +/// Sizeof ELF magic number. +pub const SELFMAG: usize = 4; + +/// File class byte index. +pub const EI_CLASS: usize = 4; +/// Invalid class. +pub const ELFCLASSNONE: u8 = 0; +/// 32-bit objects. +pub const ELFCLASS32: u8 = 1; +/// 64-bit objects. +pub const ELFCLASS64: u8 = 2; +/// ELF class number. +pub const ELFCLASSNUM: u8 = 3; + +/// Data encoding byte index. +pub const EI_DATA: usize = 5; +/// Invalid data encoding. +pub const ELFDATANONE: u8 = 0; +/// 2's complement, little endian. +pub const ELFDATA2LSB: u8 = 1; +/// 2's complement, big endian. +pub const ELFDATA2MSB: u8 = 2; + +/// File version byte index. +pub const EI_VERSION: usize = 6; +/// Current ELF version. +pub const EV_CURRENT: u8 = 1; + +/// OS ABI byte index. +pub const EI_OSABI: usize = 7; +/// UNIX System V ABI. +pub const ELFOSABI_NONE: u8 = 0; +/// UNIX System V ABI. +/// +/// Alias. +pub const ELFOSABI_SYSV: u8 = ELFOSABI_NONE; +/// HP-UX. +pub const ELFOSABI_HPUX: u8 = 1; +/// NetBSD. +pub const ELFOSABI_NETBSD: u8 = 2; +/// Object uses GNU ELF extensions. +pub const ELFOSABI_GNU: u8 = 3; +/// Object uses GNU ELF extensions. +/// +/// Alias. +pub const ELFOSABI_LINUX: u8 = ELFOSABI_GNU; +/// Sun Solaris. +pub const ELFOSABI_SOLARIS: u8 = 6; +/// IBM AIX. +pub const ELFOSABI_AIX: u8 = 7; +/// SGI Irix. +pub const ELFOSABI_IRIX: u8 = 8; +/// FreeBSD +pub const ELFOSABI_FREEBSD: u8 = 9; +/// Compaq TRU64 UNIX. +pub const ELFOSABI_TRU64: u8 = 10; +/// Novell Modesto. +pub const ELFOSABI_MODESTO: u8 = 11; +/// OpenBSD. +pub const ELFOSABI_OPENBSD: u8 = 12; +/// ARM EABI. +pub const ELFOSABI_ARM_AEABI: u8 = 64; +/// ARM. +pub const ELFOSABI_ARM: u8 = 97; +/// Standalone (embedded) application. +pub const ELFOSABI_STANDALONE: u8 = 255; + +/// ABI version byte index. +pub const EI_ABIVERSION: usize = 8; + +/// Number of bytes in an identifier. +pub const SIZEOF_IDENT: usize = 16; + +/// Convert a ELF class byte to the associated string. +#[inline] +pub fn class_to_str(et: u8) -> &'static str { + match et { + ELFCLASSNONE => "NONE", + ELFCLASS32 => "ELF32", + ELFCLASS64 => "ELF64", + _ => "UNKNOWN_CLASS", + } +} + +/// Convert an ET value to their associated string. +#[inline] +pub fn et_to_str(et: u16) -> &'static str { + match et { + ET_NONE => "NONE", + ET_REL => "REL", + ET_EXEC => "EXEC", + ET_DYN => "DYN", + ET_CORE => "CORE", + ET_NUM => "NUM", + _ => "UNKNOWN_ET", + } +} + +if_alloc! { + use crate::error; + use scroll::{ctx, Endian}; + use core::fmt; + use crate::container::{Ctx, Container}; + use alloc::string::ToString; + + #[derive(Copy, Clone, PartialEq)] + /// An ELF header + pub struct Header { + pub e_ident : [u8; SIZEOF_IDENT], + pub e_type : u16, + pub e_machine : u16, + pub e_version : u32, + pub e_entry : u64, + pub e_phoff : u64, + pub e_shoff : u64, + pub e_flags : u32, + pub e_ehsize : u16, + pub e_phentsize : u16, + pub e_phnum : u16, + pub e_shentsize : u16, + pub e_shnum : u16, + pub e_shstrndx : u16, + } + + impl Header { + /// Return the size of the underlying program header, given a `container` + #[inline] + pub fn size(ctx: Ctx) -> usize { + use scroll::ctx::SizeWith; + Self::size_with(&ctx) + } + /// Returns the container type this header specifies + pub fn container(&self) -> error::Result<Container> { + use crate::error::Error; + match self.e_ident[EI_CLASS] { + ELFCLASS32 => { Ok(Container::Little) }, + ELFCLASS64 => { Ok(Container::Big) }, + class => Err(Error::Malformed(format!("Invalid class in Header: {}", class))) + } + } + /// Returns the byte order this header specifies + pub fn endianness(&self) -> error::Result<scroll::Endian> { + use crate::error::Error; + match self.e_ident[EI_DATA] { + ELFDATA2LSB => { Ok(scroll::LE) }, + ELFDATA2MSB => { Ok(scroll::BE) }, + class => Err(Error::Malformed(format!("Invalid endianness in Header: {}", class))) + } + } + pub fn new(ctx: Ctx) -> Self { + use crate::elf32; + use crate::elf64; + let (typ, ehsize, phentsize, shentsize) = match ctx.container { + Container::Little => { + (ELFCLASS32, header32::SIZEOF_EHDR, + elf32::program_header::SIZEOF_PHDR, + elf32::section_header::SIZEOF_SHDR) + }, + Container::Big => { + (ELFCLASS64, header64::SIZEOF_EHDR, + elf64::program_header::SIZEOF_PHDR, + elf64::section_header::SIZEOF_SHDR) + } + }; + let byteorder = match ctx.le { Endian::Little => ELFDATA2LSB, Endian::Big => ELFDATA2MSB }; + Header { + e_ident: [ + 127, + 69, + 76, + 70, + typ, + byteorder, + EV_CURRENT, + ELFOSABI_NONE, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + e_type: ET_DYN, + e_machine: EM_NONE, + e_version: 1, + e_entry: 0x0, + e_phoff: 0x0, + e_shoff: 0x0, + e_flags: 0, + e_ehsize: ehsize as u16, + e_phentsize: phentsize as u16, + e_phnum: 0, + e_shentsize: shentsize as u16, + e_shnum: 0, + e_shstrndx: 0, + } + } + } + + impl fmt::Debug for Header { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Header") + .field("e_ident", &format_args!("{:?}", self.e_ident)) + .field("e_type", &et_to_str(self.e_type)) + .field("e_machine", &format_args!("0x{:x}", self.e_machine)) + .field("e_version", &format_args!("0x{:x}", self.e_version)) + .field("e_entry", &format_args!("0x{:x}", self.e_entry)) + .field("e_phoff", &format_args!("0x{:x}", self.e_phoff)) + .field("e_shoff", &format_args!("0x{:x}", self.e_shoff)) + .field("e_flags", &format_args!("{:x}", self.e_flags)) + .field("e_ehsize", &self.e_ehsize) + .field("e_phentsize", &self.e_phentsize) + .field("e_phnum", &self.e_phnum) + .field("e_shentsize", &self.e_shentsize) + .field("e_shnum", &self.e_shnum) + .field("e_shstrndx", &self.e_shstrndx) + .finish() + } + } + + impl ctx::SizeWith<crate::container::Ctx> for Header { + fn size_with(ctx: &crate::container::Ctx) -> usize { + match ctx.container { + Container::Little => { + header32::SIZEOF_EHDR + }, + Container::Big => { + header64::SIZEOF_EHDR + }, + } + } + } + + impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Header { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], _ctx: scroll::Endian) -> error::Result<(Self, usize)> { + use scroll::Pread; + if bytes.len() < SIZEOF_IDENT { + return Err(error::Error::Malformed("Too small".to_string())); + } + let ident: &[u8] = &bytes[..SIZEOF_IDENT]; + if &ident[0..SELFMAG] != ELFMAG { + let magic: u64 = ident.pread_with(0, scroll::LE)?; + return Err(error::Error::BadMagic(magic)); + } + let class = ident[EI_CLASS]; + match class { + ELFCLASS32 => { + Ok((Header::from(bytes.pread::<header32::Header>(0)?), header32::SIZEOF_EHDR)) + }, + ELFCLASS64 => { + Ok((Header::from(bytes.pread::<header64::Header>(0)?), header64::SIZEOF_EHDR)) + }, + _ => { + Err(error::Error::Malformed(format!("invalid ELF class {:x}", class))) + } + } + } + } + + impl ctx::TryIntoCtx<scroll::Endian> for Header { + type Error = crate::error::Error; + fn try_into_ctx(self, bytes: &mut [u8], _ctx: scroll::Endian) -> Result<usize, Self::Error> { + use scroll::Pwrite; + match self.container()? { + Container::Little => { + bytes.pwrite(header32::Header::from(self), 0) + }, + Container::Big => { + bytes.pwrite(header64::Header::from(self), 0) + } + } + } + } + impl ctx::IntoCtx<crate::container::Ctx> for Header { + fn into_ctx(self, bytes: &mut [u8], ctx: crate::container::Ctx) { + use scroll::Pwrite; + match ctx.container { + Container::Little => { + bytes.pwrite_with(header32::Header::from(self), 0, ctx.le).unwrap() + }, + Container::Big => { + bytes.pwrite_with(header64::Header::from(self), 0, ctx.le).unwrap() + } + }; + } + } +} // end if_alloc + +macro_rules! elf_header_std_impl { + ($size:expr, $width:ty) => { + + if_alloc! { + use crate::elf::header::Header as ElfHeader; + use crate::error::Error; + #[cfg(any(feature = "std", feature = "endian_fd"))] + use crate::error::Result; + + use scroll::{ctx, Pread}; + + use core::result; + + if_std! { + use std::fs::File; + use std::io::{Read}; + } + + impl From<ElfHeader> for Header { + fn from(eh: ElfHeader) -> Self { + Header { + e_ident: eh.e_ident, + e_type: eh.e_type, + e_machine: eh.e_machine, + e_version: eh.e_version, + e_entry: eh.e_entry as $width, + e_phoff: eh.e_phoff as $width, + e_shoff: eh.e_shoff as $width, + e_flags: eh.e_flags, + e_ehsize: eh.e_ehsize, + e_phentsize: eh.e_phentsize, + e_phnum: eh.e_phnum, + e_shentsize: eh.e_shentsize, + e_shnum: eh.e_shnum, + e_shstrndx: eh.e_shstrndx, + } + } + } + + impl From<Header> for ElfHeader { + fn from(eh: Header) -> Self { + ElfHeader { + e_ident: eh.e_ident, + e_type: eh.e_type, + e_machine: eh.e_machine, + e_version: eh.e_version, + e_entry: u64::from(eh.e_entry), + e_phoff: u64::from(eh.e_phoff), + e_shoff: u64::from(eh.e_shoff), + e_flags: eh.e_flags, + e_ehsize: eh.e_ehsize, + e_phentsize: eh.e_phentsize, + e_phnum: eh.e_phnum, + e_shentsize: eh.e_shentsize, + e_shnum: eh.e_shnum, + e_shstrndx: eh.e_shstrndx, + } + } + } + + impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Header { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], _: scroll::Endian) -> result::Result<(Self, usize), Self::Error> { + let mut elf_header = Header::default(); + let offset = &mut 0; + bytes.gread_inout(offset, &mut elf_header.e_ident)?; + let endianness = + match elf_header.e_ident[EI_DATA] { + ELFDATA2LSB => scroll::LE, + ELFDATA2MSB => scroll::BE, + d => return Err(Error::Malformed(format!("invalid ELF endianness DATA type {:x}", d)).into()), + }; + elf_header.e_type = bytes.gread_with(offset, endianness)?; + elf_header.e_machine = bytes.gread_with(offset, endianness)?; + elf_header.e_version = bytes.gread_with(offset, endianness)?; + elf_header.e_entry = bytes.gread_with(offset, endianness)?; + elf_header.e_phoff = bytes.gread_with(offset, endianness)?; + elf_header.e_shoff = bytes.gread_with(offset, endianness)?; + elf_header.e_flags = bytes.gread_with(offset, endianness)?; + elf_header.e_ehsize = bytes.gread_with(offset, endianness)?; + elf_header.e_phentsize = bytes.gread_with(offset, endianness)?; + elf_header.e_phnum = bytes.gread_with(offset, endianness)?; + elf_header.e_shentsize = bytes.gread_with(offset, endianness)?; + elf_header.e_shnum = bytes.gread_with(offset, endianness)?; + elf_header.e_shstrndx = bytes.gread_with(offset, endianness)?; + Ok((elf_header, SIZEOF_EHDR)) + } + } + + impl ctx::TryIntoCtx<scroll::Endian> for Header { + type Error = crate::error::Error; + /// a Pwrite impl for Header: **note** we use the endianness value in the header, and not a parameter + fn try_into_ctx(self, bytes: &mut [u8], _endianness: scroll::Endian) -> result::Result<usize, Self::Error> { + use scroll::{Pwrite}; + let offset = &mut 0; + let endianness = + match self.e_ident[EI_DATA] { + ELFDATA2LSB => scroll::LE, + ELFDATA2MSB => scroll::BE, + d => return Err(Error::Malformed(format!("invalid ELF DATA type {:x}", d)).into()), + }; + for i in 0..self.e_ident.len() { + bytes.gwrite(self.e_ident[i], offset)?; + } + bytes.gwrite_with(self.e_type , offset, endianness)?; + bytes.gwrite_with(self.e_machine , offset, endianness)?; + bytes.gwrite_with(self.e_version , offset, endianness)?; + bytes.gwrite_with(self.e_entry , offset, endianness)?; + bytes.gwrite_with(self.e_phoff , offset, endianness)?; + bytes.gwrite_with(self.e_shoff , offset, endianness)?; + bytes.gwrite_with(self.e_flags , offset, endianness)?; + bytes.gwrite_with(self.e_ehsize , offset, endianness)?; + bytes.gwrite_with(self.e_phentsize , offset, endianness)?; + bytes.gwrite_with(self.e_phnum , offset, endianness)?; + bytes.gwrite_with(self.e_shentsize , offset, endianness)?; + bytes.gwrite_with(self.e_shnum , offset, endianness)?; + bytes.gwrite_with(self.e_shstrndx , offset, endianness)?; + Ok(SIZEOF_EHDR) + } + } + + impl Header { + /// Load a header from a file. **You must** ensure the seek is at the correct position. + #[cfg(feature = "std")] + pub fn from_fd(bytes: &mut File) -> Result<Header> { + let mut elf_header = [0; $size]; + bytes.read_exact(&mut elf_header)?; + Ok(*Header::from_bytes(&elf_header)) + } + + #[cfg(feature = "endian_fd")] + /// Parses an ELF header from the given bytes + pub fn parse(bytes: &[u8]) -> Result<Header> { + use super::{EI_DATA, ELFDATA2LSB, ELFDATA2MSB, SIZEOF_IDENT}; + + let mut elf_header = Header::default(); + let mut offset = &mut 0; + for i in 0..SIZEOF_IDENT { + elf_header.e_ident[i] = bytes.gread(&mut offset)?; + } + let endianness = + match elf_header.e_ident[EI_DATA] { + ELFDATA2LSB => scroll::LE, + ELFDATA2MSB => scroll::BE, + d => return Err(Error::Malformed(format!("invalid ELF DATA type {:x}", d)).into()), + }; + elf_header.e_type = bytes.gread_with(offset, endianness)?; + elf_header.e_machine = bytes.gread_with(offset, endianness)?; + elf_header.e_version = bytes.gread_with(offset, endianness)?; + elf_header.e_entry = bytes.gread_with(offset, endianness)?; + elf_header.e_phoff = bytes.gread_with(offset, endianness)?; + elf_header.e_shoff = bytes.gread_with(offset, endianness)?; + elf_header.e_flags = bytes.gread_with(offset, endianness)?; + elf_header.e_ehsize = bytes.gread_with(offset, endianness)?; + elf_header.e_phentsize = bytes.gread_with(offset, endianness)?; + elf_header.e_phnum = bytes.gread_with(offset, endianness)?; + elf_header.e_shentsize = bytes.gread_with(offset, endianness)?; + elf_header.e_shnum = bytes.gread_with(offset, endianness)?; + elf_header.e_shstrndx = bytes.gread_with(offset, endianness)?; + Ok(elf_header) + } + } + } // end if_alloc + }; +} + +// tests + +macro_rules! elf_header_test { + ($class:expr) => { + #[cfg(test)] + mod tests { + use super::*; + use crate::container::{Container, Ctx}; + use crate::elf::header::Header as ElfHeader; + use alloc::vec::Vec; + use scroll::{Pread, Pwrite}; + #[test] + fn size_of() { + assert_eq!(::std::mem::size_of::<Header>(), SIZEOF_EHDR); + } + #[test] + fn header_read_write() { + let crt1: Vec<u8> = if $class == ELFCLASS64 { + include!("../../etc/crt1.rs") + } else { + include!("../../etc/crt132.rs") + }; + let header: Header = crt1.pread(0).unwrap(); + assert_eq!(header.e_type, ET_REL); + println!("header: {:?}", &header); + let mut bytes = [0u8; SIZEOF_EHDR]; + bytes.pwrite(header, 0).unwrap(); + let header2: Header = bytes.pread(0).unwrap(); + assert_eq!(header, header2); + } + #[test] + fn elfheader_read_write() { + let (container, crt1): (Container, Vec<u8>) = if $class == ELFCLASS64 { + (Container::Big, include!("../../etc/crt1.rs")) + } else { + (Container::Little, include!("../../etc/crt132.rs")) + }; + let header: Header = crt1.pread(0).unwrap(); + assert_eq!(header.e_type, ET_REL); + println!("header: {:?}", &header); + let mut bytes = [0u8; SIZEOF_EHDR]; + let header_ = Header::from(header.clone()); + bytes.pwrite(header_, 0).unwrap(); + let header2: Header = bytes.pread(0).unwrap(); + assert_eq!(header, header2); + let header = ElfHeader::new(Ctx::from(container)); + println!("header: {:?}", &header); + + let mut bytes = vec![0; 100]; + bytes.pwrite(header, 0).unwrap(); + } + } + }; +} + +pub mod header32 { + pub use super::*; + + pub const SIZEOF_EHDR: usize = 52; + pub const ELFCLASS: u8 = ELFCLASS32; + + elf_header!(u32); + elf_header_std_impl!(SIZEOF_EHDR, u32); + elf_header_test!(ELFCLASS); +} + +pub mod header64 { + pub use super::*; + + pub const SIZEOF_EHDR: usize = 64; + pub const ELFCLASS: u8 = ELFCLASS64; + + elf_header!(u64); + elf_header_std_impl!(SIZEOF_EHDR, u64); + elf_header_test!(ELFCLASS); +} diff --git a/third_party/rust/goblin/src/elf/mod.rs b/third_party/rust/goblin/src/elf/mod.rs new file mode 100644 index 0000000000..937817836d --- /dev/null +++ b/third_party/rust/goblin/src/elf/mod.rs @@ -0,0 +1,566 @@ +//! The generic ELF module, which gives access to ELF constants and other helper functions, which are independent of ELF bithood. Also defines an `Elf` struct which implements a unified parser that returns a wrapped `Elf64` or `Elf32` binary. +//! +//! To access the exact 32-bit or 64-bit versions, use [goblin::elf32::Header](header/header32/struct.Header.html)/[goblin::elf64::Header](header/header64/struct.Header.html), etc., for the various 32/64-bit structs. +//! +//! # Example +//! +//! ```rust +//! use std::fs::File; +//! +//! pub fn read (bytes: &[u8]) { +//! match goblin::elf::Elf::parse(&bytes) { +//! Ok(binary) => { +//! let entry = binary.entry; +//! for ph in binary.program_headers { +//! if ph.p_type == goblin::elf::program_header::PT_LOAD { +//! // TODO: you should validate p_filesz before allocating. +//! let mut _buf = vec![0u8; ph.p_filesz as usize]; +//! // read responsibly +//! } +//! } +//! }, +//! Err(_) => () +//! } +//! } +//! ``` +//! +//! This will properly access the underlying 32-bit or 64-bit binary automatically. Note that since +//! 32-bit binaries typically have shorter 32-bit values in some cases (specifically for addresses and pointer +//! values), these values are upcasted to u64/i64s when appropriate. +//! +//! See [goblin::elf::Elf](struct.Elf.html) for more information. +//! +//! You are still free to use the specific 32-bit or 64-bit versions by accessing them through `goblin::elf64`, etc., but you will have to parse and/or construct the various components yourself. +//! In other words, there is no unified 32/64-bit `Elf` struct. +//! +//! # Note +//! To use the automagic ELF datatype union parser, you _must_ enable/opt-in to the `elf64`, `elf32`, and +//! `endian_fd` features if you disable `default`. + +#[macro_use] +pub(crate) mod gnu_hash; + +// These are shareable values for the 32/64 bit implementations. +// +// They are publicly re-exported by the pub-using module +pub mod compression_header; +pub mod header; +pub mod program_header; +pub mod section_header; +#[macro_use] +pub mod sym; +pub mod dynamic; +#[macro_use] +pub mod reloc; +pub mod note; +#[cfg(all(any(feature = "elf32", feature = "elf64"), feature = "alloc"))] +pub mod symver; + +macro_rules! if_sylvan { + ($($i:item)*) => ($( + #[cfg(all(feature = "elf32", feature = "elf64", feature = "endian_fd"))] + $i + )*) +} + +if_sylvan! { + use scroll::{ctx, Pread, Endian}; + use crate::strtab::Strtab; + use crate::error; + use crate::container::{Container, Ctx}; + use alloc::vec::Vec; + use core::cmp; + + pub use header::Header; + pub use program_header::ProgramHeader; + pub use section_header::SectionHeader; + pub use sym::Symtab; + pub use sym::Sym; + pub use dynamic::Dyn; + pub use dynamic::Dynamic; + pub use reloc::Reloc; + pub use reloc::RelocSection; + pub use symver::{VersymSection, VerdefSection, VerneedSection}; + + pub type ProgramHeaders = Vec<ProgramHeader>; + pub type SectionHeaders = Vec<SectionHeader>; + pub type ShdrIdx = usize; + + #[derive(Debug)] + /// An ELF binary. The underlying data structures are read according to the headers byte order and container size (32 or 64). + pub struct Elf<'a> { + /// The ELF header, which provides a rudimentary index into the rest of the binary + pub header: Header, + /// The program headers; they primarily tell the kernel and the dynamic linker + /// how to load this binary + pub program_headers: ProgramHeaders, + /// The sections headers. These are strippable, never count on them being + /// here unless you're a static linker! + pub section_headers: SectionHeaders, + /// The section header string table + pub shdr_strtab: Strtab<'a>, + /// The string table for the dynamically accessible symbols + pub dynstrtab: Strtab<'a>, + /// The dynamically accessible symbols, i.e., exports, imports. + /// This is what the dynamic linker uses to dynamically load and link your binary, + /// or find imported symbols for binaries which dynamically link against your library + pub dynsyms: Symtab<'a>, + /// The debugging symbol table + pub syms: Symtab<'a>, + /// The string table for the symbol table + pub strtab: Strtab<'a>, + /// Contains dynamic linking information, with the _DYNAMIC array + a preprocessed DynamicInfo for that array + pub dynamic: Option<Dynamic>, + /// The dynamic relocation entries (strings, copy-data, etc.) with an addend + pub dynrelas: RelocSection<'a>, + /// The dynamic relocation entries without an addend + pub dynrels: RelocSection<'a>, + /// The plt relocation entries (procedure linkage table). For 32-bit binaries these are usually Rel (no addend) + pub pltrelocs: RelocSection<'a>, + /// Section relocations by section index (only present if this is a relocatable object file) + pub shdr_relocs: Vec<(ShdrIdx, RelocSection<'a>)>, + /// The binary's soname, if it has one + pub soname: Option<&'a str>, + /// The binary's program interpreter (e.g., dynamic linker), if it has one + pub interpreter: Option<&'a str>, + /// A list of this binary's dynamic libraries it uses, if there are any + pub libraries: Vec<&'a str>, + /// A list of runtime search paths for this binary's dynamic libraries it uses, if there + /// are any. (deprecated) + pub rpaths: Vec<&'a str>, + /// A list of runtime search paths for this binary's dynamic libraries it uses, if there + /// are any. + pub runpaths: Vec<&'a str>, + /// Whether this is a 64-bit elf or not + pub is_64: bool, + /// Whether this is a shared object or not + pub is_lib: bool, + /// The binaries entry point address, if it has one + pub entry: u64, + /// Whether the binary is little endian or not + pub little_endian: bool, + /// Contains the symbol version information from the optional section + /// [`SHT_GNU_VERSYM`][section_header::SHT_GNU_VERSYM] (GNU extenstion). + pub versym : Option<VersymSection<'a>>, + /// Contains the version definition information from the optional section + /// [`SHT_GNU_VERDEF`][section_header::SHT_GNU_VERDEF] (GNU extenstion). + pub verdef : Option<VerdefSection<'a>>, + /// Contains the version needed information from the optional section + /// [`SHT_GNU_VERNEED`][section_header::SHT_GNU_VERNEED] (GNU extenstion). + pub verneed : Option<VerneedSection<'a>>, + ctx: Ctx, + } + + impl<'a> Elf<'a> { + /// Try to iterate notes in PT_NOTE program headers; returns `None` if there aren't any note headers in this binary + pub fn iter_note_headers(&self, data: &'a [u8]) -> Option<note::NoteIterator<'a>> { + let mut iters = vec![]; + for phdr in &self.program_headers { + if phdr.p_type == program_header::PT_NOTE { + let offset = phdr.p_offset as usize; + let alignment = phdr.p_align as usize; + + iters.push(note::NoteDataIterator { + data, + offset, + size: offset.saturating_add(phdr.p_filesz as usize), + ctx: (alignment, self.ctx) + }); + } + } + + if iters.is_empty() { + None + } else { + Some(note::NoteIterator { + iters: iters, + index: 0, + }) + } + } + /// Try to iterate notes in SHT_NOTE sections; returns `None` if there aren't any note sections in this binary + /// + /// If a section_name is given, only the section with the according name is iterated. + pub fn iter_note_sections( + &self, + data: &'a [u8], + section_name: Option<&str>, + ) -> Option<note::NoteIterator<'a>> { + let mut iters = vec![]; + for sect in &self.section_headers { + if sect.sh_type != section_header::SHT_NOTE { + continue; + } + + if section_name.is_some() && self.shdr_strtab.get_at(sect.sh_name) != section_name { + continue; + } + + let offset = sect.sh_offset as usize; + let alignment = sect.sh_addralign as usize; + iters.push(note::NoteDataIterator { + data, + offset, + size: offset.saturating_add(sect.sh_size as usize), + ctx: (alignment, self.ctx) + }); + } + + if iters.is_empty() { + None + } else { + Some(note::NoteIterator { + iters: iters, + index: 0, + }) + } + } + pub fn is_object_file(&self) -> bool { + self.header.e_type == header::ET_REL + } + + /// Parses the contents to get the Header only. This `bytes` buffer should contain at least the length for parsing Header. + pub fn parse_header(bytes: &'a [u8]) -> error::Result<Header> { + bytes.pread::<Header>(0) + } + + /// Lazy parse the ELF contents. This function mainly just assembles an Elf struct. Once we have the struct, we can choose to parse whatever we want. + pub fn lazy_parse(header: Header) -> error::Result<Self> { + let misc = parse_misc(&header)?; + + Ok(Elf { + header, + program_headers: vec![], + section_headers: Default::default(), + shdr_strtab: Default::default(), + dynamic: None, + dynsyms: Default::default(), + dynstrtab: Strtab::default(), + syms: Default::default(), + strtab: Default::default(), + dynrelas: Default::default(), + dynrels: Default::default(), + pltrelocs: Default::default(), + shdr_relocs: Default::default(), + soname: None, + interpreter: None, + libraries: vec![], + rpaths: vec![], + runpaths: vec![], + is_64: misc.is_64, + is_lib: misc.is_lib, + entry: misc.entry, + little_endian: misc.little_endian, + ctx: misc.ctx, + versym: None, + verdef: None, + verneed: None, + }) + } + + /// Parses the contents of the byte stream in `bytes`, and maybe returns a unified binary + pub fn parse(bytes: &'a [u8]) -> error::Result<Self> { + let header = Self::parse_header(bytes)?; + let misc = parse_misc(&header)?; + let ctx = misc.ctx; + + let program_headers = ProgramHeader::parse(bytes, header.e_phoff as usize, header.e_phnum as usize, ctx)?; + + let mut interpreter = None; + for ph in &program_headers { + if ph.p_type == program_header::PT_INTERP && ph.p_filesz != 0 { + let count = (ph.p_filesz - 1) as usize; + let offset = ph.p_offset as usize; + interpreter = bytes.pread_with::<&str>(offset, ::scroll::ctx::StrCtx::Length(count)).ok(); + } + } + + let section_headers = SectionHeader::parse(bytes, header.e_shoff as usize, header.e_shnum as usize, ctx)?; + + let get_strtab = |section_headers: &[SectionHeader], mut section_idx: usize| { + if section_idx == section_header::SHN_XINDEX as usize { + if section_headers.is_empty() { + return Ok(Strtab::default()) + } + section_idx = section_headers[0].sh_link as usize; + } + + if section_idx >= section_headers.len() { + // FIXME: warn! here + Ok(Strtab::default()) + } else { + let shdr = §ion_headers[section_idx]; + shdr.check_size(bytes.len())?; + Strtab::parse(bytes, shdr.sh_offset as usize, shdr.sh_size as usize, 0x0) + } + }; + + let strtab_idx = header.e_shstrndx as usize; + let shdr_strtab = get_strtab(§ion_headers, strtab_idx)?; + + let mut syms = Symtab::default(); + let mut strtab = Strtab::default(); + if let Some(shdr) = section_headers.iter().rfind(|shdr| shdr.sh_type as u32 == section_header::SHT_SYMTAB) { + let size = shdr.sh_entsize; + let count = if size == 0 { 0 } else { shdr.sh_size / size }; + syms = Symtab::parse(bytes, shdr.sh_offset as usize, count as usize, ctx)?; + strtab = get_strtab(§ion_headers, shdr.sh_link as usize)?; + } + + let mut soname = None; + let mut libraries = vec![]; + let mut rpaths = vec![]; + let mut runpaths = vec![]; + let mut dynsyms = Symtab::default(); + let mut dynrelas = RelocSection::default(); + let mut dynrels = RelocSection::default(); + let mut pltrelocs = RelocSection::default(); + let mut dynstrtab = Strtab::default(); + let dynamic = Dynamic::parse(bytes, &program_headers, ctx)?; + if let Some(ref dynamic) = dynamic { + let dyn_info = &dynamic.info; + dynstrtab = Strtab::parse(bytes, + dyn_info.strtab, + dyn_info.strsz, + 0x0)?; + + if dyn_info.soname != 0 { + // FIXME: warn! here + soname = dynstrtab.get_at(dyn_info.soname); + } + if dyn_info.needed_count > 0 { + libraries = dynamic.get_libraries(&dynstrtab); + } + for dyn_ in &dynamic.dyns { + if dyn_.d_tag == dynamic::DT_RPATH { + if let Some(path) = dynstrtab.get_at(dyn_.d_val as usize) { + rpaths.push(path); + } + } else if dyn_.d_tag == dynamic::DT_RUNPATH { + if let Some(path) = dynstrtab.get_at(dyn_.d_val as usize) { + runpaths.push(path); + } + } + } + // parse the dynamic relocations + dynrelas = RelocSection::parse(bytes, dyn_info.rela, dyn_info.relasz, true, ctx)?; + dynrels = RelocSection::parse(bytes, dyn_info.rel, dyn_info.relsz, false, ctx)?; + let is_rela = dyn_info.pltrel as u64 == dynamic::DT_RELA; + pltrelocs = RelocSection::parse(bytes, dyn_info.jmprel, dyn_info.pltrelsz, is_rela, ctx)?; + + let mut num_syms = if let Some(gnu_hash) = dyn_info.gnu_hash { + gnu_hash_len(bytes, gnu_hash as usize, ctx)? + } else if let Some(hash) = dyn_info.hash { + hash_len(bytes, hash as usize, header.e_machine, ctx)? + } else { + 0 + }; + let max_reloc_sym = dynrelas.iter() + .chain(dynrels.iter()) + .chain(pltrelocs.iter()) + .fold(0, |num, reloc| cmp::max(num, reloc.r_sym)); + if max_reloc_sym != 0 { + num_syms = cmp::max(num_syms, max_reloc_sym + 1); + } + dynsyms = Symtab::parse(bytes, dyn_info.symtab, num_syms, ctx)?; + } + + let mut shdr_relocs = vec![]; + for (idx, section) in section_headers.iter().enumerate() { + let is_rela = section.sh_type == section_header::SHT_RELA; + if is_rela || section.sh_type == section_header::SHT_REL { + section.check_size(bytes.len())?; + let sh_relocs = RelocSection::parse(bytes, section.sh_offset as usize, section.sh_size as usize, is_rela, ctx)?; + shdr_relocs.push((idx, sh_relocs)); + } + } + + let versym = symver::VersymSection::parse(bytes, §ion_headers, ctx)?; + let verdef = symver::VerdefSection::parse(bytes, §ion_headers, ctx)?; + let verneed = symver::VerneedSection::parse(bytes, §ion_headers, ctx)?; + + Ok(Elf { + header, + program_headers, + section_headers, + shdr_strtab, + dynamic, + dynsyms, + dynstrtab, + syms, + strtab, + dynrelas, + dynrels, + pltrelocs, + shdr_relocs, + soname, + interpreter, + libraries, + rpaths, + runpaths, + is_64: misc.is_64, + is_lib: misc.is_lib, + entry: misc.entry, + little_endian: misc.little_endian, + ctx: ctx, + versym, + verdef, + verneed, + }) + } + } + + impl<'a> ctx::TryFromCtx<'a, (usize, Endian)> for Elf<'a> { + type Error = crate::error::Error; + fn try_from_ctx(src: &'a [u8], (_, _): (usize, Endian)) -> Result<(Elf<'a>, usize), Self::Error> { + let elf = Elf::parse(src)?; + Ok((elf, src.len())) + } + } + + fn gnu_hash_len(bytes: &[u8], offset: usize, ctx: Ctx) -> error::Result<usize> { + let buckets_num = bytes.pread_with::<u32>(offset, ctx.le)? as usize; + let min_chain = bytes.pread_with::<u32>(offset + 4, ctx.le)? as usize; + let bloom_size = bytes.pread_with::<u32>(offset + 8, ctx.le)? as usize; + // We could handle min_chain==0 if we really had to, but it shouldn't happen. + if buckets_num == 0 || min_chain == 0 || bloom_size == 0 { + return Err(error::Error::Malformed(format!("Invalid DT_GNU_HASH: buckets_num={} min_chain={} bloom_size={}", + buckets_num, min_chain, bloom_size))); + } + // Find the last bucket. + let buckets_offset = offset + 16 + bloom_size * if ctx.container.is_big() { 8 } else { 4 }; + let mut max_chain = 0; + for bucket in 0..buckets_num { + let chain = bytes.pread_with::<u32>(buckets_offset + bucket * 4, ctx.le)? as usize; + if max_chain < chain { + max_chain = chain; + } + } + if max_chain < min_chain { + return Ok(0); + } + // Find the last chain within the bucket. + let mut chain_offset = buckets_offset + buckets_num * 4 + (max_chain - min_chain) * 4; + loop { + let hash = bytes.pread_with::<u32>(chain_offset, ctx.le)?; + max_chain += 1; + chain_offset += 4; + if hash & 1 != 0 { + return Ok(max_chain); + } + } + } + + fn hash_len(bytes: &[u8], offset: usize, machine: u16, ctx: Ctx) -> error::Result<usize> { + // Based on readelf code. + let nchain = if (machine == header::EM_FAKE_ALPHA || machine == header::EM_S390) && ctx.container.is_big() { + bytes.pread_with::<u64>(offset.saturating_add(4), ctx.le)? as usize + } else { + bytes.pread_with::<u32>(offset.saturating_add(4), ctx.le)? as usize + }; + Ok(nchain) + } + + struct Misc { + is_64: bool, + is_lib: bool, + entry: u64, + little_endian: bool, + ctx: Ctx, + } + + fn parse_misc(header: &Header) -> error::Result<Misc> { + let entry = header.e_entry as usize; + let is_lib = header.e_type == header::ET_DYN; + let is_lsb = header.e_ident[header::EI_DATA] == header::ELFDATA2LSB; + let endianness = scroll::Endian::from(is_lsb); + let class = header.e_ident[header::EI_CLASS]; + if class != header::ELFCLASS64 && class != header::ELFCLASS32 { + return Err(error::Error::Malformed(format!("Unknown values in ELF ident header: class: {} endianness: {}", + class, + header.e_ident[header::EI_DATA]))); + } + let is_64 = class == header::ELFCLASS64; + let container = if is_64 { Container::Big } else { Container::Little }; + let ctx = Ctx::new(container, endianness); + + Ok(Misc{ + is_64, + is_lib, + entry: entry as u64, + little_endian:is_lsb, + ctx, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_crt1_64bit() { + let crt1: Vec<u8> = include!("../../etc/crt1.rs"); + match Elf::parse(&crt1) { + Ok(binary) => { + assert!(binary.is_64); + assert!(!binary.is_lib); + assert_eq!(binary.entry, 0); + assert!(binary.syms.get(1000).is_none()); + assert!(binary.syms.get(5).is_some()); + let syms = binary.syms.to_vec(); + assert!(!binary.section_headers.is_empty()); + for (i, sym) in syms.iter().enumerate() { + if i == 11 { + let symtab = binary.strtab; + println!("sym: {:?}", &sym); + assert_eq!(&symtab[sym.st_name], "_start"); + break; + } + } + assert!(!syms.is_empty()); + } + Err(err) => { + panic!("failed: {}", err); + } + } + } + + #[test] + fn parse_crt1_32bit() { + let crt1: Vec<u8> = include!("../../etc/crt132.rs"); + match Elf::parse(&crt1) { + Ok(binary) => { + assert!(!binary.is_64); + assert!(!binary.is_lib); + assert_eq!(binary.entry, 0); + assert!(binary.syms.get(1000).is_none()); + assert!(binary.syms.get(5).is_some()); + let syms = binary.syms.to_vec(); + assert!(!binary.section_headers.is_empty()); + for (i, sym) in syms.iter().enumerate() { + if i == 11 { + let symtab = binary.strtab; + println!("sym: {:?}", &sym); + assert_eq!(&symtab[sym.st_name], "__libc_csu_fini"); + break; + } + } + assert!(!syms.is_empty()); + } + Err(err) => { + panic!("failed: {}", err); + } + } + } + + // See https://github.com/m4b/goblin/issues/257 + #[test] + #[allow(unused)] + fn no_use_statement_conflict() { + use crate::elf::section_header::*; + use crate::elf::*; + + fn f(_: SectionHeader) {} + } +} diff --git a/third_party/rust/goblin/src/elf/note.rs b/third_party/rust/goblin/src/elf/note.rs new file mode 100644 index 0000000000..5ec1d47340 --- /dev/null +++ b/third_party/rust/goblin/src/elf/note.rs @@ -0,0 +1,305 @@ +// Defined note types for GNU systems. + +#[cfg(feature = "log")] +use log::debug; +#[cfg(feature = "alloc")] +use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith}; + +/// ABI information. +/// +/// The descriptor consists of words: +/// * word 0: OS descriptor +/// * word 1: major version of the ABI +/// * word 2: minor version of the ABI +/// * word 3: subminor version of the ABI +pub const NT_GNU_ABI_TAG: u32 = 1; + +/// Old name +pub const ELF_NOTE_ABI: u32 = NT_GNU_ABI_TAG; +// Known OSes. These values can appear in word 0 of an +// `NT_GNU_ABI_TAG` note section entry. +pub const ELF_NOTE_OS_LINUX: u32 = 0; +pub const ELF_NOTE_OS_GNU: u32 = 1; +pub const ELF_NOTE_OS_SOLARIS2: u32 = 2; +pub const ELF_NOTE_OS_FREEBSD: u32 = 3; + +/// Synthetic `hwcap` information. +/// +/// The descriptor begins with two words: +/// * word 0: number of entries +/// * word 1: bitmask of enabled entries +/// +/// Then follow variable-length entries, one byte followed by a '\0'-terminated +/// `hwcap` name string. The byte gives the bit number to test if enabled, +/// `(1U << bit) & bitmask`. +pub const NT_GNU_HWCAP: u32 = 2; + +/// Build ID bits as generated by ld --build-id. +/// +/// The descriptor consists of any nonzero number of bytes. +pub const NT_GNU_BUILD_ID: u32 = 3; + +/// Version note generated by GNU gold containing a version string. +pub const NT_GNU_GOLD_VERSION: u32 = 4; + +///Contains copy of prstatus struct. +pub const NT_PRSTATUS: u32 = 1; + +///Contains copy of prpsinfo struct. +pub const NT_PRPSINFO: u32 = 3; + +///Fields of siginfo_t. +pub const NT_SIGINFO: u32 = 0x5349_4749; + +///Description of mapped files. +pub const NT_FILE: u32 = 0x4649_4c45; + +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] +#[repr(C)] +/// Note section contents. Each entry in the note section begins with a header +/// of a fixed form. +pub struct Nhdr32 { + /// Length of the note's name (includes the terminator) + pub n_namesz: u32, + /// Length of the note's descriptor + pub n_descsz: u32, + /// Type of the note + pub n_type: u32, +} + +// Declare that this is a plain type. +unsafe impl plain::Plain for Nhdr32 {} + +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] +#[repr(C)] +/// Note section contents. Each entry in the note section begins with a header +/// of a fixed form. +pub struct Nhdr64 { + /// Length of the note's name (includes the terminator) + pub n_namesz: u64, + /// Length of the note's descriptor. + pub n_descsz: u64, + /// Type of the note. + pub n_type: u64, +} + +// Declare that this is a plain type. +unsafe impl plain::Plain for Nhdr64 {} + +if_alloc! { + use crate::error; + use crate::container; + use scroll::ctx; + use alloc::vec::Vec; + + /// An iterator over ELF binary notes in a note section or segment + pub struct NoteDataIterator<'a> { + pub data: &'a [u8], + pub size: usize, + pub offset: usize, + pub ctx: (usize, container::Ctx), // (alignment, ctx) + } + + impl<'a> Iterator for NoteDataIterator<'a> { + type Item = error::Result<Note<'a>>; + fn next(&mut self) -> Option<Self::Item> { + if self.offset >= self.size { + None + } else { + debug!("NoteIterator - {:#x}", self.offset); + match self.data.gread_with(&mut self.offset, self.ctx) { + Ok(res) => Some(Ok(res)), + Err(e) => Some(Err(e)) + } + } + } + } + + /// An iterator over ELF binary notes + pub struct NoteIterator<'a> { + pub iters: Vec<NoteDataIterator<'a>>, + pub index: usize, + } + + impl<'a> Iterator for NoteIterator<'a> { + type Item = error::Result<Note<'a>>; + fn next(&mut self) -> Option<Self::Item> { + while self.index < self.iters.len() { + if let Some(note_result) = self.iters[self.index].next() { + return Some(note_result); + } + + self.index += 1; + } + + None + } + } + + #[derive(Debug)] + struct NoteHeader { + n_namesz: usize, + n_descsz: usize, + n_type: u32, + } + + impl From<Nhdr32> for NoteHeader { + fn from(header: Nhdr32) -> Self { + NoteHeader { + n_namesz: header.n_namesz as usize, + n_descsz: header.n_descsz as usize, + n_type: header.n_type, + } + } + } + + impl From<Nhdr64> for NoteHeader { + fn from(header: Nhdr64) -> Self { + NoteHeader { + n_namesz: header.n_namesz as usize, + n_descsz: header.n_descsz as usize, + n_type: header.n_type as u32, + } + } + } + + fn align(alignment: usize, offset: &mut usize) { + let diff = *offset % alignment; + if diff != 0 { + *offset += alignment - diff; + } + } + + /// A 32/64 bit Note struct, with the name and desc pre-parsed + #[derive(Debug)] + pub struct Note<'a> { + /// The type of this note + pub n_type: u32, + /// NUL terminated string, where `namesz` includes the terminator + pub name: &'a str, // needs padding such that namesz + padding % {wordsize} == 0 + /// arbitrary data of length `descsz` + pub desc: &'a [u8], // needs padding such that descsz + padding % {wordsize} == 0 + } + + impl<'a> Note<'a> { + pub fn type_to_str(&self) -> &'static str { + match self.n_type { + NT_GNU_ABI_TAG => "NT_GNU_ABI_TAG", + NT_GNU_HWCAP => "NT_GNU_HWCAP", + NT_GNU_BUILD_ID => "NT_GNU_BUILD_ID", + NT_GNU_GOLD_VERSION => "NT_GNU_GOLD_VERSION", + _ => "NT_UNKNOWN" + } + } + } + + impl<'a> ctx::TryFromCtx<'a, (usize, container::Ctx)> for Note<'a> { + type Error = error::Error; + fn try_from_ctx(bytes: &'a [u8], (alignment, ctx): (usize, container::Ctx)) -> Result<(Self, usize), Self::Error> { + let offset = &mut 0; + let mut alignment = alignment; + if alignment < 4 { + alignment = 4; + } + let header: NoteHeader = { + match alignment { + 4|8 => bytes.gread_with::<Nhdr32>(offset, ctx.le)?.into(), + _ => return Err(error::Error::Malformed(format!("Notes has unimplemented alignment requirement: {:#x}", alignment))) + } + }; + debug!("{:?} - {:#x}", header, *offset); + // -1 because includes \0 terminator + let name = bytes.gread_with::<&'a str>(offset, ctx::StrCtx::Length(header.n_namesz.saturating_sub(1)))?; + if header.n_namesz > 0 { + *offset += 1; + } + align(alignment, offset); + debug!("note name {} - {:#x}", name, *offset); + let desc = bytes.gread_with::<&'a [u8]>(offset, header.n_descsz)?; + align(alignment, offset); + debug!("desc {:?} - {:#x}", desc, *offset); + Ok((Note { + name, + desc, + n_type: header.n_type, + }, *offset)) + } + } + + #[cfg(test)] + mod tests { + use super::*; + + static NOTE_DATA: [u8; 68] = [0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, + 0xbc, 0xfc, 0x66, 0xcd, 0xc7, 0xd5, 0x14, 0x7b, + 0x53, 0xb1, 0x10, 0x11, 0x94, 0x86, 0x8e, 0xf9, + 0x4f, 0xe8, 0xdd, 0xdb]; + + static CONTEXT: (usize, container::Ctx) = (4, container::Ctx { + container: container::Container::Big, + le: ::scroll::Endian::Little, + }); + + fn make_note_iter(start: usize, end: usize) -> NoteDataIterator<'static> { + NoteDataIterator { + data: &NOTE_DATA, + size: end, + offset: start, + ctx: CONTEXT, + } + } + + #[test] + fn iter_single_section() { + let mut notes = NoteIterator { + iters: vec![make_note_iter(0, 68)], + index: 0, + }; + + assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); + assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); + assert!(notes.next().is_none()); + } + + #[test] + fn iter_multiple_sections() { + let mut notes = NoteIterator { + iters: vec![make_note_iter(0, 32), make_note_iter(32, 68)], + index: 0, + }; + + assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); + assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); + assert!(notes.next().is_none()); + } + + #[test] + fn skip_empty_sections() { + let mut notes = NoteIterator { + iters: vec![ + make_note_iter(0, 32), + make_note_iter(0, 0), + make_note_iter(32, 68), + ], + index: 0, + }; + + assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); + assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); + assert!(notes.next().is_none()); + } + + #[test] + fn ignore_no_sections() { + let mut notes = NoteIterator { iters: vec![], index: 0 }; + assert!(notes.next().is_none()); + } + } +} diff --git a/third_party/rust/goblin/src/elf/program_header.rs b/third_party/rust/goblin/src/elf/program_header.rs new file mode 100644 index 0000000000..3525bb4e4a --- /dev/null +++ b/third_party/rust/goblin/src/elf/program_header.rs @@ -0,0 +1,427 @@ +/* Legal values for p_type (segment type). */ + +/// Programg header table entry unused +pub const PT_NULL: u32 = 0; +/// Loadable program segment +pub const PT_LOAD: u32 = 1; +/// Dynamic linking information +pub const PT_DYNAMIC: u32 = 2; +/// Program interpreter +pub const PT_INTERP: u32 = 3; +/// Auxiliary information +pub const PT_NOTE: u32 = 4; +/// Reserved +pub const PT_SHLIB: u32 = 5; +/// Entry for header table itself +pub const PT_PHDR: u32 = 6; +/// Thread-local storage segment +pub const PT_TLS: u32 = 7; +/// Number of defined types +pub const PT_NUM: u32 = 8; +/// Start of OS-specific +pub const PT_LOOS: u32 = 0x6000_0000; +/// GCC .eh_frame_hdr segment +pub const PT_GNU_EH_FRAME: u32 = 0x6474_e550; +/// Indicates stack executability +pub const PT_GNU_STACK: u32 = 0x6474_e551; +/// Read-only after relocation +pub const PT_GNU_RELRO: u32 = 0x6474_e552; +/// Sun Specific segment +pub const PT_LOSUNW: u32 = 0x6fff_fffa; +/// Sun Specific segment +pub const PT_SUNWBSS: u32 = 0x6fff_fffa; +/// Stack segment +pub const PT_SUNWSTACK: u32 = 0x6fff_fffb; +/// End of OS-specific +pub const PT_HISUNW: u32 = 0x6fff_ffff; +/// End of OS-specific +pub const PT_HIOS: u32 = 0x6fff_ffff; +/// Start of processor-specific +pub const PT_LOPROC: u32 = 0x7000_0000; +/// ARM unwind segment +pub const PT_ARM_EXIDX: u32 = 0x7000_0001; +/// End of processor-specific +pub const PT_HIPROC: u32 = 0x7fff_ffff; + +/* Legal values for p_flags (segment flags). */ + +/// Segment is executable +pub const PF_X: u32 = 1; +/// Segment is writable +pub const PF_W: u32 = 1 << 1; +/// Segment is readable +pub const PF_R: u32 = 1 << 2; +/// Bits reserved for OS-specific usage +pub const PF_MASKOS: u32 = 0x0ff0_0000; +/// Bits reserved for processor-specific usage +pub const PF_MASKPROC: u32 = 0xf000_0000; + +pub fn pt_to_str(pt: u32) -> &'static str { + match pt { + PT_NULL => "PT_NULL", + PT_LOAD => "PT_LOAD", + PT_DYNAMIC => "PT_DYNAMIC", + PT_INTERP => "PT_INTERP", + PT_NOTE => "PT_NOTE", + PT_SHLIB => "PT_SHLIB", + PT_PHDR => "PT_PHDR", + PT_TLS => "PT_TLS", + PT_NUM => "PT_NUM", + PT_LOOS => "PT_LOOS", + PT_GNU_EH_FRAME => "PT_GNU_EH_FRAME", + PT_GNU_STACK => "PT_GNU_STACK", + PT_GNU_RELRO => "PT_GNU_RELRO", + PT_SUNWBSS => "PT_SUNWBSS", + PT_SUNWSTACK => "PT_SUNWSTACK", + PT_HIOS => "PT_HIOS", + PT_LOPROC => "PT_LOPROC", + PT_HIPROC => "PT_HIPROC", + PT_ARM_EXIDX => "PT_ARM_EXIDX", + _ => "UNKNOWN_PT", + } +} + +if_alloc! { + use core::fmt; + use scroll::ctx; + use core::result; + use core::ops::Range; + use crate::container::{Ctx, Container}; + use alloc::vec::Vec; + + #[derive(Default, PartialEq, Clone)] + /// A unified ProgramHeader - convertable to and from 32-bit and 64-bit variants + pub struct ProgramHeader { + pub p_type : u32, + pub p_flags : u32, + pub p_offset: u64, + pub p_vaddr : u64, + pub p_paddr : u64, + pub p_filesz: u64, + pub p_memsz : u64, + pub p_align : u64, + } + + impl ProgramHeader { + /// Return the size of the underlying program header, given a `Ctx` + #[inline] + pub fn size(ctx: Ctx) -> usize { + use scroll::ctx::SizeWith; + Self::size_with(&ctx) + } + /// Create a new `PT_LOAD` ELF program header + pub fn new() -> Self { + ProgramHeader { + p_type : PT_LOAD, + p_flags : 0, + p_offset: 0, + p_vaddr : 0, + p_paddr : 0, + p_filesz: 0, + p_memsz : 0, + //TODO: check if this is true for 32-bit pt_load + p_align : 2 << 20, + } + } + /// Returns this program header's file offset range + pub fn file_range(&self) -> Range<usize> { + self.p_offset as usize..self.p_offset.saturating_add(self.p_filesz) as usize + } + /// Returns this program header's virtual memory range + pub fn vm_range(&self) -> Range<usize> { + self.p_vaddr as usize..self.p_vaddr.saturating_add(self.p_memsz) as usize + } + /// Sets the executable flag + pub fn executable(&mut self) { + self.p_flags |= PF_X; + } + /// Sets the write flag + pub fn write(&mut self) { + self.p_flags |= PF_W; + } + /// Sets the read flag + pub fn read(&mut self) { + self.p_flags |= PF_R; + } + /// Whether this program header is executable + pub fn is_executable(&self) -> bool { + self.p_flags & PF_X != 0 + } + /// Whether this program header is readable + pub fn is_read(&self) -> bool { + self.p_flags & PF_R != 0 + } + /// Whether this program header is writable + pub fn is_write(&self) -> bool { + self.p_flags & PF_W != 0 + } + #[cfg(feature = "endian_fd")] + pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> crate::error::Result<Vec<ProgramHeader>> { + use scroll::Pread; + // Sanity check to avoid OOM + if count > bytes.len() / Self::size(ctx) { + return Err(crate::error::Error::BufferTooShort(count, "program headers")); + } + let mut program_headers = Vec::with_capacity(count); + for _ in 0..count { + let phdr = bytes.gread_with(&mut offset, ctx)?; + program_headers.push(phdr); + } + Ok(program_headers) + } + } + + impl fmt::Debug for ProgramHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ProgramHeader") + .field("p_type", &pt_to_str(self.p_type)) + .field("p_flags", &format_args!("0x{:x}", self.p_flags)) + .field("p_offset", &format_args!("0x{:x}", self.p_offset)) + .field("p_vaddr", &format_args!("0x{:x}", self.p_vaddr)) + .field("p_paddr", &format_args!("0x{:x}", self.p_paddr)) + .field("p_filesz", &format_args!("0x{:x}", self.p_filesz)) + .field("p_memsz", &format_args!("0x{:x}", self.p_memsz)) + .field("p_align", &self.p_align) + .finish() + } + } + + impl ctx::SizeWith<Ctx> for ProgramHeader { + fn size_with(ctx: &Ctx) -> usize { + match ctx.container { + Container::Little => { + program_header32::SIZEOF_PHDR + }, + Container::Big => { + program_header64::SIZEOF_PHDR + }, + } + } + } + + impl<'a> ctx::TryFromCtx<'a, Ctx> for ProgramHeader { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> { + use scroll::Pread; + let res = match container { + Container::Little => { + (bytes.pread_with::<program_header32::ProgramHeader>(0, le)?.into(), program_header32::SIZEOF_PHDR) + }, + Container::Big => { + (bytes.pread_with::<program_header64::ProgramHeader>(0, le)?.into(), program_header64::SIZEOF_PHDR) + } + }; + Ok(res) + } + } + + impl ctx::TryIntoCtx<Ctx> for ProgramHeader { + type Error = crate::error::Error; + fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> { + use scroll::Pwrite; + match container { + Container::Little => { + let phdr: program_header32::ProgramHeader = self.into(); + Ok(bytes.pwrite_with(phdr, 0, le)?) + }, + Container::Big => { + let phdr: program_header64::ProgramHeader = self.into(); + Ok(bytes.pwrite_with(phdr, 0, le)?) + } + } + } + } +} // end if_alloc + +macro_rules! elf_program_header_std_impl { + ($size:ty) => { + #[cfg(test)] + mod tests { + use super::*; + #[test] + fn size_of() { + assert_eq!(::std::mem::size_of::<ProgramHeader>(), SIZEOF_PHDR); + } + } + + if_alloc! { + + + use crate::elf::program_header::ProgramHeader as ElfProgramHeader; + #[cfg(any(feature = "std", feature = "endian_fd"))] + use crate::error::Result; + + use plain::Plain; + + if_std! { + use std::fs::File; + use std::io::{Seek, Read}; + use std::io::SeekFrom::Start; + } + + impl From<ProgramHeader> for ElfProgramHeader { + fn from(ph: ProgramHeader) -> Self { + ElfProgramHeader { + p_type : ph.p_type, + p_flags : ph.p_flags, + p_offset : u64::from(ph.p_offset), + p_vaddr : u64::from(ph.p_vaddr), + p_paddr : u64::from(ph.p_paddr), + p_filesz : u64::from(ph.p_filesz), + p_memsz : u64::from(ph.p_memsz), + p_align : u64::from(ph.p_align), + } + } + } + + impl From<ElfProgramHeader> for ProgramHeader { + fn from(ph: ElfProgramHeader) -> Self { + ProgramHeader { + p_type : ph.p_type, + p_flags : ph.p_flags, + p_offset : ph.p_offset as $size, + p_vaddr : ph.p_vaddr as $size, + p_paddr : ph.p_paddr as $size, + p_filesz : ph.p_filesz as $size, + p_memsz : ph.p_memsz as $size, + p_align : ph.p_align as $size, + } + } + } + } // end if_alloc + + use core::fmt; + use core::slice; + + impl fmt::Debug for ProgramHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ProgramHeader") + .field("p_type", &pt_to_str(self.p_type)) + .field("p_flags", &format_args!("0x{:x}", self.p_flags)) + .field("p_offset", &format_args!("0x{:x}", self.p_offset)) + .field("p_vaddr", &format_args!("0x{:x}", self.p_vaddr)) + .field("p_paddr", &format_args!("0x{:x}", self.p_paddr)) + .field("p_filesz", &format_args!("0x{:x}", self.p_filesz)) + .field("p_memsz", &format_args!("0x{:x}", self.p_memsz)) + .field("p_align", &self.p_align) + .finish() + } + } + + impl ProgramHeader { + #[cfg(feature = "endian_fd")] + pub fn parse( + bytes: &[u8], + mut offset: usize, + count: usize, + ctx: ::scroll::Endian, + ) -> Result<Vec<ProgramHeader>> { + use scroll::Pread; + let mut program_headers = vec![ProgramHeader::default(); count]; + let offset = &mut offset; + bytes.gread_inout_with(offset, &mut program_headers, ctx)?; + Ok(program_headers) + } + + #[cfg(feature = "alloc")] + pub fn from_bytes(bytes: &[u8], phnum: usize) -> Vec<ProgramHeader> { + let mut phdrs = vec![ProgramHeader::default(); phnum]; + phdrs + .copy_from_bytes(bytes) + .expect("buffer is too short for given number of entries"); + phdrs + } + + /// # Safety + /// + /// This function creates a `ProgramHeader` directly from a raw pointer + pub unsafe fn from_raw_parts<'a>( + phdrp: *const ProgramHeader, + phnum: usize, + ) -> &'a [ProgramHeader] { + slice::from_raw_parts(phdrp, phnum) + } + + #[cfg(feature = "std")] + pub fn from_fd(fd: &mut File, offset: u64, count: usize) -> Result<Vec<ProgramHeader>> { + let mut phdrs = vec![ProgramHeader::default(); count]; + fd.seek(Start(offset))?; + unsafe { + fd.read_exact(plain::as_mut_bytes(&mut *phdrs))?; + } + Ok(phdrs) + } + } + }; +} + +#[cfg(feature = "alloc")] +use scroll::{Pread, Pwrite, SizeWith}; + +pub mod program_header32 { + pub use crate::elf::program_header::*; + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// A 32-bit ProgramHeader typically specifies how to map executable and data segments into memory + pub struct ProgramHeader { + /// Segment type + pub p_type: u32, + /// Segment file offset + pub p_offset: u32, + /// Segment virtual address + pub p_vaddr: u32, + /// Segment physical address + pub p_paddr: u32, + /// Segment size in file + pub p_filesz: u32, + /// Segment size in memory + pub p_memsz: u32, + /// Segment flags + pub p_flags: u32, + /// Segment alignment + pub p_align: u32, + } + + pub const SIZEOF_PHDR: usize = 32; + + // Declare that this is a plain type. + unsafe impl plain::Plain for ProgramHeader {} + + elf_program_header_std_impl!(u32); +} + +pub mod program_header64 { + pub use crate::elf::program_header::*; + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// A 64-bit ProgramHeader typically specifies how to map executable and data segments into memory + pub struct ProgramHeader { + /// Segment type + pub p_type: u32, + /// Segment flags + pub p_flags: u32, + /// Segment file offset + pub p_offset: u64, + /// Segment virtual address + pub p_vaddr: u64, + /// Segment physical address + pub p_paddr: u64, + /// Segment size in file + pub p_filesz: u64, + /// Segment size in memory + pub p_memsz: u64, + /// Segment alignment + pub p_align: u64, + } + + pub const SIZEOF_PHDR: usize = 56; + + // Declare that this is a plain type. + unsafe impl plain::Plain for ProgramHeader {} + + elf_program_header_std_impl!(u64); +} diff --git a/third_party/rust/goblin/src/elf/reloc.rs b/third_party/rust/goblin/src/elf/reloc.rs new file mode 100644 index 0000000000..6225a3865b --- /dev/null +++ b/third_party/rust/goblin/src/elf/reloc.rs @@ -0,0 +1,518 @@ +//! # Relocation computations +//! +//! The following notation is used to describe relocation computations +//! specific to x86_64 ELF. +//! +//! * A: The addend used to compute the value of the relocatable field. +//! * B: The base address at which a shared object is loaded into memory +//! during execution. Generally, a shared object file is built with a +//! base virtual address of 0. However, the execution address of the +//! shared object is different. +//! * G: The offset into the global offset table at which the address of +//! the relocation entry's symbol resides during execution. +//! * GOT: The address of the global offset table. +//! * L: The section offset or address of the procedure linkage table entry +//! for a symbol. +//! * P: The section offset or address of the storage unit being relocated, +//! computed using r_offset. +//! * S: The value of the symbol whose index resides in the relocation entry. +//! * Z: The size of the symbol whose index resides in the relocation entry. +//! +//! Below are some common x86_64 relocation computations you might find useful: +//! +//! | Relocation | Value | Size | Formula | +//! |:--------------------------|:------|:----------|:------------------| +//! | `R_X86_64_NONE` | 0 | NONE | NONE | +//! | `R_X86_64_64` | 1 | 64 | S + A | +//! | `R_X86_64_PC32` | 2 | 32 | S + A - P | +//! | `R_X86_64_GOT32` | 3 | 32 | G + A | +//! | `R_X86_64_PLT32` | 4 | 32 | L + A - P | +//! | `R_X86_64_COPY` | 5 | NONE | NONE | +//! | `R_X86_64_GLOB_DAT` | 6 | 64 | S | +//! | `R_X86_64_JUMP_SLOT` | 7 | 64 | S | +//! | `R_X86_64_RELATIVE` | 8 | 64 | B + A | +//! | `R_X86_64_GOTPCREL` | 9 | 32 | G + GOT + A - P | +//! | `R_X86_64_32` | 10 | 32 | S + A | +//! | `R_X86_64_32S` | 11 | 32 | S + A | +//! | `R_X86_64_16` | 12 | 16 | S + A | +//! | `R_X86_64_PC16` | 13 | 16 | S + A - P | +//! | `R_X86_64_8` | 14 | 8 | S + A | +//! | `R_X86_64_PC8` | 15 | 8 | S + A - P | +//! | `R_X86_64_DTPMOD64` | 16 | 64 | | +//! | `R_X86_64_DTPOFF64` | 17 | 64 | | +//! | `R_X86_64_TPOFF64` | 18 | 64 | | +//! | `R_X86_64_TLSGD` | 19 | 32 | | +//! | `R_X86_64_TLSLD` | 20 | 32 | | +//! | `R_X86_64_DTPOFF32` | 21 | 32 | | +//! | `R_X86_64_GOTTPOFF` | 22 | 32 | | +//! | `R_X86_64_TPOFF32` | 23 | 32 | | +//! | `R_X86_64_PC64` | 24 | 64 | S + A - P | +//! | `R_X86_64_GOTOFF64` | 25 | 64 | S + A - GOT | +//! | `R_X86_64_GOTPC32` | 26 | 32 | GOT + A - P | +//! | `R_X86_64_SIZE32` | 32 | 32 | Z + A | +//! | `R_X86_64_SIZE64` | 33 | 64 | Z + A | +//! | `R_X86_64_GOTPC32_TLSDESC` 34 | 32 | | +//! | `R_X86_64_TLSDESC_CALL` | 35 | NONE | | +//! | `R_X86_64_TLSDESC` | 36 | 64 × 2 | | +//! | `R_X86_64_IRELATIVE` | 37 | 64 | indirect (B + A) | +//! +//! TLS information is at http://people.redhat.com/aoliva/writeups/TLS/RFC-TLSDESC-x86.txt +//! +//! `R_X86_64_IRELATIVE` is similar to `R_X86_64_RELATIVE` except that +//! the value used in this relocation is the program address returned by the function, +//! which takes no arguments, at the address of the result of the corresponding +//! `R_X86_64_RELATIVE` relocation. +//! +//! Read more https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html + +include!("constants_relocation.rs"); + +macro_rules! elf_reloc { + ($size:ident, $isize:ty) => { + use core::fmt; + #[cfg(feature = "alloc")] + use scroll::{Pread, Pwrite, SizeWith}; + #[repr(C)] + #[derive(Clone, Copy, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// Relocation with an explicit addend + pub struct Rela { + /// Address + pub r_offset: $size, + /// Relocation type and symbol index + pub r_info: $size, + /// Addend + pub r_addend: $isize, + } + #[repr(C)] + #[derive(Clone, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// Relocation without an addend + pub struct Rel { + /// address + pub r_offset: $size, + /// relocation type and symbol address + pub r_info: $size, + } + use plain; + unsafe impl plain::Plain for Rela {} + unsafe impl plain::Plain for Rel {} + + impl fmt::Debug for Rela { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let sym = r_sym(self.r_info); + let typ = r_type(self.r_info); + f.debug_struct("Rela") + .field("r_offset", &format_args!("{:x}", self.r_offset)) + .field("r_info", &format_args!("{:x}", self.r_info)) + .field("r_addend", &format_args!("{:x}", self.r_addend)) + .field("r_typ", &typ) + .field("r_sym", &sym) + .finish() + } + } + impl fmt::Debug for Rel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let sym = r_sym(self.r_info); + let typ = r_type(self.r_info); + f.debug_struct("Rel") + .field("r_offset", &format_args!("{:x}", self.r_offset)) + .field("r_info", &format_args!("{:x}", self.r_info)) + .field("r_typ", &typ) + .field("r_sym", &sym) + .finish() + } + } + }; +} + +macro_rules! elf_rela_std_impl { + ($size:ident, $isize:ty) => { + if_alloc! { + use crate::elf::reloc::Reloc; + + use core::slice; + + if_std! { + use crate::error::Result; + + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + } + + impl From<Rela> for Reloc { + fn from(rela: Rela) -> Self { + Reloc { + r_offset: u64::from(rela.r_offset), + r_addend: Some(i64::from(rela.r_addend)), + r_sym: r_sym(rela.r_info) as usize, + r_type: r_type(rela.r_info), + } + } + } + + impl From<Rel> for Reloc { + fn from(rel: Rel) -> Self { + Reloc { + r_offset: u64::from(rel.r_offset), + r_addend: None, + r_sym: r_sym(rel.r_info) as usize, + r_type: r_type(rel.r_info), + } + } + } + + impl From<Reloc> for Rela { + fn from(rela: Reloc) -> Self { + let r_info = r_info(rela.r_sym as $size, $size::from(rela.r_type)); + Rela { + r_offset: rela.r_offset as $size, + r_info: r_info, + r_addend: rela.r_addend.unwrap_or(0) as $isize, + } + } + } + + impl From<Reloc> for Rel { + fn from(rel: Reloc) -> Self { + let r_info = r_info(rel.r_sym as $size, $size::from(rel.r_type)); + Rel { + r_offset: rel.r_offset as $size, + r_info: r_info, + } + } + } + + /// Gets the rela entries given a rela pointer and the _size_ of the rela section in the binary, + /// in bytes. + /// Assumes the pointer is valid and can safely return a slice of memory pointing to the relas because: + /// 1. `ptr` points to memory received from the kernel (i.e., it loaded the executable), _or_ + /// 2. The binary has already been mmapped (i.e., it's a `SharedObject`), and hence it's safe to return a slice of that memory. + /// 3. Or if you obtained the pointer in some other lawful manner + pub unsafe fn from_raw_rela<'a>(ptr: *const Rela, size: usize) -> &'a [Rela] { + slice::from_raw_parts(ptr, size / SIZEOF_RELA) + } + + /// Gets the rel entries given a rel pointer and the _size_ of the rel section in the binary, + /// in bytes. + /// Assumes the pointer is valid and can safely return a slice of memory pointing to the rels because: + /// 1. `ptr` points to memory received from the kernel (i.e., it loaded the executable), _or_ + /// 2. The binary has already been mmapped (i.e., it's a `SharedObject`), and hence it's safe to return a slice of that memory. + /// 3. Or if you obtained the pointer in some other lawful manner + pub unsafe fn from_raw_rel<'a>(ptr: *const Rel, size: usize) -> &'a [Rel] { + slice::from_raw_parts(ptr, size / SIZEOF_REL) + } + + #[cfg(feature = "std")] + pub fn from_fd(fd: &mut File, offset: usize, size: usize) -> Result<Vec<Rela>> { + let count = size / SIZEOF_RELA; + let mut relocs = vec![Rela::default(); count]; + fd.seek(Start(offset as u64))?; + unsafe { + fd.read_exact(plain::as_mut_bytes(&mut *relocs))?; + } + Ok(relocs) + } + } // end if_alloc + }; +} + +pub mod reloc32 { + + pub use crate::elf::reloc::*; + + elf_reloc!(u32, i32); + + pub const SIZEOF_RELA: usize = 4 + 4 + 4; + pub const SIZEOF_REL: usize = 4 + 4; + + #[inline(always)] + pub fn r_sym(info: u32) -> u32 { + info >> 8 + } + + #[inline(always)] + pub fn r_type(info: u32) -> u32 { + info & 0xff + } + + #[inline(always)] + pub fn r_info(sym: u32, typ: u32) -> u32 { + (sym << 8) + (typ & 0xff) + } + + elf_rela_std_impl!(u32, i32); +} + +pub mod reloc64 { + pub use crate::elf::reloc::*; + + elf_reloc!(u64, i64); + + pub const SIZEOF_RELA: usize = 8 + 8 + 8; + pub const SIZEOF_REL: usize = 8 + 8; + + #[inline(always)] + pub fn r_sym(info: u64) -> u32 { + (info >> 32) as u32 + } + + #[inline(always)] + pub fn r_type(info: u64) -> u32 { + (info & 0xffff_ffff) as u32 + } + + #[inline(always)] + pub fn r_info(sym: u64, typ: u64) -> u64 { + (sym << 32) + typ + } + + elf_rela_std_impl!(u64, i64); +} + +////////////////////////////// +// Generic Reloc +///////////////////////////// +if_alloc! { + use scroll::{ctx, Pread}; + use scroll::ctx::SizeWith; + use core::fmt; + use core::result; + use crate::container::{Ctx, Container}; + use alloc::vec::Vec; + + #[derive(Clone, Copy, PartialEq, Default)] + /// A unified ELF relocation structure + pub struct Reloc { + /// Address + pub r_offset: u64, + /// Addend + pub r_addend: Option<i64>, + /// The index into the corresponding symbol table - either dynamic or regular + pub r_sym: usize, + /// The relocation type + pub r_type: u32, + } + + impl Reloc { + pub fn size(is_rela: bool, ctx: Ctx) -> usize { + use scroll::ctx::SizeWith; + Reloc::size_with(&(is_rela, ctx)) + } + } + + type RelocCtx = (bool, Ctx); + + impl ctx::SizeWith<RelocCtx> for Reloc { + fn size_with( &(is_rela, Ctx { container, .. }): &RelocCtx) -> usize { + match container { + Container::Little => { + if is_rela { reloc32::SIZEOF_RELA } else { reloc32::SIZEOF_REL } + }, + Container::Big => { + if is_rela { reloc64::SIZEOF_RELA } else { reloc64::SIZEOF_REL } + } + } + } + } + + impl<'a> ctx::TryFromCtx<'a, RelocCtx> for Reloc { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], (is_rela, Ctx { container, le }): RelocCtx) -> result::Result<(Self, usize), Self::Error> { + use scroll::Pread; + let reloc = match container { + Container::Little => { + if is_rela { + (bytes.pread_with::<reloc32::Rela>(0, le)?.into(), reloc32::SIZEOF_RELA) + } else { + (bytes.pread_with::<reloc32::Rel>(0, le)?.into(), reloc32::SIZEOF_REL) + } + }, + Container::Big => { + if is_rela { + (bytes.pread_with::<reloc64::Rela>(0, le)?.into(), reloc64::SIZEOF_RELA) + } else { + (bytes.pread_with::<reloc64::Rel>(0, le)?.into(), reloc64::SIZEOF_REL) + } + } + }; + Ok(reloc) + } + } + + impl ctx::TryIntoCtx<RelocCtx> for Reloc { + type Error = crate::error::Error; + /// Writes the relocation into `bytes` + fn try_into_ctx(self, bytes: &mut [u8], (is_rela, Ctx {container, le}): RelocCtx) -> result::Result<usize, Self::Error> { + use scroll::Pwrite; + match container { + Container::Little => { + if is_rela { + let rela: reloc32::Rela = self.into(); + Ok(bytes.pwrite_with(rela, 0, le)?) + } else { + let rel: reloc32::Rel = self.into(); + Ok(bytes.pwrite_with(rel, 0, le)?) + } + }, + Container::Big => { + if is_rela { + let rela: reloc64::Rela = self.into(); + Ok(bytes.pwrite_with(rela, 0, le)?) + } else { + let rel: reloc64::Rel = self.into(); + Ok(bytes.pwrite_with(rel, 0, le)?) + } + }, + } + } + } + + impl ctx::IntoCtx<(bool, Ctx)> for Reloc { + /// Writes the relocation into `bytes` + fn into_ctx(self, bytes: &mut [u8], ctx: RelocCtx) { + use scroll::Pwrite; + bytes.pwrite_with(self, 0, ctx).unwrap(); + } + } + + impl fmt::Debug for Reloc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Reloc") + .field("r_offset", &format_args!("{:x}", self.r_offset)) + .field("r_addend", &format_args!("{:x}", self.r_addend.unwrap_or(0))) + .field("r_sym", &self.r_sym) + .field("r_type", &self.r_type) + .finish() + } + } + + #[derive(Default)] + /// An ELF section containing relocations, allowing lazy iteration over symbols. + pub struct RelocSection<'a> { + bytes: &'a [u8], + count: usize, + ctx: RelocCtx, + start: usize, + end: usize, + } + + impl<'a> fmt::Debug for RelocSection<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let len = self.bytes.len(); + fmt.debug_struct("RelocSection") + .field("bytes", &len) + .field("range", &format!("{:#x}..{:#x}", self.start, self.end)) + .field("count", &self.count) + .field("Relocations", &self.to_vec()) + .finish() + } + } + + impl<'a> RelocSection<'a> { + #[cfg(feature = "endian_fd")] + /// Parse a REL or RELA section of size `filesz` from `offset`. + pub fn parse(bytes: &'a [u8], offset: usize, filesz: usize, is_rela: bool, ctx: Ctx) -> crate::error::Result<RelocSection<'a>> { + // TODO: better error message when too large (see symtab implementation) + let bytes = bytes.pread_with(offset, filesz)?; + + Ok(RelocSection { + bytes: bytes, + count: filesz / Reloc::size(is_rela, ctx), + ctx: (is_rela, ctx), + start: offset, + end: offset + filesz, + }) + } + + /// Try to parse a single relocation from the binary, at `index`. + #[inline] + pub fn get(&self, index: usize) -> Option<Reloc> { + if index >= self.count { + None + } else { + Some(self.bytes.pread_with(index * Reloc::size_with(&self.ctx), self.ctx).unwrap()) + } + } + + /// The number of relocations in the section. + #[inline] + pub fn len(&self) -> usize { + self.count + } + + /// Returns true if section has no relocations. + #[inline] + pub fn is_empty(&self) -> bool { + self.count == 0 + } + + /// Iterate over all relocations. + pub fn iter(&self) -> RelocIterator<'a> { + self.into_iter() + } + + /// Parse all relocations into a vector. + pub fn to_vec(&self) -> Vec<Reloc> { + self.iter().collect() + } + } + + impl<'a, 'b> IntoIterator for &'b RelocSection<'a> { + type Item = <RelocIterator<'a> as Iterator>::Item; + type IntoIter = RelocIterator<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + RelocIterator { + bytes: self.bytes, + offset: 0, + index: 0, + count: self.count, + ctx: self.ctx, + } + } + } + + pub struct RelocIterator<'a> { + bytes: &'a [u8], + offset: usize, + index: usize, + count: usize, + ctx: RelocCtx, + } + + impl<'a> fmt::Debug for RelocIterator<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("RelocIterator") + .field("bytes", &"<... redacted ...>") + .field("offset", &self.offset) + .field("index", &self.index) + .field("count", &self.count) + .field("ctx", &self.ctx) + .finish() + } + } + + impl<'a> Iterator for RelocIterator<'a> { + type Item = Reloc; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + if self.index >= self.count { + None + } else { + self.index += 1; + Some(self.bytes.gread_with(&mut self.offset, self.ctx).unwrap()) + } + } + } + + impl<'a> ExactSizeIterator for RelocIterator<'a> { + #[inline] + fn len(&self) -> usize { + self.count - self.index + } + } +} // end if_alloc diff --git a/third_party/rust/goblin/src/elf/section_header.rs b/third_party/rust/goblin/src/elf/section_header.rs new file mode 100644 index 0000000000..3bd891cc46 --- /dev/null +++ b/third_party/rust/goblin/src/elf/section_header.rs @@ -0,0 +1,581 @@ +macro_rules! elf_section_header { + ($size:ident) => { + // XXX: Do not import scroll traits here. + // See: https://github.com/rust-lang/rust/issues/65090#issuecomment-538668155 + + #[repr(C)] + #[derive(Copy, Clone, Eq, PartialEq, Default)] + #[cfg_attr( + feature = "alloc", + derive(scroll::Pread, scroll::Pwrite, scroll::SizeWith) + )] + /// Section Headers are typically used by humans and static linkers for additional information or how to relocate the object + /// + /// **NOTE** section headers are strippable from a binary without any loss of portability/executability; _do not_ rely on them being there! + pub struct SectionHeader { + /// Section name (string tbl index) + pub sh_name: u32, + /// Section type + pub sh_type: u32, + /// Section flags + pub sh_flags: $size, + /// Section virtual addr at execution + pub sh_addr: $size, + /// Section file offset + pub sh_offset: $size, + /// Section size in bytes + pub sh_size: $size, + /// Link to another section + pub sh_link: u32, + /// Additional section information + pub sh_info: u32, + /// Section alignment + pub sh_addralign: $size, + /// Entry size if section holds table + pub sh_entsize: $size, + } + + use plain; + // Declare that this is a plain type. + unsafe impl plain::Plain for SectionHeader {} + + impl ::core::fmt::Debug for SectionHeader { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.debug_struct("SectionHeader") + .field("sh_name", &self.sh_name) + .field("sh_type", &sht_to_str(self.sh_type)) + .field("sh_flags", &format_args!("0x{:x}", self.sh_flags)) + .field("sh_addr", &format_args!("0x{:x}", self.sh_addr)) + .field("sh_offset", &format_args!("0x{:x}", self.sh_offset)) + .field("sh_size", &format_args!("0x{:x}", self.sh_size)) + .field("sh_link", &format_args!("0x{:x}", self.sh_link)) + .field("sh_info", &format_args!("0x{:x}", self.sh_info)) + .field("sh_addralign", &format_args!("0x{:x}", self.sh_addralign)) + .field("sh_entsize", &format_args!("0x{:x}", self.sh_entsize)) + .finish() + } + } + }; +} + +/// Undefined section. +pub const SHN_UNDEF: u32 = 0; +/// Start of reserved indices. +pub const SHN_LORESERVE: u32 = 0xff00; +/// Start of processor-specific. +pub const SHN_LOPROC: u32 = 0xff00; +/// Order section before all others (Solaris). +pub const SHN_BEFORE: u32 = 0xff00; +/// Order section after all others (Solaris). +pub const SHN_AFTER: u32 = 0xff01; +/// End of processor-specific. +pub const SHN_HIPROC: u32 = 0xff1f; +/// Start of OS-specific. +pub const SHN_LOOS: u32 = 0xff20; +/// End of OS-specific. +pub const SHN_HIOS: u32 = 0xff3f; +/// Associated symbol is absolute. +pub const SHN_ABS: u32 = 0xfff1; +/// Associated symbol is common. +pub const SHN_COMMON: u32 = 0xfff2; +/// Index is in extra table. +pub const SHN_XINDEX: u32 = 0xffff; +/// End of reserved indices. +pub const SHN_HIRESERVE: u32 = 0xffff; + +// === Legal values for sh_type (section type). === +/// Section header table entry unused. +pub const SHT_NULL: u32 = 0; +/// Program data. +pub const SHT_PROGBITS: u32 = 1; +/// Symbol table. +pub const SHT_SYMTAB: u32 = 2; +/// String table. +pub const SHT_STRTAB: u32 = 3; +/// Relocation entries with addends. +pub const SHT_RELA: u32 = 4; +/// Symbol hash table. +pub const SHT_HASH: u32 = 5; +/// Dynamic linking information. +pub const SHT_DYNAMIC: u32 = 6; +/// Notes. +pub const SHT_NOTE: u32 = 7; +/// Program space with no data (bss). +pub const SHT_NOBITS: u32 = 8; +/// Relocation entries, no addends. +pub const SHT_REL: u32 = 9; +/// Reserved. +pub const SHT_SHLIB: u32 = 10; +/// Dynamic linker symbol table. +pub const SHT_DYNSYM: u32 = 11; +/// Array of constructors. +pub const SHT_INIT_ARRAY: u32 = 14; +/// Array of destructors. +pub const SHT_FINI_ARRAY: u32 = 15; +/// Array of pre-constructors. +pub const SHT_PREINIT_ARRAY: u32 = 16; +/// Section group. +pub const SHT_GROUP: u32 = 17; +/// Extended section indeces. +pub const SHT_SYMTAB_SHNDX: u32 = 18; +/// Number of defined types. +pub const SHT_NUM: u32 = 19; +/// Start OS-specific. +pub const SHT_LOOS: u32 = 0x6000_0000; +/// Object attributes. +pub const SHT_GNU_ATTRIBUTES: u32 = 0x6fff_fff5; +/// GNU-style hash table. +pub const SHT_GNU_HASH: u32 = 0x6fff_fff6; +/// Prelink library list. +pub const SHT_GNU_LIBLIST: u32 = 0x6fff_fff7; +/// Checksum for DSO content. +pub const SHT_CHECKSUM: u32 = 0x6fff_fff8; +/// Sun-specific low bound. +pub const SHT_LOSUNW: u32 = 0x6fff_fffa; +pub const SHT_SUNW_MOVE: u32 = 0x6fff_fffa; +pub const SHT_SUNW_COMDAT: u32 = 0x6fff_fffb; +pub const SHT_SUNW_SYMINFO: u32 = 0x6fff_fffc; +/// Version definition section. +pub const SHT_GNU_VERDEF: u32 = 0x6fff_fffd; +/// Version needs section. +pub const SHT_GNU_VERNEED: u32 = 0x6fff_fffe; +/// Version symbol table. +pub const SHT_GNU_VERSYM: u32 = 0x6fff_ffff; +/// Sun-specific high bound. +pub const SHT_HISUNW: u32 = 0x6fff_ffff; +/// End OS-specific type. +pub const SHT_HIOS: u32 = 0x6fff_ffff; +/// Start of processor-specific. +pub const SHT_LOPROC: u32 = 0x7000_0000; +/// X86-64 unwind information. +pub const SHT_X86_64_UNWIND: u32 = 0x7000_0001; +/// End of processor-specific. +pub const SHT_HIPROC: u32 = 0x7fff_ffff; +/// Start of application-specific. +pub const SHT_LOUSER: u32 = 0x8000_0000; +/// End of application-specific. +pub const SHT_HIUSER: u32 = 0x8fff_ffff; + +// Legal values for sh_flags (section flags) +/// Writable. +pub const SHF_WRITE: u32 = 0x1; +/// Occupies memory during execution. +pub const SHF_ALLOC: u32 = 0x2; +/// Executable. +pub const SHF_EXECINSTR: u32 = 0x4; +/// Might be merged. +pub const SHF_MERGE: u32 = 0x10; +/// Contains nul-terminated strings. +pub const SHF_STRINGS: u32 = 0x20; +/// `sh_info' contains SHT index. +pub const SHF_INFO_LINK: u32 = 0x40; +/// Preserve order after combining. +pub const SHF_LINK_ORDER: u32 = 0x80; +/// Non-standard OS specific handling required. +pub const SHF_OS_NONCONFORMING: u32 = 0x100; +/// Section is member of a group. +pub const SHF_GROUP: u32 = 0x200; +/// Section hold thread-local data. +pub const SHF_TLS: u32 = 0x400; +/// Section with compressed data. +pub const SHF_COMPRESSED: u32 = 0x800; +/// OS-specific.. +pub const SHF_MASKOS: u32 = 0x0ff0_0000; +/// Processor-specific. +pub const SHF_MASKPROC: u32 = 0xf000_0000; +/// Special ordering requirement (Solaris). +pub const SHF_ORDERED: u32 = 1 << 30; +/// Number of "regular" section header flags +pub const SHF_NUM_REGULAR_FLAGS: usize = 12; +/// Section is excluded unless referenced or allocated (Solaris). +pub const SHF_EXCLUDE: u32 = 0x80000000; // 1U << 31 + +pub const SHF_FLAGS: [u32; SHF_NUM_REGULAR_FLAGS] = [ + SHF_WRITE, + SHF_ALLOC, + SHF_EXECINSTR, + SHF_MERGE, + SHF_STRINGS, + SHF_INFO_LINK, + SHF_LINK_ORDER, + SHF_OS_NONCONFORMING, + SHF_GROUP, + SHF_TLS, + SHF_COMPRESSED, + SHF_ORDERED, +]; + +pub fn sht_to_str(sht: u32) -> &'static str { + match sht { + SHT_NULL => "SHT_NULL", + SHT_PROGBITS => "SHT_PROGBITS", + SHT_SYMTAB => "SHT_SYMTAB", + SHT_STRTAB => "SHT_STRTAB", + SHT_RELA => "SHT_RELA", + SHT_HASH => "SHT_HASH", + SHT_DYNAMIC => "SHT_DYNAMIC", + SHT_NOTE => "SHT_NOTE", + SHT_NOBITS => "SHT_NOBITS", + SHT_REL => "SHT_REL", + SHT_SHLIB => "SHT_SHLIB", + SHT_DYNSYM => "SHT_DYNSYM", + SHT_INIT_ARRAY => "SHT_INIT_ARRAY", + SHT_FINI_ARRAY => "SHT_FINI_ARRAY", + SHT_PREINIT_ARRAY => "SHT_PREINIT_ARRAY", + SHT_GROUP => "SHT_GROUP", + SHT_SYMTAB_SHNDX => "SHT_SYMTAB_SHNDX", + SHT_NUM => "SHT_NUM", + SHT_LOOS => "SHT_LOOS", + SHT_GNU_ATTRIBUTES => "SHT_GNU_ATTRIBUTES", + SHT_GNU_HASH => "SHT_GNU_HASH", + SHT_GNU_LIBLIST => "SHT_GNU_LIBLIST", + SHT_CHECKSUM => "SHT_CHECKSUM", + SHT_SUNW_MOVE => "SHT_SUNW_MOVE", + SHT_SUNW_COMDAT => "SHT_SUNW_COMDAT", + SHT_SUNW_SYMINFO => "SHT_SUNW_SYMINFO", + SHT_GNU_VERDEF => "SHT_GNU_VERDEF", + SHT_GNU_VERNEED => "SHT_GNU_VERNEED", + SHT_GNU_VERSYM => "SHT_GNU_VERSYM", + SHT_LOPROC => "SHT_LOPROC", + SHT_X86_64_UNWIND => "SHT_X86_64_UNWIND", + SHT_HIPROC => "SHT_HIPROC", + SHT_LOUSER => "SHT_LOUSER", + SHT_HIUSER => "SHT_HIUSER", + _ => "UNKNOWN_SHT", + } +} + +pub fn shf_to_str(shf: u32) -> &'static str { + match shf { + SHF_WRITE => "SHF_WRITE", + SHF_ALLOC => "SHF_ALLOC", + SHF_EXECINSTR => "SHF_EXECINSTR", + SHF_MERGE => "SHF_MERGE", + SHF_STRINGS => "SHF_STRINGS", + SHF_INFO_LINK => "SHF_INFO_LINK", + SHF_LINK_ORDER => "SHF_LINK_ORDER", + SHF_OS_NONCONFORMING => "SHF_OS_NONCONFORMING", + SHF_GROUP => "SHF_GROUP", + SHF_TLS => "SHF_TLS", + SHF_COMPRESSED => "SHF_COMPRESSED", + //SHF_MASKOS..SHF_MASKPROC => "SHF_OSFLAG", + SHF_ORDERED => "SHF_ORDERED", + _ => "SHF_UNKNOWN", + } +} + +macro_rules! elf_section_header_std_impl { ($size:ty) => { + + #[cfg(test)] + mod tests { + use super::*; + #[test] + fn size_of() { + assert_eq!(::std::mem::size_of::<SectionHeader>(), SIZEOF_SHDR); + } + } + + if_alloc! { + use crate::elf::section_header::SectionHeader as ElfSectionHeader; + + use plain::Plain; + use alloc::vec::Vec; + + if_std! { + use crate::error::Result; + + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + } + + impl From<SectionHeader> for ElfSectionHeader { + fn from(sh: SectionHeader) -> Self { + ElfSectionHeader { + sh_name: sh.sh_name as usize, + sh_type: sh.sh_type, + sh_flags: u64::from(sh.sh_flags), + sh_addr: u64::from(sh.sh_addr), + sh_offset: u64::from(sh.sh_offset), + sh_size: u64::from(sh.sh_size), + sh_link: sh.sh_link, + sh_info: sh.sh_info, + sh_addralign: u64::from(sh.sh_addralign), + sh_entsize: u64::from(sh.sh_entsize), + } + } + } + impl From<ElfSectionHeader> for SectionHeader { + fn from(sh: ElfSectionHeader) -> Self { + SectionHeader { + sh_name : sh.sh_name as u32, + sh_type : sh.sh_type, + sh_flags : sh.sh_flags as $size, + sh_addr : sh.sh_addr as $size, + sh_offset : sh.sh_offset as $size, + sh_size : sh.sh_size as $size, + sh_link : sh.sh_link, + sh_info : sh.sh_info, + sh_addralign: sh.sh_addralign as $size, + sh_entsize : sh.sh_entsize as $size, + } + } + } + + impl SectionHeader { + // FIXME: > 65535 sections + pub fn from_bytes(bytes: &[u8], shnum: usize) -> Vec<SectionHeader> { + let mut shdrs = vec![SectionHeader::default(); shnum]; + shdrs.copy_from_bytes(bytes).expect("buffer is too short for given number of entries"); + shdrs + } + + #[cfg(feature = "std")] + // FIXME: > 65535 sections + pub fn from_fd(fd: &mut File, offset: u64, shnum: usize) -> Result<Vec<SectionHeader>> { + let mut shdrs = vec![SectionHeader::default(); shnum]; + fd.seek(Start(offset))?; + unsafe { + fd.read_exact(plain::as_mut_bytes(&mut *shdrs))?; + } + Ok(shdrs) + } + } + } // end if_alloc +};} + +pub mod section_header32 { + pub use crate::elf::section_header::*; + + elf_section_header!(u32); + + pub const SIZEOF_SHDR: usize = 40; + + elf_section_header_std_impl!(u32); +} + +pub mod section_header64 { + + pub use crate::elf::section_header::*; + + elf_section_header!(u64); + + pub const SIZEOF_SHDR: usize = 64; + + elf_section_header_std_impl!(u64); +} + +/////////////////////////////// +// Std/analysis/Unified Structs +/////////////////////////////// + +if_alloc! { + use crate::error; + use core::fmt; + use core::result; + use core::ops::Range; + use scroll::ctx; + use crate::container::{Container, Ctx}; + + #[cfg(feature = "endian_fd")] + use alloc::vec::Vec; + + #[derive(Default, PartialEq, Clone)] + /// A unified SectionHeader - convertable to and from 32-bit and 64-bit variants + pub struct SectionHeader { + /// Section name (string tbl index) + pub sh_name: usize, + /// Section type + pub sh_type: u32, + /// Section flags + pub sh_flags: u64, + /// Section virtual addr at execution + pub sh_addr: u64, + /// Section file offset + pub sh_offset: u64, + /// Section size in bytes + pub sh_size: u64, + /// Link to another section + pub sh_link: u32, + /// Additional section information + pub sh_info: u32, + /// Section alignment + pub sh_addralign: u64, + /// Entry size if section holds table + pub sh_entsize: u64, + } + + impl SectionHeader { + /// Return the size of the underlying program header, given a `container` + #[inline] + pub fn size(ctx: Ctx) -> usize { + use scroll::ctx::SizeWith; + Self::size_with(&ctx) + } + pub fn new() -> Self { + SectionHeader { + sh_name: 0, + sh_type: SHT_PROGBITS, + sh_flags: u64::from(SHF_ALLOC), + sh_addr: 0, + sh_offset: 0, + sh_size: 0, + sh_link: 0, + sh_info: 0, + sh_addralign: 2 << 8, + sh_entsize: 0, + } + } + /// Returns this section header's file offset range, + /// if the section occupies space in fhe file. + pub fn file_range(&self) -> Option<Range<usize>> { + // Sections with type SHT_NOBITS have no data in the file itself, + // they only exist in memory. + if self.sh_type == SHT_NOBITS { + None + } else { + Some(self.sh_offset as usize..(self.sh_offset as usize).saturating_add(self.sh_size as usize)) + } + } + /// Returns this section header's virtual memory range + pub fn vm_range(&self) -> Range<usize> { + self.sh_addr as usize..(self.sh_addr as usize).saturating_add(self.sh_size as usize) + } + /// Parse `count` section headers from `bytes` at `offset`, using the given `ctx` + #[cfg(feature = "endian_fd")] + pub fn parse(bytes: &[u8], mut offset: usize, mut count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> { + use scroll::Pread; + // Zero offset means no section headers, not even the null section header. + if offset == 0 { + return Ok(Vec::new()); + } + let empty_sh = bytes.gread_with::<SectionHeader>(&mut offset, ctx)?; + if count == 0 as usize { + // Zero count means either no section headers if offset is also zero (checked + // above), or the number of section headers overflows SHN_LORESERVE, in which + // case the count is stored in the sh_size field of the null section header. + count = empty_sh.sh_size as usize; + } + + // Sanity check to avoid OOM + if count > bytes.len() / Self::size(ctx) { + return Err(error::Error::BufferTooShort(count, "section headers")); + } + let mut section_headers = Vec::with_capacity(count); + section_headers.push(empty_sh); + for _ in 1..count { + let shdr = bytes.gread_with(&mut offset, ctx)?; + section_headers.push(shdr); + } + Ok(section_headers) + } + pub fn check_size(&self, size: usize) -> error::Result<()> { + if self.sh_type == SHT_NOBITS { + return Ok(()); + } + let (end, overflow) = self.sh_offset.overflowing_add(self.sh_size); + if overflow || end > size as u64 { + let message = format!("Section {} size ({}) + offset ({}) is out of bounds. Overflowed: {}", + self.sh_name, self.sh_offset, self.sh_size, overflow); + return Err(error::Error::Malformed(message)); + } + let (_, overflow) = self.sh_addr.overflowing_add(self.sh_size); + if overflow { + let message = format!("Section {} size ({}) + addr ({}) is out of bounds. Overflowed: {}", + self.sh_name, self.sh_addr, self.sh_size, overflow); + return Err(error::Error::Malformed(message)); + } + Ok(()) + } + pub fn is_relocation(&self) -> bool { + self.sh_type == SHT_RELA + } + pub fn is_executable(&self) -> bool { + self.is_alloc() && self.sh_flags as u32 & SHF_EXECINSTR == SHF_EXECINSTR + } + pub fn is_writable(&self) -> bool { + self.is_alloc() && self.sh_flags as u32 & SHF_WRITE == SHF_WRITE + } + pub fn is_alloc(&self) -> bool { + self.sh_flags as u32 & SHF_ALLOC == SHF_ALLOC + } + } + + impl fmt::Debug for SectionHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SectionHeader") + .field("sh_name", &self.sh_name) + .field("sh_type", &sht_to_str(self.sh_type)) + .field("sh_flags", &format_args!("0x{:x}", self.sh_flags)) + .field("sh_addr", &format_args!("0x{:x}", self.sh_addr)) + .field("sh_offset", &format_args!("0x{:x}", self.sh_offset)) + .field("sh_size", &format_args!("0x{:x}", self.sh_size)) + .field("sh_link", &format_args!("0x{:x}", self.sh_link)) + .field("sh_info", &format_args!("0x{:x}", self.sh_info)) + .field("sh_addralign", &format_args!("0x{:x}", self.sh_addralign)) + .field("sh_entsize", &format_args!("0x{:x}", self.sh_entsize)) + .finish() + } + } + + impl ctx::SizeWith<Ctx> for SectionHeader { + fn size_with( &Ctx { container, .. }: &Ctx) -> usize { + match container { + Container::Little => { + section_header32::SIZEOF_SHDR + }, + Container::Big => { + section_header64::SIZEOF_SHDR + }, + } + } + } + + impl<'a> ctx::TryFromCtx<'a, Ctx> for SectionHeader { + type Error = crate::error::Error; + fn try_from_ctx(bytes: &'a [u8], Ctx {container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> { + use scroll::Pread; + let res = match container { + Container::Little => { + (bytes.pread_with::<section_header32::SectionHeader>(0, le)?.into(), section_header32::SIZEOF_SHDR) + }, + Container::Big => { + (bytes.pread_with::<section_header64::SectionHeader>(0, le)?.into(), section_header64::SIZEOF_SHDR) + } + }; + Ok(res) + } + } + + impl ctx::TryIntoCtx<Ctx> for SectionHeader { + type Error = crate::error::Error; + fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> { + use scroll::Pwrite; + match container { + Container::Little => { + let shdr: section_header32::SectionHeader = self.into(); + Ok(bytes.pwrite_with(shdr, 0, le)?) + }, + Container::Big => { + let shdr: section_header64::SectionHeader = self.into(); + Ok(bytes.pwrite_with(shdr, 0, le)?) + } + } + } + } + impl ctx::IntoCtx<Ctx> for SectionHeader { + fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) { + use scroll::Pwrite; + match container { + Container::Little => { + let shdr: section_header32::SectionHeader = self.into(); + bytes.pwrite_with(shdr, 0, le).unwrap(); + }, + Container::Big => { + let shdr: section_header64::SectionHeader = self.into(); + bytes.pwrite_with(shdr, 0, le).unwrap(); + } + } + } + } +} // end if_alloc diff --git a/third_party/rust/goblin/src/elf/sym.rs b/third_party/rust/goblin/src/elf/sym.rs new file mode 100644 index 0000000000..a13e7abcfd --- /dev/null +++ b/third_party/rust/goblin/src/elf/sym.rs @@ -0,0 +1,607 @@ +/// === Sym bindings === +/// Local symbol. +pub const STB_LOCAL: u8 = 0; +/// Global symbol. +pub const STB_GLOBAL: u8 = 1; +/// Weak symbol. +pub const STB_WEAK: u8 = 2; +/// Number of defined types.. +pub const STB_NUM: u8 = 3; +/// Start of OS-specific. +pub const STB_LOOS: u8 = 10; +/// Unique symbol.. +pub const STB_GNU_UNIQUE: u8 = 10; +/// End of OS-specific. +pub const STB_HIOS: u8 = 12; +/// Start of processor-specific. +pub const STB_LOPROC: u8 = 13; +/// End of processor-specific. +pub const STB_HIPROC: u8 = 15; + +/// === Sym types === +/// Symbol type is unspecified. +pub const STT_NOTYPE: u8 = 0; +/// Symbol is a data object. +pub const STT_OBJECT: u8 = 1; +/// Symbol is a code object. +pub const STT_FUNC: u8 = 2; +/// Symbol associated with a section. +pub const STT_SECTION: u8 = 3; +/// Symbol's name is file name. +pub const STT_FILE: u8 = 4; +/// Symbol is a common data object. +pub const STT_COMMON: u8 = 5; +/// Symbol is thread-local data object. +pub const STT_TLS: u8 = 6; +/// Number of defined types. +pub const STT_NUM: u8 = 7; +/// Start of OS-specific. +pub const STT_LOOS: u8 = 10; +/// Symbol is indirect code object. +pub const STT_GNU_IFUNC: u8 = 10; +/// End of OS-specific. +pub const STT_HIOS: u8 = 12; +/// Start of processor-specific. +pub const STT_LOPROC: u8 = 13; +/// End of processor-specific. +pub const STT_HIPROC: u8 = 15; + +/// === Sym visibility === +/// Default: Visibility is specified by the symbol's binding type +pub const STV_DEFAULT: u8 = 0; +/// Internal: use of this attribute is currently reserved. +pub const STV_INTERNAL: u8 = 1; +/// Hidden: Not visible to other components, necessarily protected. Binding scope becomes local +/// when the object is included in an executable or shared object. +pub const STV_HIDDEN: u8 = 2; +/// Protected: Symbol defined in current component is visible in other components, but cannot be preempted. +/// Any reference from within the defining component must be resolved to the definition in that +/// component. +pub const STV_PROTECTED: u8 = 3; +/// Exported: ensures a symbol remains global, cannot be demoted or eliminated by any other symbol +/// visibility technique. +pub const STV_EXPORTED: u8 = 4; +/// Singleton: ensures a symbol remains global, and that a single instance of the definition is +/// bound to by all references within a process. Cannot be demoted or eliminated. +pub const STV_SINGLETON: u8 = 5; +/// Eliminate: extends the hidden attribute. Not written in any symbol table of a dynamic +/// executable or shared object. +pub const STV_ELIMINATE: u8 = 6; + +/// Get the ST bind. +/// +/// This is the first four bits of the "info" byte. +#[inline] +pub fn st_bind(info: u8) -> u8 { + info >> 4 +} + +/// Get the ST type. +/// +/// This is the last four bits of the "info" byte. +#[inline] +pub fn st_type(info: u8) -> u8 { + info & 0xf +} + +/// Get the ST visibility. +/// +/// This is the last three bits of the "other" byte. +#[inline] +pub fn st_visibility(other: u8) -> u8 { + other & 0x7 +} + +/// Is this information defining an import? +#[inline] +pub fn is_import(info: u8, value: u64) -> bool { + let bind = st_bind(info); + bind == STB_GLOBAL && value == 0 +} + +/// Convenience function to get the &'static str type from the symbols `st_info`. +#[inline] +pub fn get_type(info: u8) -> &'static str { + type_to_str(st_type(info)) +} + +/// Get the string for some bind. +#[inline] +pub fn bind_to_str(typ: u8) -> &'static str { + match typ { + STB_LOCAL => "LOCAL", + STB_GLOBAL => "GLOBAL", + STB_WEAK => "WEAK", + STB_NUM => "NUM", + STB_GNU_UNIQUE => "GNU_UNIQUE", + _ => "UNKNOWN_STB", + } +} + +/// Get the string for some type. +#[inline] +pub fn type_to_str(typ: u8) -> &'static str { + match typ { + STT_NOTYPE => "NOTYPE", + STT_OBJECT => "OBJECT", + STT_FUNC => "FUNC", + STT_SECTION => "SECTION", + STT_FILE => "FILE", + STT_COMMON => "COMMON", + STT_TLS => "TLS", + STT_NUM => "NUM", + STT_GNU_IFUNC => "GNU_IFUNC", + _ => "UNKNOWN_STT", + } +} + +/// Get the string for some visibility +#[inline] +pub fn visibility_to_str(typ: u8) -> &'static str { + match typ { + STV_DEFAULT => "DEFAULT", + STV_INTERNAL => "INTERNAL", + STV_HIDDEN => "HIDDEN", + STV_PROTECTED => "PROTECTED", + STV_EXPORTED => "EXPORTED", + STV_SINGLETON => "SINGLETON", + STV_ELIMINATE => "ELIMINATE", + _ => "UNKNOWN_STV", + } +} + +macro_rules! elf_sym_std_impl { + ($size:ty) => { + #[cfg(test)] + mod tests { + use super::*; + #[test] + fn size_of() { + assert_eq!(::std::mem::size_of::<Sym>(), SIZEOF_SYM); + } + } + + use crate::elf::sym::Sym as ElfSym; + + use core::fmt; + use core::slice; + + impl Sym { + /// Checks whether this `Sym` has `STB_GLOBAL`/`STB_WEAK` bind and a `st_value` of 0 + #[inline] + pub fn is_import(&self) -> bool { + let bind = self.st_info >> 4; + (bind == STB_GLOBAL || bind == STB_WEAK) && self.st_value == 0 + } + /// Checks whether this `Sym` has type `STT_FUNC` + #[inline] + pub fn is_function(&self) -> bool { + st_type(self.st_info) == STT_FUNC + } + } + + impl From<Sym> for ElfSym { + #[inline] + fn from(sym: Sym) -> Self { + ElfSym { + st_name: sym.st_name as usize, + st_info: sym.st_info, + st_other: sym.st_other, + st_shndx: sym.st_shndx as usize, + st_value: u64::from(sym.st_value), + st_size: u64::from(sym.st_size), + } + } + } + + impl From<ElfSym> for Sym { + #[inline] + fn from(sym: ElfSym) -> Self { + Sym { + st_name: sym.st_name as u32, + st_info: sym.st_info, + st_other: sym.st_other, + st_shndx: sym.st_shndx as u16, + st_value: sym.st_value as $size, + st_size: sym.st_size as $size, + } + } + } + + impl fmt::Debug for Sym { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bind = st_bind(self.st_info); + let typ = st_type(self.st_info); + let vis = st_visibility(self.st_other); + f.debug_struct("Sym") + .field("st_name", &self.st_name) + .field("st_value", &format_args!("{:x}", self.st_value)) + .field("st_size", &self.st_size) + .field( + "st_info", + &format_args!( + "{:x} {} {}", + self.st_info, + bind_to_str(bind), + type_to_str(typ) + ), + ) + .field( + "st_other", + &format_args!("{} {}", self.st_other, visibility_to_str(vis)), + ) + .field("st_shndx", &self.st_shndx) + .finish() + } + } + + /// # Safety + /// + /// This function creates a `Sym` slice directly from a raw pointer + #[inline] + pub unsafe fn from_raw<'a>(symp: *const Sym, count: usize) -> &'a [Sym] { + slice::from_raw_parts(symp, count) + } + + if_std! { + use crate::error::Result; + + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + + pub fn from_fd(fd: &mut File, offset: usize, count: usize) -> Result<Vec<Sym>> { + // TODO: AFAIK this shouldn't work, since i pass in a byte size... + let mut syms = vec![Sym::default(); count]; + fd.seek(Start(offset as u64))?; + unsafe { + fd.read_exact(plain::as_mut_bytes(&mut *syms))?; + } + syms.dedup(); + Ok(syms) + } + } + }; +} + +#[cfg(feature = "alloc")] +use scroll::{Pread, Pwrite, SizeWith}; + +pub mod sym32 { + pub use crate::elf::sym::*; + + #[repr(C)] + #[derive(Clone, Copy, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// 32-bit Sym - used for both static and dynamic symbol information in a binary + pub struct Sym { + /// Symbol name (string tbl index) + pub st_name: u32, + /// Symbol value + pub st_value: u32, + /// Symbol size + pub st_size: u32, + /// Symbol type and binding + pub st_info: u8, + /// Symbol visibility + pub st_other: u8, + /// Section index + pub st_shndx: u16, + } + + // Declare that the type is plain. + unsafe impl plain::Plain for Sym {} + + pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 4 + 4; + + elf_sym_std_impl!(u32); +} + +pub mod sym64 { + pub use crate::elf::sym::*; + + #[repr(C)] + #[derive(Clone, Copy, PartialEq, Default)] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] + /// 64-bit Sym - used for both static and dynamic symbol information in a binary + pub struct Sym { + /// Symbol name (string tbl index) + pub st_name: u32, + /// Symbol type and binding + pub st_info: u8, + /// Symbol visibility + pub st_other: u8, + /// Section index + pub st_shndx: u16, + /// Symbol value + pub st_value: u64, + /// Symbol size + pub st_size: u64, + } + + // Declare that the type is plain. + unsafe impl plain::Plain for Sym {} + + pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 8 + 8; + + elf_sym_std_impl!(u64); +} + +use crate::container::{Container, Ctx}; +#[cfg(feature = "alloc")] +use crate::error::Result; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use core::fmt; +use scroll::ctx; +use scroll::ctx::SizeWith; + +#[derive(Clone, Copy, PartialEq, Default)] +/// A unified Sym definition - convertible to and from 32-bit and 64-bit variants +pub struct Sym { + pub st_name: usize, + pub st_info: u8, + pub st_other: u8, + pub st_shndx: usize, + pub st_value: u64, + pub st_size: u64, +} + +impl Sym { + #[inline] + pub fn size(container: Container) -> usize { + Self::size_with(&Ctx::from(container)) + } + /// Checks whether this `Sym` has `STB_GLOBAL`/`STB_WEAK` bind and a `st_value` of 0 + #[inline] + pub fn is_import(&self) -> bool { + let bind = self.st_bind(); + (bind == STB_GLOBAL || bind == STB_WEAK) && self.st_value == 0 + } + /// Checks whether this `Sym` has type `STT_FUNC` + #[inline] + pub fn is_function(&self) -> bool { + st_type(self.st_info) == STT_FUNC + } + /// Get the ST bind. + /// + /// This is the first four bits of the "info" byte. + #[inline] + pub fn st_bind(&self) -> u8 { + self.st_info >> 4 + } + /// Get the ST type. + /// + /// This is the last four bits of the "info" byte. + #[inline] + pub fn st_type(&self) -> u8 { + st_type(self.st_info) + } + /// Get the ST visibility. + /// + /// This is the last three bits of the "other" byte. + #[inline] + pub fn st_visibility(&self) -> u8 { + st_visibility(self.st_other) + } + #[cfg(feature = "endian_fd")] + /// Parse `count` vector of ELF symbols from `offset` + pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> Result<Vec<Sym>> { + if count > bytes.len() / Sym::size_with(&ctx) { + return Err(crate::error::Error::BufferTooShort(count, "symbols")); + } + let mut syms = Vec::with_capacity(count); + for _ in 0..count { + let sym = bytes.gread_with(&mut offset, ctx)?; + syms.push(sym); + } + Ok(syms) + } +} + +impl fmt::Debug for Sym { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bind = self.st_bind(); + let typ = self.st_type(); + let vis = self.st_visibility(); + f.debug_struct("Sym") + .field("st_name", &self.st_name) + .field( + "st_info", + &format_args!( + "0x{:x} {} {}", + self.st_info, + bind_to_str(bind), + type_to_str(typ) + ), + ) + .field( + "st_other", + &format_args!("{} {}", self.st_other, visibility_to_str(vis)), + ) + .field("st_shndx", &self.st_shndx) + .field("st_value", &format_args!("0x{:x}", self.st_value)) + .field("st_size", &self.st_size) + .finish() + } +} + +impl ctx::SizeWith<Ctx> for Sym { + #[inline] + fn size_with(&Ctx { container, .. }: &Ctx) -> usize { + match container { + Container::Little => sym32::SIZEOF_SYM, + Container::Big => sym64::SIZEOF_SYM, + } + } +} + +if_alloc! { + use core::result; + + impl<'a> ctx::TryFromCtx<'a, Ctx> for Sym { + type Error = crate::error::Error; + #[inline] + fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> { + let sym = match container { + Container::Little => { + (bytes.pread_with::<sym32::Sym>(0, le)?.into(), sym32::SIZEOF_SYM) + }, + Container::Big => { + (bytes.pread_with::<sym64::Sym>(0, le)?.into(), sym64::SIZEOF_SYM) + } + }; + Ok(sym) + } + } + + impl ctx::TryIntoCtx<Ctx> for Sym { + type Error = crate::error::Error; + #[inline] + fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> { + match container { + Container::Little => { + let sym: sym32::Sym = self.into(); + Ok(bytes.pwrite_with(sym, 0, le)?) + }, + Container::Big => { + let sym: sym64::Sym = self.into(); + Ok(bytes.pwrite_with(sym, 0, le)?) + } + } + } + } + + impl ctx::IntoCtx<Ctx> for Sym { + #[inline] + fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) { + match container { + Container::Little => { + let sym: sym32::Sym = self.into(); + bytes.pwrite_with(sym, 0, le).unwrap(); + }, + Container::Big => { + let sym: sym64::Sym = self.into(); + bytes.pwrite_with(sym, 0, le).unwrap(); + } + } + } + } +} + +if_alloc! { + #[derive(Default)] + /// An ELF symbol table, allowing lazy iteration over symbols + pub struct Symtab<'a> { + bytes: &'a [u8], + count: usize, + ctx: Ctx, + start: usize, + end: usize, + } + + impl<'a> fmt::Debug for Symtab<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let len = self.bytes.len(); + fmt.debug_struct("Symtab") + .field("bytes", &len) + .field("range", &format_args!("{:#x}..{:#x}", self.start, self.end)) + .field("count", &self.count) + .field("Symbols", &self.to_vec()) + .finish() + } + } + + impl<'a> Symtab<'a> { + /// Parse a table of `count` ELF symbols from `offset`. + pub fn parse(bytes: &'a [u8], offset: usize, count: usize, ctx: Ctx) -> Result<Symtab<'a>> { + let size = count + .checked_mul(Sym::size_with(&ctx)) + .ok_or_else(|| crate::error::Error::Malformed( + format!("Too many ELF symbols (offset {:#x}, count {})", offset, count) + ))?; + // TODO: make this a better error message when too large + let bytes = bytes.pread_with(offset, size)?; + Ok(Symtab { bytes, count, ctx, start: offset, end: offset+size }) + } + + /// Try to parse a single symbol from the binary, at `index`. + #[inline] + pub fn get(&self, index: usize) -> Option<Sym> { + if index >= self.count { + None + } else { + Some(self.bytes.pread_with(index * Sym::size_with(&self.ctx), self.ctx).unwrap()) + } + } + + /// The number of symbols in the table. + #[inline] + pub fn len(&self) -> usize { + self.count + } + + /// Returns true if table has no symbols. + #[inline] + pub fn is_empty(&self) -> bool { + self.count == 0 + } + + /// Iterate over all symbols. + #[inline] + pub fn iter(&self) -> SymIterator<'a> { + self.into_iter() + } + + /// Parse all symbols into a vector. + pub fn to_vec(&self) -> Vec<Sym> { + self.iter().collect() + } + } + + impl<'a, 'b> IntoIterator for &'b Symtab<'a> { + type Item = <SymIterator<'a> as Iterator>::Item; + type IntoIter = SymIterator<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + SymIterator { + bytes: self.bytes, + offset: 0, + index: 0, + count: self.count, + ctx: self.ctx, + } + } + } + + /// An iterator over symbols in an ELF symbol table + pub struct SymIterator<'a> { + bytes: &'a [u8], + offset: usize, + index: usize, + count: usize, + ctx: Ctx, + } + + impl<'a> Iterator for SymIterator<'a> { + type Item = Sym; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + if self.index >= self.count { + None + } else { + self.index += 1; + Some(self.bytes.gread_with(&mut self.offset, self.ctx).unwrap()) + } + } + } + + impl<'a> ExactSizeIterator for SymIterator<'a> { + #[inline] + fn len(&self) -> usize { + self.count - self.index + } + } +} // end if_alloc diff --git a/third_party/rust/goblin/src/elf/symver.rs b/third_party/rust/goblin/src/elf/symver.rs new file mode 100644 index 0000000000..0dd55e3d25 --- /dev/null +++ b/third_party/rust/goblin/src/elf/symver.rs @@ -0,0 +1,880 @@ +//! Symbol versioning +//! +//! Implementation of the GNU symbol versioning extension according to +//! [LSB Core Specification - Symbol Versioning][lsb-symver]. +//! +//! # Examples +//! +//! List the dependencies of an ELF file that have [version needed][lsb-verneed] information along +//! with the versions needed for each dependency. +//! ```rust +//! use goblin::error::Error; +//! +//! pub fn show_verneed(bytes: &[u8]) -> Result<(), Error> { +//! let binary = goblin::elf::Elf::parse(&bytes)?; +//! +//! if let Some(verneed) = binary.verneed { +//! for need_file in verneed.iter() { +//! println!( +//! "Depend on {:?} with version(s):", +//! binary.dynstrtab.get_at(need_file.vn_file) +//! ); +//! for need_ver in need_file.iter() { +//! println!("{:?}", binary.dynstrtab.get_at(need_ver.vna_name)); +//! } +//! } +//! } +//! +//! Ok(()) +//! } +//! ``` +//! +//! List the [version defined][lsb-verdef] information of an ELF file, effectively listing the version +//! defined by this ELF file. +//! ```rust +//! use goblin::error::Error; +//! +//! pub fn show_verdef(bytes: &[u8]) -> Result<(), Error> { +//! let binary = goblin::elf::Elf::parse(&bytes)?; +//! +//! if let Some(verdef) = &binary.verdef { +//! for def in verdef.iter() { +//! for (n, aux) in def.iter().enumerate() { +//! let name = binary.dynstrtab.get_at(aux.vda_name); +//! match n { +//! 0 => print!("Name: {:?}", name), +//! 1 => print!(" Parent: {:?}", name), +//! _ => print!(", {:?}", name), +//! } +//! } +//! print!("\n"); +//! } +//! } +//! +//! Ok(()) +//! } +//! ``` +//! +//! [lsb-symver]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html +//! [lsb-verneed]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERRQMTS +//! [lsb-verdef]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERDEFS + +use crate::container; +use crate::elf::section_header::{SectionHeader, SHT_GNU_VERDEF, SHT_GNU_VERNEED, SHT_GNU_VERSYM}; +use crate::error::Result; +use core::iter::FusedIterator; +use scroll::Pread; + +/****************** + * ELF Constants * + ******************/ + +// Versym constants. + +/// Constant describing a local symbol, see [`Versym::is_local`]. +pub const VER_NDX_LOCAL: u16 = 0; +/// Constant describing a global symbol, see [`Versym::is_global`]. +pub const VER_NDX_GLOBAL: u16 = 1; +/// Bitmask to check hidden bit, see [`Versym::is_hidden`]. +pub const VERSYM_HIDDEN: u16 = 0x8000; +/// Bitmask to get version information, see [`Versym::version`]. +pub const VERSYM_VERSION: u16 = 0x7fff; + +// Verdef constants. + +/// Bitmask to check `base` flag in [`Verdef::vd_flags`]. +pub const VER_FLG_BASE: u16 = 0x1; +/// Bitmask to check `weak` flag in [`Verdef::vd_flags`]. +pub const VER_FLG_WEAK: u16 = 0x2; +/// Bitmask to check `info` flag in [`Verdef::vd_flags`]. +pub const VER_FLG_INFO: u16 = 0x4; + +/******************** + * ELF Structures * + ********************/ + +/// An ELF `Symbol Version` entry. +/// +/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERTBL +#[repr(C)] +#[derive(Debug, Pread)] +struct ElfVersym { + vs_val: u16, +} + +/// An ELF `Version Definition` entry Elfxx_Verdef. +/// +/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFENTRIES +#[repr(C)] +#[derive(Debug, Pread)] +struct ElfVerdef { + vd_version: u16, + vd_flags: u16, + vd_ndx: u16, + vd_cnt: u16, + vd_hash: u32, + vd_aux: u32, + vd_next: u32, +} + +/// An ELF `Version Definition Auxiliary` entry Elfxx_Verdaux. +/// +/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFEXTS +#[repr(C)] +#[derive(Debug, Pread)] +struct ElfVerdaux { + vda_name: u32, + vda_next: u32, +} + +/// An ELF `Version Need` entry Elfxx_Verneed. +/// +/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDFIG +#[repr(C)] +#[derive(Debug, Pread)] +struct ElfVerneed { + vn_version: u16, + vn_cnt: u16, + vn_file: u32, + vn_aux: u32, + vn_next: u32, +} + +/// An ELF `Version Need Auxiliary` entry Elfxx_Vernaux. +/// +/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDEXTFIG +#[repr(C)] +#[derive(Debug, Pread)] +struct ElfVernaux { + vna_hash: u32, + vna_flags: u16, + vna_other: u16, + vna_name: u32, + vna_next: u32, +} + +/******************** + * Symbol Version * + ********************/ + +/// Helper struct to iterate over [Symbol Version][Versym] entries. +#[derive(Debug)] +pub struct VersymSection<'a> { + bytes: &'a [u8], + ctx: container::Ctx, +} + +impl<'a> VersymSection<'a> { + pub fn parse( + bytes: &'a [u8], + shdrs: &[SectionHeader], + ctx: container::Ctx, + ) -> Result<Option<VersymSection<'a>>> { + // Get fields needed from optional `symbol version` section. + let (offset, size) = + if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERSYM) { + (shdr.sh_offset as usize, shdr.sh_size as usize) + } else { + return Ok(None); + }; + + // Get a slice of bytes of the `version definition` section content. + let bytes: &'a [u8] = bytes.pread_with(offset, size)?; + + Ok(Some(VersymSection { bytes, ctx })) + } + + /// Get an iterator over the [`Versym`] entries. + #[inline] + pub fn iter(&'a self) -> VersymIter<'a> { + self.into_iter() + } + + /// True if there are no [`Versym`] entries. + #[inline] + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + /// Number of [`Versym`] entries. + #[inline] + pub fn len(&self) -> usize { + let entsize = core::mem::size_of::<ElfVersym>(); + + self.bytes.len() / entsize + } + + /// Get [`Versym`] entry at index. + #[inline] + pub fn get_at(&self, idx: usize) -> Option<Versym> { + let entsize = core::mem::size_of::<ElfVersym>(); + let offset = idx.checked_mul(entsize)?; + + self.bytes + .pread_with::<ElfVersym>(offset, self.ctx.le) + .ok() + .map(Versym::from) + } +} + +impl<'a> IntoIterator for &'_ VersymSection<'a> { + type Item = <VersymIter<'a> as Iterator>::Item; + type IntoIter = VersymIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + VersymIter { + bytes: self.bytes, + offset: 0, + ctx: self.ctx, + } + } +} + +/// Iterator over the [`Versym`] entries from the [`SHT_GNU_VERSYM`] section. +pub struct VersymIter<'a> { + bytes: &'a [u8], + offset: usize, + ctx: container::Ctx, +} + +impl<'a> Iterator for VersymIter<'a> { + type Item = Versym; + + fn next(&mut self) -> Option<Self::Item> { + if self.offset >= self.bytes.len() { + None + } else { + self.bytes + .gread_with::<ElfVersym>(&mut self.offset, self.ctx.le) + .ok() + .map(Versym::from) + .or_else(|| { + // self.bytes are not a multiple of ElfVersym. + // Adjust offset to continue yielding Nones. + self.offset = self.bytes.len(); + None + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let len = (self.bytes.len() - self.offset) / core::mem::size_of::<Self::Item>(); + (len, Some(len)) + } +} + +impl ExactSizeIterator for VersymIter<'_> {} + +impl FusedIterator for VersymIter<'_> {} + +/// An ELF [Symbol Version][lsb-versym] entry. +/// +/// [lsb-versym]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERTBL +#[derive(Debug)] +pub struct Versym { + pub vs_val: u16, +} + +impl Versym { + /// Returns true if the symbol is local and not available outside the object according to + /// [`VER_NDX_LOCAL`]. + #[inline] + pub fn is_local(&self) -> bool { + self.vs_val == VER_NDX_LOCAL + } + + /// Returns true if the symbol is defined in this object and globally available according + /// to [`VER_NDX_GLOBAL`]. + #[inline] + pub fn is_global(&self) -> bool { + self.vs_val == VER_NDX_GLOBAL + } + + /// Returns true if the `hidden` bit is set according to the [`VERSYM_HIDDEN`] bitmask. + #[inline] + pub fn is_hidden(&self) -> bool { + (self.vs_val & VERSYM_HIDDEN) == VERSYM_HIDDEN + } + + /// Returns the symbol version index according to the [`VERSYM_VERSION`] bitmask. + #[inline] + pub fn version(&self) -> u16 { + self.vs_val & VERSYM_VERSION + } +} + +impl From<ElfVersym> for Versym { + fn from(ElfVersym { vs_val }: ElfVersym) -> Self { + Versym { vs_val } + } +} + +/************************ + * Version Definition * + ************************/ + +/// Helper struct to iterate over [Version Definition][Verdef] and [Version Definition +/// Auxiliary][Verdaux] entries. +#[derive(Debug)] +pub struct VerdefSection<'a> { + /// String table used to resolve version strings. + bytes: &'a [u8], + count: usize, + ctx: container::Ctx, +} + +impl<'a> VerdefSection<'a> { + pub fn parse( + bytes: &'a [u8], + shdrs: &[SectionHeader], + ctx: container::Ctx, + ) -> Result<Option<VerdefSection<'a>>> { + // Get fields needed from optional `version definition` section. + let (offset, size, count) = + if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERDEF) { + ( + shdr.sh_offset as usize, + shdr.sh_size as usize, + shdr.sh_info as usize, // Encodes the number of ElfVerdef entries. + ) + } else { + return Ok(None); + }; + + // Get a slice of bytes of the `version definition` section content. + let bytes: &'a [u8] = bytes.pread_with(offset, size)?; + + Ok(Some(VerdefSection { bytes, count, ctx })) + } + + /// Get an iterator over the [`Verdef`] entries. + #[inline] + pub fn iter(&'a self) -> VerdefIter<'a> { + self.into_iter() + } +} + +impl<'a> IntoIterator for &'_ VerdefSection<'a> { + type Item = <VerdefIter<'a> as Iterator>::Item; + type IntoIter = VerdefIter<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + VerdefIter { + bytes: self.bytes, + count: self.count, + index: 0, + offset: 0, + ctx: self.ctx, + } + } +} + +/// Iterator over the [`Verdef`] entries from the [`SHT_GNU_VERDEF`] section. +pub struct VerdefIter<'a> { + bytes: &'a [u8], + count: usize, + index: usize, + offset: usize, + ctx: container::Ctx, +} + +impl<'a> Iterator for VerdefIter<'a> { + type Item = Verdef<'a>; + + fn next(&mut self) -> Option<Self::Item> { + if self.index >= self.count { + None + } else { + self.index += 1; + + let do_next = |iter: &mut Self| { + let ElfVerdef { + vd_version, + vd_flags, + vd_ndx, + vd_cnt, + vd_hash, + vd_aux, + vd_next, + } = iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?; + + // Validate offset to first ElfVerdaux entry. + let offset = iter.offset.checked_add(vd_aux as usize)?; + + // Validate if offset is valid index into bytes slice. + if offset >= iter.bytes.len() { + return None; + } + + // Get a slice of bytes starting with the first ElfVerdaux entry. + let bytes: &'a [u8] = &iter.bytes[offset..]; + + // Bump the offset to the next ElfVerdef entry. + iter.offset = iter.offset.checked_add(vd_next as usize)?; + + // Start yielding None on the next call if there is no next offset. + if vd_next == 0 { + iter.index = iter.count; + } + + Some(Verdef { + vd_version, + vd_flags, + vd_ndx, + vd_cnt, + vd_hash, + vd_aux, + vd_next, + bytes, + ctx: iter.ctx, + }) + }; + + do_next(self).or_else(|| { + // Adjust current index to count in case of an error. + self.index = self.count; + None + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let len = self.count - self.index; + (0, Some(len)) + } +} + +impl ExactSizeIterator for VerdefIter<'_> {} + +impl FusedIterator for VerdefIter<'_> {} + +/// An ELF [Version Definition][lsb-verdef] entry . +/// +/// [lsb-verdef]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFENTRIES +#[derive(Debug)] +pub struct Verdef<'a> { + /// Version revision. This field shall be set to 1. + pub vd_version: u16, + /// Version information flag bitmask. + pub vd_flags: u16, + /// Version index numeric value referencing the SHT_GNU_versym section. + pub vd_ndx: u16, + /// Number of associated verdaux array entries. + pub vd_cnt: u16, + /// Version name hash value (ELF hash function). + pub vd_hash: u32, + /// Offset in bytes to a corresponding entry in an array of Elfxx_Verdaux structures. + pub vd_aux: u32, + /// Offset to the next verdef entry, in bytes. + pub vd_next: u32, + + bytes: &'a [u8], + ctx: container::Ctx, +} + +impl<'a> Verdef<'a> { + /// Get an iterator over the [`Verdaux`] entries of this [`Verdef`] entry. + #[inline] + pub fn iter(&'a self) -> VerdauxIter<'a> { + self.into_iter() + } +} + +impl<'a> IntoIterator for &'_ Verdef<'a> { + type Item = <VerdauxIter<'a> as Iterator>::Item; + type IntoIter = VerdauxIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + VerdauxIter { + bytes: self.bytes, + count: self.vd_cnt, + index: 0, + offset: 0, + ctx: self.ctx, + } + } +} + +/// Iterator over the [`Verdaux`] entries for an specific [`Verdef`] entry. +pub struct VerdauxIter<'a> { + bytes: &'a [u8], + count: u16, + index: u16, + offset: usize, + ctx: container::Ctx, +} + +impl<'a> Iterator for VerdauxIter<'a> { + type Item = Verdaux; + + fn next(&mut self) -> Option<Self::Item> { + if self.index >= self.count { + None + } else { + self.index += 1; + + let do_next = |iter: &mut Self| { + let ElfVerdaux { vda_name, vda_next } = + iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?; + + // Bump the offset to the next ElfVerdaux entry. + iter.offset = iter.offset.checked_add(vda_next as usize)?; + + // Start yielding None on the next call if there is no next offset. + if vda_next == 0 { + iter.index = iter.count; + } + + Some(Verdaux { + vda_name: vda_name as usize, + vda_next, + }) + }; + + do_next(self).or_else(|| { + // Adjust current index to count in case of an error. + self.index = self.count; + None + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let len = usize::from(self.count - self.index); + (0, Some(len)) + } +} + +impl ExactSizeIterator for VerdauxIter<'_> {} + +impl FusedIterator for VerdauxIter<'_> {} + +/// An ELF [Version Definition Auxiliary][lsb-verdaux] entry. +/// +/// [lsb-verdaux]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFEXTS +#[derive(Debug)] +pub struct Verdaux { + /// Offset to the version or dependency name string in the section header, in bytes. + pub vda_name: usize, + /// Offset to the next verdaux entry, in bytes. + pub vda_next: u32, +} + +/************************** + * Version Requirements * + **************************/ + +/// Helper struct to iterate over [Version Needed][Verneed] and [Version Needed +/// Auxiliary][Vernaux] entries. +#[derive(Debug)] +pub struct VerneedSection<'a> { + bytes: &'a [u8], + count: usize, + ctx: container::Ctx, +} + +impl<'a> VerneedSection<'a> { + /// Try to parse the optional [`SHT_GNU_VERNEED`] section. + pub fn parse( + bytes: &'a [u8], + shdrs: &[SectionHeader], + ctx: container::Ctx, + ) -> Result<Option<VerneedSection<'a>>> { + // Get fields needed from optional `version needed` section. + let (offset, size, count) = + if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERNEED) { + ( + shdr.sh_offset as usize, + shdr.sh_size as usize, + shdr.sh_info as usize, // Encodes the number of ElfVerneed entries. + ) + } else { + return Ok(None); + }; + + // Get a slice of bytes of the `version needed` section content. + let bytes: &'a [u8] = bytes.pread_with(offset, size)?; + + Ok(Some(VerneedSection { bytes, count, ctx })) + } + + /// Get an iterator over the [`Verneed`] entries. + #[inline] + pub fn iter(&'a self) -> VerneedIter<'a> { + self.into_iter() + } +} + +impl<'a> IntoIterator for &'_ VerneedSection<'a> { + type Item = <VerneedIter<'a> as Iterator>::Item; + type IntoIter = VerneedIter<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + VerneedIter { + bytes: self.bytes, + count: self.count, + index: 0, + offset: 0, + ctx: self.ctx, + } + } +} + +/// Iterator over the [`Verneed`] entries from the [`SHT_GNU_VERNEED`] section. +pub struct VerneedIter<'a> { + bytes: &'a [u8], + count: usize, + index: usize, + offset: usize, + ctx: container::Ctx, +} + +impl<'a> Iterator for VerneedIter<'a> { + type Item = Verneed<'a>; + + fn next(&mut self) -> Option<Self::Item> { + if self.index >= self.count { + None + } else { + self.index += 1; + + let do_next = |iter: &mut Self| { + let ElfVerneed { + vn_version, + vn_cnt, + vn_file, + vn_aux, + vn_next, + } = iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?; + + // Validate offset to first ElfVernaux entry. + let offset = iter.offset.checked_add(vn_aux as usize)?; + + // Validate if offset is valid index into bytes slice. + if offset >= iter.bytes.len() { + return None; + } + + // Get a slice of bytes starting with the first ElfVernaux entry. + let bytes: &'a [u8] = &iter.bytes[offset..]; + + // Bump the offset to the next ElfVerneed entry. + iter.offset = iter.offset.checked_add(vn_next as usize)?; + + // Start yielding None on the next call if there is no next offset. + if vn_next == 0 { + iter.index = iter.count; + } + + Some(Verneed { + vn_version, + vn_cnt, + vn_file: vn_file as usize, + vn_aux, + vn_next, + bytes, + ctx: iter.ctx, + }) + }; + + do_next(self).or_else(|| { + // Adjust current index to count in case of an error. + self.index = self.count; + None + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let len = self.count - self.index; + (0, Some(len)) + } +} + +impl ExactSizeIterator for VerneedIter<'_> {} + +impl FusedIterator for VerneedIter<'_> {} + +/// An ELF [Version Need][lsb-verneed] entry . +/// +/// [lsb-verneed]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDFIG +#[derive(Debug)] +pub struct Verneed<'a> { + /// Version of structure. This value is currently set to 1, and will be reset if the versioning + /// implementation is incompatibly altered. + pub vn_version: u16, + /// Number of associated verneed array entries. + pub vn_cnt: u16, + /// Offset to the file name string in the section header, in bytes. + pub vn_file: usize, + /// Offset to a corresponding entry in the vernaux array, in bytes. + pub vn_aux: u32, + /// Offset to the next verneed entry, in bytes. + pub vn_next: u32, + + bytes: &'a [u8], + ctx: container::Ctx, +} + +impl<'a> Verneed<'a> { + /// Get an iterator over the [`Vernaux`] entries of this [`Verneed`] entry. + #[inline] + pub fn iter(&'a self) -> VernauxIter<'a> { + self.into_iter() + } +} + +impl<'a> IntoIterator for &'_ Verneed<'a> { + type Item = <VernauxIter<'a> as Iterator>::Item; + type IntoIter = VernauxIter<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + VernauxIter { + bytes: self.bytes, + count: self.vn_cnt, + index: 0, + offset: 0, + ctx: self.ctx, + } + } +} + +/// Iterator over the [`Vernaux`] entries for an specific [`Verneed`] entry. +pub struct VernauxIter<'a> { + bytes: &'a [u8], + count: u16, + index: u16, + offset: usize, + ctx: container::Ctx, +} + +impl<'a> Iterator for VernauxIter<'a> { + type Item = Vernaux; + + fn next(&mut self) -> Option<Self::Item> { + if self.index >= self.count { + None + } else { + self.index += 1; + + let do_next = |iter: &mut Self| { + let ElfVernaux { + vna_hash, + vna_flags, + vna_other, + vna_name, + vna_next, + } = iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?; + + // Bump the offset to the next ElfVernaux entry. + iter.offset = iter.offset.checked_add(vna_next as usize)?; + + // Start yielding None on the next call if there is no next offset. + if vna_next == 0 { + iter.index = iter.count; + } + + Some(Vernaux { + vna_hash, + vna_flags, + vna_other, + vna_name: vna_name as usize, + vna_next, + }) + }; + + do_next(self).or_else(|| { + // Adjust current index to count in case of an error. + self.index = self.count; + None + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let len = usize::from(self.count - self.index); + (0, Some(len)) + } +} + +impl ExactSizeIterator for VernauxIter<'_> {} + +impl FusedIterator for VernauxIter<'_> {} + +/// An ELF [Version Need Auxiliary][lsb-vernaux] entry. +/// +/// [lsb-vernaux]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDEXTFIG +#[derive(Debug)] +pub struct Vernaux { + /// Dependency name hash value (ELF hash function). + pub vna_hash: u32, + /// Dependency information flag bitmask. + pub vna_flags: u16, + /// Object file version identifier used in the .gnu.version symbol version array. Bit number 15 + /// controls whether or not the object is hidden; if this bit is set, the object cannot be used + /// and the static linker will ignore the symbol's presence in the object. + pub vna_other: u16, + /// Offset to the dependency name string in the section header, in bytes. + pub vna_name: usize, + /// Offset to the next vernaux entry, in bytes. + pub vna_next: u32, +} + +#[cfg(test)] +mod test { + use super::{ElfVerdaux, ElfVerdef, ElfVernaux, ElfVerneed, ElfVersym}; + use super::{Versym, VERSYM_HIDDEN, VER_NDX_GLOBAL, VER_NDX_LOCAL}; + use core::mem::size_of; + + #[test] + fn check_size() { + assert_eq!(2, size_of::<ElfVersym>()); + assert_eq!(20, size_of::<ElfVerdef>()); + assert_eq!(8, size_of::<ElfVerdaux>()); + assert_eq!(16, size_of::<ElfVerneed>()); + assert_eq!(16, size_of::<ElfVernaux>()); + } + + #[test] + fn check_versym() { + let local = Versym { + vs_val: VER_NDX_LOCAL, + }; + assert_eq!(true, local.is_local()); + assert_eq!(false, local.is_global()); + assert_eq!(false, local.is_hidden()); + assert_eq!(VER_NDX_LOCAL, local.version()); + + let global = Versym { + vs_val: VER_NDX_GLOBAL, + }; + assert_eq!(false, global.is_local()); + assert_eq!(true, global.is_global()); + assert_eq!(false, global.is_hidden()); + assert_eq!(VER_NDX_GLOBAL, global.version()); + + let hidden = Versym { + vs_val: VERSYM_HIDDEN, + }; + assert_eq!(false, hidden.is_local()); + assert_eq!(false, hidden.is_global()); + assert_eq!(true, hidden.is_hidden()); + assert_eq!(0, hidden.version()); + + let hidden = Versym { + vs_val: VERSYM_HIDDEN | 0x123, + }; + assert_eq!(false, hidden.is_local()); + assert_eq!(false, hidden.is_global()); + assert_eq!(true, hidden.is_hidden()); + assert_eq!(0x123, hidden.version()); + } +} |