More improvements for relocation handling
This commit is contained in:
+97
-76
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user