Skip to content
Snippets Groups Projects
Commit 763bb248 authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Merge branch 'init_fini_ld.so' into 'master'

Init fini ld.so

See merge request !265
parents 7724989b b717f6cf
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 ...@@ -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); eprintln!("dlopen: linker_ptr: {:p}", tcb.linker_ptr);
let mut linker = (&*tcb.linker_ptr).lock(); let mut linker = (&*tcb.linker_ptr).lock();
match linker.load_library(filename) { if let Err(err) = linker.load_library(filename) {
Ok(()) => (), eprintln!("dlopen: failed to load {}", filename);
Err(err) => { ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
eprintln!("dlopen: failed to load {}", filename); return ptr::null_mut();
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
return ptr::null_mut();
}
} }
match linker.link(None, None) { if let Err(err) = linker.link(None, None) {
Ok(ok) => (), eprintln!("dlopen: failed to link '{}': {}", filename, err);
Err(err) => { ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
eprintln!("dlopen: failed to link '{}': {}", filename, err); return ptr::null_mut();
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
return ptr::null_mut();
}
}; };
// TODO // TODO
...@@ -125,6 +119,8 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m ...@@ -125,6 +119,8 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
#[no_mangle] #[no_mangle]
pub extern "C" fn dlclose(handle: *mut c_void) -> c_int { pub extern "C" fn dlclose(handle: *mut c_void) -> c_int {
// TODO: Loader::fini() should be called about here
0 0
} }
......
use alloc::{ use alloc::{
boxed::Box, boxed::Box,
collections::BTreeMap, collections::{BTreeMap, BTreeSet},
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
...@@ -42,7 +42,20 @@ pub struct DSO { ...@@ -42,7 +42,20 @@ pub struct DSO {
pub base_addr: usize, pub base_addr: usize,
pub entry_point: 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 { pub struct Linker {
// Used by load // Used by load
/// Library path to search when loading library by name /// Library path to search when loading library by name
...@@ -59,6 +72,10 @@ pub struct Linker { ...@@ -59,6 +72,10 @@ pub struct Linker {
mmaps: BTreeMap<String, &'static mut [u8]>, mmaps: BTreeMap<String, &'static mut [u8]>,
verbose: bool, verbose: bool,
tls_index_offset: usize, tls_index_offset: usize,
/// 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 { impl Linker {
...@@ -71,15 +88,33 @@ impl Linker { ...@@ -71,15 +88,33 @@ impl Linker {
mmaps: BTreeMap::new(), mmaps: BTreeMap::new(),
verbose, verbose,
tls_index_offset: 0, tls_index_offset: 0,
cir_dep: BTreeSet::new(),
dep_tree: Default::default(),
} }
} }
pub fn load(&mut self, name: &str, path: &str) -> Result<()> { 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 { if self.verbose {
println!("load {}: {}", name, path); println!("load {}: {}", name, path);
} }
let mut data = Vec::new(); if self.cir_dep.contains(name) {
return Err(Error::Malformed(format!(
"Circular dependency: {} is a dependency of itself",
name
)));
}
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) let path_c = CString::new(path)
.map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?; .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
...@@ -91,31 +126,32 @@ impl Linker { ...@@ -91,31 +126,32 @@ impl Linker {
file.read_to_end(&mut data) file.read_to_end(&mut data)
.map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?; .map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
} }
deps.deps = self.load_data(name, data.into_boxed_slice())?;
self.load_data(name, data.into_boxed_slice()) self.cir_dep.remove(name);
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>> {
//TODO: Prevent failures due to recursion let elf = Elf::parse(&data)?;
{ //println!("{:#?}", elf);
let elf = Elf::parse(&data)?; let mut deps = Vec::new();
//println!("{:#?}", elf); for library in elf.libraries.iter() {
if let Some(dep) = self.load_library(library)? {
for library in elf.libraries.iter() { deps.push(dep);
self.load_library(library)?;
} }
} }
self.objects.insert(name.to_string(), data); 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) { 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('/') { } else if name.contains('/') {
self.load(name, name) Ok(Some(self.load_recursive(name, name)?))
} else { } else {
let library_path = self.library_path.clone(); let library_path = self.library_path.clone();
for part in library_path.split(PATH_SEP) { for part in library_path.split(PATH_SEP) {
...@@ -137,8 +173,7 @@ impl Linker { ...@@ -137,8 +173,7 @@ impl Linker {
}; };
if access { if access {
self.load(name, &path)?; return Ok(Some(self.load_recursive(name, &path)?));
return Ok(());
} }
} }
...@@ -203,6 +238,73 @@ impl Linker { ...@@ -203,6 +238,73 @@ impl Linker {
None 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>> { pub fn link(&mut self, primary_opt: Option<&str>, dso: Option<DSO>) -> Result<Option<usize>> {
unsafe { _r_debug.state = RTLDState::RT_ADD }; unsafe { _r_debug.state = RTLDState::RT_ADD };
...@@ -717,3 +819,18 @@ impl Linker { ...@@ -717,3 +819,18 @@ impl Linker {
Ok(entry_opt) 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 ...@@ -33,6 +33,7 @@ next: pop rsi
xor r11, r11 xor r11, r11
fninit fninit
jmp rax 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) -> ...@@ -203,7 +203,11 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
loop {} 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() } { if let Some(tcb) = unsafe { Tcb::current() } {
tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
} }
......
...@@ -60,6 +60,24 @@ pub unsafe fn relibc_verify_host() { ...@@ -60,6 +60,24 @@ pub unsafe fn relibc_verify_host() {
intrinsics::abort(); intrinsics::abort();
} }
} }
#[link_section = ".init_array"]
#[used]
static INIT_ARRAY: [extern "C" fn(); 1] = [init_array];
static mut init_complete: bool = false;
extern "C" fn init_array() {
io_init();
unsafe { init_complete = true };
}
fn io_init() {
unsafe {
// Initialize stdin/stdout/stderr, see https://github.com/rust-lang/rust/issues/51718
stdio::stdin = stdio::default_stdin.get();
stdio::stdout = stdio::default_stdout.get();
stdio::stderr = stdio::default_stderr.get();
}
}
#[inline(never)] #[inline(never)]
#[no_mangle] #[no_mangle]
...@@ -95,11 +113,9 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { ...@@ -95,11 +113,9 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
platform::inner_environ = copy_string_array(envp, len); platform::inner_environ = copy_string_array(envp, len);
platform::environ = platform::inner_environ.as_mut_ptr(); platform::environ = platform::inner_environ.as_mut_ptr();
// Initialize stdin/stdout/stderr, see https://github.com/rust-lang/rust/issues/51718 if !init_complete {
stdio::stdin = stdio::default_stdin.get(); init_array();
stdio::stdout = stdio::default_stdout.get(); }
stdio::stderr = stdio::default_stderr.get();
pthread_init(); pthread_init();
// Run preinit array // Run preinit array
......
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