Merge branch 'patch5' into 'master'

feat(ld.so): add support for DT_RELR

See merge request redox-os/relibc!602
This commit is contained in:
Jeremy Soller
2025-01-15 13:52:06 +00:00
2 changed files with 71 additions and 15 deletions
+13 -6
View File
@@ -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,9 +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,--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
+58 -9
View File
@@ -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::<c_char>() * 8;
pub type Relr = usize;
#[cfg(target_pointer_width = "32")]
mod shim {
use object::{elf::*, read::elf::ElfFile32, NativeEndian};
@@ -129,6 +133,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 +550,10 @@ impl DSO {
is_pie: bool,
(_, entries): (&ProgramHeader, &[Dyn]),
) -> object::Result<(Dynamic<'a>, Option<usize>)> {
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 +564,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 +609,21 @@ impl DSO {
elf::DT_SONAME => soname = Some(entry),
elf::DT_RELA => rela_offset = Some(ptr.cast::<Rela>()),
elf::DT_RELASZ => rela_size = Some(val as usize / size_of::<Rela>()),
elf::DT_RELASZ => rela_len = Some(val as usize / size_of::<Rela>()),
elf::DT_RELAENT => {
assert_eq!(val as usize, size_of::<elf::Rela64<Endianness>>())
assert_eq!(val, size_of::<Rela>() as u64)
}
elf::DT_REL => rel_ptr = Some(ptr.cast::<Rel>()),
elf::DT_RELSZ => rel_size = Some(val as usize / size_of::<Rel>()),
elf::DT_RELSZ => rel_len = Some(val as usize / size_of::<Rel>()),
elf::DT_RELENT => {
assert_eq!(val as usize, size_of::<elf::Rel64<Endianness>>())
assert_eq!(val, size_of::<Rel>() as u64)
}
DT_RELR => relr_ptr = Some(ptr.cast::<Relr>()),
DT_RELRSZ => relr_len = Some(val as usize / size_of::<Relr>()),
DT_RELRENT => {
assert_eq!(val, size_of::<Relr>() as u64)
}
elf::DT_PLTREL => {
@@ -680,8 +696,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 +714,7 @@ impl DSO {
fini_array,
rela,
rel,
relr,
explicit_addend: explicit_addend.unwrap_or_default(),
pltrelsz: pltrelsz.unwrap_or_default(),
},
@@ -836,6 +854,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::<Relr>() - 1) };
}
}
self.dynamic
.static_relocations()