From 03f863d742f14e73388facba8487350af8277ff3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 18 Apr 2025 14:26:39 -0600 Subject: [PATCH] ld_so: better support for other arches --- src/ld_so/dso.rs | 150 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 117 insertions(+), 33 deletions(-) diff --git a/src/ld_so/dso.rs b/src/ld_so/dso.rs index 9e868cba71..649efe7e46 100644 --- a/src/ld_so/dso.rs +++ b/src/ld_so/dso.rs @@ -3,7 +3,7 @@ //! * use object::{ - elf::{self, Sym64}, + elf, read::elf::{ Dyn as _, GnuHashTable, HashTable as SysVHashTable, ProgramHeader as _, Rel as _, Rela as _, Sym as _, Version, VersionTable, @@ -207,6 +207,89 @@ impl From<&Rel> for Relocation { } } +#[allow(dead_code)] +#[derive(Clone, Copy, Debug)] +pub enum R { + COPY, + DIRECT, + DTPMOD, + DTPOFF, + GLOB_DAT, + IRELATIVE, + JUMP_SLOT, + RELATIVE, + PC, + TPOFF, + UNKNOWN(u32), +} + +impl R { + #[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), + } + } + + #[cfg(target_arch = "riscv64")] + 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), + } + } + + #[cfg(target_arch = "x86")] + 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), + } + } + + #[cfg(target_arch = "x86_64")] + 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), + } + } +} + #[derive(Debug, PartialEq)] #[repr(u8)] pub enum SymbolBinding { @@ -726,11 +809,12 @@ 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 reloc.kind == elf::R_X86_64_COPY { + let sym = if matches!(r, R::COPY) { lookup_scopes .iter() .find_map(|scope| scope._get_sym(name, 1)) @@ -755,45 +839,44 @@ impl DSO { } else { reloc.offset as *mut u8 }; + let p = ptr as usize; - let set_u64 = |value| unsafe { - *(ptr as *mut u64) = value; + //TODO: support different sizes? + let set_usize = |value| unsafe { + *(ptr as *mut usize) = value; }; - match reloc.kind { - elf::R_X86_64_64 => set_u64((s + a) as u64), - elf::R_X86_64_DTPMOD64 => set_u64(self.tls_module_id as u64), - elf::R_X86_64_DTPOFF64 => { + match r { + R::DIRECT => set_usize(s + a), + R::DTPMOD => set_usize(self.tls_module_id), + R::DTPOFF => { if s != 0 { - set_u64((s - b) as u64); + set_usize(s - b); } else { - set_u64(s as u64); + set_usize(s); } } - elf::R_X86_64_GLOB_DAT => set_u64(s as u64), - elf::R_X86_64_RELATIVE => set_u64((b + a) as u64), - elf::R_X86_64_TPOFF64 => { + R::GLOB_DAT => set_usize(s), + R::PC => set_usize((s + a).wrapping_sub(p)), + R::RELATIVE => set_usize(b + a), + R::TPOFF => { if reloc.sym.0 > 0 { - let (sym, _) = sym - .as_ref() - .expect("R_X86_64_TPOFF64 called without valid symbol"); - set_u64((sym.value + a).wrapping_sub(t) as u64); + let (sym, _) = sym.as_ref().expect("R::TPOFF called without valid symbol"); + set_usize((sym.value + a).wrapping_sub(t)); } else { - set_u64(a.wrapping_sub(t) as u64); + set_usize(a.wrapping_sub(t)); } } - elf::R_X86_64_IRELATIVE => unsafe { - let f: unsafe extern "C" fn() -> u64 = core::mem::transmute(b + a); - set_u64(f()); + R::IRELATIVE => unsafe { + let f: unsafe extern "C" fn() -> usize = core::mem::transmute(b + a); + set_usize(f()); }, - elf::R_X86_64_COPY => unsafe { - let (sym, obj) = sym - .as_ref() - .expect("R_X86_64_COPY called without valid symbol"); - let my_sym = my_sym.expect("R_X86_64_COPY called without valid symbol"); + 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"); assert!( sym.size == my_sym.st_size(NativeEndian) as usize, - "R_X86_64_COPY failed: I was trying to use the symbol {} from {} for {} but they had different sizes. Please consider relinking.", + "R::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 @@ -801,7 +884,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 {:#x}", reloc.kind), + _ => unimplemented!("relocation type {:?}", r), } Ok(()) @@ -841,16 +924,17 @@ impl DSO { reloc.offset as *mut usize }; - match (reloc.kind, resolve) { - (elf::R_X86_64_JUMP_SLOT, Resolve::Lazy) if self.pie => unsafe { + let r = R::new(reloc.kind); + match (r, resolve) { + (R::JUMP_SLOT, Resolve::Lazy) if self.pie => unsafe { *ptr += object_base_addr; }, - (elf::R_X86_64_JUMP_SLOT, Resolve::Lazy) => { + (R::JUMP_SLOT, Resolve::Lazy) => { // NOP. } - (elf::R_X86_64_JUMP_SLOT, Resolve::Now) => { + (R::JUMP_SLOT, Resolve::Now) => { let name = self.dynamic.symbol_name(reloc.sym).unwrap(); let resolved = resolve_sym(name, &[global_scope, self.scope()]) @@ -863,7 +947,7 @@ impl DSO { } _ => { - unimplemented!("relocation type {:#x}", reloc.kind) + unimplemented!("relocation type {:?} with resolve {:?}", r, resolve) } } }