Explorar o código

Merge branch 'dlopen_dlclose_dlsym' into 'master'

Dlopen dlclose dlsym

See merge request redox-os/relibc!290
Jeremy Soller %!s(int64=4) %!d(string=hai) anos
pai
achega
677f0c989d

+ 10 - 8
src/c_vec.rs

@@ -1,10 +1,9 @@
 use crate::{
     io::{self, Write},
-    platform::{self, WriteByte, types::*},
+    platform::{self, types::*, WriteByte},
 };
 use core::{
-    cmp,
-    fmt,
+    cmp, fmt,
     iter::IntoIterator,
     mem,
     ops::{Deref, DerefMut},
@@ -60,7 +59,8 @@ impl<T> CVec<T> {
         let ptr = if cap == 0 {
             NonNull::dangling()
         } else if self.cap > 0 {
-            NonNull::new(platform::realloc(self.ptr.as_ptr() as *mut c_void, size) as *mut T).ok_or(AllocError)?
+            NonNull::new(platform::realloc(self.ptr.as_ptr() as *mut c_void, size) as *mut T)
+                .ok_or(AllocError)?
         } else {
             NonNull::new((platform::alloc(size)) as *mut T).ok_or(AllocError)?
         };
@@ -208,10 +208,12 @@ impl<'a, T> IntoIterator for &'a mut CVec<T> {
 
 impl Write for CVec<u8> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.extend_from_slice(buf).map_err(|err| io::Error::new(
-            io::ErrorKind::Other,
-            "AllocStringWriter::write failed to allocate",
-        ))?;
+        self.extend_from_slice(buf).map_err(|err| {
+            io::Error::new(
+                io::ErrorKind::Other,
+                "AllocStringWriter::write failed to allocate",
+            )
+        })?;
         Ok(buf.len())
     }
     fn flush(&mut self) -> io::Result<()> {

+ 82 - 55
src/header/dlfcn/mod.rs

@@ -27,6 +27,7 @@ pub struct Dl_info {
 
 #[no_mangle]
 pub unsafe extern "C" fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int {
+    //TODO
     (*info).dli_fname = ptr::null();
     (*info).dli_fbase = ptr::null_mut();
     (*info).dli_sname = ptr::null();
@@ -35,50 +36,56 @@ pub unsafe extern "C" fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c_void {
-    let filename_opt = if filename.is_null() {
-        None
+pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut c_void {
+    //TODO support all sort of flags
+
+    let filename = if cfilename.is_null() {
+        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+        return ptr::null_mut();
     } else {
-        Some(str::from_utf8_unchecked(
-            CStr::from_ptr(filename).to_bytes(),
-        ))
+        str::from_utf8_unchecked(CStr::from_ptr(cfilename).to_bytes())
     };
 
-    eprintln!("dlopen({:?}, {:#>04x})", filename_opt, flags);
-
-    if let Some(filename) = filename_opt {
-        if let Some(tcb) = Tcb::current() {
-            if tcb.linker_ptr.is_null() {
-                eprintln!("dlopen: linker not found");
-                ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-                return ptr::null_mut();
-            }
-
-            eprintln!("dlopen: linker_ptr: {:p}", tcb.linker_ptr);
-            let mut linker = (&*tcb.linker_ptr).lock();
-
-            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();
-            }
-
-            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
-            1 as *mut c_void
-        } else {
+    let tcb = match Tcb::current() {
+        Some(tcb) => tcb,
+        None => {
             eprintln!("dlopen: tcb not found");
             ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-            ptr::null_mut()
+            return ptr::null_mut();
         }
-    } else {
-        1 as *mut c_void
+    };
+    if tcb.linker_ptr.is_null() {
+        eprintln!("dlopen: linker not found");
+        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+        return ptr::null_mut();
     }
+    let mut linker = (&*tcb.linker_ptr).lock();
+    let cbs_c = linker.cbs.clone();
+    let cbs = cbs_c.borrow();
+
+    let id = match (cbs.load_library)(&mut linker, filename) {
+        Err(err) => {
+            eprintln!("dlopen: failed to load {}", filename);
+            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+            return ptr::null_mut();
+        }
+        Ok(id) => id,
+    };
+
+    if let Err(err) = (cbs.link)(&mut linker, None, None, Some(id)) {
+        (cbs.unload)(&mut linker, id);
+        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) = (cbs.run_init)(&mut linker, Some(id)) {
+        (cbs.unload)(&mut linker, id);
+        eprintln!("dlopen: failed to link '{}': {}", filename, err);
+        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+        return ptr::null_mut();
+    };
+    id as *mut c_void
 }
 
 #[no_mangle]
@@ -90,37 +97,57 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
 
     let symbol_str = str::from_utf8_unchecked(CStr::from_ptr(symbol).to_bytes());
 
-    eprintln!("dlsym({:p}, {})", handle, symbol_str);
-
-    if let Some(tcb) = Tcb::current() {
-        if tcb.linker_ptr.is_null() {
-            eprintln!("dlopen: linker not found");
+    let tcb = match Tcb::current() {
+        Some(tcb) => tcb,
+        None => {
+            eprintln!("dlsym: tcb not found");
             ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
             return ptr::null_mut();
         }
+    };
 
-        eprintln!("dlsym: linker_ptr: {:p}", tcb.linker_ptr);
-        let linker = (&*tcb.linker_ptr).lock();
+    if tcb.linker_ptr.is_null() {
+        eprintln!("dlsym: linker not found");
+        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+        return ptr::null_mut();
+    }
 
-        if let Some(global) = linker.get_sym(symbol_str) {
-            eprintln!("dlsym({:p}, {}) = 0x{:x}", handle, symbol_str, global);
-            global as *mut c_void
-        } else {
-            eprintln!("dlsym: symbol not found");
-            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-            ptr::null_mut()
-        }
+    let linker = (&*tcb.linker_ptr).lock();
+    let cbs_c = linker.cbs.clone();
+    let cbs = cbs_c.borrow();
+    if let Some(global) = (cbs.get_sym)(&linker, symbol_str, Some(handle as usize)) {
+        global as *mut c_void
     } else {
-        eprintln!("dlsym: tcb not found");
+        eprintln!("dlsym: symbol not found");
         ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
         ptr::null_mut()
     }
 }
 
 #[no_mangle]
-pub extern "C" fn dlclose(handle: *mut c_void) -> c_int {
-    // TODO: Loader::fini() should be called about here
+pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
+    let tcb = match Tcb::current() {
+        Some(tcb) => tcb,
+        None => {
+            eprintln!("dlclose: tcb not found");
+            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+            return -1;
+        }
+    };
 
+    if tcb.linker_ptr.is_null() {
+        eprintln!("dlclose: linker not found");
+        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+        return -1;
+    };
+    let mut linker = (&*tcb.linker_ptr).lock();
+    let cbs_c = linker.cbs.clone();
+    let cbs = cbs_c.borrow();
+    if let Err(err) = (cbs.run_fini)(&mut linker, Some(handle as usize)) {
+        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+        return -1;
+    };
+    (cbs.unload)(&mut linker, handle as usize);
     0
 }
 

+ 1 - 1
src/header/netdb/mod.rs

@@ -12,7 +12,7 @@ use alloc::{borrow::ToOwned, boxed::Box, str::SplitWhitespace, vec::Vec};
 use crate::{
     c_str::{CStr, CString},
     header::{
-        arpa_inet::htons, arpa_inet::ntohl, arpa_inet::inet_aton,
+        arpa_inet::{htons, inet_aton, ntohl},
         errno::*,
         fcntl::O_RDONLY,
         netinet_in::{in_addr, sockaddr_in, sockaddr_in6},

+ 53 - 0
src/ld_so/callbacks.rs

@@ -0,0 +1,53 @@
+use super::linker::{Linker, DSO};
+use alloc::boxed::Box;
+use goblin::error::Result;
+
+pub struct LinkerCallbacks {
+    pub unload: Box<dyn Fn(&mut Linker, usize)>,
+    pub load_library: Box<dyn Fn(&mut Linker, &str) -> Result<usize>>,
+    pub link:
+        Box<dyn Fn(&mut Linker, Option<&str>, Option<DSO>, Option<usize>) -> Result<Option<usize>>>,
+    pub get_sym: Box<dyn Fn(&Linker, &str, Option<usize>) -> Option<usize>>,
+    pub run_init: Box<dyn Fn(&Linker, Option<usize>) -> Result<()>>,
+    pub run_fini: Box<dyn Fn(&Linker, Option<usize>) -> Result<()>>,
+}
+
+impl LinkerCallbacks {
+    pub fn new() -> LinkerCallbacks {
+        LinkerCallbacks {
+            unload: Box::new(unload),
+            load_library: Box::new(load_library),
+            link: Box::new(link),
+            get_sym: Box::new(get_sym),
+            run_init: Box::new(run_init),
+            run_fini: Box::new(run_fini),
+        }
+    }
+}
+
+fn unload(linker: &mut Linker, libspace: usize) {
+    linker.unload(libspace)
+}
+
+fn load_library(linker: &mut Linker, name: &str) -> Result<usize> {
+    linker.load_library(name)
+}
+
+fn link(
+    linker: &mut Linker,
+    primary_opt: Option<&str>,
+    dso: Option<DSO>,
+    libspace: Option<usize>,
+) -> Result<Option<usize>> {
+    linker.link(primary_opt, dso, libspace)
+}
+
+fn get_sym(linker: &Linker, name: &str, libspace: Option<usize>) -> Option<usize> {
+    linker.get_sym(name, libspace)
+}
+fn run_init(linker: &Linker, libspace: Option<usize>) -> Result<()> {
+    linker.run_init(libspace)
+}
+fn run_fini(linker: &Linker, libspace: Option<usize>) -> Result<()> {
+    linker.run_fini(libspace)
+}

+ 52 - 0
src/ld_so/library.rs

@@ -0,0 +1,52 @@
+use alloc::{
+    boxed::Box,
+    collections::{BTreeMap, BTreeSet},
+    string::String,
+    vec::Vec,
+};
+
+#[derive(Default, Debug)]
+pub struct DepTree {
+    pub name: String,
+    pub deps: Vec<DepTree>,
+}
+
+impl DepTree {
+    pub fn new(name: String) -> DepTree {
+        DepTree {
+            name,
+            deps: Vec::new(),
+        }
+    }
+}
+
+/// Use to represnt a library as well as all th symbols that is loaded withen it.
+#[derive(Default)]
+pub struct Library {
+    /// Global symbols
+    pub globals: BTreeMap<String, usize>,
+    /// Weak symbols
+    pub weak_syms: BTreeMap<String, usize>,
+    /// Loaded library raw data
+    pub objects: BTreeMap<String, Box<[u8]>>,
+    /// Loaded library in-memory data
+    pub mmaps: BTreeMap<String, &'static mut [u8]>,
+    /// Each object will have its children called once with no repetition.
+    pub dep_tree: DepTree,
+    /// A set used to detect circular dependencies in the Linker::load function
+    pub cir_dep: BTreeSet<String>,
+}
+impl Library {
+    pub fn new() -> Library {
+        Default::default()
+    }
+    pub fn get_sym(&self, name: &str) -> Option<usize> {
+        if let Some(value) = self.globals.get(name) {
+            Some(*value)
+        } else if let Some(value) = self.weak_syms.get(name) {
+            Some(*value)
+        } else {
+            None
+        }
+    }
+}

+ 124 - 122
src/ld_so/linker.rs

@@ -1,11 +1,13 @@
 use alloc::{
     boxed::Box,
-    collections::{BTreeMap, BTreeSet},
+    collections::BTreeMap,
+    rc::Rc,
     string::{String, ToString},
     vec::Vec,
 };
 use core::{
-    mem::{size_of, transmute},
+    cell::RefCell,
+    mem::{size_of, swap, transmute},
     ptr, slice,
 };
 use goblin::{
@@ -28,7 +30,9 @@ use crate::{
 
 use super::{
     access::access,
+    callbacks::LinkerCallbacks,
     debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
+    library::{DepTree, Library},
     tcb::{Master, Tcb},
     PAGE_SIZE,
 };
@@ -43,70 +47,53 @@ 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
     library_path: String,
-    /// Loaded library raw data
-    objects: BTreeMap<String, Box<[u8]>>,
-
-    // Used by link
-    /// Global symbols
-    globals: BTreeMap<String, usize>,
-    /// Weak symbols
-    weak_syms: BTreeMap<String, usize>,
-    /// Loaded library in-memory data
-    mmaps: BTreeMap<String, &'static mut [u8]>,
+    root: Library,
     verbose: bool,
     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,
+    lib_spaces: BTreeMap<usize, Library>,
+    counter: usize,
+    pub cbs: Rc<RefCell<LinkerCallbacks>>,
 }
 
 impl Linker {
     pub fn new(library_path: &str, verbose: bool) -> Self {
         Self {
             library_path: library_path.to_string(),
-            objects: BTreeMap::new(),
-            globals: BTreeMap::new(),
-            weak_syms: BTreeMap::new(),
-            mmaps: BTreeMap::new(),
+            root: Library::new(),
             verbose,
             tls_index_offset: 0,
-            cir_dep: BTreeSet::new(),
-            dep_tree: Default::default(),
+            lib_spaces: BTreeMap::new(),
+            counter: 1,
+            cbs: Rc::new(RefCell::new(LinkerCallbacks::new())),
         }
     }
-
     pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
-        self.dep_tree = self.load_recursive(name, path)?;
+        let mut lib: Library = Library::new();
+        swap(&mut lib, &mut self.root);
+        lib.dep_tree = self.load_recursive(name, path, &mut lib)?;
+        swap(&mut lib, &mut self.root);
         if self.verbose {
-            println!("Dep tree: {:#?}", self.dep_tree);
+            println!("Dep tree: {:#?}", self.root.dep_tree);
         }
         return Ok(());
     }
-
-    fn load_recursive(&mut self, name: &str, path: &str) -> Result<DepTree> {
+    pub fn unload(&mut self, libspace: usize) {
+        if let Some(lib) = self.lib_spaces.remove(&libspace) {
+            for (_, mmap) in lib.mmaps {
+                unsafe { sys_mman::munmap(mmap.as_mut_ptr() as *mut c_void, mmap.len()) };
+            }
+        }
+    }
+    fn load_recursive(&mut self, name: &str, path: &str, lib: &mut Library) -> Result<DepTree> {
         if self.verbose {
             println!("load {}: {}", name, path);
         }
-        if self.cir_dep.contains(name) {
+        if lib.cir_dep.contains(name) {
             return Err(Error::Malformed(format!(
                 "Circular dependency: {} is a dependency of itself",
                 name
@@ -115,7 +102,7 @@ impl Linker {
 
         let mut deps = DepTree::new(name.to_string());
         let mut data = Vec::new();
-        self.cir_dep.insert(name.to_string());
+        lib.cir_dep.insert(name.to_string());
         let path_c = CString::new(path)
             .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
 
@@ -127,32 +114,45 @@ impl Linker {
             file.read_to_end(&mut data)
                 .map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
         }
-        deps.deps = self.load_data(name, data.into_boxed_slice())?;
-        self.cir_dep.remove(name);
+        deps.deps = self.load_data(name, data.into_boxed_slice(), lib)?;
+        lib.cir_dep.remove(name);
         Ok(deps)
     }
 
-    pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result<Vec<DepTree>> {
+    fn load_data(
+        &mut self,
+        name: &str,
+        data: Box<[u8]>,
+        lib: &mut Library,
+    ) -> Result<Vec<DepTree>> {
         let elf = Elf::parse(&data)?;
         //println!("{:#?}", elf);
         let mut deps = Vec::new();
         for library in elf.libraries.iter() {
-            if let Some(dep) = self.load_library(library)? {
+            if let Some(dep) = self._load_library(library, lib)? {
                 deps.push(dep);
             }
         }
 
-        self.objects.insert(name.to_string(), data);
+        lib.objects.insert(name.to_string(), data);
 
         return Ok(deps);
     }
 
-    pub fn load_library(&mut self, name: &str) -> Result<Option<DepTree>> {
-        if self.objects.contains_key(name) {
+    pub fn load_library(&mut self, name: &str) -> Result<usize> {
+        let mut lib = Library::new();
+        self._load_library(name, &mut lib)?;
+        let ret = self.counter;
+        self.lib_spaces.insert(ret, lib);
+        self.counter += 1;
+        return Ok(ret);
+    }
+    fn _load_library(&mut self, name: &str, lib: &mut Library) -> Result<Option<DepTree>> {
+        if lib.objects.contains_key(name) || self.root.objects.contains_key(name) {
             // It should be previously resolved so we don't need to worry about it
             Ok(None)
         } else if name.contains('/') {
-            Ok(Some(self.load_recursive(name, name)?))
+            Ok(Some(self.load_recursive(name, name, lib)?))
         } else {
             let library_path = self.library_path.clone();
             for part in library_path.split(PATH_SEP) {
@@ -176,7 +176,7 @@ impl Linker {
                 };
 
                 if access {
-                    return Ok(Some(self.load_recursive(name, &path)?));
+                    return Ok(Some(self.load_recursive(name, &path, lib)?));
                 }
             }
 
@@ -227,40 +227,51 @@ impl Linker {
         return Ok((globals, weak_syms));
     }
 
-    pub fn get_sym(&self, name: &str) -> Option<usize> {
-        if let Some(value) = self.globals.get(name) {
-            if self.verbose {
-                println!("    sym {} = {:#x}", name, value);
-            }
-            Some(*value)
-        } else if let Some(value) = self.weak_syms.get(name) {
-            if self.verbose {
-                println!("    sym {} = {:#x}", name, value);
+    pub fn get_sym(&self, name: &str, libspace: Option<usize>) -> Option<usize> {
+        match libspace {
+            Some(id) => {
+                let lib = self.lib_spaces.get(&id)?;
+                lib.get_sym(name)
             }
-            Some(*value)
-        } else {
-            if self.verbose {
-                println!("    sym {} = undefined", name);
+            None => self.root.get_sym(name),
+        }
+    }
+
+    pub fn run_init(&self, libspace: Option<usize>) -> Result<()> {
+        match libspace {
+            Some(id) => {
+                let lib = self.lib_spaces.get(&id).unwrap();
+                self.run_tree(&lib, &lib.dep_tree, ".init_array")
             }
-            None
+            None => self.run_tree(&self.root, &self.root.dep_tree, ".init_array"),
         }
     }
-    pub fn run_init(&self) -> Result<()> {
-        self.run_init_tree(&self.dep_tree)
+
+    pub fn run_fini(&self, libspace: Option<usize>) -> Result<()> {
+        match libspace {
+            Some(id) => {
+                let lib = self.lib_spaces.get(&id).unwrap();
+                self.run_tree(&lib, &lib.dep_tree, ".fini_array")
+            }
+            None => {
+                //TODO we first need to deinitialize all the loaded libraries first!
+                self.run_tree(&self.root, &self.root.dep_tree, ".fini_array")
+            }
+        }
     }
 
-    fn run_init_tree(&self, root: &DepTree) -> Result<()> {
+    fn run_tree(&self, lib: &Library, root: &DepTree, tree_name: &str) -> Result<()> {
         for node in root.deps.iter() {
-            self.run_init_tree(node)?;
+            self.run_tree(lib, node, tree_name)?;
         }
         if self.verbose {
-            println!("init {}", &root.name);
+            println!("running {} {}", tree_name, &root.name);
         }
-        let mmap = match self.mmaps.get(&root.name) {
+        let mmap = match lib.mmaps.get(&root.name) {
             Some(some) => some,
             None => return Ok(()),
         };
-        let elf = Elf::parse(self.objects.get(&root.name).unwrap())?;
+        let elf = Elf::parse(lib.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 {
@@ -269,7 +280,7 @@ impl Linker {
                 },
                 _ => continue,
             };
-            if name == ".init_array" {
+            if name == tree_name {
                 let addr = if is_pie_enabled(&elf) {
                     mmap.as_ptr() as usize + section.vm_range().start
                 } else {
@@ -283,52 +294,42 @@ impl Linker {
         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 = if is_pie_enabled(&elf) {
-                    mmap.as_ptr() as usize + section.vm_range().start
-                } else {
-                    section.vm_range().start
-                };
-                for i in (0..section.sh_size).step_by(8) {
-                    unsafe { call_inits_finis(addr + i as usize) };
-                }
+    pub fn link(
+        &mut self,
+        primary_opt: Option<&str>,
+        dso: Option<DSO>,
+        libspace: Option<usize>,
+    ) -> Result<Option<usize>> {
+        match libspace {
+            Some(id) => {
+                let mut lib = self.lib_spaces.remove(&id).unwrap();
+                let res = self._link(primary_opt, dso, &mut lib);
+                self.lib_spaces.insert(id, lib);
+                res
+            }
+            None => {
+                let mut lib = Library::new();
+                swap(&mut lib, &mut self.root);
+                let res = self._link(primary_opt, dso, &mut lib);
+                swap(&mut lib, &mut self.root);
+                res
             }
         }
-        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>,
+        lib: &mut Library,
+    ) -> Result<Option<usize>> {
         unsafe { _r_debug.state = RTLDState::RT_ADD };
         _dl_debug_state();
         let elfs = {
             let mut elfs = BTreeMap::new();
-            for (name, data) in self.objects.iter() {
+            for (name, data) in lib.objects.iter() {
                 // Skip already linked libraries
-                if !self.mmaps.contains_key(&*name) {
+                if !lib.mmaps.contains_key(&*name) && !self.root.mmaps.contains_key(&*name) {
                     elfs.insert(name.as_str(), Elf::parse(&data)?);
                 }
             }
@@ -342,7 +343,7 @@ impl Linker {
             if self.verbose {
                 println!("map {}", elf_name);
             }
-            let object = match self.objects.get(*elf_name) {
+            let object = match lib.objects.get(*elf_name) {
                 Some(some) => some,
                 None => continue,
             };
@@ -478,9 +479,9 @@ impl Linker {
                 println!("  mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len());
             }
             let (globals, weak_syms) = Linker::collect_syms(&elf, &mmap, self.verbose)?;
-            self.globals.extend(globals.into_iter());
-            self.weak_syms.extend(weak_syms.into_iter());
-            self.mmaps.insert(elf_name.to_string(), mmap);
+            lib.globals.extend(globals.into_iter());
+            lib.weak_syms.extend(weak_syms.into_iter());
+            lib.mmaps.insert(elf_name.to_string(), mmap);
         }
 
         // Allocate TLS
@@ -515,12 +516,12 @@ impl Linker {
             if same_elf {
                 continue;
             }
-            let object = match self.objects.get(*elf_name) {
+            let object = match lib.objects.get(*elf_name) {
                 Some(some) => some,
                 None => continue,
             };
 
-            let mmap = match self.mmaps.get_mut(*elf_name) {
+            let mmap = match lib.mmaps.get_mut(*elf_name) {
                 Some(some) => some,
                 None => continue,
             };
@@ -653,14 +654,15 @@ impl Linker {
                                 "missing name for symbol {:?}",
                                 sym
                             )))??;
-                    self.get_sym(name).unwrap_or(0)
+                    lib.get_sym(name)
+                        .unwrap_or(self.root.get_sym(name).unwrap_or(0))
                 } else {
                     0
                 };
 
                 let a = rel.r_addend.unwrap_or(0) as usize;
 
-                let mmap = match self.mmaps.get_mut(*elf_name) {
+                let mmap = match lib.mmaps.get_mut(*elf_name) {
                     Some(some) => some,
                     None => continue,
                 };
@@ -741,7 +743,7 @@ impl Linker {
             }
             if let Some(dyn_start_addr) = dyn_start {
                 if let Some(i) = debug_start {
-                    let mmap = match self.mmaps.get_mut(*elf_name) {
+                    let mmap = match lib.mmaps.get_mut(*elf_name) {
                         Some(some) => some,
                         None => continue,
                     };
@@ -778,7 +780,7 @@ impl Linker {
                         prot |= sys_mman::PROT_WRITE;
                     }
 
-                    let mmap = match self.mmaps.get_mut(*elf_name) {
+                    let mmap = match lib.mmaps.get_mut(*elf_name) {
                         Some(some) => some,
                         None => continue,
                     };
@@ -811,7 +813,7 @@ impl Linker {
         // Perform indirect relocations (necessary evil), gather entry point
         let mut entry_opt = None;
         for (elf_name, elf) in elfs.iter() {
-            let mmap = match self.mmaps.get_mut(*elf_name) {
+            let mmap = match lib.mmaps.get_mut(*elf_name) {
                 Some(some) => some,
                 None => continue,
             };
@@ -898,7 +900,7 @@ impl Linker {
             }
         }
         unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
-        //_dl_debug_state();
+        _dl_debug_state();
         Ok(entry_opt)
     }
 }

+ 2 - 1
src/ld_so/mod.rs

@@ -5,11 +5,12 @@ use crate::start::Stack;
 pub const PAGE_SIZE: usize = 4096;
 
 mod access;
+pub mod callbacks;
 pub mod debug;
+mod library;
 pub mod linker;
 pub mod start;
 pub mod tcb;
-
 pub fn static_init(sp: &'static Stack) {
     let mut phdr_opt = None;
     let mut phent_opt = None;

+ 2 - 2
src/ld_so/start.rs

@@ -195,7 +195,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
         }
     }
 
-    let entry = match linker.link(Some(&path), program) {
+    let entry = match linker.link(Some(&path), program, None) {
         Ok(ok) => match ok {
             Some(some) => some,
             None => {
@@ -210,7 +210,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
             loop {}
         }
     };
-    if let Err(e) = linker.run_init() {
+    if let Err(e) = linker.run_init(None) {
         eprintln!("ld.so: failed to run .init_array");
         unistd::_exit(1);
         loop {}

+ 5 - 5
src/platform/allocator/dlmalloc.rs

@@ -1,8 +1,8 @@
+use crate::ALLOCATOR;
 use core::{
     alloc::{GlobalAlloc, Layout},
     sync::atomic::{AtomicUsize, Ordering},
 };
-use crate::ALLOCATOR;
 
 use super::types::*;
 
@@ -12,10 +12,10 @@ extern "C" {
     fn mspace_memalign(msp: usize, alignment: size_t, bytes: size_t) -> *mut c_void;
     fn mspace_realloc(msp: usize, oldmem: *mut c_void, bytes: size_t) -> *mut c_void;
     fn mspace_free(msp: usize, mem: *mut c_void);
-    //fn dlmalloc(bytes: size_t) -> *mut c_void;
-    //fn dlmemalign(alignment: size_t, bytes: size_t) -> *mut c_void;
-    //fn dlrealloc(oldmem: *mut c_void, bytes: size_t) -> *mut c_void;
-    //fn dlfree(mem: *mut c_void);
+//fn dlmalloc(bytes: size_t) -> *mut c_void;
+//fn dlmemalign(alignment: size_t, bytes: size_t) -> *mut c_void;
+//fn dlrealloc(oldmem: *mut c_void, bytes: size_t) -> *mut c_void;
+//fn dlfree(mem: *mut c_void);
 }
 
 pub struct Allocator {

+ 3 - 1
src/platform/redox/epoll.rs

@@ -117,7 +117,9 @@ impl PalEpoll for Sys {
                 }
                 *event_ptr = epoll_event {
                     events: event.flags.bits() as _,
-                    data: epoll_data { u64: event.data as u64, },
+                    data: epoll_data {
+                        u64: event.data as u64,
+                    },
                     ..Default::default()
                 };
                 count += 1;

+ 14 - 9
src/platform/redox/socket.rs

@@ -8,7 +8,7 @@ use super::{
 };
 use crate::header::{
     arpa_inet::inet_aton,
-    netinet_in::{in_port_t, sockaddr_in, in_addr},
+    netinet_in::{in_addr, in_port_t, sockaddr_in},
     string::strnlen,
     sys_socket::{constants::*, sa_family_t, sockaddr, socklen_t},
     sys_time::timeval,
@@ -112,10 +112,8 @@ unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut so
 
     data.sun_family = AF_UNIX as c_ushort;
 
-    let path = slice::from_raw_parts_mut(
-        &mut data.sun_path as *mut _ as *mut u8,
-        data.sun_path.len(),
-    );
+    let path =
+        slice::from_raw_parts_mut(&mut data.sun_path as *mut _ as *mut u8, data.sun_path.len());
 
     let len = cmp::min(path.len(), buf.len());
     path[..len].copy_from_slice(&buf[..len]);
@@ -139,7 +137,10 @@ unsafe fn inner_af_inet(
     let sep = memchr::memchr(b':', &unparsed_addr).expect("missing port");
     let (raw_addr, rest) = unparsed_addr.split_at_mut(sep);
     let (colon, raw_port) = rest.split_at_mut(1);
-    let port = str::from_utf8(raw_port).expect("non-utf8 port").parse().expect("invalid port");
+    let port = str::from_utf8(raw_port)
+        .expect("non-utf8 port")
+        .parse()
+        .expect("invalid port");
 
     // Make address be followed by a NUL-byte
     colon[0] = b'\0';
@@ -147,7 +148,11 @@ unsafe fn inner_af_inet(
     trace!("address: {:?}, port: {:?}", str::from_utf8(&raw_addr), port);
 
     let mut addr = in_addr::default();
-    assert_eq!(inet_aton(raw_addr.as_ptr() as *mut i8, &mut addr), 1, "inet_aton might be broken, failed to parse netstack address");
+    assert_eq!(
+        inet_aton(raw_addr.as_ptr() as *mut i8, &mut addr),
+        1,
+        "inet_aton might be broken, failed to parse netstack address"
+    );
 
     let ret = sockaddr_in {
         sin_family: AF_INET as sa_family_t,
@@ -414,7 +419,7 @@ impl PalSocket for Sys {
             _ => {
                 errno = syscall::EPROTONOSUPPORT;
                 -1
-            },
+            }
         }
     }
 
@@ -448,7 +453,7 @@ impl PalSocket for Sys {
                 sv[0] = fd0 as c_int;
                 sv[1] = fd1 as c_int;
                 0
-            },
+            }
             _ => unsafe {
                 eprintln!(
                     "socketpair({}, {}, {}, {:p})",

+ 1 - 1
src/start.rs

@@ -68,7 +68,7 @@ static INIT_ARRAY: [extern "C" fn(); 1] = [init_array];
 static mut init_complete: bool = false;
 
 fn alloc_init() {
-    unsafe{
+    unsafe {
         if let Some(tcb) = ld_so::tcb::Tcb::current() {
             if tcb.mspace != 0 {
                 ALLOCATOR.set_book_keeper(tcb.mspace);