1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use crate::elf::symbol::Symbol;
pub trait Relocatable {
fn base(&self) -> usize;
fn symbol(&self, symbol_index: usize) -> Symbol;
fn relocation_slices(&self) -> RelocationSlices;
}
#[derive(Clone, Copy)]
pub struct RelocationSlices {
pub rela_slice: &'static [Rela],
pub relr_slice: &'static [usize],
}
/// An ELF relocation entry with an addend.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Rela {
pub r_offset: usize,
pub r_info: usize,
pub r_addend: isize,
}
impl Rela {
/// Extracts the symbol table index from the `r_info` field.
pub fn r_sym(&self) -> u32 {
#[cfg(target_pointer_width = "64")]
{
(self.r_info >> 32) as u32
}
#[cfg(target_pointer_width = "32")]
{
(self.r_info >> 8) as u32
}
}
/// Extracts the relocation type from the `r_info` field.
pub fn r_type(&self) -> u32 {
#[cfg(target_pointer_width = "64")]
{
(self.r_info & 0xFFFFFFFF) as u32
}
#[cfg(target_pointer_width = "32")]
{
(self.r_info & 0xFF) as u32
}
}
}
#[cfg(target_arch = "x86_64")]
pub mod relocations {
// Variables in relocation formulae:
// - A(rela.r_addend): This is the addend used to compute the value of the relocatable field.
// - B(self.base.addr): This is the base address at which a shared object has been loaded into memory during execution.
// - G(??): This is the offset into the global offset table at which the address of the relocation entry’s symbol will reside during execution.
// - GOT(global_offset_table_address): This is the address of the global offset table.
// - L(??): ??
// - P(relocate_address): This is the address of the storage unit being relocated.
// - S(self.symbol.st_value): This is the value of the symbol table entry indexed at `rela.r_sym()`.
// NOTE: In the ELF specification `S` is equal to (symbol.st_value + base_address) but that doesn't make any sense to me.
// - Z(??): ??
// x86_64 relocation types:
/// | None
pub const R_X86_64_NONE: u32 = 0;
/// S + B + A | u64
pub const R_X86_64_64: u32 = 1;
/// S + B + A - P | u32
pub const R_X86_64_PC32: u32 = 2;
/// G + A | u32
pub const R_X86_64_GOT32: u32 = 3;
/// L + A - P | u32
pub const R_X86_64_PLT32: u32 = 4;
/// | None
pub const R_X86_64_COPY: u32 = 5;
/// S + B | u64
pub const R_X86_64_GLOB_DAT: u32 = 6;
/// S + B | u64
pub const R_X86_64_JUMP_SLOT: u32 = 7;
/// B + A | u64
pub const R_X86_64_RELATIVE: u32 = 8;
/// G + GOT + A - P | u32
pub const R_X86_64_GOTPCREL: u32 = 9;
/// S + B + A | u32
pub const R_X86_64_32: u32 = 10;
/// S + B + A | u32
pub const R_X86_64_32S: u32 = 11;
/// S + B + A | u16
pub const R_X86_64_16: u32 = 12;
/// S + B + A - P | u16
pub const R_X86_64_PC16: u32 = 13;
/// S + B + A | u8
pub const R_X86_64_8: u32 = 14;
/// S + B + A - P | u8
pub const R_X86_64_PC8: u32 = 15;
/// S + B + A - P | u64
pub const R_X86_64_PC64: u32 = 24;
/// S + B + A - GOT | u64
pub const R_X86_64_GOTOFF64: u32 = 25;
/// GOT + A - P | u32
pub const R_X86_64_GOTPC32: u32 = 26;
/// Z + A | u32
pub const R_X86_64_SIZE32: u32 = 32;
/// Z + A | u64
pub const R_X86_64_SIZE64: u32 = 33;
/// The returned value from the function located at (B + A) | u64
pub const R_X86_64_IRELATIVE: u32 = 37; // This one is fucking awesome... I mean, it's a little annoying but really cool.
// You may notice some are missing values; those are part of the Thread-Local Storage ABI see "ELF Handling for Thread-Local Storage":
pub const R_X86_64_DTPMOD64: u32 = 16;
}