summaryrefslogtreecommitdiffstats
path: root/third_party/rust/goblin/src/mach/relocation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/goblin/src/mach/relocation.rs')
-rw-r--r--third_party/rust/goblin/src/mach/relocation.rs222
1 files changed, 222 insertions, 0 deletions
diff --git a/third_party/rust/goblin/src/mach/relocation.rs b/third_party/rust/goblin/src/mach/relocation.rs
new file mode 100644
index 0000000000..8e39fb749f
--- /dev/null
+++ b/third_party/rust/goblin/src/mach/relocation.rs
@@ -0,0 +1,222 @@
+// Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD
+// format. The modifications from the original format were changing the value
+// of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
+// This modification is required to support symbols in an arbitrary number of
+// sections not just the three sections (text, data and bss) in a 4.3BSD file.
+// Also the last 4 bits have had the r_type tag added to them.
+
+// The r_address is not really the address as it's name indicates but an offset.
+// In 4.3BSD a.out objects this offset is from the start of the "segment" for
+// which relocation entry is for (text or data). For Mach-O object files it is
+// also an offset but from the start of the "section" for which the relocation
+// entry is for. See comments in <mach-o/loader.h> about the r_address feild
+// in images for used with the dynamic linker.
+
+// In 4.3BSD a.out objects if r_extern is zero then r_symbolnum is an ordinal
+// for the segment the symbol being relocated is in. These ordinals are the
+// symbol types N_TEXT, N_DATA, N_BSS or N_ABS. In Mach-O object files these
+// ordinals refer to the sections in the object file in the order their section
+// structures appear in the headers of the object file they are in. The first
+// section has the ordinal 1, the second 2, and so on. This means that the
+// same ordinal in two different object files could refer to two different
+// sections. And further could have still different ordinals when combined
+// by the link-editor. The value R_ABS is used for relocation entries for
+// absolute symbols which need no further relocation.
+use crate::mach;
+use core::fmt;
+use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith};
+
+// TODO: armv7 relocations are scattered, must and r_address with 0x8000_0000 to check if its scattered or not
+#[derive(Copy, Clone, Pread, Pwrite, IOwrite, SizeWith, IOread)]
+#[repr(C)]
+pub struct RelocationInfo {
+ /// Offset in the section to what is being relocated
+ pub r_address: i32,
+ /// Contains all of the relocation info as a bitfield.
+ /// r_symbolnum, 24 bits, r_pcrel 1 bit, r_length 2 bits, r_extern 1 bit, r_type 4 bits
+ pub r_info: u32,
+}
+
+pub const SIZEOF_RELOCATION_INFO: usize = 8;
+
+impl RelocationInfo {
+ /// Symbol index if `r_extern` == 1 or section ordinal if `r_extern` == 0. In bits :24
+ #[inline]
+ pub fn r_symbolnum(self) -> usize {
+ (self.r_info & 0x00ff_ffffu32) as usize
+ }
+ /// Was relocated pc relative already, 1 bit
+ #[inline]
+ pub fn r_pcrel(self) -> u8 {
+ ((self.r_info & 0x0100_0000u32) >> 24) as u8
+ }
+ /// The length of the relocation, 0=byte, 1=word, 2=long, 3=quad, 2 bits
+ #[inline]
+ pub fn r_length(self) -> u8 {
+ ((self.r_info & 0x0600_0000u32) >> 25) as u8
+ }
+ /// Does not include value of sym referenced, 1 bit
+ #[inline]
+ pub fn r_extern(self) -> u8 {
+ ((self.r_info & 0x0800_0000) >> 27) as u8
+ }
+ /// Ff not 0, machine specific relocation type, in bits :4
+ #[inline]
+ pub fn r_type(self) -> u8 {
+ ((self.r_info & 0xf000_0000) >> 28) as u8
+ }
+ /// If true, this relocation is for a symbol; if false, or a section ordinal otherwise
+ #[inline]
+ pub fn is_extern(self) -> bool {
+ self.r_extern() == 1
+ }
+ /// If true, this is a PIC relocation
+ #[inline]
+ pub fn is_pic(self) -> bool {
+ self.r_pcrel() > 0
+ }
+ /// Returns a string representation of this relocation, given the machine `cputype`
+ pub fn to_str(self, cputype: mach::cputype::CpuType) -> &'static str {
+ reloc_to_str(self.r_type(), cputype)
+ }
+}
+
+/// Absolute relocation type for Mach-O files
+pub const R_ABS: u8 = 0;
+
+impl fmt::Debug for RelocationInfo {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("RelocationInfo")
+ .field("r_address", &format_args!("{:#x}", &self.r_address))
+ .field("r_info", &format_args!("{:#x}", &self.r_info))
+ .field("r_symbolnum", &format_args!("{:#x}", &self.r_symbolnum()))
+ .field("r_pcrel", &(self.r_pcrel()))
+ .field("r_length", &self.r_length())
+ .field("r_extern", &self.r_extern())
+ .field("r_type", &self.r_type())
+ .finish()
+ }
+}
+
+pub type RelocType = u8;
+
+/// Absolute address
+pub const X86_64_RELOC_UNSIGNED: RelocType = 0;
+/// Signed 32-bit displacement
+pub const X86_64_RELOC_SIGNED: RelocType = 1;
+/// A CALL/JMP instruction with 32-bit displacement
+pub const X86_64_RELOC_BRANCH: RelocType = 2;
+/// A MOVQ load of a GOT entry
+pub const X86_64_RELOC_GOT_LOAD: RelocType = 3;
+/// Other GOT references
+pub const X86_64_RELOC_GOT: RelocType = 4;
+/// Must be followed by a X86_64_RELOC_UNSIGNED relocation
+pub const X86_64_RELOC_SUBTRACTOR: RelocType = 5;
+/// for signed 32-bit displacement with a -1 addend
+pub const X86_64_RELOC_SIGNED_1: RelocType = 6;
+/// for signed 32-bit displacement with a -2 addend
+pub const X86_64_RELOC_SIGNED_2: RelocType = 7;
+/// for signed 32-bit displacement with a -4 addend
+pub const X86_64_RELOC_SIGNED_4: RelocType = 8;
+/// for thread local variables
+pub const X86_64_RELOC_TLV: RelocType = 9;
+
+// x86 relocations
+pub const GENERIC_RELOC_VANILLA: RelocType = 0;
+pub const GENERIC_RELOC_PAIR: RelocType = 1;
+pub const GENERIC_RELOC_SECTDIFF: RelocType = 2;
+pub const GENERIC_RELOC_PB_LA_PTR: RelocType = 3;
+pub const GENERIC_RELOC_LOCAL_SECTDIFF: RelocType = 4;
+pub const GENERIC_RELOC_TLV: RelocType = 5;
+
+// arm relocations
+pub const ARM_RELOC_VANILLA: RelocType = GENERIC_RELOC_VANILLA;
+pub const ARM_RELOC_PAIR: RelocType = GENERIC_RELOC_PAIR;
+pub const ARM_RELOC_SECTDIFF: RelocType = GENERIC_RELOC_SECTDIFF;
+pub const ARM_RELOC_LOCAL_SECTDIFF: RelocType = 3;
+pub const ARM_RELOC_PB_LA_PTR: RelocType = 4;
+pub const ARM_RELOC_BR24: RelocType = 5;
+pub const ARM_THUMB_RELOC_BR22: RelocType = 6;
+/// Obsolete
+pub const ARM_THUMB_32BIT_BRANCH: RelocType = 7;
+pub const ARM_RELOC_HALF: RelocType = 8;
+pub const ARM_RELOC_HALF_SECTDIFF: RelocType = 9;
+
+/// For pointers.
+pub const ARM64_RELOC_UNSIGNED: RelocType = 0;
+/// Must be followed by an ARM64_RELOC_UNSIGNED
+pub const ARM64_RELOC_SUBTRACTOR: RelocType = 1;
+/// A B/BL instruction with 26-bit displacement.
+pub const ARM64_RELOC_BRANCH26: RelocType = 2;
+/// PC-rel distance to page of target.
+pub const ARM64_RELOC_PAGE21: RelocType = 3;
+/// Offset within page, scaled by r_length.
+pub const ARM64_RELOC_PAGEOFF12: RelocType = 4;
+/// PC-rel distance to page of GOT slot.
+pub const ARM64_RELOC_GOT_LOAD_PAGE21: RelocType = 5;
+/// Offset within page of GOT slot, scaled by r_length.
+pub const ARM64_RELOC_GOT_LOAD_PAGEOFF12: RelocType = 6;
+/// For pointers to GOT slots.
+pub const ARM64_RELOC_POINTER_TO_GOT: RelocType = 7;
+/// PC-rel distance to page of TLVP slot.
+pub const ARM64_RELOC_TLVP_LOAD_PAGE21: RelocType = 8;
+/// Offset within page of TLVP slot, scaled by r_length.
+pub const ARM64_RELOC_TLVP_LOAD_PAGEOFF12: RelocType = 9;
+/// Must be followed by ARM64_RELOC_PAGE21 or ARM64_RELOC_PAGEOFF12.
+pub const ARM64_RELOC_ADDEND: RelocType = 10;
+
+pub fn reloc_to_str(reloc: RelocType, cputype: mach::cputype::CpuType) -> &'static str {
+ use crate::mach::constants::cputype::*;
+ match cputype {
+ CPU_TYPE_ARM64 | CPU_TYPE_ARM64_32 => match reloc {
+ ARM64_RELOC_UNSIGNED => "ARM64_RELOC_UNSIGNED",
+ ARM64_RELOC_SUBTRACTOR => "ARM64_RELOC_SUBTRACTOR",
+ ARM64_RELOC_BRANCH26 => "ARM64_RELOC_BRANCH26",
+ ARM64_RELOC_PAGE21 => "ARM64_RELOC_PAGE21",
+ ARM64_RELOC_PAGEOFF12 => "ARM64_RELOC_PAGEOFF12",
+ ARM64_RELOC_GOT_LOAD_PAGE21 => "ARM64_RELOC_GOT_LOAD_PAGE21",
+ ARM64_RELOC_GOT_LOAD_PAGEOFF12 => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
+ ARM64_RELOC_POINTER_TO_GOT => "ARM64_RELOC_POINTER_TO_GOT",
+ ARM64_RELOC_TLVP_LOAD_PAGE21 => "ARM64_RELOC_TLVP_LOAD_PAGE21",
+ ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
+ ARM64_RELOC_ADDEND => "ARM64_RELOC_ADDEND",
+ _ => "UNKNOWN",
+ },
+ CPU_TYPE_X86_64 => match reloc {
+ X86_64_RELOC_UNSIGNED => "X86_64_RELOC_UNSIGNED",
+ X86_64_RELOC_SIGNED => "X86_64_RELOC_SIGNED",
+ X86_64_RELOC_BRANCH => "X86_64_RELOC_BRANCH",
+ X86_64_RELOC_GOT_LOAD => "X86_64_RELOC_GOT_LOAD",
+ X86_64_RELOC_GOT => "X86_64_RELOC_GOT",
+ X86_64_RELOC_SUBTRACTOR => "X86_64_RELOC_SUBTRACTOR",
+ X86_64_RELOC_SIGNED_1 => "X86_64_RELOC_SIGNED_1",
+ X86_64_RELOC_SIGNED_2 => "X86_64_RELOC_SIGNED_2",
+ X86_64_RELOC_SIGNED_4 => "X86_64_RELOC_SIGNED_4",
+ X86_64_RELOC_TLV => "X86_64_RELOC_TLV",
+ _ => "UNKNOWN",
+ },
+ CPU_TYPE_ARM => match reloc {
+ ARM_RELOC_VANILLA => "ARM_RELOC_VANILLA",
+ ARM_RELOC_PAIR => "ARM_RELOC_PAIR",
+ ARM_RELOC_SECTDIFF => "ARM_RELOC_SECTDIFF",
+ ARM_RELOC_LOCAL_SECTDIFF => "ARM_RELOC_LOCAL_SECTDIFF",
+ ARM_RELOC_PB_LA_PTR => "ARM_RELOC_PB_LA_PTR",
+ ARM_RELOC_BR24 => "ARM_RELOC_BR24",
+ ARM_THUMB_RELOC_BR22 => "ARM_THUMB_RELOC_BR22",
+ ARM_THUMB_32BIT_BRANCH => "ARM_THUMB_32BIT_BRANCH",
+ ARM_RELOC_HALF => "ARM_RELOC_HALF",
+ ARM_RELOC_HALF_SECTDIFF => "ARM_RELOC_HALF_SECTDIFF",
+ _ => "UNKNOWN",
+ },
+ CPU_TYPE_X86 => match reloc {
+ GENERIC_RELOC_VANILLA => "GENERIC_RELOC_VANILLA",
+ GENERIC_RELOC_PAIR => "GENERIC_RELOC_PAIR",
+ GENERIC_RELOC_SECTDIFF => "GENERIC_RELOC_SECTDIFF",
+ GENERIC_RELOC_PB_LA_PTR => "GENERIC_RELOC_PB_LA_PTR",
+ GENERIC_RELOC_LOCAL_SECTDIFF => "GENERIC_RELOC_LOCAL_SECTDIFF",
+ GENERIC_RELOC_TLV => "GENERIC_RELOC_TLV",
+ _ => "UNKNOWN",
+ },
+ _ => "BAD_CPUTYPE",
+ }
+}