Skip to content
Snippets Groups Projects
Commit 6aeb2d6f authored by Ahmed Abd El Mawgood's avatar Ahmed Abd El Mawgood
Browse files

Implement code that use .init_array and .fini_array

This patch implements ld.so code that makes use of both .init_array and
.fini_array. .init_array is fully utilized and is used in the correct
manner. However .fini_array is not used yet although the function that
runs .fini_array exists
parent cc7ff54d
No related branches found
No related tags found
No related merge requests found
......@@ -57,22 +57,16 @@ pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c
eprintln!("dlopen: linker_ptr: {:p}", tcb.linker_ptr);
let mut linker = (&*tcb.linker_ptr).lock();
match linker.load_library(filename) {
Ok(()) => (),
Err(err) => {
eprintln!("dlopen: failed to load {}", filename);
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
return ptr::null_mut();
}
if let Err(err) = linker.load_library(filename) {
eprintln!("dlopen: failed to load {}", filename);
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
return ptr::null_mut();
}
match linker.link(None, None) {
Ok(ok) => (),
Err(err) => {
eprintln!("dlopen: failed to link '{}': {}", filename, err);
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
return ptr::null_mut();
}
if let Err(err) = linker.link(None, None) {
eprintln!("dlopen: failed to link '{}': {}", filename, err);
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
return ptr::null_mut();
};
// TODO
......@@ -125,6 +119,8 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
#[no_mangle]
pub extern "C" fn dlclose(handle: *mut c_void) -> c_int {
// TODO: Loader::fini() should be called about here
0
}
......
......@@ -42,7 +42,20 @@ pub struct DSO {
pub base_addr: usize,
pub entry_point: usize,
}
#[derive(Default, Debug)]
pub struct DepTree {
pub name: String,
pub deps: Vec<DepTree>,
}
impl DepTree {
fn new(name: String) -> DepTree {
DepTree {
name,
deps: Vec::new(),
}
}
}
pub struct Linker {
// Used by load
/// Library path to search when loading library by name
......@@ -59,8 +72,10 @@ pub struct Linker {
mmaps: BTreeMap<String, &'static mut [u8]>,
verbose: bool,
tls_index_offset: usize,
// used to detect circular dependencies in the Linker::load function
/// A set used to detect circular dependencies in the Linker::load function
cir_dep: BTreeSet<String>,
/// Each object will have its children callec once with no repetition.
dep_tree: DepTree,
}
impl Linker {
......@@ -74,10 +89,19 @@ impl Linker {
verbose,
tls_index_offset: 0,
cir_dep: BTreeSet::new(),
dep_tree: Default::default(),
}
}
pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
self.dep_tree = self.load_recursive(name, path)?;
if self.verbose {
println!("Dep tree: {:#?}", self.dep_tree);
}
return Ok(());
}
fn load_recursive(&mut self, name: &str, path: &str) -> Result<DepTree> {
if self.verbose {
println!("load {}: {}", name, path);
}
......@@ -88,9 +112,9 @@ impl Linker {
)));
}
self.cir_dep.insert(name.to_string());
let mut deps = DepTree::new(name.to_string());
let mut data = Vec::new();
self.cir_dep.insert(name.to_string());
let path_c = CString::new(path)
.map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
......@@ -102,29 +126,32 @@ impl Linker {
file.read_to_end(&mut data)
.map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
}
let result = self.load_data(name, data.into_boxed_slice());
deps.deps = self.load_data(name, data.into_boxed_slice())?;
self.cir_dep.remove(name);
result
Ok(deps)
}
pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result<()> {
pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result<Vec<DepTree>> {
let elf = Elf::parse(&data)?;
//println!("{:#?}", elf);
let mut deps = Vec::new();
for library in elf.libraries.iter() {
self.load_library(library)?;
if let Some(dep) = self.load_library(library)? {
deps.push(dep);
}
}
self.objects.insert(name.to_string(), data);
Ok(())
return Ok(deps);
}
pub fn load_library(&mut self, name: &str) -> Result<()> {
pub fn load_library(&mut self, name: &str) -> Result<Option<DepTree>> {
if self.objects.contains_key(name) {
Ok(())
// It should be previously resolved so we don't need to worry about it
Ok(None)
} else if name.contains('/') {
self.load(name, name)
Ok(Some(self.load_recursive(name, name)?))
} else {
let library_path = self.library_path.clone();
for part in library_path.split(PATH_SEP) {
......@@ -146,8 +173,7 @@ impl Linker {
};
if access {
self.load(name, &path)?;
return Ok(());
return Ok(Some(self.load_recursive(name, &path)?));
}
}
......@@ -212,6 +238,73 @@ impl Linker {
None
}
}
pub fn run_init(&self) -> Result<()> {
self.run_init_tree(&self.dep_tree)
}
fn run_init_tree(&self, root: &DepTree) -> Result<()> {
for node in root.deps.iter() {
self.run_init_tree(node)?;
}
if self.verbose {
println!("init {}", &root.name);
}
let mmap = match self.mmaps.get(&root.name) {
Some(some) => some,
None => return Ok(()),
};
let elf = Elf::parse(self.objects.get(&root.name).unwrap())?;
for section in elf.section_headers {
let name = match elf.shdr_strtab.get(section.sh_name) {
Some(x) => match x {
Ok(y) => y,
_ => continue,
},
_ => continue,
};
if name == ".init_array" {
let addr = mmap.as_ptr() as usize + section.vm_range().start;
for i in (0..section.sh_size).step_by(8) {
unsafe { call_inits_finis(addr + i as usize) };
}
}
}
return Ok(());
}
pub fn run_fini(&self) -> Result<()> {
self.run_fini_tree(&self.dep_tree)
}
fn run_fini_tree(&self, root: &DepTree) -> Result<()> {
if self.verbose {
println!("init {}", &root.name);
}
let mmap = match self.mmaps.get(&root.name) {
Some(some) => some,
None => return Ok(()),
};
let elf = Elf::parse(self.objects.get(&root.name).unwrap())?;
for section in elf.section_headers {
let name = match elf.shdr_strtab.get(section.sh_name) {
Some(x) => match x {
Ok(y) => y,
_ => continue,
},
_ => continue,
};
if name == ".fini_array" {
let addr = mmap.as_ptr() as usize + section.vm_range().start;
for i in (0..section.sh_size).step_by(8) {
unsafe { call_inits_finis(addr + i as usize) };
}
}
}
for node in root.deps.iter() {
self.run_fini_tree(node)?;
}
return Ok(());
}
pub fn link(&mut self, primary_opt: Option<&str>, dso: Option<DSO>) -> Result<Option<usize>> {
unsafe { _r_debug.state = RTLDState::RT_ADD };
......@@ -726,3 +819,18 @@ impl Linker {
Ok(entry_opt)
}
}
unsafe extern "C" fn call_inits_finis(addr: usize) {
#[cfg(target_arch = "x86_64")]
asm!("
cmp qword ptr [rdi], 0
je end
call [rdi]
end: nop
"
:
:
:
: "intel", "volatile"
);
}
......@@ -33,6 +33,7 @@ next: pop rsi
xor r11, r11
fninit
jmp rax
# TODO: Loader::fini() should be called about here
"
:
:
......
......@@ -203,7 +203,11 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
loop {}
}
};
if let Err(e) = linker.run_init() {
eprintln!("ld.so: failed to run .init_array");
unistd::_exit(1);
loop {}
}
if let Some(tcb) = unsafe { Tcb::current() } {
tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment