goblin_experimental/mach/
relocation.rs

1// Format of a relocation entry of a Mach-O file.  Modified from the 4.3BSD
2// format.  The modifications from the original format were changing the value
3// of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
4// This modification is required to support symbols in an arbitrary number of
5// sections not just the three sections (text, data and bss) in a 4.3BSD file.
6// Also the last 4 bits have had the r_type tag added to them.
7
8// The r_address is not really the address as it's name indicates but an offset.
9// In 4.3BSD a.out objects this offset is from the start of the "segment" for
10// which relocation entry is for (text or data).  For Mach-O object files it is
11// also an offset but from the start of the "section" for which the relocation
12// entry is for.  See comments in <mach-o/loader.h> about the r_address feild
13// in images for used with the dynamic linker.
14
15// In 4.3BSD a.out objects if r_extern is zero then r_symbolnum is an ordinal
16// for the segment the symbol being relocated is in.  These ordinals are the
17// symbol types N_TEXT, N_DATA, N_BSS or N_ABS.  In Mach-O object files these
18// ordinals refer to the sections in the object file in the order their section
19// structures appear in the headers of the object file they are in.  The first
20// section has the ordinal 1, the second 2, and so on.  This means that the
21// same ordinal in two different object files could refer to two different
22// sections.  And further could have still different ordinals when combined
23// by the link-editor.  The value R_ABS is used for relocation entries for
24// absolute symbols which need no further relocation.
25use crate::mach;
26use core::fmt;
27use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith};
28
29// TODO: armv7 relocations are scattered, must and r_address with 0x8000_0000 to check if its scattered or not
30#[derive(Copy, Clone, Pread, Pwrite, IOwrite, SizeWith, IOread)]
31#[repr(C)]
32pub struct RelocationInfo {
33    /// Offset in the section to what is being relocated
34    pub r_address: i32,
35    /// Contains all of the relocation info as a bitfield.
36    /// r_symbolnum, 24 bits, r_pcrel 1 bit, r_length 2 bits, r_extern 1 bit, r_type 4 bits
37    pub r_info: u32,
38}
39
40pub const SIZEOF_RELOCATION_INFO: usize = 8;
41
42impl RelocationInfo {
43    /// Symbol index if `r_extern` == 1 or section ordinal if `r_extern` == 0. In bits :24
44    #[inline]
45    pub fn r_symbolnum(self) -> usize {
46        (self.r_info & 0x00ff_ffffu32) as usize
47    }
48    /// Was relocated pc relative already, 1 bit
49    #[inline]
50    pub fn r_pcrel(self) -> u8 {
51        ((self.r_info & 0x0100_0000u32) >> 24) as u8
52    }
53    /// The length of the relocation, 0=byte, 1=word, 2=long, 3=quad, 2 bits
54    #[inline]
55    pub fn r_length(self) -> u8 {
56        ((self.r_info & 0x0600_0000u32) >> 25) as u8
57    }
58    /// Does not include value of sym referenced, 1 bit
59    #[inline]
60    pub fn r_extern(self) -> u8 {
61        ((self.r_info & 0x0800_0000) >> 27) as u8
62    }
63    /// Ff not 0, machine specific relocation type, in bits :4
64    #[inline]
65    pub fn r_type(self) -> u8 {
66        ((self.r_info & 0xf000_0000) >> 28) as u8
67    }
68    /// If true, this relocation is for a symbol; if false,  or a section ordinal otherwise
69    #[inline]
70    pub fn is_extern(self) -> bool {
71        self.r_extern() == 1
72    }
73    /// If true, this is a PIC relocation
74    #[inline]
75    pub fn is_pic(self) -> bool {
76        self.r_pcrel() > 0
77    }
78    /// Returns a string representation of this relocation, given the machine `cputype`
79    pub fn to_str(self, cputype: mach::cputype::CpuType) -> &'static str {
80        reloc_to_str(self.r_type(), cputype)
81    }
82}
83
84/// Absolute relocation type for Mach-O files
85pub const R_ABS: u8 = 0;
86
87impl fmt::Debug for RelocationInfo {
88    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89        f.debug_struct("RelocationInfo")
90            .field("r_address", &format_args!("{:#x}", &self.r_address))
91            .field("r_info", &format_args!("{:#x}", &self.r_info))
92            .field("r_symbolnum", &format_args!("{:#x}", &self.r_symbolnum()))
93            .field("r_pcrel", &(self.r_pcrel()))
94            .field("r_length", &self.r_length())
95            .field("r_extern", &self.r_extern())
96            .field("r_type", &self.r_type())
97            .finish()
98    }
99}
100
101pub type RelocType = u8;
102
103/// Absolute address
104pub const X86_64_RELOC_UNSIGNED: RelocType = 0;
105/// Signed 32-bit displacement
106pub const X86_64_RELOC_SIGNED: RelocType = 1;
107/// A CALL/JMP instruction with 32-bit displacement
108pub const X86_64_RELOC_BRANCH: RelocType = 2;
109/// A MOVQ load of a GOT entry
110pub const X86_64_RELOC_GOT_LOAD: RelocType = 3;
111/// Other GOT references
112pub const X86_64_RELOC_GOT: RelocType = 4;
113/// Must be followed by a X86_64_RELOC_UNSIGNED relocation
114pub const X86_64_RELOC_SUBTRACTOR: RelocType = 5;
115/// for signed 32-bit displacement with a -1 addend
116pub const X86_64_RELOC_SIGNED_1: RelocType = 6;
117/// for signed 32-bit displacement with a -2 addend
118pub const X86_64_RELOC_SIGNED_2: RelocType = 7;
119/// for signed 32-bit displacement with a -4 addend
120pub const X86_64_RELOC_SIGNED_4: RelocType = 8;
121/// for thread local variables
122pub const X86_64_RELOC_TLV: RelocType = 9;
123
124// x86 relocations
125pub const GENERIC_RELOC_VANILLA: RelocType = 0;
126pub const GENERIC_RELOC_PAIR: RelocType = 1;
127pub const GENERIC_RELOC_SECTDIFF: RelocType = 2;
128pub const GENERIC_RELOC_PB_LA_PTR: RelocType = 3;
129pub const GENERIC_RELOC_LOCAL_SECTDIFF: RelocType = 4;
130pub const GENERIC_RELOC_TLV: RelocType = 5;
131
132// arm relocations
133pub const ARM_RELOC_VANILLA: RelocType = GENERIC_RELOC_VANILLA;
134pub const ARM_RELOC_PAIR: RelocType = GENERIC_RELOC_PAIR;
135pub const ARM_RELOC_SECTDIFF: RelocType = GENERIC_RELOC_SECTDIFF;
136pub const ARM_RELOC_LOCAL_SECTDIFF: RelocType = 3;
137pub const ARM_RELOC_PB_LA_PTR: RelocType = 4;
138pub const ARM_RELOC_BR24: RelocType = 5;
139pub const ARM_THUMB_RELOC_BR22: RelocType = 6;
140/// Obsolete
141pub const ARM_THUMB_32BIT_BRANCH: RelocType = 7;
142pub const ARM_RELOC_HALF: RelocType = 8;
143pub const ARM_RELOC_HALF_SECTDIFF: RelocType = 9;
144
145/// For pointers.
146pub const ARM64_RELOC_UNSIGNED: RelocType = 0;
147/// Must be followed by an ARM64_RELOC_UNSIGNED
148pub const ARM64_RELOC_SUBTRACTOR: RelocType = 1;
149/// A B/BL instruction with 26-bit displacement.
150pub const ARM64_RELOC_BRANCH26: RelocType = 2;
151/// PC-rel distance to page of target.
152pub const ARM64_RELOC_PAGE21: RelocType = 3;
153/// Offset within page, scaled by r_length.
154pub const ARM64_RELOC_PAGEOFF12: RelocType = 4;
155/// PC-rel distance to page of GOT slot.
156pub const ARM64_RELOC_GOT_LOAD_PAGE21: RelocType = 5;
157/// Offset within page of GOT slot, scaled by r_length.
158pub const ARM64_RELOC_GOT_LOAD_PAGEOFF12: RelocType = 6;
159/// For pointers to GOT slots.
160pub const ARM64_RELOC_POINTER_TO_GOT: RelocType = 7;
161/// PC-rel distance to page of TLVP slot.
162pub const ARM64_RELOC_TLVP_LOAD_PAGE21: RelocType = 8;
163/// Offset within page of TLVP slot, scaled by r_length.
164pub const ARM64_RELOC_TLVP_LOAD_PAGEOFF12: RelocType = 9;
165/// Must be followed by ARM64_RELOC_PAGE21 or ARM64_RELOC_PAGEOFF12.
166pub const ARM64_RELOC_ADDEND: RelocType = 10;
167
168pub fn reloc_to_str(reloc: RelocType, cputype: mach::cputype::CpuType) -> &'static str {
169    use crate::mach::constants::cputype::*;
170    match cputype {
171        CPU_TYPE_ARM64 | CPU_TYPE_ARM64_32 => match reloc {
172            ARM64_RELOC_UNSIGNED => "ARM64_RELOC_UNSIGNED",
173            ARM64_RELOC_SUBTRACTOR => "ARM64_RELOC_SUBTRACTOR",
174            ARM64_RELOC_BRANCH26 => "ARM64_RELOC_BRANCH26",
175            ARM64_RELOC_PAGE21 => "ARM64_RELOC_PAGE21",
176            ARM64_RELOC_PAGEOFF12 => "ARM64_RELOC_PAGEOFF12",
177            ARM64_RELOC_GOT_LOAD_PAGE21 => "ARM64_RELOC_GOT_LOAD_PAGE21",
178            ARM64_RELOC_GOT_LOAD_PAGEOFF12 => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
179            ARM64_RELOC_POINTER_TO_GOT => "ARM64_RELOC_POINTER_TO_GOT",
180            ARM64_RELOC_TLVP_LOAD_PAGE21 => "ARM64_RELOC_TLVP_LOAD_PAGE21",
181            ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
182            ARM64_RELOC_ADDEND => "ARM64_RELOC_ADDEND",
183            _ => "UNKNOWN",
184        },
185        CPU_TYPE_X86_64 => match reloc {
186            X86_64_RELOC_UNSIGNED => "X86_64_RELOC_UNSIGNED",
187            X86_64_RELOC_SIGNED => "X86_64_RELOC_SIGNED",
188            X86_64_RELOC_BRANCH => "X86_64_RELOC_BRANCH",
189            X86_64_RELOC_GOT_LOAD => "X86_64_RELOC_GOT_LOAD",
190            X86_64_RELOC_GOT => "X86_64_RELOC_GOT",
191            X86_64_RELOC_SUBTRACTOR => "X86_64_RELOC_SUBTRACTOR",
192            X86_64_RELOC_SIGNED_1 => "X86_64_RELOC_SIGNED_1",
193            X86_64_RELOC_SIGNED_2 => "X86_64_RELOC_SIGNED_2",
194            X86_64_RELOC_SIGNED_4 => "X86_64_RELOC_SIGNED_4",
195            X86_64_RELOC_TLV => "X86_64_RELOC_TLV",
196            _ => "UNKNOWN",
197        },
198        CPU_TYPE_ARM => match reloc {
199            ARM_RELOC_VANILLA => "ARM_RELOC_VANILLA",
200            ARM_RELOC_PAIR => "ARM_RELOC_PAIR",
201            ARM_RELOC_SECTDIFF => "ARM_RELOC_SECTDIFF",
202            ARM_RELOC_LOCAL_SECTDIFF => "ARM_RELOC_LOCAL_SECTDIFF",
203            ARM_RELOC_PB_LA_PTR => "ARM_RELOC_PB_LA_PTR",
204            ARM_RELOC_BR24 => "ARM_RELOC_BR24",
205            ARM_THUMB_RELOC_BR22 => "ARM_THUMB_RELOC_BR22",
206            ARM_THUMB_32BIT_BRANCH => "ARM_THUMB_32BIT_BRANCH",
207            ARM_RELOC_HALF => "ARM_RELOC_HALF",
208            ARM_RELOC_HALF_SECTDIFF => "ARM_RELOC_HALF_SECTDIFF",
209            _ => "UNKNOWN",
210        },
211        CPU_TYPE_X86 => match reloc {
212            GENERIC_RELOC_VANILLA => "GENERIC_RELOC_VANILLA",
213            GENERIC_RELOC_PAIR => "GENERIC_RELOC_PAIR",
214            GENERIC_RELOC_SECTDIFF => "GENERIC_RELOC_SECTDIFF",
215            GENERIC_RELOC_PB_LA_PTR => "GENERIC_RELOC_PB_LA_PTR",
216            GENERIC_RELOC_LOCAL_SECTDIFF => "GENERIC_RELOC_LOCAL_SECTDIFF",
217            GENERIC_RELOC_TLV => "GENERIC_RELOC_TLV",
218            _ => "UNKNOWN",
219        },
220        _ => "BAD_CPUTYPE",
221    }
222}