feat(libc.so.6): merge with ld.so
Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
+196
-65
@@ -3,7 +3,7 @@
|
||||
//! * <https://www.akkadia.org/drepper/dsohowto.pdf>
|
||||
|
||||
use object::{
|
||||
NativeEndian, Object, StringTable, SymbolIndex, elf,
|
||||
NativeEndian, Object, StringTable, SymbolIndex, U32, elf,
|
||||
read::elf::{
|
||||
Dyn as _, GnuHashTable, HashTable as SysVHashTable, ProgramHeader as _, Rel as _,
|
||||
Rela as _, Sym as _, Version, VersionTable,
|
||||
@@ -42,25 +42,27 @@ pub type Relr = usize;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
mod shim {
|
||||
use object::{NativeEndian, elf::*, read::elf::ElfFile32};
|
||||
pub type Dyn = Dyn32<NativeEndian>;
|
||||
pub type Rel = Rel32<NativeEndian>;
|
||||
pub type Rela = Rela32<NativeEndian>;
|
||||
pub type Sym = Sym32<NativeEndian>;
|
||||
pub type FileHeader = FileHeader32<NativeEndian>;
|
||||
pub type ProgramHeader = ProgramHeader32<NativeEndian>;
|
||||
use object::{NativeEndian, read::elf::ElfFile32};
|
||||
pub type Dyn = elf::Dyn32<NativeEndian>;
|
||||
pub type Rel = elf::Rel32<NativeEndian>;
|
||||
pub type Rela = elf::Rela32<NativeEndian>;
|
||||
pub type Sym = elf::Sym32<NativeEndian>;
|
||||
pub type FileHeader = elf::FileHeader32<NativeEndian>;
|
||||
pub type ProgramHeader = elf::ProgramHeader32<NativeEndian>;
|
||||
pub type GnuHashHeader = elf::GnuHashHeader<NativeEndian>;
|
||||
pub type ElfFile<'a> = ElfFile32<'a, NativeEndian>;
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod shim {
|
||||
use object::{NativeEndian, elf::*, read::elf::ElfFile64};
|
||||
pub type Dyn = Dyn64<NativeEndian>;
|
||||
pub type Rel = Rel64<NativeEndian>;
|
||||
pub type Rela = Rela64<NativeEndian>;
|
||||
pub type Sym = Sym64<NativeEndian>;
|
||||
pub type FileHeader = FileHeader64<NativeEndian>;
|
||||
pub type ProgramHeader = ProgramHeader64<NativeEndian>;
|
||||
use object::{NativeEndian, elf, read::elf::ElfFile64};
|
||||
pub type Dyn = elf::Dyn64<NativeEndian>;
|
||||
pub type Rel = elf::Rel64<NativeEndian>;
|
||||
pub type Rela = elf::Rela64<NativeEndian>;
|
||||
pub type Sym = elf::Sym64<NativeEndian>;
|
||||
pub type FileHeader = elf::FileHeader64<NativeEndian>;
|
||||
pub type ProgramHeader = elf::ProgramHeader64<NativeEndian>;
|
||||
pub type GnuHashHeader = elf::GnuHashHeader<NativeEndian>;
|
||||
pub type ElfFile<'a> = ElfFile64<'a, NativeEndian>;
|
||||
}
|
||||
|
||||
@@ -176,7 +178,7 @@ impl<'data> Dynamic<'data> {
|
||||
unsafe impl Send for Dynamic<'_> {}
|
||||
unsafe impl Sync for Dynamic<'_> {}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct Relocation {
|
||||
pub(super) offset: usize,
|
||||
pub(super) addend: Option<usize>,
|
||||
@@ -331,14 +333,35 @@ impl SymbolBinding {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MemoryMapHandle {
|
||||
ptr: *const u8,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl MemoryMapHandle {
|
||||
pub fn as_ptr(&self) -> *const u8 {
|
||||
self.ptr
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemoryMapHandle {
|
||||
fn drop(&mut self) {
|
||||
unsafe { Sys::munmap(self.ptr as *mut c_void, self.size).unwrap() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Use to represent a library as well as all the symbols that is loaded withen it.
|
||||
pub struct DSO {
|
||||
pub name: String,
|
||||
pub id: usize,
|
||||
pub dlopened: bool,
|
||||
pub entry_point: usize,
|
||||
/// Loaded library in-memory data
|
||||
pub mmap: &'static [u8],
|
||||
pub base: *const u8,
|
||||
pub mmap: Option<MemoryMapHandle>,
|
||||
pub tls_module_id: usize,
|
||||
pub tls_offset: usize,
|
||||
|
||||
@@ -349,10 +372,56 @@ pub struct DSO {
|
||||
pub pie: bool,
|
||||
|
||||
/// Whether this DSO *and* its dependencies have been successfully loaded.
|
||||
is_ready: AtomicBool,
|
||||
pub is_ready: AtomicBool,
|
||||
|
||||
/// Is this DSO for ld.so?
|
||||
is_me: bool,
|
||||
}
|
||||
|
||||
impl DSO {
|
||||
pub fn from_raw(
|
||||
base: *const u8,
|
||||
dyns: &[Dyn],
|
||||
phdrs: &[ProgramHeader],
|
||||
id: usize,
|
||||
tls_module_id: usize,
|
||||
tls_offset: usize,
|
||||
) -> (Self, Master) {
|
||||
// FIXME: What should `path` be set to?
|
||||
// FIXME: this function and `parse_dynamic` should be unsafe.
|
||||
let (dynamic, _debug) = Self::parse_dynamic("", base, true, dyns).unwrap();
|
||||
|
||||
let tcb_master = phdrs
|
||||
.iter()
|
||||
.find(|ph| ph.p_type(NativeEndian) == elf::PT_TLS)
|
||||
.map(|ph| Master {
|
||||
ptr: unsafe { base.byte_add(ph.p_vaddr(NativeEndian) as usize) },
|
||||
image_size: ph.p_filesz(NativeEndian) as usize,
|
||||
segment_size: ph.p_memsz(NativeEndian) as usize,
|
||||
offset: tls_offset + ph.p_memsz(NativeEndian) as usize,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
(
|
||||
Self {
|
||||
name: String::from("libc.so.6"),
|
||||
id,
|
||||
tls_offset: tcb_master.offset,
|
||||
tls_module_id,
|
||||
dlopened: false,
|
||||
entry_point: 0,
|
||||
base,
|
||||
mmap: None,
|
||||
dynamic,
|
||||
scope: spin::Once::new(),
|
||||
pie: true,
|
||||
is_ready: AtomicBool::new(false),
|
||||
is_me: true,
|
||||
},
|
||||
tcb_master,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
path: &str,
|
||||
data: &[u8],
|
||||
@@ -385,7 +454,10 @@ impl DSO {
|
||||
id,
|
||||
dlopened,
|
||||
entry_point,
|
||||
mmap,
|
||||
|
||||
base: mmap.as_ptr(),
|
||||
mmap: Some(mmap),
|
||||
|
||||
tls_module_id: if tcb_master.is_some() {
|
||||
tls_module_id
|
||||
} else {
|
||||
@@ -397,6 +469,7 @@ impl DSO {
|
||||
dynamic,
|
||||
scope: spin::Once::new(),
|
||||
is_ready: AtomicBool::new(false),
|
||||
is_me: false,
|
||||
};
|
||||
|
||||
Ok((dso, tcb_master, elf.elf_program_headers().to_vec()))
|
||||
@@ -444,11 +517,7 @@ impl DSO {
|
||||
Some((
|
||||
Symbol {
|
||||
name,
|
||||
base: if self.pie {
|
||||
self.mmap.as_ptr() as usize
|
||||
} else {
|
||||
0
|
||||
},
|
||||
base: if self.pie { self.base as usize } else { 0 },
|
||||
value: sym.st_value(NativeEndian) as usize,
|
||||
size: sym.st_size(NativeEndian) as usize,
|
||||
sym_type: sym.st_type(),
|
||||
@@ -480,7 +549,7 @@ impl DSO {
|
||||
data: &'a [u8],
|
||||
base_addr: Option<usize>,
|
||||
tls_offset: usize,
|
||||
) -> Result<(&'static [u8], Option<Master>, Dynamic<'static>), String> {
|
||||
) -> Result<(MemoryMapHandle, Option<Master>, Dynamic<'static>), String> {
|
||||
let endian = elf.endian();
|
||||
log::trace!("# {}", path);
|
||||
// data for struct LinkMap
|
||||
@@ -640,8 +709,9 @@ impl DSO {
|
||||
|
||||
let dynamic = dynamic.ok_or_else(|| "Unable to find PT_DYNAMIC section".to_string())?;
|
||||
|
||||
let (parsed_dynamic, debug) = Self::parse_dynamic(path, mmap, is_pie_enabled(elf), dynamic)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let (parsed_dynamic, debug) =
|
||||
Self::parse_dynamic(path, mmap.as_ptr(), is_pie_enabled(elf), dynamic.1)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
if let Some(i) = debug {
|
||||
// FIXME: cleanup
|
||||
@@ -664,14 +734,21 @@ impl DSO {
|
||||
}
|
||||
}
|
||||
|
||||
Ok((mmap, tcb_master, parsed_dynamic))
|
||||
Ok((
|
||||
MemoryMapHandle {
|
||||
ptr: mmap.as_ptr(),
|
||||
size: mmap.len(),
|
||||
},
|
||||
tcb_master,
|
||||
parsed_dynamic,
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_dynamic<'a>(
|
||||
path: &str,
|
||||
mmap: &'a [u8],
|
||||
mmap: *const u8,
|
||||
is_pie: bool,
|
||||
(_, entries): (&ProgramHeader, &[Dyn]),
|
||||
entries: &[Dyn],
|
||||
) -> object::Result<(Dynamic<'a>, Option<usize>)> {
|
||||
let mut runpath = None;
|
||||
let mut got = None;
|
||||
@@ -692,28 +769,66 @@ impl DSO {
|
||||
|
||||
for (i, entry) in entries.iter().enumerate() {
|
||||
let val = entry.d_val(NativeEndian);
|
||||
let relative_idx = val as usize - if is_pie { 0 } else { mmap.as_ptr() as usize };
|
||||
let ptr = (val as usize + if is_pie { mmap.as_ptr() as usize } else { 0 }) as *const u8;
|
||||
let relative_idx = val as usize - if is_pie { 0 } else { mmap as usize };
|
||||
let ptr = (val as usize + if is_pie { mmap as usize } else { 0 }) as *const u8;
|
||||
let tag = entry.d_tag(NativeEndian) as u32;
|
||||
|
||||
match tag {
|
||||
elf::DT_DEBUG => debug = Some(i),
|
||||
|
||||
// {Gnu,SysV}HashTable::parse()
|
||||
//
|
||||
// > The header does not contain a length field, and so all of
|
||||
// > `data` will be used as the hash table values. It does not
|
||||
// > matter if this is longer than needed...
|
||||
elf::DT_GNU_HASH => {
|
||||
let value = GnuHashTable::parse(NativeEndian, &mmap[relative_idx..])?;
|
||||
hash_table = Some(HashTable::Gnu(value));
|
||||
let header = unsafe { ptr.cast::<GnuHashHeader>().as_ref() }.unwrap();
|
||||
let bloom_count = header.bloom_count.get(NativeEndian) as usize;
|
||||
let bucket_count = header.bucket_count.get(NativeEndian) as usize;
|
||||
let symbol_base = header.symbol_base.get(NativeEndian);
|
||||
|
||||
let bloom_size = bloom_count * size_of::<usize>();
|
||||
let mut ptr = unsafe { ptr.byte_add(size_of::<GnuHashHeader>()) };
|
||||
|
||||
let bloom_filters = unsafe { slice::from_raw_parts(ptr, bloom_size) };
|
||||
unsafe { ptr = ptr.byte_add(bloom_size) };
|
||||
|
||||
let buckets = unsafe {
|
||||
slice::from_raw_parts(ptr.cast::<U32<NativeEndian>>(), bucket_count)
|
||||
};
|
||||
unsafe { ptr = ptr.byte_add(bucket_count * size_of::<u32>()) };
|
||||
|
||||
let mut max_symbol = 0;
|
||||
for bucket in buckets {
|
||||
let bucket = bucket.get(NativeEndian);
|
||||
if max_symbol < bucket {
|
||||
max_symbol = bucket;
|
||||
}
|
||||
}
|
||||
|
||||
assert_ne!(max_symbol, 0);
|
||||
let chains_ptr = ptr.cast::<u32>();
|
||||
let mut i = max_symbol - symbol_base;
|
||||
|
||||
while unsafe { chains_ptr.add(i as usize).read() & 1 == 0 } {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let values = unsafe {
|
||||
slice::from_raw_parts(ptr.cast::<U32<NativeEndian>>(), i as usize + 1)
|
||||
};
|
||||
|
||||
let table = GnuHashTable {
|
||||
symbol_base,
|
||||
bloom_shift: header.bloom_shift.get(NativeEndian),
|
||||
bloom_filters,
|
||||
buckets,
|
||||
values,
|
||||
};
|
||||
|
||||
hash_table = Some(HashTable::Gnu(table));
|
||||
}
|
||||
|
||||
// XXX: Both GNU_HASH and HASH may be present, we give priority
|
||||
// to GNU_HASH as it is significantly faster.
|
||||
elf::DT_HASH if hash_table.is_none() => {
|
||||
let value = SysVHashTable::parse(NativeEndian, &mmap[relative_idx..])?;
|
||||
hash_table = Some(HashTable::Sysv(value));
|
||||
// FIXME: BEFORE MR FIX THIS
|
||||
// todo!();
|
||||
}
|
||||
|
||||
elf::DT_PLTGOT => {
|
||||
@@ -771,14 +886,16 @@ impl DSO {
|
||||
}
|
||||
}
|
||||
|
||||
let strtab_offset = strtab_offset.expect("mandatory DT_STRTAB not present");
|
||||
let strtab_size = strtab_size.expect("mandatory DT_STRSZ not present");
|
||||
let hash_table = hash_table.expect("either DT_GNU_HASH and/or DT_HASH mut be present");
|
||||
|
||||
let strtab_offset = strtab_offset.expect("DT_STRTAB must be present");
|
||||
let strtab_size = strtab_size.expect("DT_STRSZ must be present");
|
||||
|
||||
#[expect(clippy::unnecessary_cast, reason = "needed on i586")]
|
||||
let dynstrtab = StringTable::new(
|
||||
mmap,
|
||||
strtab_offset as u64,
|
||||
strtab_offset as u64 + strtab_size as u64,
|
||||
unsafe { slice::from_raw_parts(mmap.byte_add(strtab_offset), strtab_size as usize) },
|
||||
0,
|
||||
strtab_size as u64,
|
||||
);
|
||||
|
||||
let get_str = |entry: &Dyn| {
|
||||
@@ -812,7 +929,6 @@ impl DSO {
|
||||
let soname = soname.map(get_str).transpose()?;
|
||||
|
||||
let jmprel = jmprel.unwrap_or_default();
|
||||
let hash_table = hash_table.expect("either DT_GNU_HASH and/or DT_HASH mut be present");
|
||||
|
||||
let init_array = unsafe { get_array(init_array_ptr, init_array_len) };
|
||||
let fini_array = unsafe { get_array(fini_array_ptr, fini_array_len) };
|
||||
@@ -889,8 +1005,6 @@ impl DSO {
|
||||
}
|
||||
|
||||
fn static_relocate(&self, global_scope: &Scope, reloc: Relocation) -> object::Result<()> {
|
||||
let b = self.mmap.as_ptr() as usize;
|
||||
|
||||
let (sym, my_sym) = if reloc.sym != STN_UNDEF {
|
||||
let name = self.dynamic.symbol_name(reloc.sym).unwrap();
|
||||
|
||||
@@ -923,7 +1037,7 @@ impl DSO {
|
||||
.unwrap_or((0, self));
|
||||
|
||||
let ptr = if self.pie {
|
||||
(b + reloc.offset) as *mut u8
|
||||
unsafe { self.base.byte_add(reloc.offset).cast_mut() }
|
||||
} else {
|
||||
reloc.offset as *mut u8
|
||||
};
|
||||
@@ -956,7 +1070,7 @@ impl DSO {
|
||||
}
|
||||
RelocationKind::GOT => set_usize(s),
|
||||
RelocationKind::OFFSET => set_usize((s + a).wrapping_sub(p)),
|
||||
RelocationKind::RELATIVE => set_usize(b + a),
|
||||
RelocationKind::RELATIVE => set_usize(self.base as usize + a),
|
||||
RelocationKind::SYMBOLIC => set_usize(s + a),
|
||||
RelocationKind::TPOFF => {
|
||||
assert!(
|
||||
@@ -974,7 +1088,8 @@ impl DSO {
|
||||
}
|
||||
}
|
||||
RelocationKind::IRELATIVE => unsafe {
|
||||
let f: unsafe extern "C" fn() -> usize = core::mem::transmute(b + a);
|
||||
let f: unsafe extern "C" fn() -> usize =
|
||||
core::mem::transmute(self.base as usize + a);
|
||||
set_usize(f());
|
||||
},
|
||||
RelocationKind::COPY => unsafe {
|
||||
@@ -1007,7 +1122,6 @@ impl DSO {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let object_base_addr = self.mmap.as_ptr() as usize;
|
||||
let jmprel = self.dynamic.jmprel;
|
||||
let pltrelsz = self.dynamic.pltrelsz;
|
||||
|
||||
@@ -1031,14 +1145,14 @@ impl DSO {
|
||||
};
|
||||
|
||||
let ptr = if self.pie {
|
||||
(object_base_addr + reloc.offset) as *mut usize
|
||||
(self.base as usize + reloc.offset) as *mut usize
|
||||
} else {
|
||||
reloc.offset as *mut usize
|
||||
};
|
||||
|
||||
match (reloc.kind, resolve) {
|
||||
(RelocationKind::PLT, Resolve::Lazy) if self.pie => unsafe {
|
||||
*ptr += object_base_addr;
|
||||
*ptr += self.base as usize;
|
||||
},
|
||||
|
||||
(RelocationKind::PLT, Resolve::Lazy) => {
|
||||
@@ -1082,20 +1196,31 @@ impl DSO {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn relocate(&self, ph: &[ProgramHeader], resolve: Resolve) -> object::Result<()> {
|
||||
pub fn relocate(&self, ph: Option<&[ProgramHeader]>, resolve: Resolve) -> object::Result<()> {
|
||||
let global_scope = GLOBAL_SCOPE.read();
|
||||
let base = self.mmap.as_ptr();
|
||||
|
||||
unsafe {
|
||||
apply_relr(base, self.dynamic.relr);
|
||||
if !self.is_me {
|
||||
unsafe {
|
||||
apply_relr(self.base, self.dynamic.relr);
|
||||
}
|
||||
}
|
||||
|
||||
self.dynamic
|
||||
.static_relocations()
|
||||
.try_for_each(|reloc| self.static_relocate(&global_scope, reloc))?;
|
||||
for reloc in self.dynamic.static_relocations() {
|
||||
if reloc.kind == RelocationKind::RELATIVE && self.is_me {
|
||||
continue;
|
||||
}
|
||||
self.static_relocate(&global_scope, reloc)?;
|
||||
}
|
||||
|
||||
if self.is_me {
|
||||
// TODO: assert that ld.so have no lazy relocations.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.lazy_relocate(&global_scope, resolve)?;
|
||||
|
||||
let ph = ph.unwrap();
|
||||
|
||||
// Protect pages
|
||||
for ph in ph
|
||||
.iter()
|
||||
@@ -1120,7 +1245,7 @@ impl DSO {
|
||||
|
||||
unsafe {
|
||||
let ptr = if self.pie {
|
||||
self.mmap.as_ptr().add(vaddr)
|
||||
self.base.add(vaddr)
|
||||
} else {
|
||||
vaddr as *const u8
|
||||
};
|
||||
@@ -1135,12 +1260,14 @@ impl DSO {
|
||||
|
||||
impl Drop for DSO {
|
||||
fn drop(&mut self) {
|
||||
if self.is_me {
|
||||
return;
|
||||
}
|
||||
if self.is_ready.load(Ordering::SeqCst) {
|
||||
// `run_fini` should not be called if we are being prematurely
|
||||
// dropped (e.g. failed to satisfy dependencies).
|
||||
self.run_fini();
|
||||
}
|
||||
unsafe { Sys::munmap(self.mmap.as_ptr() as *mut c_void, self.mmap.len()).unwrap() };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1309,3 +1436,7 @@ pub unsafe fn apply_relr(base: *const u8, relr: &[Relr]) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add safety comment.
|
||||
unsafe impl Send for DSO {}
|
||||
unsafe impl Sync for DSO {}
|
||||
|
||||
+64
-8
@@ -26,7 +26,7 @@ use crate::{
|
||||
fcntl, sys_mman,
|
||||
unistd::F_OK,
|
||||
},
|
||||
ld_so::dso::SymbolBinding,
|
||||
ld_so::dso::{Dyn, SymbolBinding},
|
||||
out::Out,
|
||||
platform::{
|
||||
Pal, Sys,
|
||||
@@ -417,9 +417,17 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Me {
|
||||
pub base: *const u8,
|
||||
pub phdrs: &'static [ProgramHeader],
|
||||
pub dyns: &'static [Dyn],
|
||||
}
|
||||
|
||||
pub struct Linker {
|
||||
config: Config,
|
||||
|
||||
me: Me,
|
||||
|
||||
next_object_id: usize,
|
||||
next_tls_module_id: usize,
|
||||
tls_size: usize,
|
||||
@@ -431,8 +439,9 @@ pub struct Linker {
|
||||
const ROOT_ID: usize = 1;
|
||||
|
||||
impl Linker {
|
||||
pub fn new(config: Config) -> Self {
|
||||
pub fn new(me: Me, config: Config) -> Self {
|
||||
Self {
|
||||
me,
|
||||
config,
|
||||
next_object_id: ROOT_ID,
|
||||
next_tls_module_id: 1,
|
||||
@@ -642,7 +651,11 @@ impl Linker {
|
||||
)?;
|
||||
|
||||
for (i, obj) in new_objects.iter().enumerate() {
|
||||
obj.relocate(&objects_data[i], resolve).unwrap();
|
||||
obj.relocate(
|
||||
objects_data[i].as_ref().map(|phdrs| phdrs.as_slice()),
|
||||
resolve,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
@@ -788,7 +801,7 @@ impl Linker {
|
||||
base_addr: Option<usize>,
|
||||
dlopened: bool,
|
||||
new_objects: &mut Vec<Arc<DSO>>,
|
||||
objects_data: &mut Vec<Vec<ProgramHeader>>,
|
||||
objects_data: &mut Vec<Option<Vec<ProgramHeader>>>,
|
||||
tcb_masters: &mut Vec<Master>,
|
||||
// Scope of the object that caused this object to be loaded.
|
||||
dependent_scope: Option<&mut Scope>,
|
||||
@@ -821,6 +834,49 @@ impl Linker {
|
||||
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::LOAD);
|
||||
|
||||
if name == "libc.so.6" || name == "libc.so" {
|
||||
if debug {
|
||||
println!(
|
||||
"[ld.so]: loading libc.so.6 (aka. ld.so) at {:#?}",
|
||||
self.me.base
|
||||
);
|
||||
}
|
||||
|
||||
let (me, master) = DSO::from_raw(
|
||||
self.me.base,
|
||||
self.me.dyns,
|
||||
self.me.phdrs,
|
||||
self.next_object_id,
|
||||
self.next_tls_module_id,
|
||||
self.tls_size.next_multiple_of(16),
|
||||
);
|
||||
|
||||
self.tls_size = master.offset;
|
||||
self.next_tls_module_id += 1;
|
||||
self.next_object_id += 1;
|
||||
|
||||
let obj = Arc::new(me);
|
||||
|
||||
tcb_masters.push(master);
|
||||
objects_data.push(None);
|
||||
new_objects.push(obj.clone());
|
||||
|
||||
if let Some(dependent_scope) = dependent_scope {
|
||||
match scope_kind {
|
||||
ScopeKind::Local => dependent_scope.add(&obj),
|
||||
ScopeKind::Global => GLOBAL_SCOPE.write().add(&obj),
|
||||
}
|
||||
} else if let ScopeKind::Global = scope_kind {
|
||||
GLOBAL_SCOPE.write().add(&obj);
|
||||
}
|
||||
|
||||
let mut scope = Scope::local();
|
||||
scope.set_owner(Arc::downgrade(&obj));
|
||||
obj.scope.call_once(|| scope);
|
||||
|
||||
return Ok(obj);
|
||||
}
|
||||
|
||||
let path = self.search_object(name, parent_runpath)?;
|
||||
let file = self.read_file(&path)?;
|
||||
let data = file.data();
|
||||
@@ -846,8 +902,8 @@ impl Linker {
|
||||
eprintln!(
|
||||
"[ld.so]: loading object: {} at {:#x}:{:#x} (pie: {})",
|
||||
name,
|
||||
obj.mmap.as_ptr() as usize,
|
||||
obj.mmap.as_ptr() as usize + obj.mmap.len(),
|
||||
obj.mmap.as_ref().unwrap().as_ptr() as usize,
|
||||
obj.mmap.as_ref().unwrap().as_ptr() as usize + obj.mmap.as_ref().unwrap().size(),
|
||||
obj.pie,
|
||||
);
|
||||
}
|
||||
@@ -896,7 +952,7 @@ impl Linker {
|
||||
)?;
|
||||
}
|
||||
|
||||
objects_data.push(elf);
|
||||
objects_data.push(Some(elf));
|
||||
new_objects.push(obj.clone());
|
||||
|
||||
scope.set_owner(Arc::downgrade(&obj));
|
||||
@@ -1011,7 +1067,7 @@ impl Linker {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) -> *mut c_void {
|
||||
let obj = unsafe { &*obj };
|
||||
let obj_base = obj.mmap.as_ptr() as usize;
|
||||
let obj_base = obj.base as usize;
|
||||
let jmprel = obj.dynamic.jmprel;
|
||||
|
||||
let rela = unsafe { &*(jmprel as *const Rela).add(relocation_index as usize) };
|
||||
|
||||
+39
-10
@@ -12,7 +12,7 @@ use alloc::{
|
||||
use object::{
|
||||
NativeEndian,
|
||||
elf::{self, PT_DYNAMIC, PT_PHDR},
|
||||
read::elf::{Dyn as _, ProgramHeader as _},
|
||||
read::elf::{Dyn as _, FileHeader as _, ProgramHeader as _},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -23,10 +23,10 @@ use crate::{
|
||||
},
|
||||
ld_so::{
|
||||
dso::{
|
||||
DT_RELR, DT_RELRENT, DT_RELRSZ, Dyn, ProgramHeader, Rel, Rela, Relocation,
|
||||
DT_RELR, DT_RELRENT, DT_RELRSZ, Dyn, FileHeader, ProgramHeader, Rel, Rela, Relocation,
|
||||
RelocationKind, Relr, apply_relr,
|
||||
},
|
||||
linker::DebugFlags,
|
||||
linker::{DebugFlags, Me},
|
||||
},
|
||||
platform::{auxv_iter, get_auxvs, types::c_char},
|
||||
start::Stack,
|
||||
@@ -211,7 +211,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
|
||||
|
||||
let is_manual = at_entry == ld_entry; // Whether the dynamic linker was invoked as a command.
|
||||
|
||||
let mut i = dynamic;
|
||||
let mut i = 0;
|
||||
let mut rela_ptr = None;
|
||||
let mut rela_len = None;
|
||||
let mut relr_ptr = None;
|
||||
@@ -219,7 +219,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
|
||||
let mut rel_ptr = None;
|
||||
let mut rel_len = None;
|
||||
loop {
|
||||
let entry = unsafe { &*i };
|
||||
let entry = unsafe { &*dynamic.add(i) };
|
||||
let val = entry.d_val(NativeEndian);
|
||||
let ptr = val as *const u8;
|
||||
match entry.d_tag(NativeEndian) as u32 {
|
||||
@@ -241,9 +241,11 @@ pub unsafe extern "C" fn relibc_ld_so_start(
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
i = unsafe { i.add(1) };
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let dyns = unsafe { slice::from_raw_parts(dynamic, i) };
|
||||
|
||||
unsafe fn get_array<'a, T>(
|
||||
ptr: Option<*const T>,
|
||||
len: Option<usize>,
|
||||
@@ -251,7 +253,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
|
||||
) -> &'a [T] {
|
||||
if let Some(ptr) = ptr {
|
||||
let len = len.expect("dynamic entry was present without it's corresponding size");
|
||||
unsafe { core::slice::from_raw_parts(ptr.byte_add(base_addr), len) }
|
||||
unsafe { slice::from_raw_parts(ptr.byte_add(base_addr), len) }
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
@@ -298,7 +300,23 @@ pub unsafe extern "C" fn relibc_ld_so_start(
|
||||
}
|
||||
}
|
||||
|
||||
stage2(sp, self_base, is_manual, base_addr)
|
||||
unsafe extern "C" {
|
||||
safe static __ehdr_start: FileHeader;
|
||||
}
|
||||
|
||||
let ph_off = __ehdr_start.e_phoff(NativeEndian) as usize;
|
||||
let ph_num = __ehdr_start.e_phnum(NativeEndian) as usize;
|
||||
|
||||
let my_phdrs = unsafe {
|
||||
slice::from_raw_parts(
|
||||
core::ptr::addr_of!(__ehdr_start)
|
||||
.byte_add(ph_off)
|
||||
.cast::<ProgramHeader>(),
|
||||
ph_num,
|
||||
)
|
||||
};
|
||||
|
||||
stage2(sp, self_base, is_manual, base_addr, dyns, my_phdrs)
|
||||
}
|
||||
|
||||
fn stage2(
|
||||
@@ -306,6 +324,8 @@ fn stage2(
|
||||
self_base: usize,
|
||||
is_manual: bool,
|
||||
base_addr: Option<usize>,
|
||||
my_dyns: &'static [Dyn],
|
||||
my_phdrs: &'static [ProgramHeader],
|
||||
) -> usize {
|
||||
// Setup TCB for ourselves.
|
||||
unsafe {
|
||||
@@ -394,7 +414,9 @@ fn stage2(
|
||||
|
||||
crate::platform::environ = crate::platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr();
|
||||
|
||||
crate::platform::logger::init();
|
||||
if let Err(_) = crate::platform::logger::init() {
|
||||
log::error!("Logger has already been initialised");
|
||||
}
|
||||
}
|
||||
|
||||
// we might need global lock for this kind of stuff
|
||||
@@ -435,7 +457,14 @@ fn stage2(
|
||||
}
|
||||
}
|
||||
|
||||
let mut linker = Linker::new(config);
|
||||
let mut linker = Linker::new(
|
||||
Me {
|
||||
base: self_base as *const u8,
|
||||
phdrs: my_phdrs,
|
||||
dyns: my_dyns,
|
||||
},
|
||||
config,
|
||||
);
|
||||
let entry = match linker.load_program(&path, base_addr) {
|
||||
Ok(entry) => entry,
|
||||
Err(err) => {
|
||||
|
||||
Reference in New Issue
Block a user