diff --git a/src/header/dlfcn/mod.rs b/src/header/dlfcn/mod.rs index cc10390c07e12800b2f2ce7a7a31d8fe969e7fee..f9c3bc8149c59b02b4b95aa2fadc1b97921e3100 100644 --- a/src/header/dlfcn/mod.rs +++ b/src/header/dlfcn/mod.rs @@ -66,7 +66,7 @@ pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c } } - match linker.link(None) { + match linker.link(None, None) { Ok(ok) => (), Err(err) => { eprintln!("dlopen: failed to link '{}': {}", filename, err); diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 848645146058b9695a7493b6902ce18656904226..15c666711c436468b224c25e2754a6f9e8418665 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -29,6 +29,12 @@ const PATH_SEP: char = ';'; #[cfg(target_os = "linux")] const PATH_SEP: char = ':'; +pub struct DSO { + pub name: String, + pub base_addr: usize, + pub entry_point: usize, +} + pub struct Linker { // Used by load /// Library path to search when loading library by name @@ -190,7 +196,7 @@ impl Linker { } } - pub fn link(&mut self, primary_opt: Option<&str>) -> Result<Option<usize>> { + pub fn link(&mut self, primary_opt: Option<&str>, dso: Option<DSO>) -> Result<Option<usize>> { let elfs = { let mut elfs = BTreeMap::new(); for (name, data) in self.objects.iter() { @@ -262,22 +268,41 @@ impl Linker { // Allocate memory let mmap = unsafe { let size = bounds.1 /* - bounds.0 */; - let ptr = sys_mman::mmap( - ptr::null_mut(), - size, - //TODO: Make it possible to not specify PROT_EXEC on Redox - sys_mman::PROT_READ | sys_mman::PROT_WRITE, - sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE, - -1, - 0, - ); - if ptr as usize == !0 - /* MAP_FAILED */ - { - return Err(Error::Malformed(format!("failed to map {}", elf_name))); + let same_elf = if let Some(prog) = dso.as_ref() { + if prog.name == *elf_name { + true + } else { + false + } + } else { + false + }; + if same_elf { + let addr = dso.as_ref().unwrap().base_addr; + sys_mman::mprotect( + addr as *mut c_void, + size, + sys_mman::PROT_READ | sys_mman::PROT_WRITE, + ); + slice::from_raw_parts_mut(addr as *mut u8, size) + } else { + let ptr = sys_mman::mmap( + ptr::null_mut(), + size, + //TODO: Make it possible to not specify PROT_EXEC on Redox + sys_mman::PROT_READ | sys_mman::PROT_WRITE, + sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE, + -1, + 0, + ); + if ptr as usize == !0 + /* MAP_FAILED */ + { + return Err(Error::Malformed(format!("failed to map {}", elf_name))); + } + ptr::write_bytes(ptr as *mut u8, 0, size); + slice::from_raw_parts_mut(ptr as *mut u8, size) } - ptr::write_bytes(ptr as *mut u8, 0, size); - slice::from_raw_parts_mut(ptr as *mut u8, size) }; if self.verbose { println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len()); @@ -308,6 +333,18 @@ impl Linker { }); let mut tls_ranges = BTreeMap::new(); for (elf_name, elf) in elfs.iter() { + let same_elf = if let Some(prog) = dso.as_ref() { + if prog.name == *elf_name { + true + } else { + false + } + } else { + false + }; + if same_elf { + continue; + } let object = match self.objects.get(*elf_name) { Some(some) => some, None => continue, diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index 28856a46fef6ab87b96f9b793ccd1c445c363041..16075479925ddb0a794f37adf2968137953dc89d 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -6,8 +6,11 @@ use crate::{ c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex, }; -use super::{linker::Linker, tcb::Tcb}; -use crate::header::sys_auxv::AT_ENTRY; +use super::{ + linker::{Linker, DSO}, + tcb::Tcb, +}; +use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR}; unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) { //traverse the stack and collect argument vector @@ -149,7 +152,26 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> } else { &argv[0] }; - + // if we are not running in manual mode, then the main + // program is already loaded by the kernel and we want + // to use it. + let program = { + let mut pr = None; + if !is_manual { + let phdr = *auxv.get(&AT_PHDR).unwrap(); + if phdr != 0 { + let p = DSO { + name: path.to_owned(), + entry_point: *auxv.get(&AT_ENTRY).unwrap(), + // The 0x40 is the size of Elf header not a good idea for different bit size + // compatiablility but it will always work on 64 bit systems, + base_addr: phdr - 0x40, + }; + pr = Some(p); + } + } + pr + }; let mut linker = Linker::new(library_path, false); match linker.load(&path, &path) { Ok(()) => (), @@ -160,7 +182,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> } } - let entry = match linker.link(Some(&path)) { + let entry = match linker.link(Some(&path), program) { Ok(ok) => match ok { Some(some) => some, None => {