ld: call global constructors
This commit is contained in:
parent
6dc77143b0
commit
98ea969675
@ -53,6 +53,12 @@ fn run(binary: &str, args: &[String]) -> Result<!, Error> {
|
||||
lib.relocate(&mut state)?;
|
||||
}
|
||||
|
||||
// Call global constructors before handing off control to the program
|
||||
for (_, lib) in libraries.iter_mut() {
|
||||
lib.call_constructors();
|
||||
}
|
||||
root.call_constructors();
|
||||
|
||||
let entry = root.entry().ok_or(Error::NoEntrypoint)?;
|
||||
debug_trace!("entry = {:p}", entry);
|
||||
|
||||
|
@ -1,15 +1,14 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Read, Seek, SeekFrom},
|
||||
ops::Range,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use elf::{
|
||||
abi::{
|
||||
DF_1_PIE, DT_FLAGS_1, DT_NEEDED, ET_DYN, ET_EXEC, PT_DYNAMIC, PT_GNU_EH_FRAME,
|
||||
PT_GNU_RELRO, PT_GNU_STACK, PT_INTERP, PT_LOAD, PT_NOTE, PT_NULL, PT_PHDR, SHN_UNDEF,
|
||||
SHT_REL, SHT_RELA, STB_GLOBAL, STB_LOCAL, STB_WEAK,
|
||||
DF_1_PIE, DT_FINI, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_FLAGS_1, DT_INIT, DT_INIT_ARRAY, DT_INIT_ARRAYSZ, DT_NEEDED, DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, ET_DYN, ET_EXEC, PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_GNU_STACK, PT_INTERP, PT_LOAD, PT_NOTE, PT_NULL, PT_PHDR, SHN_UNDEF, SHT_REL, SHT_RELA, STB_GLOBAL, STB_LOCAL, STB_WEAK
|
||||
},
|
||||
endian::AnyEndian,
|
||||
symbol::Symbol,
|
||||
@ -55,6 +54,8 @@ pub struct Object {
|
||||
|
||||
mapping: Option<Mapping>,
|
||||
dynamic_symbol_array: Vec<DynamicSymbol>,
|
||||
|
||||
init_array: Option<Range<usize>>,
|
||||
}
|
||||
|
||||
impl ResolvedSymbol<'_> {
|
||||
@ -142,6 +143,8 @@ impl Object {
|
||||
|
||||
mapping: None,
|
||||
dynamic_symbol_array,
|
||||
|
||||
init_array: None
|
||||
})
|
||||
}
|
||||
|
||||
@ -157,7 +160,9 @@ impl Object {
|
||||
// TODO segment granularity mappings
|
||||
let mapping_size = self.vma_end - self.vma_start;
|
||||
let mut mapping = match self.ty {
|
||||
ElfType::Relocatable(_) => Mapping::new(mapping_size, MappingFlags::WRITE | MappingFlags::EXEC)?,
|
||||
ElfType::Relocatable(_) => {
|
||||
Mapping::new(mapping_size, MappingFlags::WRITE | MappingFlags::EXEC)?
|
||||
}
|
||||
// TODO fixed mapping for this one
|
||||
ElfType::Static => todo!(),
|
||||
};
|
||||
@ -168,6 +173,34 @@ impl Object {
|
||||
mapping.base() as i64 - self.vma_start as i64
|
||||
);
|
||||
|
||||
// Parse .dynamic section again to extract extra info
|
||||
if let Some(dynamic) = self.elf.dynamic()? {
|
||||
let mut dt_init_array = None;
|
||||
let mut dt_init_array_sz = None;
|
||||
|
||||
for dynamic in dynamic {
|
||||
match dynamic.d_tag {
|
||||
DT_INIT_ARRAY => dt_init_array = Some(dynamic.d_ptr()),
|
||||
DT_INIT_ARRAYSZ => dt_init_array_sz = Some(dynamic.d_val()),
|
||||
DT_FINI_ARRAY => todo!(),
|
||||
DT_FINI_ARRAYSZ => todo!(),
|
||||
DT_INIT => todo!(),
|
||||
DT_FINI => todo!(),
|
||||
DT_PREINIT_ARRAY => todo!(),
|
||||
DT_PREINIT_ARRAYSZ => todo!(),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(ptr), Some(size)) = (dt_init_array, dt_init_array_sz) {
|
||||
// This address is subject to relocation
|
||||
debug_trace!("{:?}: DT_INIT_ARRAY: {:#x?}", self.path, ptr..ptr + size);
|
||||
let ptr = ptr as i64 + mapping.base() as i64 - self.vma_start as i64;
|
||||
let ptr = ptr as usize;
|
||||
self.init_array = Some(ptr..ptr + size as usize);
|
||||
}
|
||||
}
|
||||
|
||||
// Load segments
|
||||
for segment in self.elf.segments() {
|
||||
let mem_size = segment.p_memsz as usize;
|
||||
@ -220,6 +253,24 @@ impl Object {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn call_constructors(&mut self) {
|
||||
type Constructor = extern "C" fn();
|
||||
|
||||
if let Some(init_array) = self.init_array.as_ref() {
|
||||
for slot in init_array.clone().step_by(size_of::<usize>()) {
|
||||
let func = unsafe { core::ptr::with_exposed_provenance::<usize>(slot).read_unaligned() };
|
||||
|
||||
if func == 0 || func == usize::MAX {
|
||||
continue;
|
||||
}
|
||||
|
||||
let func = unsafe { core::mem::transmute::<_, Constructor>(func) };
|
||||
|
||||
func();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn entry(&self) -> Option<extern "C" fn(usize)> {
|
||||
let entry = self.elf.ehdr.e_entry as i64;
|
||||
let offset = match &self.ty {
|
||||
@ -273,7 +324,7 @@ impl Object {
|
||||
for rela in rela_section {
|
||||
let dynsym = &self.dynamic_symbol_array[rela.r_sym as usize];
|
||||
let sym = match dynsym.raw.st_bind() {
|
||||
STB_GLOBAL => ResolvedSymbol::Global(state.lookup(dynsym).unwrap()),
|
||||
STB_GLOBAL | STB_WEAK => ResolvedSymbol::Global(state.lookup(dynsym).unwrap()),
|
||||
STB_LOCAL => {
|
||||
if dynsym.name.is_empty() {
|
||||
ResolvedSymbol::Null
|
||||
|
@ -28,7 +28,7 @@ impl Relocation for Rela {
|
||||
// S
|
||||
R_X86_64_JUMP_SLOT | R_X86_64_GLOB_DAT => Ok(Some(RelaValue::QWord(s))),
|
||||
// S + A
|
||||
R_X86_64_64 => todo!(),
|
||||
R_X86_64_64 => Ok(Some(RelaValue::QWord(s + self.r_addend))),
|
||||
// B + A
|
||||
R_X86_64_RELATIVE => Ok(Some(RelaValue::QWord(load_base as i64 + self.r_addend))),
|
||||
// TLS
|
||||
|
Loading…
x
Reference in New Issue
Block a user