From 07ff79069ef2492602745de4419cee0698ae0957 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 14 Jan 2025 15:47:17 +1100 Subject: [PATCH] feat(ld.so): add support for DT_RELR Signed-off-by: Anhad Singh --- src/ld_so/dso.rs | 66 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/src/ld_so/dso.rs b/src/ld_so/dso.rs index 6bf1115f45..964aef5c8e 100644 --- a/src/ld_so/dso.rs +++ b/src/ld_so/dso.rs @@ -46,7 +46,9 @@ mod shim { #[cfg(target_pointer_width = "64")] mod shim { + use core::{ffi::c_char, mem::size_of}; use object::{elf::*, read::elf::ElfFile64, NativeEndian}; + pub type Dyn = Dyn64; pub type Rel = Rel64; pub type Rela = Rela64; @@ -54,6 +56,9 @@ mod shim { pub type FileHeader = FileHeader64; pub type ProgramHeader = ProgramHeader64; pub type ElfFile<'a> = ElfFile64<'a, NativeEndian>; + pub type Relr = u64; + + pub const CHAR_BITS: usize = size_of::() * 8; } pub use shim::*; @@ -129,6 +134,7 @@ pub(super) struct Dynamic<'data> { init_array: &'data [unsafe extern "C" fn()], fini_array: &'data [unsafe extern "C" fn()], rela: &'data [Rela], + relr: &'data [Relr], rel: &'data [Rel], symbols: &'data [Sym], explicit_addend: bool, @@ -545,6 +551,10 @@ impl DSO { is_pie: bool, (_, entries): (&ProgramHeader, &[Dyn]), ) -> object::Result<(Dynamic<'a>, Option)> { + const DT_RELRSZ: u32 = 35; + const DT_RELR: u32 = 36; + const DT_RELRENT: u32 = 37; + let mut runpath = None; let mut got = None; let mut needed = vec![]; @@ -555,11 +565,12 @@ impl DSO { let mut pltrelsz = None; let mut debug = None; let mut symtab_ptr = None; - let (mut rel_ptr, mut rel_size) = (None, None); + let (mut rel_ptr, mut rel_len) = (None, None); + let (mut relr_ptr, mut relr_len) = (None, None); let (mut strtab_offset, mut strtab_size) = (None, None); let (mut init_array_ptr, mut init_array_len) = (None, None); let (mut fini_array_ptr, mut fini_array_len) = (None, None); - let (mut rela_offset, mut rela_size) = (None, None); + let (mut rela_offset, mut rela_len) = (None, None); for (i, entry) in entries.iter().enumerate() { let val = entry.d_val(NativeEndian); @@ -599,15 +610,21 @@ impl DSO { elf::DT_SONAME => soname = Some(entry), elf::DT_RELA => rela_offset = Some(ptr.cast::()), - elf::DT_RELASZ => rela_size = Some(val as usize / size_of::()), + elf::DT_RELASZ => rela_len = Some(val as usize / size_of::()), elf::DT_RELAENT => { - assert_eq!(val as usize, size_of::>()) + assert_eq!(val, size_of::() as u64) } elf::DT_REL => rel_ptr = Some(ptr.cast::()), - elf::DT_RELSZ => rel_size = Some(val as usize / size_of::()), + elf::DT_RELSZ => rel_len = Some(val as usize / size_of::()), elf::DT_RELENT => { - assert_eq!(val as usize, size_of::>()) + assert_eq!(val, size_of::() as u64) + } + + DT_RELR => relr_ptr = Some(ptr.cast::()), + DT_RELRSZ => relr_len = Some(val as usize / size_of::()), + DT_RELRENT => { + assert_eq!(val, size_of::() as u64) } elf::DT_PLTREL => { @@ -680,8 +697,9 @@ impl DSO { let init_array = unsafe { get_array(init_array_ptr, init_array_len) }; let fini_array = unsafe { get_array(fini_array_ptr, fini_array_len) }; - let rela = unsafe { get_array(rela_offset, rela_size) }; - let rel = unsafe { get_array(rel_ptr, rel_size) }; + let rela = unsafe { get_array(rela_offset, rela_len) }; + let relr = unsafe { get_array(relr_ptr, relr_len) }; + let rel = unsafe { get_array(rel_ptr, rel_len) }; Ok(( Dynamic { @@ -697,6 +715,7 @@ impl DSO { fini_array, rela, rel, + relr, explicit_addend: explicit_addend.unwrap_or_default(), pltrelsz: pltrelsz.unwrap_or_default(), }, @@ -836,6 +855,37 @@ impl DSO { pub fn relocate(&self, ph: &[ProgramHeader], resolve: Resolve) -> object::Result<()> { let global_scope = GLOBAL_SCOPE.read(); + let base = self.mmap.as_ptr(); + + // Apply DT_RELR relative relocations. + let mut addr = ptr::null_mut(); + for &entry in self.dynamic.relr { + if entry & 1 == 0 { + // An even entry sets up `addr` for subsequent odd entries. + unsafe { + addr = base.add(entry as usize) as *mut usize; + *addr += base as usize; + addr = addr.add(1); + } + } else { + // An odd entry indicates a bitmap describing at maximum 63 + // (for 64-bit) or 31 (for 32-bit) locations following `addr`. + // Odd entries can be chained. + let mut entry = entry >> 1; + let mut i = 0; + while entry != 0 { + if entry & 1 != 0 { + unsafe { + *addr.add(i) += base as usize; + } + } + entry >>= 1; + i += 1; + } + + addr = unsafe { addr.add(CHAR_BITS * size_of::() - 1) }; + } + } self.dynamic .static_relocations()