From 07ff79069ef2492602745de4419cee0698ae0957 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 14 Jan 2025 15:47:17 +1100 Subject: [PATCH 1/4] 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() From cf21cf24fc496d31938136c804cd2cffadf8c63f Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 14 Jan 2025 15:49:13 +1100 Subject: [PATCH 2/4] feat(libc.so): link flags * -z pack-relative-relocs * --sort-common * --gc-sections Signed-off-by: Anhad Singh --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1edf530c9b..c9a8b2bfad 100644 --- a/Makefile +++ b/Makefile @@ -218,7 +218,15 @@ $(BUILD)/release/libc.a: $(BUILD)/release/librelibc.a $(BUILD)/openlibm/libopenl $(AR) -M < "$@.mri" $(BUILD)/release/libc.so: $(BUILD)/release/librelibc.a $(BUILD)/openlibm/libopenlibm.a - $(CC) -nostdlib -shared -Wl,--allow-multiple-definition -Wl,--whole-archive $^ -Wl,--no-whole-archive -Wl,-soname,libc.so.6 -lgcc -o $@ + $(CC) -nostdlib -shared \ + -Wl,--gc-sections \ + -Wl,-z,pack-relative-relocs \ + -Wl,--sort-common \ + -Wl,--allow-multiple-definition \ + -Wl,--whole-archive $^ -Wl,--no-whole-archive \ + -Wl,-soname,libc.so.6 \ + -lgcc \ + -o $@ $(BUILD)/release/librelibc.a: $(SRC) $(CARGO) rustc --release $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS) From a6317038378533b5a32c6c9de6b8d2afcf8e6026 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 15 Jan 2025 19:16:37 +1100 Subject: [PATCH 3/4] cleanup(makefile): unify rule for libc.so Does the same thing. Signed-off-by: Anhad Singh --- Makefile | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index c9a8b2bfad..a76a66c630 100644 --- a/Makefile +++ b/Makefile @@ -168,6 +168,19 @@ test: sysroot $(MAKE) -C tests run $(MAKE) -C tests verify + +$(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/librelibc.a $(BUILD)/openlibm/libopenlibm.a + $(CC) -nostdlib \ + -shared \ + -Wl,--gc-sections \ + -Wl,-z,pack-relative-relocs \ + -Wl,--sort-common \ + -Wl,--allow-multiple-definition \ + -Wl,--whole-archive $^ -Wl,--no-whole-archive \ + -Wl,-soname,libc.so.6 \ + -lgcc \ + -o $@ + # Debug targets $(BUILD)/debug/libc.a: $(BUILD)/debug/librelibc.a $(BUILD)/openlibm/libopenlibm.a @@ -179,9 +192,6 @@ $(BUILD)/debug/libc.a: $(BUILD)/debug/librelibc.a $(BUILD)/openlibm/libopenlibm. echo "end" >> "$@.mri" $(AR) -M < "$@.mri" -$(BUILD)/debug/libc.so: $(BUILD)/debug/librelibc.a $(BUILD)/openlibm/libopenlibm.a - $(CC) -nostdlib -shared -Wl,--allow-multiple-definition -Wl,--whole-archive $^ -Wl,--no-whole-archive -Wl,-soname,libc.so.6 -lgcc -o $@ - $(BUILD)/debug/librelibc.a: $(SRC) $(CARGO) rustc $(CARGOFLAGS) -- --emit link=$@ -g -C debug-assertions=no $(RUSTCFLAGS) ./renamesyms.sh "$@" "$(BUILD)/debug/deps/" @@ -217,17 +227,6 @@ $(BUILD)/release/libc.a: $(BUILD)/release/librelibc.a $(BUILD)/openlibm/libopenl echo "end" >> "$@.mri" $(AR) -M < "$@.mri" -$(BUILD)/release/libc.so: $(BUILD)/release/librelibc.a $(BUILD)/openlibm/libopenlibm.a - $(CC) -nostdlib -shared \ - -Wl,--gc-sections \ - -Wl,-z,pack-relative-relocs \ - -Wl,--sort-common \ - -Wl,--allow-multiple-definition \ - -Wl,--whole-archive $^ -Wl,--no-whole-archive \ - -Wl,-soname,libc.so.6 \ - -lgcc \ - -o $@ - $(BUILD)/release/librelibc.a: $(SRC) $(CARGO) rustc --release $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS) # TODO: Better to only allow a certain whitelisted set of symbols? Perhaps From 34409857294312125cd3fb124c2f8087514ca5b2 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 15 Jan 2025 21:32:40 +1100 Subject: [PATCH 4/4] fix(dso): 32-bit Signed-off-by: Anhad Singh --- src/ld_so/dso.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ld_so/dso.rs b/src/ld_so/dso.rs index 964aef5c8e..e401cf5d36 100644 --- a/src/ld_so/dso.rs +++ b/src/ld_so/dso.rs @@ -8,7 +8,7 @@ use object::{ Dyn as _, GnuHashTable, HashTable as SysVHashTable, ProgramHeader as _, Rel as _, Rela as _, Sym as _, Version, VersionTable, }, - Endianness, NativeEndian, Object, StringTable, SymbolIndex, + NativeEndian, Object, StringTable, SymbolIndex, }; use super::{ @@ -27,11 +27,15 @@ use alloc::{ vec::Vec, }; use core::{ + ffi::c_char, mem::size_of, ptr::{self, NonNull}, slice, }; +pub const CHAR_BITS: usize = size_of::() * 8; +pub type Relr = usize; + #[cfg(target_pointer_width = "32")] mod shim { use object::{elf::*, read::elf::ElfFile32, NativeEndian}; @@ -46,9 +50,7 @@ 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; @@ -56,9 +58,6 @@ 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::*;