More improvements for relocation handling

This commit is contained in:
Jeremy Soller
2025-04-18 16:03:09 -06:00
parent 03f863d742
commit 228d53dcd5
+97 -76
View File
@@ -166,9 +166,9 @@ unsafe impl Sync for Dynamic<'_> {}
#[derive(Debug)]
struct Relocation {
offset: usize,
addend: usize,
addend: Option<usize>,
sym: SymbolIndex,
kind: u32,
kind: RelocationKind,
}
#[cfg(target_pointer_width = "32")]
@@ -176,9 +176,9 @@ impl From<&Rela> for Relocation {
fn from(reloc: &Rela) -> Self {
Self {
offset: reloc.r_offset(NativeEndian) as usize,
addend: reloc.r_addend(NativeEndian) as usize,
addend: Some(reloc.r_addend(NativeEndian) as usize),
sym: SymbolIndex(reloc.r_sym(NativeEndian) as usize),
kind: reloc.r_type(NativeEndian),
kind: RelocationKind::new(reloc.r_type(NativeEndian)),
}
}
}
@@ -189,9 +189,9 @@ impl From<&Rela> for Relocation {
let is_mips64el = cfg!(all(target_arch = "mips64", target_endian = "little"));
Self {
offset: reloc.r_offset(NativeEndian) as usize,
addend: reloc.r_addend(NativeEndian) as usize,
addend: Some(reloc.r_addend(NativeEndian) as usize),
sym: SymbolIndex(reloc.r_sym(NativeEndian, is_mips64el) as usize),
kind: reloc.r_type(NativeEndian, is_mips64el),
kind: RelocationKind::new(reloc.r_type(NativeEndian, is_mips64el)),
}
}
}
@@ -200,41 +200,47 @@ impl From<&Rel> for Relocation {
fn from(reloc: &Rel) -> Self {
Self {
offset: reloc.r_offset(NativeEndian) as usize,
addend: 0,
addend: None,
sym: SymbolIndex(reloc.r_sym(NativeEndian) as usize),
kind: reloc.r_type(NativeEndian),
kind: RelocationKind::new(reloc.r_type(NativeEndian)),
}
}
}
// This is matched up to REL_* constants used by musl for ease of comparison
#[allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub enum R {
pub enum RelocationKind {
COPY,
DIRECT,
DTPMOD,
DTPOFF,
GLOB_DAT,
GOT,
IRELATIVE,
JUMP_SLOT,
OFFSET,
PLT,
RELATIVE,
PC,
SYMBOLIC,
TLSDESC,
TPOFF,
UNKNOWN(u32),
}
impl R {
impl RelocationKind {
#[cfg(target_arch = "aarch64")]
pub fn new(kind: u32) -> Self {
//WARNING: Only use R_AARCH64_* constants here!
match kind {
elf::R_AARCH64_COPY => R::COPY,
elf::R_AARCH64_ABS64 => R::DIRECT,
elf::R_AARCH64_GLOB_DAT => R::GLOB_DAT,
elf::R_AARCH64_IRELATIVE => R::IRELATIVE,
elf::R_AARCH64_JUMP_SLOT => R::JUMP_SLOT,
elf::R_AARCH64_RELATIVE => R::RELATIVE,
_ => R::UNKNOWN(kind),
elf::R_AARCH64_COPY => Self::COPY,
elf::R_AARCH64_TLS_DTPMOD => Self::DTPMOD,
elf::R_AARCH64_TLS_DTPREL => Self::DTPOFF,
elf::R_AARCH64_GLOB_DAT => Self::GOT,
elf::R_AARCH64_IRELATIVE => Self::IRELATIVE,
elf::R_AARCH64_JUMP_SLOT => Self::PLT,
elf::R_AARCH64_RELATIVE => Self::RELATIVE,
elf::R_AARCH64_ABS64 => Self::SYMBOLIC,
elf::R_AARCH64_TLSDESC => Self::TLSDESC,
elf::R_AARCH64_TLS_TPREL => Self::TPOFF,
_ => Self::UNKNOWN(kind),
}
}
@@ -242,15 +248,16 @@ impl R {
pub fn new(kind: u32) -> Self {
//WARNING: Only use R_RISCV_* constants here!
match kind {
elf::R_RISCV_COPY => R::COPY,
elf::R_RISCV_64 => R::DIRECT,
elf::R_RISCV_TLS_DTPMOD64 => R::DTPMOD,
elf::R_RISCV_TLS_DTPREL64 => R::DTPOFF,
elf::R_RISCV_IRELATIVE => R::IRELATIVE,
elf::R_RISCV_JUMP_SLOT => R::JUMP_SLOT,
elf::R_RISCV_RELATIVE => R::RELATIVE,
elf::R_RISCV_TLS_TPREL64 => R::TPOFF,
_ => R::UNKNOWN(kind),
elf::R_RISCV_COPY => Self::COPY,
elf::R_RISCV_TLS_DTPMOD64 => Self::DTPMOD,
elf::R_RISCV_TLS_DTPREL64 => Self::DTPOFF,
elf::R_RISCV_IRELATIVE => Self::IRELATIVE,
elf::R_RISCV_JUMP_SLOT => Self::PLT,
elf::R_RISCV_RELATIVE => Self::RELATIVE,
elf::R_RISCV_64 => Self::SYMBOLIC,
//TODO: not defined, should be 12: elf::R_RISCV_TLSDESC => Self::TLSDESC,
elf::R_RISCV_TLS_TPREL64 => Self::TPOFF,
_ => Self::UNKNOWN(kind),
}
}
@@ -258,17 +265,18 @@ impl R {
pub fn new(kind: u32) -> Self {
//WARNING: Only use R_386_* constants here!
match kind {
elf::R_386_COPY => R::COPY,
elf::R_386_32 => R::DIRECT,
elf::R_386_TLS_DTPMOD32 => R::DTPMOD,
elf::R_386_TLS_DTPOFF32 => R::DTPOFF,
elf::R_386_GLOB_DAT => R::GLOB_DAT,
elf::R_386_IRELATIVE => R::IRELATIVE,
elf::R_386_JMP_SLOT => R::JUMP_SLOT,
elf::R_386_PC32 => R::PC,
elf::R_386_RELATIVE => R::RELATIVE,
elf::R_386_TLS_TPOFF32 => R::TPOFF,
_ => R::UNKNOWN(kind),
elf::R_386_COPY => Self::COPY,
elf::R_386_TLS_DTPMOD32 => Self::DTPMOD,
elf::R_386_TLS_DTPOFF32 => Self::DTPOFF,
elf::R_386_GLOB_DAT => Self::GOT,
elf::R_386_IRELATIVE => Self::IRELATIVE,
elf::R_386_JMP_SLOT => Self::PLT,
elf::R_386_PC32 => Self::OFFSET,
elf::R_386_RELATIVE => Self::RELATIVE,
elf::R_386_32 => Self::SYMBOLIC,
elf::R_386_TLS_DESC => Self::TLSDESC,
elf::R_386_TLS_TPOFF => Self::TPOFF,
_ => Self::UNKNOWN(kind),
}
}
@@ -276,16 +284,17 @@ impl R {
pub fn new(kind: u32) -> Self {
//WARNING: Only use R_X86_64_* constants here!
match kind {
elf::R_X86_64_COPY => R::COPY,
elf::R_X86_64_64 => R::DIRECT,
elf::R_X86_64_DTPMOD64 => R::DTPMOD,
elf::R_X86_64_DTPOFF64 => R::DTPOFF,
elf::R_X86_64_GLOB_DAT => R::GLOB_DAT,
elf::R_X86_64_IRELATIVE => R::IRELATIVE,
elf::R_X86_64_JUMP_SLOT => R::JUMP_SLOT,
elf::R_X86_64_RELATIVE => R::RELATIVE,
elf::R_X86_64_TPOFF64 => R::TPOFF,
_ => R::UNKNOWN(kind),
elf::R_X86_64_COPY => Self::COPY,
elf::R_X86_64_DTPMOD64 => Self::DTPMOD,
elf::R_X86_64_DTPOFF64 => Self::DTPOFF,
elf::R_X86_64_GLOB_DAT => Self::GOT,
elf::R_X86_64_IRELATIVE => Self::IRELATIVE,
elf::R_X86_64_JUMP_SLOT => Self::PLT,
elf::R_X86_64_RELATIVE => Self::RELATIVE,
elf::R_X86_64_64 => Self::SYMBOLIC,
elf::R_X86_64_TLSDESC => Self::TLSDESC,
elf::R_X86_64_TPOFF64 => Self::TPOFF,
_ => Self::UNKNOWN(kind),
}
}
}
@@ -809,12 +818,11 @@ impl DSO {
fn static_relocate(&self, global_scope: &Scope, reloc: Relocation) -> object::Result<()> {
let b = self.mmap.as_ptr() as usize;
let r = R::new(reloc.kind);
let (sym, my_sym) = if reloc.sym.0 > 0 {
let name = self.dynamic.symbol_name(reloc.sym).unwrap();
let lookup_scopes = [global_scope, self.scope()];
let sym = if matches!(r, R::COPY) {
let sym = if matches!(reloc.kind, RelocationKind::COPY) {
lookup_scopes
.iter()
.find_map(|scope| scope._get_sym(name, 1))
@@ -833,50 +841,60 @@ impl DSO {
.map(|(sym, obj)| (sym.as_ptr() as usize, obj.tls_offset))
.unwrap_or((0, 0));
let a = reloc.addend;
let ptr = if self.pie {
(b + reloc.offset) as *mut u8
} else {
reloc.offset as *mut u8
};
let p = ptr as usize;
let a = match reloc.addend {
Some(some) => some,
None => match reloc.kind {
RelocationKind::COPY | RelocationKind::GOT | RelocationKind::PLT => 0,
_ => unsafe { *(ptr as *mut usize) },
},
};
//TODO: support different sizes?
let set_usize = |value| unsafe {
*(ptr as *mut usize) = value;
};
match r {
R::DIRECT => set_usize(s + a),
R::DTPMOD => set_usize(self.tls_module_id),
R::DTPOFF => {
match reloc.kind {
RelocationKind::DTPMOD => set_usize(self.tls_module_id),
RelocationKind::DTPOFF => {
if s != 0 {
set_usize(s - b);
} else {
set_usize(s);
}
}
R::GLOB_DAT => set_usize(s),
R::PC => set_usize((s + a).wrapping_sub(p)),
R::RELATIVE => set_usize(b + a),
R::TPOFF => {
RelocationKind::GOT => set_usize(s),
RelocationKind::OFFSET => set_usize((s + a).wrapping_sub(p)),
RelocationKind::RELATIVE => set_usize(b + a),
RelocationKind::SYMBOLIC => set_usize(s + a),
RelocationKind::TPOFF => {
if reloc.sym.0 > 0 {
let (sym, _) = sym.as_ref().expect("R::TPOFF called without valid symbol");
let (sym, _) = sym
.as_ref()
.expect("RelocationKind::TPOFF called without valid symbol");
set_usize((sym.value + a).wrapping_sub(t));
} else {
set_usize(a.wrapping_sub(t));
}
}
R::IRELATIVE => unsafe {
RelocationKind::IRELATIVE => unsafe {
let f: unsafe extern "C" fn() -> usize = core::mem::transmute(b + a);
set_usize(f());
},
R::COPY => unsafe {
let (sym, obj) = sym.as_ref().expect("R::COPY called without valid symbol");
let my_sym = my_sym.expect("R::COPY called without valid symbol");
RelocationKind::COPY => unsafe {
let (sym, obj) = sym
.as_ref()
.expect("RelocationKind::COPY called without valid symbol");
let my_sym = my_sym.expect("RelocationKind::COPY called without valid symbol");
assert!(
sym.size == my_sym.st_size(NativeEndian) as usize,
"R::COPY failed: I was trying to use the symbol {} from {} for {} but they had different sizes. Please consider relinking.",
"RelocationKind::COPY failed: I was trying to use the symbol {} from {} for {} but they had different sizes. Please consider relinking.",
sym.name,
obj.name,
self.name
@@ -884,7 +902,7 @@ impl DSO {
// SAFETY: Both the source and destination have the same size.
ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size);
},
_ => unimplemented!("relocation type {:?}", r),
_ => unimplemented!("relocation type {:?}", reloc.kind),
}
Ok(())
@@ -924,17 +942,16 @@ impl DSO {
reloc.offset as *mut usize
};
let r = R::new(reloc.kind);
match (r, resolve) {
(R::JUMP_SLOT, Resolve::Lazy) if self.pie => unsafe {
match (reloc.kind, resolve) {
(RelocationKind::PLT, Resolve::Lazy) if self.pie => unsafe {
*ptr += object_base_addr;
},
(R::JUMP_SLOT, Resolve::Lazy) => {
(RelocationKind::PLT, Resolve::Lazy) => {
// NOP.
}
(R::JUMP_SLOT, Resolve::Now) => {
(RelocationKind::PLT, Resolve::Now) => {
let name = self.dynamic.symbol_name(reloc.sym).unwrap();
let resolved = resolve_sym(name, &[global_scope, self.scope()])
@@ -942,12 +959,16 @@ impl DSO {
.unwrap_or_else(|| panic!("unresolved symbol: {name}"));
unsafe {
*ptr = resolved + reloc.addend;
*ptr = resolved + reloc.addend.unwrap_or(0);
}
}
_ => {
unimplemented!("relocation type {:?} with resolve {:?}", r, resolve)
unimplemented!(
"relocation type {:?} with resolve {:?}",
reloc.kind,
resolve
)
}
}
}