diff --git a/.gitignore b/.gitignore
index 3d392c13630eaa6442c7ab7751a5876de6205d55..f0f3a36cd6bc2d2df8736d3badc9b3d3479b9711 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@ sysroot/
 **/target/
 .gdb_history
 *.patch
+*.swp
+*.swo
diff --git a/src/header/dl-tls/mod.rs b/src/header/dl-tls/mod.rs
index 83db3fa3f39202be40ab5712f03c6724c1159313..cb5fec330282b5fcf795ca84bd111e8f44d84675 100644
--- a/src/header/dl-tls/mod.rs
+++ b/src/header/dl-tls/mod.rs
@@ -17,21 +17,17 @@ pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
         (*ti).ti_offset
     );
     if let Some(tcb) = Tcb::current() {
-        if let Some(tls) = tcb.tls() {
-            if let Some(masters) = tcb.masters() {
-                if let Some(master) = masters.get((*ti).ti_module as usize) {
-                    let addr = tls
-                        .as_mut_ptr()
-                        .add(master.offset + (*ti).ti_offset as usize);
-                    trace!(
-                        "__tls_get_addr({:p}: {:#x}, {:#x}) = {:p}",
-                        ti,
-                        (*ti).ti_module,
-                        (*ti).ti_offset,
-                        addr
-                    );
-                    return addr as *mut c_void;
-                }
+        if let Some(masters) = tcb.masters() {
+            if let Some(master) = masters.get((*ti).ti_module as usize) {
+                let addr = tcb.tls_end.sub(master.offset).add((*ti).ti_offset as usize);
+                trace!(
+                    "__tls_get_addr({:p}: {:#x}, {:#x}) = {:p}",
+                    ti,
+                    (*ti).ti_module,
+                    (*ti).ti_offset,
+                    addr
+                );
+                return addr as *mut c_void;
             }
         }
     }
diff --git a/src/header/dlfcn/mod.rs b/src/header/dlfcn/mod.rs
index 784a2b83c2b41bc72e7d2042176ee4729797340a..0f7ab20ec84d9f52b1bf70be838adbf8957de611 100644
--- a/src/header/dlfcn/mod.rs
+++ b/src/header/dlfcn/mod.rs
@@ -50,13 +50,11 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
     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);
             return ptr::null_mut();
         }
     };
     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();
     }
@@ -67,28 +65,12 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
 
     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 Some(fname) = filename {
-        if let Err(err) = (cbs.link)(&mut linker, None, None, Some(id)) {
-            (cbs.unload)(&mut linker, id);
-            eprintln!("dlopen: failed to link '{}': {}", fname, 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 '{}': {}", fname, err);
-            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-            return ptr::null_mut();
-        };
-    }
     id as *mut c_void
 }
 
@@ -104,14 +86,12 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
     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();
         }
     };
 
     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();
     }
@@ -119,12 +99,12 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
     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_ptr()
-    } else {
-        eprintln!("dlsym: symbol not found");
-        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-        ptr::null_mut()
+    match (cbs.get_sym)(&linker, handle as usize, symbol_str) {
+        Some(sym) => sym,
+        _ => {
+            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+            ptr::null_mut()
+        }
     }
 }
 
@@ -133,24 +113,18 @@ 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
 }
diff --git a/src/ld_so/callbacks.rs b/src/ld_so/callbacks.rs
index f0e851cbc7623b064d6bdaab23f98081a22bbf55..1d7d7a05f499226e27820faf8bbb1cdc965a96e4 100644
--- a/src/ld_so/callbacks.rs
+++ b/src/ld_so/callbacks.rs
@@ -1,15 +1,12 @@
-use super::linker::{Linker, Symbol, DSO};
+use super::linker::Linker;
+use crate::platform::types::c_void;
 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, Option<&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<Symbol>>,
-    pub run_init: Box<dyn Fn(&Linker, Option<usize>) -> Result<()>>,
-    pub run_fini: Box<dyn Fn(&Linker, Option<usize>) -> Result<()>>,
+    pub get_sym: Box<dyn Fn(&Linker, usize, &str) -> Option<*mut c_void>>,
 }
 
 impl LinkerCallbacks {
@@ -17,37 +14,19 @@ impl 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 unload(linker: &mut Linker, lib_id: usize) {
+    linker.unload(lib_id)
 }
 
 fn load_library(linker: &mut Linker, name: Option<&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<Symbol> {
-    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)
+fn get_sym(linker: &Linker, lib_id: usize, name: &str) -> Option<*mut c_void> {
+    linker.get_sym(lib_id, name)
 }
diff --git a/src/ld_so/dso.rs b/src/ld_so/dso.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3f053d091e126a718a40f84e22bac93a5882803a
--- /dev/null
+++ b/src/ld_so/dso.rs
@@ -0,0 +1,429 @@
+use super::{
+    debug::{RTLDDebug, _r_debug},
+    linker::Symbol,
+    tcb::{round_up, Master},
+};
+use crate::{
+    header::{errno::STR_ERROR, sys_mman},
+    platform::{errno, types::c_void},
+};
+use alloc::{
+    collections::BTreeMap,
+    string::{String, ToString},
+    vec::Vec,
+};
+use core::{
+    mem::{size_of, transmute},
+    ptr, slice,
+};
+use goblin::{
+    elf::{
+        header::ET_DYN,
+        program_header,
+        r#dyn::{Dyn, DT_DEBUG, DT_RUNPATH},
+        section_header::{SHN_UNDEF, SHT_FINI_ARRAY, SHT_INIT_ARRAY},
+        sym, Elf,
+    },
+    error::{Error, Result},
+};
+
+/// Use to represent a library as well as all the symbols that is loaded withen it.
+#[derive(Default)]
+pub struct DSO {
+    pub name: String,
+    pub id: usize,
+    pub dlopened: bool,
+    pub entry_point: usize,
+    pub runpath: Option<String>,
+    /// Loaded library in-memory data
+    pub mmap: &'static mut [u8],
+    pub global_syms: BTreeMap<String, Symbol>,
+    pub weak_syms: BTreeMap<String, Symbol>,
+    pub dependencies: Vec<String>,
+    /// .init_array addr and len
+    pub init_array: (usize, usize),
+    /// .fini_array addr and len
+    pub fini_array: (usize, usize),
+    pub tls_module_id: usize,
+    pub tls_offset: usize,
+    pub use_count: usize,
+}
+
+impl DSO {
+    pub fn new(
+        path: &str,
+        data: &Vec<u8>,
+        base_addr: Option<usize>,
+        dlopened: bool,
+        id: usize,
+        tls_module_id: usize,
+        tls_offset: usize,
+    ) -> Result<(DSO, Option<Master>)> {
+        let elf = Elf::parse(data)?;
+        let (mmap, tcb_master) = DSO::mmap_and_copy(&path, &elf, &data, base_addr, tls_offset)?;
+        let (global_syms, weak_syms) = DSO::collect_syms(&elf, &mmap)?;
+        let (init_array, fini_array) = DSO::init_fini_arrays(&elf, mmap.as_ptr() as usize);
+
+        let name = match elf.soname {
+            Some(soname) => soname.to_string(),
+            _ => basename(&path),
+        };
+        let tls_offset = match tcb_master {
+            Some(ref master) => master.offset,
+            _ => 0,
+        };
+        let entry_point = if is_pie_enabled(&elf) {
+            mmap.as_ptr() as usize + elf.header.e_entry as usize
+        } else {
+            elf.header.e_entry as usize
+        };
+        let dso = DSO {
+            name: name,
+            id: id,
+            use_count: 1,
+            dlopened: dlopened,
+            entry_point: entry_point,
+            runpath: DSO::get_runpath(&path, &elf)?,
+            mmap: mmap,
+            global_syms: global_syms,
+            weak_syms: weak_syms,
+            dependencies: elf.libraries.iter().map(|s| s.to_string()).collect(),
+            init_array: init_array,
+            fini_array: fini_array,
+            tls_module_id: tls_module_id,
+            tls_offset: tls_offset,
+        };
+        return Ok((dso, tcb_master));
+    }
+
+    pub fn get_sym(&self, name: &str) -> Option<Symbol> {
+        if let Some(value) = self.global_syms.get(name) {
+            Some(*value)
+        } else if let Some(value) = self.weak_syms.get(name) {
+            Some(*value)
+        } else {
+            None
+        }
+    }
+
+    pub fn run_init(&self) {
+        unsafe {
+            let (addr, size) = self.init_array;
+            for i in (0..size).step_by(8) {
+                let func = transmute::<usize, *const Option<extern "C" fn()>>(addr + i);
+                (*func).map(|x| x());
+            }
+        }
+    }
+
+    pub fn run_fini(&self) {
+        unsafe {
+            let (addr, size) = self.fini_array;
+            for i in (0..size).step_by(8).rev() {
+                let func = transmute::<usize, *const Option<extern "C" fn()>>(addr + i);
+                (*func).map(|x| x());
+            }
+        }
+    }
+
+    fn get_runpath(path: &str, elf: &Elf) -> Result<Option<String>> {
+        if let Some(dynamic) = &elf.dynamic {
+            let entry = dynamic.dyns.iter().find(|d| d.d_tag == DT_RUNPATH);
+            match entry {
+                Some(entry) => {
+                    let runpath = elf
+                        .dynstrtab
+                        .get(entry.d_val as usize)
+                        .ok_or(Error::Malformed("Missing RUNPATH in dynstrtab".to_string()))??;
+                    let base = dirname(path);
+                    return Ok(Some(runpath.replace("$ORIGIN", &base)));
+                }
+                _ => return Ok(None),
+            }
+        }
+        return Ok(None);
+    }
+
+    fn mmap_and_copy(
+        path: &str,
+        elf: &Elf,
+        data: &Vec<u8>,
+        base_addr: Option<usize>,
+        tls_offset: usize,
+    ) -> Result<(&'static mut [u8], Option<Master>)> {
+        // data for struct LinkMap
+        let mut l_ld = 0;
+        // Calculate virtual memory bounds
+        let bounds = {
+            let mut bounds_opt: Option<(usize, usize)> = None;
+            for ph in elf.program_headers.iter() {
+                let voff = ph.p_vaddr % ph.p_align;
+                let vaddr = (ph.p_vaddr - voff) as usize;
+                let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
+
+                match ph.p_type {
+                    program_header::PT_DYNAMIC => {
+                        l_ld = ph.p_vaddr;
+                    }
+                    program_header::PT_LOAD => {
+                        trace!("  load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
+                        if let Some(ref mut bounds) = bounds_opt {
+                            if vaddr < bounds.0 {
+                                bounds.0 = vaddr;
+                            }
+                            if vaddr + vsize > bounds.1 {
+                                bounds.1 = vaddr + vsize;
+                            }
+                        } else {
+                            bounds_opt = Some((vaddr, vaddr + vsize));
+                        }
+                    }
+                    _ => (),
+                }
+            }
+            bounds_opt.ok_or(Error::Malformed(
+                "Unable to find PT_LOAD section".to_string(),
+            ))?
+        };
+        trace!("  bounds {:#x}, {:#x}", bounds.0, bounds.1);
+        // Allocate memory
+        let mmap = unsafe {
+            if let Some(addr) = base_addr {
+                let size = if is_pie_enabled(&elf) {
+                    bounds.1
+                } else {
+                    bounds.1 - bounds.0
+                };
+                _r_debug.insert_first(addr as usize, path, addr + l_ld as usize);
+                slice::from_raw_parts_mut(addr as *mut u8, size)
+            } else {
+                let (start, end) = bounds;
+                let size = end - start;
+                let mut flags = sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE;
+                if start != 0 {
+                    flags |= sys_mman::MAP_FIXED_NOREPLACE;
+                }
+                trace!("mmap({:#x}, {:x}, {:x})", start, size, flags);
+                let ptr = sys_mman::mmap(
+                    start as *mut c_void,
+                    size,
+                    //TODO: Make it possible to not specify PROT_EXEC on Redox
+                    sys_mman::PROT_READ | sys_mman::PROT_WRITE,
+                    flags,
+                    -1,
+                    0,
+                );
+                if ptr as usize == !0
+                /* MAP_FAILED */
+                {
+                    return Err(Error::Malformed(format!(
+                        "failed to map {}. errno: {}",
+                        path, STR_ERROR[errno as usize]
+                    )));
+                }
+                if start as *mut c_void != ptr::null_mut() {
+                    assert_eq!(
+                        ptr, start as *mut c_void,
+                        "mmap must always map on the destination we requested"
+                    );
+                }
+                ptr::write_bytes(ptr as *mut u8, 0, size);
+                _r_debug.insert(ptr as usize, path, ptr as usize + l_ld as usize);
+                slice::from_raw_parts_mut(ptr as *mut u8, size)
+            }
+        };
+
+        let skip_load_segment_copy = base_addr.is_some();
+        let mut tcb_master = None;
+
+        // Copy data
+        for ph in elf.program_headers.iter() {
+            let voff = ph.p_vaddr % ph.p_align;
+            let vaddr = (ph.p_vaddr - voff) as usize;
+            let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
+
+            match ph.p_type {
+                program_header::PT_LOAD => {
+                    if skip_load_segment_copy {
+                        continue;
+                    }
+                    let obj_data = {
+                        let range = ph.file_range();
+                        match data.get(range.clone()) {
+                            Some(some) => some,
+                            None => {
+                                return Err(Error::Malformed(format!(
+                                    "failed to read {:x?}",
+                                    range
+                                )))
+                            }
+                        }
+                    };
+
+                    let mmap_data = {
+                        let range = if is_pie_enabled(elf) {
+                            let addr = ph.p_vaddr as usize;
+                            addr..addr + obj_data.len()
+                        } else {
+                            let addr = ph.p_vaddr as usize - mmap.as_ptr() as usize;
+                            addr..addr + obj_data.len()
+                        };
+                        match mmap.get_mut(range.clone()) {
+                            Some(some) => some,
+                            None => {
+                                return Err(Error::Malformed(format!(
+                                    "failed to write {:x?}",
+                                    range
+                                )));
+                            }
+                        }
+                    };
+                    trace!(
+                        "  copy {:#x}, {:#x}: {:#x}, {:#x}",
+                        vaddr,
+                        vsize,
+                        voff,
+                        obj_data.len()
+                    );
+                    mmap_data.copy_from_slice(obj_data);
+                }
+                program_header::PT_TLS => {
+                    let ptr = unsafe {
+                        if is_pie_enabled(elf) {
+                            mmap.as_ptr().add(ph.p_vaddr as usize)
+                        } else {
+                            ph.p_vaddr as *const u8
+                        }
+                    };
+                    tcb_master = Some(Master {
+                        ptr: ptr,
+                        len: ph.p_filesz as usize,
+                        offset: tls_offset + vsize,
+                    });
+                    trace!("  tcb master {:x?}", tcb_master);
+                }
+                program_header::PT_DYNAMIC => {
+                    // overwrite DT_DEBUG if exist in DYNAMIC segment
+                    // first we identify the location of DYNAMIC segment
+                    let dyn_start = ph.p_vaddr as usize;
+                    let mut debug_start = None;
+                    // next we identify the location of DT_DEBUG in .dynamic section
+                    if let Some(dynamic) = elf.dynamic.as_ref() {
+                        let mut i = 0;
+                        for entry in &dynamic.dyns {
+                            if entry.d_tag == DT_DEBUG {
+                                debug_start = Some(i as usize);
+                                break;
+                            }
+                            i += 1;
+                        }
+                    }
+                    if let Some(i) = debug_start {
+                        let bytes: [u8; size_of::<Dyn>() / 2] =
+                            unsafe { transmute((&_r_debug) as *const RTLDDebug as usize) };
+                        let start = if is_pie_enabled(elf) {
+                            dyn_start + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
+                        } else {
+                            dyn_start + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
+                                - mmap.as_mut_ptr() as usize
+                        };
+                        mmap[start..start + size_of::<Dyn>() / 2].clone_from_slice(&bytes);
+                    }
+                }
+                _ => (),
+            }
+        }
+        return Ok((mmap, tcb_master));
+    }
+
+    fn collect_syms(
+        elf: &Elf,
+        mmap: &[u8],
+    ) -> Result<(BTreeMap<String, Symbol>, BTreeMap<String, Symbol>)> {
+        let mut globals = BTreeMap::new();
+        let mut weak_syms = BTreeMap::new();
+        for sym in elf.dynsyms.iter() {
+            let bind = sym.st_bind();
+            if sym.st_shndx == SHN_UNDEF as usize
+                || ![sym::STB_GLOBAL, sym::STB_WEAK].contains(&bind)
+            {
+                continue;
+            }
+            let name: String;
+            let value: Symbol;
+            if let Some(name_res) = elf.dynstrtab.get(sym.st_name) {
+                name = name_res?.to_string();
+                value = if is_pie_enabled(elf) {
+                    Symbol {
+                        base: mmap.as_ptr() as usize,
+                        value: sym.st_value as usize,
+                        size: sym.st_size as usize,
+                    }
+                } else {
+                    Symbol {
+                        base: 0,
+                        value: sym.st_value as usize,
+                        size: sym.st_size as usize,
+                    }
+                };
+            } else {
+                continue;
+            }
+            match sym.st_bind() {
+                sym::STB_GLOBAL => {
+                    trace!("  global {}: {:x?} = {:p}", &name, sym, value.as_ptr());
+                    globals.insert(name, value);
+                }
+                sym::STB_WEAK => {
+                    trace!("  weak {}: {:x?} = {:p}", &name, sym, value.as_ptr());
+                    weak_syms.insert(name, value);
+                }
+                _ => unreachable!(),
+            }
+        }
+        return Ok((globals, weak_syms));
+    }
+
+    fn init_fini_arrays(elf: &Elf, mmap_addr: usize) -> ((usize, usize), (usize, usize)) {
+        let mut init_array: (usize, usize) = (0, 0);
+        let mut fini_array: (usize, usize) = (0, 0);
+        for section in elf
+            .section_headers
+            .iter()
+            .filter(|s| s.sh_type == SHT_INIT_ARRAY || s.sh_type == SHT_FINI_ARRAY)
+        {
+            let addr = if is_pie_enabled(&elf) {
+                mmap_addr + section.vm_range().start
+            } else {
+                section.vm_range().start
+            };
+            if section.sh_type == SHT_INIT_ARRAY {
+                init_array = (addr, section.sh_size as usize);
+            } else {
+                fini_array = (addr, section.sh_size as usize);
+            }
+        }
+        return (init_array, fini_array);
+    }
+}
+
+impl Drop for DSO {
+    fn drop(&mut self) {
+        self.run_fini();
+        unsafe { sys_mman::munmap(self.mmap.as_mut_ptr() as *mut c_void, self.mmap.len()) };
+    }
+}
+
+pub fn is_pie_enabled(elf: &Elf) -> bool {
+    return elf.header.e_type == ET_DYN;
+}
+
+fn basename(path: &str) -> String {
+    return path.split("/").last().unwrap_or(path).to_string();
+}
+
+fn dirname(path: &str) -> String {
+    let mut parts: Vec<&str> = path.split("/").collect();
+    parts.truncate(parts.len() - 1);
+    return parts.join("/");
+}
diff --git a/src/ld_so/library.rs b/src/ld_so/library.rs
deleted file mode 100644
index 19862f7e3d4281b908bf86903a54914b3cb7eb87..0000000000000000000000000000000000000000
--- a/src/ld_so/library.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use super::linker::Symbol;
-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, Symbol>,
-    /// Weak symbols
-    pub weak_syms: BTreeMap<String, Symbol>,
-    /// Loaded library raw data
-    pub objects: BTreeMap<String, Box<[u8]>>,
-    /// Loaded library in-memory data
-    pub mmaps: BTreeMap<String, (usize, &'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>,
-    pub runpath: Option<String>,
-}
-impl Library {
-    pub fn new() -> Library {
-        Default::default()
-    }
-    pub fn get_sym(&self, name: &str) -> Option<Symbol> {
-        if let Some(value) = self.globals.get(name) {
-            Some(*value)
-        } else if let Some(value) = self.weak_syms.get(name) {
-            Some(*value)
-        } else {
-            None
-        }
-    }
-}
diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs
index bf3b65ba349cf55967aa1f8553f5a33f12a5c74c..21d35b1804a3b9b4548a0b789b84723626f8cd4f 100644
--- a/src/ld_so/linker.rs
+++ b/src/ld_so/linker.rs
@@ -1,52 +1,31 @@
 use alloc::{
-    boxed::Box,
-    collections::{BTreeMap, BTreeSet},
+    collections::BTreeMap,
     rc::Rc,
     string::{String, ToString},
     vec::Vec,
 };
-use core::{
-    cell::RefCell,
-    mem::{size_of, swap, transmute},
-    ptr, slice,
-};
+use core::{cell::RefCell, mem::transmute, ptr};
 use goblin::{
-    elf::{
-        header::ET_DYN,
-        program_header,
-        r#dyn::{Dyn, DT_DEBUG, DT_RUNPATH},
-        reloc, sym, Elf,
-    },
+    elf::{program_header, reloc, Elf},
     error::{Error, Result},
 };
 
 use crate::{
     c_str::CString,
     fs::File,
-    header::{errno::STR_ERROR, fcntl, sys_mman, unistd},
+    header::{fcntl, sys_mman, unistd::F_OK},
     io::Read,
-    platform::{errno, types::c_void},
+    platform::types::c_void,
 };
 
 use super::{
     access::accessible,
     callbacks::LinkerCallbacks,
-    debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
-    library::{DepTree, Library},
-    tcb::{Master, Tcb},
-    PAGE_SIZE,
+    debug::{RTLDState, _dl_debug_state, _r_debug},
+    dso::{is_pie_enabled, DSO},
+    tcb::{round_up, Master, Tcb},
+    PATH_SEP,
 };
-#[cfg(target_os = "redox")]
-pub const PATH_SEP: char = ';';
-
-#[cfg(target_os = "linux")]
-pub const PATH_SEP: char = ':';
-
-pub struct DSO {
-    pub name: String,
-    pub base_addr: usize,
-    pub entry_point: usize,
-}
 
 #[derive(Clone, Copy, Debug)]
 pub struct Symbol {
@@ -54,6 +33,7 @@ pub struct Symbol {
     pub base: usize,
     pub size: usize,
 }
+
 impl Symbol {
     pub fn as_ptr(self) -> *mut c_void {
         (self.base + self.value) as *mut c_void
@@ -61,684 +41,242 @@ impl Symbol {
 }
 
 pub struct Linker {
-    // Used by load
-    /// Library path to search when loading library by name
-    default_library_path: String,
     ld_library_path: Option<String>,
-    root: Library,
-    verbose: bool,
-    tls_index_offset: usize,
-    lib_spaces: BTreeMap<usize, Library>,
-    counter: usize,
+    next_object_id: usize,
+    next_tls_module_id: usize,
+    tls_size: usize,
+    objects: BTreeMap<usize, DSO>,
+    name_to_object_id_map: BTreeMap<String, usize>,
     pub cbs: Rc<RefCell<LinkerCallbacks>>,
 }
 
 const root_id: usize = 1;
 
 impl Linker {
-    pub fn new(ld_library_path: Option<String>, verbose: bool) -> Self {
+    pub fn new(ld_library_path: Option<String>) -> Self {
         Self {
-            default_library_path: "/lib".to_string(),
             ld_library_path: ld_library_path,
-            root: Library::new(),
-            verbose,
-            tls_index_offset: 0,
-            lib_spaces: BTreeMap::new(),
-            counter: root_id + 1,
+            next_object_id: root_id,
+            next_tls_module_id: 0,
+            tls_size: 0,
+            objects: BTreeMap::new(),
+            name_to_object_id_map: BTreeMap::new(),
             cbs: Rc::new(RefCell::new(LinkerCallbacks::new())),
         }
     }
-    pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
-        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.root.dep_tree);
-        }
-        return Ok(());
-    }
-    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 lib.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();
-        lib.cir_dep.insert(name.to_string());
-        let path_c = CString::new(path)
-            .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
-
-        {
-            let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
-            let mut file = File::open(&path_c, flags)
-                .map_err(|err| Error::Malformed(format!("failed to open '{}': {}", path, err)))?;
 
-            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(), lib)?;
-        lib.cir_dep.remove(name);
-        Ok(deps)
-    }
-
-    fn load_data(
-        &mut self,
-        name: &str,
-        data: Box<[u8]>,
-        lib: &mut Library,
-    ) -> Result<Vec<DepTree>> {
-        let elf = Elf::parse(&data)?;
-        //println!("{:#?}", elf);
-
-        // search for RUNPATH
-        lib.runpath = if let Some(dynamic) = elf.dynamic {
-            let entry = dynamic.dyns.iter().find(|d| d.d_tag == DT_RUNPATH);
-            match entry {
-                Some(entry) => {
-                    let path = elf
-                        .dynstrtab
-                        .get(entry.d_val as usize)
-                        .ok_or(Error::Malformed("Missing RUNPATH in dynstrtab".to_string()))??;
-                    Some(path.to_string())
-                }
-                _ => None,
-            }
-        } else {
-            None
-        };
-
-        let mut deps = Vec::new();
-        for library in elf.libraries.iter() {
-            if let Some(dep) = self._load_library(library, lib)? {
-                deps.push(dep);
-            }
-        }
-        let key = match elf.soname {
-            Some(soname) => soname,
-            _ => name,
-        };
-        if !lib.objects.contains_key(key) {
-            lib.objects.insert(key.to_string(), data);
-        }
-        return Ok(deps);
+    pub fn load_program(&mut self, path: &str, base_addr: Option<usize>) -> Result<usize> {
+        self.load_object(path, &None, base_addr, false)?;
+        return Ok(self.objects.get(&root_id).unwrap().entry_point);
     }
 
     pub fn load_library(&mut self, name: Option<&str>) -> Result<usize> {
         match name {
             Some(name) => {
-                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);
-            }
-            None => return Ok(root_id),
-        }
-    }
-    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, lib)?))
-        } else {
-            let mut paths = Vec::new();
-            if let Some(ld_library_path) = &self.ld_library_path {
-                paths.push(ld_library_path);
-            }
-            if let Some(runpath) = &lib.runpath {
-                paths.push(runpath);
-            }
-            paths.push(&self.default_library_path);
-            for part in paths.iter() {
-                let path = if part.is_empty() {
-                    format!("./{}", name)
+                if let Some(id) = self.name_to_object_id_map.get(name) {
+                    let obj = self.objects.get_mut(id).unwrap();
+                    obj.use_count += 1;
+                    return Ok(*id);
                 } else {
-                    format!("{}/{}", part, name)
-                };
-                if self.verbose {
-                    println!("check {}", path);
-                }
+                    let parent_runpath = &self.objects.get(&root_id).unwrap().runpath.clone();
+                    let lib_id = self.next_object_id;
+                    self.load_object(name, parent_runpath, None, true)?;
 
-                if accessible(&path, unistd::F_OK) == 0 {
-                    return Ok(Some(self.load_recursive(name, &path, lib)?));
+                    return Ok(lib_id);
                 }
             }
+            None => return Ok(root_id),
+        }
+    }
 
-            Err(Error::Malformed(format!("failed to locate '{}'", name)))
+    pub fn get_sym(&self, lib_id: usize, name: &str) -> Option<*mut c_void> {
+        match self.objects.get(&lib_id) {
+            Some(obj) => obj.get_sym(name).map(|s| s.as_ptr()),
+            _ => None,
         }
     }
 
-    fn collect_syms(
-        elf: &Elf,
-        mmap: &[u8],
-        verbose: bool,
-    ) -> Result<(BTreeMap<String, Symbol>, BTreeMap<String, Symbol>)> {
-        let mut globals = BTreeMap::new();
-        let mut weak_syms = BTreeMap::new();
-        for sym in elf.dynsyms.iter() {
-            let bind = sym.st_bind();
-            if sym.st_value == 0 || ![sym::STB_GLOBAL, sym::STB_WEAK].contains(&bind) {
-                continue;
-            }
-            let name: String;
-            let value: Symbol;
-            if let Some(name_res) = elf.dynstrtab.get(sym.st_name) {
-                name = name_res?.to_string();
-                value = if is_pie_enabled(elf) {
-                    Symbol {
-                        base: mmap.as_ptr() as usize,
-                        value: sym.st_value as usize,
-                        size: sym.st_size as usize,
+    pub fn unload(&mut self, lib_id: usize) {
+        if let Some(obj) = self.objects.get_mut(&lib_id) {
+            if obj.dlopened {
+                if obj.use_count == 1 {
+                    let obj = self.objects.remove(&lib_id).unwrap();
+                    for dep in obj.dependencies.iter() {
+                        self.unload(*self.name_to_object_id_map.get(dep).unwrap());
                     }
+                    self.name_to_object_id_map.remove(&obj.name);
+                    drop(obj);
                 } else {
-                    Symbol {
-                        base: 0,
-                        value: sym.st_value as usize,
-                        size: sym.st_size as usize,
-                    }
-                };
-            } else {
-                continue;
-            }
-            match sym.st_bind() {
-                sym::STB_GLOBAL => {
-                    if verbose {
-                        println!("  global {}: {:x?} = {:p}", &name, sym, value.as_ptr());
-                    }
-                    globals.insert(name, value);
-                }
-                sym::STB_WEAK => {
-                    if verbose {
-                        println!("  weak {}: {:x?} = {:p}", &name, sym, value.as_ptr());
-                    }
-                    weak_syms.insert(name, value);
+                    obj.use_count -= 1;
                 }
-                _ => unreachable!(),
             }
         }
-        return Ok((globals, weak_syms));
     }
 
-    pub fn get_sym(&self, name: &str, libspace: Option<usize>) -> Option<Symbol> {
-        match libspace {
-            None | Some(root_id) => self.root.get_sym(name),
-            Some(id) => {
-                let lib = self.lib_spaces.get(&id)?;
-                lib.get_sym(name)
-            }
-        }
-    }
+    fn load_object(
+        &mut self,
+        path: &str,
+        runpath: &Option<String>,
+        base_addr: Option<usize>,
+        dlopened: bool,
+    ) -> Result<()> {
+        unsafe { _r_debug.state = RTLDState::RT_ADD };
+        _dl_debug_state();
 
-    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 => self.run_tree(&self.root, &self.root.dep_tree, ".init_array"),
+        let mut new_objects = Vec::new();
+        let mut objects_data = Vec::new();
+        let mut tcb_masters = Vec::new();
+        self.load_objects_recursive(
+            path,
+            runpath,
+            base_addr,
+            dlopened,
+            &mut new_objects,
+            &mut objects_data,
+            &mut tcb_masters,
+        )?;
+
+        unsafe {
+            let tcb = if self.objects.len() == 0 {
+                Tcb::new(self.tls_size)?
+            } else {
+                Tcb::current().unwrap()
+            };
+            tcb.append_masters(tcb_masters);
+            tcb.copy_masters()?;
+            tcb.activate();
         }
-    }
 
-    pub fn run_fini(&self, libspace: Option<usize>) -> Result<()> {
-        match libspace {
-            Some(root_id) => return Ok(()),
-            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")
-            }
-        }
-    }
+        self.relocate(&new_objects, &objects_data)?;
+        self.run_init(&new_objects);
 
-    fn run_tree(&self, lib: &Library, root: &DepTree, tree_name: &str) -> Result<()> {
-        for node in root.deps.iter() {
-            self.run_tree(lib, node, tree_name)?;
-        }
-        if self.verbose {
-            println!("running {} {}", tree_name, &root.name);
-        }
-        let (_, mmap) = match lib.mmaps.get(&root.name) {
-            Some(some) => some,
-            None => return Ok(()),
-        };
-        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 {
-                    Ok(y) => y,
-                    _ => continue,
-                },
-                _ => continue,
-            };
-            if name == tree_name {
-                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) };
-                }
-            }
+        for obj in new_objects.into_iter() {
+            self.name_to_object_id_map.insert(obj.name.clone(), obj.id);
+            self.objects.insert(obj.id, obj);
         }
+
+        unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
+        _dl_debug_state();
+
         return Ok(());
     }
 
-    pub fn link(
+    fn load_objects_recursive(
         &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
+        name: &str,
+        parent_runpath: &Option<String>,
+        base_addr: Option<usize>,
+        dlopened: bool,
+        new_objects: &mut Vec<DSO>,
+        objects_data: &mut Vec<Vec<u8>>,
+        tcb_masters: &mut Vec<Master>,
+    ) -> Result<()> {
+        if let Some(obj) = {
+            if let Some(id) = self.name_to_object_id_map.get(name) {
+                self.objects.get_mut(id)
+            } else {
+                new_objects.iter_mut().find(|o| o.name == name)
             }
+        } {
+            obj.use_count += 1;
+            return Ok(());
         }
-    }
 
-    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 mut skip_list = BTreeSet::new();
-        let elfs = {
-            let mut elfs = BTreeMap::new();
-            for (name, data) in lib.objects.iter() {
-                // Skip already linked libraries
-                if !lib.mmaps.contains_key(&*name) && !self.root.mmaps.contains_key(&*name) {
-                    elfs.insert(name.as_str(), Elf::parse(&data)?);
-                } else {
-                    skip_list.insert(name.as_str());
-                }
-            }
-            elfs
-        };
+        let path = Linker::search_object(name, &self.ld_library_path, parent_runpath)?;
+        let data = Linker::read_file(&path)?;
+        let (obj, tcb_master) = DSO::new(
+            &path,
+            &data,
+            base_addr,
+            dlopened,
+            self.next_object_id,
+            self.next_tls_module_id,
+            self.tls_size,
+        )?;
+        new_objects.push(obj);
+        objects_data.push(data);
+        self.next_object_id += 1;
+
+        if let Some(master) = tcb_master {
+            self.next_tls_module_id += 1;
+            self.tls_size = master.offset;
+            tcb_masters.push(master);
+        }
 
-        // Load all ELF files into memory and find all globals
-        let mut tls_primary = 0;
-        let mut tls_size = 0;
-        for (elf_name, elf) in elfs.iter() {
-            if skip_list.contains(elf_name) {
-                continue;
-            }
-            if self.verbose {
-                println!("map {}", elf_name);
-            }
-            let object = match lib.objects.get(*elf_name) {
-                Some(some) => some,
-                None => continue,
-            };
-            // data for struct LinkMap
-            let mut l_ld = 0;
-            // Calculate virtual memory bounds
-            let bounds = {
-                let mut bounds_opt: Option<(usize, usize)> = None;
-                for ph in elf.program_headers.iter() {
-                    let voff = ph.p_vaddr as usize % PAGE_SIZE;
-                    let vaddr = ph.p_vaddr as usize - voff;
-                    let vsize =
-                        ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
+        let (runpath, dependencies) = {
+            let parent = new_objects.last().unwrap();
+            (parent.runpath.clone(), parent.dependencies.clone())
+        };
+        for dep_name in dependencies.iter() {
+            self.load_objects_recursive(
+                dep_name,
+                &runpath,
+                None,
+                dlopened,
+                new_objects,
+                objects_data,
+                tcb_masters,
+            )?;
+        }
 
-                    match ph.p_type {
-                        program_header::PT_DYNAMIC => {
-                            l_ld = ph.p_vaddr;
-                        }
-                        program_header::PT_LOAD => {
-                            if self.verbose {
-                                println!("  load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
-                            }
-                            if let Some(ref mut bounds) = bounds_opt {
-                                if vaddr < bounds.0 {
-                                    bounds.0 = vaddr;
-                                }
-                                if vaddr + vsize > bounds.1 {
-                                    bounds.1 = vaddr + vsize;
-                                }
-                            } else {
-                                bounds_opt = Some((vaddr, vaddr + vsize));
-                            }
-                        }
-                        program_header::PT_TLS => {
-                            if self.verbose {
-                                println!("  load tls {:#x}: {:x?}", vsize, ph);
-                            }
-                            tls_size += vsize;
-                            if Some(*elf_name) == primary_opt {
-                                tls_primary += vsize;
-                            }
-                        }
-                        _ => (),
-                    }
-                }
-                match bounds_opt {
-                    Some(some) => some,
-                    None => continue,
-                }
-            };
-            if self.verbose {
-                println!("  bounds {:#x}, {:#x}", bounds.0, bounds.1);
-            }
-            // Allocate memory
-            let mmap = unsafe {
-                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;
-                    let size = if is_pie_enabled(&elf) {
-                        bounds.1
-                    } else {
-                        bounds.1 - bounds.0
-                    };
+        return Ok(());
+    }
 
-                    // Fill the gaps i the binary
-                    let mut ranges = Vec::new();
-                    for ph in elf.program_headers.iter() {
-                        if ph.p_type == program_header::PT_LOAD {
-                            let voff = ph.p_vaddr as usize % PAGE_SIZE;
-                            let vaddr = ph.p_vaddr as usize - voff;
-                            let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE)
-                                * PAGE_SIZE;
-                            if is_pie_enabled(&elf) {
-                                ranges.push((vaddr, vsize));
-                            } else {
-                                ranges.push((vaddr - addr, vsize));
-                            }
-                        }
-                    }
-                    ranges.sort();
-                    let mut start = addr;
-                    for (vaddr, vsize) in ranges.iter() {
-                        if start < addr + vaddr {
-                            if self.verbose {
-                                println!("mmap({:#x}, {})", start, addr + vaddr - start);
-                            }
-                            let mut flags = sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE;
-                            if start != 0 {
-                                flags |= sys_mman::MAP_FIXED_NOREPLACE;
-                            }
-                            let ptr = sys_mman::mmap(
-                                start as *mut c_void,
-                                addr + vaddr - start,
-                                //TODO: Make it possible to not specify PROT_EXEC on Redox
-                                sys_mman::PROT_READ | sys_mman::PROT_WRITE,
-                                flags,
-                                -1,
-                                0,
-                            );
-                            if ptr as usize == !0
-                            /* MAP_FAILED */
-                            {
-                                return Err(Error::Malformed(format!(
-                                    "failed to map {}. errno: {}",
-                                    elf_name, STR_ERROR[errno as usize]
-                                )));
-                            }
-                            if start as *mut c_void != ptr::null_mut() {
-                                assert_eq!(
-                                    ptr, start as *mut c_void,
-                                    "mmap must always map on the destination we requested"
-                                );
-                            }
-                        }
-                        start = addr + vaddr + vsize
-                    }
-                    sys_mman::mprotect(
-                        addr as *mut c_void,
-                        size,
-                        sys_mman::PROT_READ | sys_mman::PROT_WRITE,
-                    );
-                    _r_debug.insert_first(addr as usize, &elf_name, addr + l_ld as usize);
-                    (
-                        addr as usize,
-                        slice::from_raw_parts_mut(addr as *mut u8, size),
-                    )
-                } else {
-                    let (start, end) = bounds;
-                    let size = end - start;
-                    if self.verbose {
-                        println!("mmap({:#x}, {})", start, size);
-                    }
-                    let mut flags = sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE;
-                    if start != 0 {
-                        flags |= sys_mman::MAP_FIXED_NOREPLACE;
-                    }
-                    let ptr = sys_mman::mmap(
-                        start as *mut c_void,
-                        size,
-                        //TODO: Make it possible to not specify PROT_EXEC on Redox
-                        sys_mman::PROT_READ | sys_mman::PROT_WRITE,
-                        flags,
-                        -1,
-                        0,
-                    );
-                    if ptr as usize == !0
-                    /* MAP_FAILED */
-                    {
-                        return Err(Error::Malformed(format!(
-                            "failed to map {}. errno: {}",
-                            elf_name, STR_ERROR[errno as usize]
-                        )));
-                    }
-                    if start as *mut c_void != ptr::null_mut() {
-                        assert_eq!(
-                            ptr, start as *mut c_void,
-                            "mmap must always map on the destination we requested"
-                        );
-                    }
-                    ptr::write_bytes(ptr as *mut u8, 0, size);
-                    _r_debug.insert(ptr as usize, &elf_name, ptr as usize + l_ld as usize);
-                    (start, slice::from_raw_parts_mut(ptr as *mut u8, size))
+    fn search_object(
+        name: &str,
+        ld_library_path: &Option<String>,
+        parent_runpath: &Option<String>,
+    ) -> Result<String> {
+        let mut full_path = name.to_string();
+        if accessible(&full_path, F_OK) == 0 {
+            return Ok(full_path);
+        } else {
+            let mut search_paths = Vec::new();
+            if let Some(runpath) = parent_runpath {
+                search_paths.extend(runpath.split(PATH_SEP));
+            }
+            if let Some(ld_path) = ld_library_path {
+                search_paths.extend(ld_path.split(PATH_SEP));
+            }
+            search_paths.push("/lib");
+            for part in search_paths.iter() {
+                full_path = format!("{}/{}", part, name);
+                trace!("trying path {}", full_path);
+                if accessible(&full_path, F_OK) == 0 {
+                    return Ok(full_path);
                 }
-            };
-            if self.verbose {
-                println!("  mmap {:p}, {:#x}", mmap.1.as_mut_ptr(), mmap.1.len());
             }
-            let (globals, weak_syms) = Linker::collect_syms(&elf, &mmap.1, self.verbose)?;
-            lib.globals.extend(globals.into_iter());
-            lib.weak_syms.extend(weak_syms.into_iter());
-            lib.mmaps.insert(elf_name.to_string(), mmap);
         }
+        return Err(Error::Malformed(format!("failed to locate '{}'", name)));
+    }
 
-        // Allocate TLS
-        let mut tcb_opt = if primary_opt.is_some() {
-            Some(unsafe { Tcb::new(tls_size)? })
-        } else {
-            None
-        };
-        if self.verbose {
-            println!("tcb {:x?}", tcb_opt);
-        }
-        // Copy data
-        let mut tls_offset = tls_primary;
-        let mut tcb_masters = Vec::new();
-        // Insert main image master
-        tcb_masters.push(Master {
-            ptr: ptr::null_mut(),
-            len: 0,
-            offset: 0,
-        });
-        let mut tls_ranges = BTreeMap::new();
-        for (elf_name, elf) in elfs.iter() {
-            if skip_list.contains(elf_name) {
-                continue;
-            }
-            let same_elf = if let Some(prog) = dso.as_ref() {
-                if prog.name == *elf_name {
-                    true
-                } else {
-                    false
-                }
-            } else {
-                false
-            };
-            let object = match lib.objects.get(*elf_name) {
-                Some(some) => some,
-                None => continue,
-            };
+    fn read_file(path: &str) -> Result<Vec<u8>> {
+        let mut data = Vec::new();
+        let path_c = CString::new(path)
+            .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
+        let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
+        let mut file = File::open(&path_c, flags)
+            .map_err(|err| Error::Malformed(format!("failed to open '{}': {}", path, err)))?;
+        file.read_to_end(&mut data)
+            .map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
 
-            let &mut (base_addr, ref mut mmap) = match lib.mmaps.get_mut(*elf_name) {
-                Some(some) => some,
-                None => continue,
-            };
-            if self.verbose {
-                println!("load {}", elf_name);
-            }
-            // Copy data
-            for ph in elf.program_headers.iter() {
-                let voff = ph.p_vaddr as usize % PAGE_SIZE;
-                let vaddr = ph.p_vaddr as usize - voff;
-                let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
+        return Ok(data);
+    }
 
-                match ph.p_type {
-                    program_header::PT_LOAD => {
-                        if same_elf {
-                            continue;
-                        }
-                        let obj_data = {
-                            let range = ph.file_range();
-                            match object.get(range.clone()) {
-                                Some(some) => some,
-                                None => {
-                                    return Err(Error::Malformed(format!(
-                                        "failed to read {:x?}",
-                                        range
-                                    )))
-                                }
-                            }
-                        };
+    fn relocate(&self, new_objects: &Vec<DSO>, objects_data: &Vec<Vec<u8>>) -> Result<()> {
+        let symbols_lookup_objects: Vec<&DSO> =
+            self.objects.values().chain(new_objects.iter()).collect();
 
-                        let mmap_data = {
-                            let range = ph.p_vaddr as usize - base_addr
-                                ..ph.p_vaddr as usize + obj_data.len() - base_addr;
-                            match mmap.get_mut(range.clone()) {
-                                Some(some) => some,
-                                None => {
-                                    println!("mmap: {}", mmap.len());
-                                    return Err(Error::Malformed(format!(
-                                        "failed to write {:x?}",
-                                        range
-                                    )));
-                                }
-                            }
-                        };
-                        if self.verbose {
-                            println!(
-                                "  copy {:#x}, {:#x}: {:#x}, {:#x}",
-                                vaddr,
-                                vsize,
-                                voff,
-                                obj_data.len()
-                            );
-                        }
-                        mmap_data.copy_from_slice(obj_data);
-                    }
-                    program_header::PT_TLS => {
-                        let valign = if ph.p_align > 0 {
-                            ((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align
-                        } else {
-                            ph.p_memsz
-                        } as usize;
-                        let ptr = unsafe {
-                            if is_pie_enabled(elf) {
-                                mmap.as_ptr().add(ph.p_vaddr as usize)
-                            } else {
-                                ph.p_vaddr as *const u8
-                            }
-                        };
-                        let mut tcb_master = Master {
-                            ptr: ptr,
-                            len: ph.p_filesz as usize,
-                            offset: tls_size - valign,
-                        };
-                        if self.verbose {
-                            println!(
-                                "  tls master {:p}, {:#x}: {:#x}, {:#x}",
-                                tcb_master.ptr, tcb_master.len, tcb_master.offset, valign,
-                            );
-                        }
-                        if Some(*elf_name) == primary_opt {
-                            tls_ranges.insert(
-                                elf_name.to_string(),
-                                (self.tls_index_offset, tcb_master.range()),
-                            );
-                            tcb_masters[0] = tcb_master;
-                        } else {
-                            tcb_master.offset -= tls_offset;
-                            tls_offset += vsize;
-                            tls_ranges.insert(
-                                elf_name.to_string(),
-                                (
-                                    self.tls_index_offset + tcb_masters.len(),
-                                    tcb_master.range(),
-                                ),
-                            );
-                            tcb_masters.push(tcb_master);
-                        }
-                    }
-                    _ => (),
-                }
-            }
-        }
+        // Perform relocations
+        for i in (0..new_objects.len()).rev() {
+            let elf = Elf::parse(&objects_data[i])?;
+            let obj = &new_objects[i];
 
-        self.tls_index_offset += tcb_masters.len();
+            trace!("link {}", obj.name);
 
-        // Set master images for TLS and copy TLS data
-        if let Some(ref mut tcb) = tcb_opt {
-            unsafe {
-                tcb.set_masters(tcb_masters.into_boxed_slice());
-                tcb.copy_masters()?;
-            }
-        }
+            let mmap = &obj.mmap;
+            let b = mmap.as_ptr() as usize;
 
-        // Perform relocations, and protect pages
-        for (elf_name, elf) in elfs.iter() {
-            if skip_list.contains(elf_name) {
-                continue;
-            }
-            if self.verbose {
-                println!("link {}", elf_name);
-            }
             // Relocate
             for rel in elf
                 .dynrelas
@@ -746,16 +284,18 @@ impl Linker {
                 .chain(elf.dynrels.iter())
                 .chain(elf.pltrelocs.iter())
             {
-                // println!("  rel {}: {:x?}",
-                //     reloc::r_to_str(rel.r_type, elf.header.e_machine),
-                //     rel
-                // );
-                let symbol = if rel.r_sym > 0 {
+                trace!(
+                    "  rel {}: {:x?}",
+                    reloc::r_to_str(rel.r_type, elf.header.e_machine),
+                    rel
+                );
+                let (symbol, t) = if rel.r_sym > 0 {
                     let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(format!(
                         "missing symbol for relocation {:?}",
                         rel
                     )))?;
 
+                    let mut t = 0;
                     let name =
                         elf.dynstrtab
                             .get(sym.st_name)
@@ -763,9 +303,32 @@ impl Linker {
                                 "missing name for symbol {:?}",
                                 sym
                             )))??;
-                    lib.get_sym(name).or_else(|| self.root.get_sym(name))
+                    let mut symbol = None;
+                    let mut found = false;
+                    let lookup_start = match rel.r_type {
+                        reloc::R_X86_64_COPY => 1,
+                        _ => 0,
+                    };
+                    for lookup_id in lookup_start..symbols_lookup_objects.len() {
+                        let obj = &symbols_lookup_objects[lookup_id];
+                        let s = obj.get_sym(name);
+                        if s.is_some() {
+                            trace!("symbol {} from {} found in {}", name, obj.name, obj.name);
+                            symbol = s;
+                            t = obj.tls_offset;
+                            found = true;
+                            break;
+                        }
+                    }
+                    // TODO: below doesn't work because of missing __preinit_array_{start,end} and __init_array_{start,end} symbols in dynamic linked programs
+                    /*
+                    if !found {
+                        return Err(Error::Malformed(format!("missing symbol for name {}", name)));
+                    }
+                    */
+                    (symbol, t)
                 } else {
-                    None
+                    (None, 0)
                 };
 
                 let s = symbol
@@ -775,26 +338,13 @@ impl Linker {
 
                 let a = rel.r_addend.unwrap_or(0) as usize;
 
-                let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
-                    Some(some) => some,
-                    None => continue,
-                };
-
-                let b = mmap.as_mut_ptr() as usize;
-
-                let (tm, t) = if let Some((tls_index, tls_range)) = tls_ranges.get(*elf_name) {
-                    (*tls_index, tls_range.start)
-                } else {
-                    (0, 0)
-                };
-
                 let ptr = if is_pie_enabled(&elf) {
-                    unsafe { mmap.as_mut_ptr().add(rel.r_offset as usize) }
+                    (b + rel.r_offset as usize) as *mut u8
                 } else {
                     rel.r_offset as *mut u8
                 };
                 let set_u64 = |value| {
-                    // println!("    set_u64 {:#x}", value);
+                    trace!("    set_u64 {:#x}", value);
                     unsafe {
                         *(ptr as *mut u64) = value;
                     }
@@ -805,7 +355,7 @@ impl Linker {
                         set_u64((s + a) as u64);
                     }
                     reloc::R_X86_64_DTPMOD64 => {
-                        set_u64(tm as u64);
+                        set_u64(obj.tls_module_id as u64);
                     }
                     reloc::R_X86_64_DTPOFF64 => {
                         if s != 0 {
@@ -821,11 +371,16 @@ impl Linker {
                         set_u64((b + a) as u64);
                     }
                     reloc::R_X86_64_TPOFF64 => {
-                        set_u64((s + a).wrapping_sub(t) as u64);
+                        let sym = symbol
+                            .as_ref()
+                            .expect("R_X86_64_TPOFF64 called without valid symbol");
+                        set_u64((sym.value + a).wrapping_sub(t) as u64);
                     }
-                    reloc::R_X86_64_IRELATIVE => (), // Handled below
+                    reloc::R_X86_64_IRELATIVE => unsafe {
+                        let f: unsafe extern "C" fn() -> u64 = transmute(b + a);
+                        set_u64(f());
+                    },
                     reloc::R_X86_64_COPY => unsafe {
-                        // TODO: Make this work
                         let sym = symbol
                             .as_ref()
                             .expect("R_X86_64_COPY called without valid symbol");
@@ -840,202 +395,49 @@ impl Linker {
                 }
             }
 
-            // overwrite DT_DEBUG if exist in DYNAMIC segment
-            // first we identify the location of DYNAMIC segment
-            let mut dyn_start = None;
-            let mut debug_start = None;
-            for ph in elf.program_headers.iter() {
-                if ph.p_type == program_header::PT_DYNAMIC {
-                    dyn_start = Some(ph.p_vaddr as usize);
-                }
-            }
-            // next we identify the location of DT_DEBUG in .dynamic section
-            if let Some(dynamic) = elf.dynamic.as_ref() {
-                let mut i = 0;
-                for entry in &dynamic.dyns {
-                    if entry.d_tag == DT_DEBUG {
-                        debug_start = Some(i as usize);
-                        break;
-                    }
-                    i += 1;
-                }
-            }
-            if let Some(dyn_start_addr) = dyn_start {
-                if let Some(i) = debug_start {
-                    let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
-                        Some(some) => some,
-                        None => continue,
-                    };
-                    let bytes: [u8; size_of::<Dyn>() / 2] =
-                        unsafe { transmute((&_r_debug) as *const RTLDDebug as usize) };
-                    let start = if is_pie_enabled(elf) {
-                        dyn_start_addr + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
-                    } else {
-                        dyn_start_addr + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
-                            - mmap.as_mut_ptr() as usize
-                    };
-                    mmap[start..start + size_of::<Dyn>() / 2].clone_from_slice(&bytes);
-                }
-            }
-
             // Protect pages
-            for ph in elf.program_headers.iter() {
-                if ph.p_type == program_header::PT_LOAD {
-                    let voff = ph.p_vaddr as usize % PAGE_SIZE;
-                    let vaddr = ph.p_vaddr as usize - voff;
-                    let vsize =
-                        ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
-
-                    let mut prot = 0;
-
-                    if ph.p_flags & program_header::PF_R == program_header::PF_R {
-                        prot |= sys_mman::PROT_READ;
-                    }
-
-                    // W ^ X. If it is executable, do not allow it to be writable, even if requested
-                    if ph.p_flags & program_header::PF_X == program_header::PF_X {
-                        prot |= sys_mman::PROT_EXEC;
-                    } else if ph.p_flags & program_header::PF_W == program_header::PF_W {
-                        prot |= sys_mman::PROT_WRITE;
-                    }
-
-                    let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
-                        Some(some) => some,
-                        None => continue,
-                    };
-                    let res = unsafe {
-                        let ptr = if is_pie_enabled(elf) {
-                            mmap.as_mut_ptr().add(vaddr)
-                        } else {
-                            vaddr as *const u8
-                        };
-                        if self.verbose {
-                            println!("  prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
-                        }
-                        sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
-                    };
-
-                    if res < 0 {
-                        return Err(Error::Malformed(format!("failed to mprotect {}", elf_name)));
-                    }
-                }
-            }
-        }
-
-        // Activate TLS
-        if let Some(ref mut tcb) = tcb_opt {
-            unsafe {
-                tcb.activate();
-            }
-        }
-
-        // Perform indirect relocations (necessary evil), gather entry point
-        let mut entry_opt = None;
-        for (elf_name, elf) in elfs.iter() {
-            if skip_list.contains(elf_name) {
-                continue;
-            }
-            let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
-                Some(some) => some,
-                None => continue,
-            };
-            if self.verbose {
-                println!("entry {}", elf_name);
-            }
-            if Some(*elf_name) == primary_opt {
-                if is_pie_enabled(&elf) {
-                    entry_opt = Some(mmap.as_mut_ptr() as usize + elf.header.e_entry as usize);
-                } else {
-                    entry_opt = Some(elf.header.e_entry as usize);
-                }
-            }
-
-            // Relocate
-            for rel in elf
-                .dynrelas
+            for ph in elf
+                .program_headers
                 .iter()
-                .chain(elf.dynrels.iter())
-                .chain(elf.pltrelocs.iter())
+                .filter(|ph| ph.p_type == program_header::PT_LOAD)
             {
-                // println!("  rel {}: {:x?}",
-                //     reloc::r_to_str(rel.r_type, elf.header.e_machine),
-                //     rel
-                // );
-
-                let a = rel.r_addend.unwrap_or(0) as usize;
-
-                let b = mmap.as_mut_ptr() as usize;
-
-                let ptr = unsafe { mmap.as_mut_ptr().add(rel.r_offset as usize) };
-
-                let set_u64 = |value| {
-                    // println!("    set_u64 {:#x}", value);
-                    unsafe {
-                        *(ptr as *mut u64) = value;
-                    }
-                };
-
-                if rel.r_type == reloc::R_X86_64_IRELATIVE {
-                    unsafe {
-                        let f: unsafe extern "C" fn() -> u64 = transmute(b + a);
-                        set_u64(f());
-                    }
+                let voff = ph.p_vaddr % ph.p_align;
+                let vaddr = (ph.p_vaddr - voff) as usize;
+                let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
+                let mut prot = 0;
+                if ph.p_flags & program_header::PF_R == program_header::PF_R {
+                    prot |= sys_mman::PROT_READ;
                 }
-            }
-            // Protect pages
-            for ph in elf.program_headers.iter() {
-                if let program_header::PT_LOAD = ph.p_type {
-                    let voff = ph.p_vaddr as usize % PAGE_SIZE;
-                    let vaddr = ph.p_vaddr as usize - voff;
-                    let vsize =
-                        ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
-
-                    let mut prot = 0;
-
-                    if ph.p_flags & program_header::PF_R == program_header::PF_R {
-                        prot |= sys_mman::PROT_READ;
-                    }
 
-                    // W ^ X. If it is executable, do not allow it to be writable, even if requested
-                    if ph.p_flags & program_header::PF_X == program_header::PF_X {
-                        prot |= sys_mman::PROT_EXEC;
-                    } else if ph.p_flags & program_header::PF_W == program_header::PF_W {
-                        prot |= sys_mman::PROT_WRITE;
-                    }
+                // W ^ X. If it is executable, do not allow it to be writable, even if requested
+                if ph.p_flags & program_header::PF_X == program_header::PF_X {
+                    prot |= sys_mman::PROT_EXEC;
+                } else if ph.p_flags & program_header::PF_W == program_header::PF_W {
+                    prot |= sys_mman::PROT_WRITE;
+                }
 
-                    let res = unsafe {
-                        let ptr = if is_pie_enabled(&elf) {
-                            mmap.as_mut_ptr().add(vaddr)
-                        } else {
-                            vaddr as *const u8
-                        };
-                        if self.verbose {
-                            println!("  prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
-                        }
-                        sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
+                let res = unsafe {
+                    let ptr = if is_pie_enabled(&elf) {
+                        mmap.as_ptr().add(vaddr)
+                    } else {
+                        vaddr as *const u8
                     };
+                    trace!("  prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
+                    sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
+                };
 
-                    if res < 0 {
-                        return Err(Error::Malformed(format!("failed to mprotect {}", elf_name)));
-                    }
+                if res < 0 {
+                    return Err(Error::Malformed(format!("failed to mprotect {}", obj.name)));
                 }
             }
         }
-        unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
-        _dl_debug_state();
-        Ok(entry_opt)
-    }
-}
 
-unsafe fn call_inits_finis(addr: usize) {
-    let func = transmute::<usize, *const Option<extern "C" fn()>>(addr);
-    (*func).map(|x| x());
-}
+        return Ok(());
+    }
 
-fn is_pie_enabled(elf: &Elf) -> bool {
-    if elf.header.e_type == ET_DYN {
-        true
-    } else {
-        false
+    fn run_init(&self, objects: &Vec<DSO>) {
+        for obj in objects.iter().rev() {
+            obj.run_init();
+        }
     }
 }
diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs
index 19dfe05f521964d1cb6d4d229a976ee1ba698340..7a1324387612d0a9a8aceca53f82dc7be86dba3b 100644
--- a/src/ld_so/mod.rs
+++ b/src/ld_so/mod.rs
@@ -6,10 +6,16 @@ use crate::{header::sys_auxv::AT_NULL, start::Stack};
 
 pub const PAGE_SIZE: usize = 4096;
 
+#[cfg(target_os = "redox")]
+pub const PATH_SEP: char = ';';
+
+#[cfg(target_os = "linux")]
+pub const PATH_SEP: char = ':';
+
 mod access;
 pub mod callbacks;
 pub mod debug;
-mod library;
+mod dso;
 pub mod linker;
 pub mod start;
 pub mod tcb;
@@ -73,7 +79,7 @@ pub fn static_init(sp: &'static Stack) {
                 unsafe {
                     STATIC_TCB_MASTER.ptr = ph.p_vaddr as usize as *const u8;
                     STATIC_TCB_MASTER.len = ph.p_filesz as usize;
-                    STATIC_TCB_MASTER.offset = vsize - valign;
+                    STATIC_TCB_MASTER.offset = valign;
 
                     let tcb = Tcb::new(vsize).expect("failed to allocate TCB");
                     tcb.masters_ptr = &mut STATIC_TCB_MASTER;
diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs
index 6a9439d001d6aabc03bd6f6ae9a8879294f80c8d..25a1f16d0af132ff08a952a0b091c0f98369284d 100644
--- a/src/ld_so/start.rs
+++ b/src/ld_so/start.rs
@@ -17,13 +17,9 @@ use crate::{
     ALLOCATOR,
 };
 
-use super::{
-    access::accessible,
-    debug::_r_debug,
-    linker::{Linker, DSO, PATH_SEP},
-    tcb::Tcb,
-};
+use super::{access::accessible, debug::_r_debug, linker::Linker, tcb::Tcb, PATH_SEP};
 use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR};
+use goblin::elf::header::header64::SIZEOF_EHDR;
 
 unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
     //traverse the stack and collect argument vector
@@ -214,53 +210,25 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
     // if we are not running in manual mode, then the main
     // program is already loaded by the kernel and we want
     // to use it. on redox, we treat it the same.
-    let program = {
-        let mut pr = None;
+    let base_addr = {
+        let mut base = None;
         if !is_manual && cfg!(not(target_os = "redox")) {
             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);
+                base = Some(phdr - SIZEOF_EHDR);
             }
         }
-        pr
+        base
     };
-    let mut linker = Linker::new(ld_library_path, false);
-    match linker.load(&path, &path) {
-        Ok(()) => (),
-        Err(err) => {
-            eprintln!("ld.so: failed to load '{}': {}", path, err);
-            unistd::_exit(1);
-            loop {}
-        }
-    }
-
-    let entry = match linker.link(Some(&path), program, None) {
-        Ok(ok) => match ok {
-            Some(some) => some,
-            None => {
-                eprintln!("ld.so: failed to link '{}': missing entry", path);
-                unistd::_exit(1);
-                loop {}
-            }
-        },
+    let mut linker = Linker::new(ld_library_path);
+    let entry = match linker.load_program(&path, base_addr) {
+        Ok(entry) => entry,
         Err(err) => {
             eprintln!("ld.so: failed to link '{}': {}", path, err);
             unistd::_exit(1);
             loop {}
         }
     };
-    if let Err(e) = linker.run_init(None) {
-        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)));
         tcb.mspace = ALLOCATOR.get_book_keeper();
diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs
index 848901a6ed106fd50f218679a67a54a58b50f70b..0ff9e557d358aef22bdc89d01c3ca3129cad930e 100644
--- a/src/ld_so/tcb.rs
+++ b/src/ld_so/tcb.rs
@@ -1,5 +1,5 @@
-use alloc::boxed::Box;
-use core::{mem, ops::Range, ptr, slice};
+use alloc::vec::Vec;
+use core::{mem, ptr, slice};
 use goblin::error::{Error, Result};
 
 use crate::{header::sys_mman, ld_so::linker::Linker, sync::mutex::Mutex};
@@ -7,6 +7,7 @@ use crate::{header::sys_mman, ld_so::linker::Linker, sync::mutex::Mutex};
 use super::PAGE_SIZE;
 
 #[repr(C)]
+#[derive(Debug)]
 pub struct Master {
     /// Pointer to initial data
     pub ptr: *const u8,
@@ -21,11 +22,6 @@ impl Master {
     pub unsafe fn data(&self) -> &'static [u8] {
         slice::from_raw_parts(self.ptr, self.len)
     }
-
-    /// The region of TLS that the master will initialize
-    pub fn range(&self) -> Range<usize> {
-        self.offset..self.offset + self.len
-    }
 }
 
 #[derive(Debug)]
@@ -43,6 +39,8 @@ pub struct Tcb {
     pub masters_ptr: *mut Master,
     /// Size of the masters list in bytes (multiple of mem::size_of::<Master>())
     pub masters_len: usize,
+    /// Index of last copied Master
+    pub last_master_copied: usize,
     /// Pointer to dynamic linker
     pub linker_ptr: *const Mutex<Linker>,
     /// pointer to rust memory allocator structure
@@ -52,10 +50,10 @@ pub struct Tcb {
 impl Tcb {
     /// Create a new TCB
     pub unsafe fn new(size: usize) -> Result<&'static mut Self> {
-        let (tls, tcb_page) = Self::os_new(size)?;
+        let (tls, tcb_page) = Self::os_new(round_up(size, PAGE_SIZE))?;
 
         let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self;
-        // println!("New TCB: {:p}", tcb_ptr);
+        trace!("New TCB: {:p}", tcb_ptr);
         ptr::write(
             tcb_ptr,
             Self {
@@ -65,6 +63,7 @@ impl Tcb {
                 tcb_len: tcb_page.len(),
                 masters_ptr: ptr::null_mut(),
                 masters_len: 0,
+                last_master_copied: 0,
                 linker_ptr: ptr::null(),
                 mspace: 0,
             },
@@ -109,26 +108,34 @@ impl Tcb {
     }
 
     /// Copy data from masters
-    pub unsafe fn copy_masters(&self) -> Result<()> {
+    pub unsafe fn copy_masters(&mut self) -> Result<()> {
         //TODO: Complain if masters or tls exist without the other
         if let Some(tls) = self.tls() {
             if let Some(masters) = self.masters() {
-                for (i, master) in masters.iter().enumerate() {
-                    let range = master.range();
-                    let data = master.data();
+                for (i, master) in masters
+                    .iter()
+                    .skip(self.last_master_copied)
+                    .filter(|m| m.len > 0)
+                    .enumerate()
+                {
+                    let range =
+                        self.tls_len - master.offset..self.tls_len - master.offset + master.len;
                     if let Some(tls_data) = tls.get_mut(range) {
-                        // println!(
-                        //     "tls master {}: {:p}, {:#x}: {:p}, {:#x}",
-                        //     i,
-                        //     data.as_ptr(), data.len(),
-                        //     tls_data.as_mut_ptr(), tls_data.len()
-                        // );
-
+                        let data = master.data();
+                        trace!(
+                            "tls master {}: {:p}, {:#x}: {:p}, {:#x}",
+                            i,
+                            data.as_ptr(),
+                            data.len(),
+                            tls_data.as_mut_ptr(),
+                            tls_data.len()
+                        );
                         tls_data.copy_from_slice(data);
                     } else {
                         return Err(Error::Malformed(format!("failed to copy tls master {}", i)));
                     }
                 }
+                self.last_master_copied = masters.len();
             }
         }
 
@@ -136,10 +143,19 @@ impl Tcb {
     }
 
     /// The initial images for TLS
-    pub unsafe fn set_masters(&mut self, mut masters: Box<[Master]>) {
-        self.masters_ptr = masters.as_mut_ptr();
-        self.masters_len = masters.len() * mem::size_of::<Master>();
-        mem::forget(masters);
+    pub unsafe fn append_masters(&mut self, mut new_masters: Vec<Master>) {
+        if self.masters_ptr.is_null() {
+            self.masters_ptr = new_masters.as_mut_ptr();
+            self.masters_len = new_masters.len() * mem::size_of::<Master>();
+            mem::forget(new_masters);
+        } else {
+            let len = self.masters_len / mem::size_of::<Master>();
+            let mut masters = Vec::from_raw_parts(self.masters_ptr, len, len);
+            masters.extend(new_masters.into_iter());
+            self.masters_ptr = masters.as_mut_ptr();
+            self.masters_len = masters.len() * mem::size_of::<Master>();
+            mem::forget(masters);
+        }
     }
 
     /// Activate TLS
@@ -217,3 +233,7 @@ impl Tcb {
         //TODO: Consider setting FS offset to TCB pointer
     }
 }
+
+pub fn round_up(value: usize, alignment: usize) -> usize {
+    return (value + alignment - 1) & (!(alignment - 1));
+}
diff --git a/src/macros.rs b/src/macros.rs
index 132d784186e16994125fed666518ae6d0e682a81..6f9db24f7b8187a3be1a0d7672e807bcbdb0c0c5 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -78,7 +78,6 @@ macro_rules! trace {
     ($($arg:tt)*) => ({
         use $crate::{Pal, Sys};
         eprintln!($($arg)*);
-        Sys::fsync(2);
     });
 }
 
diff --git a/src/sync/semaphore.rs b/src/sync/semaphore.rs
index 7734c58a171bb0c8c8afecb94e30f792f8b189b3..aba5aff6689962f768c911ab395f8edfbd0b3390 100644
--- a/src/sync/semaphore.rs
+++ b/src/sync/semaphore.rs
@@ -1,8 +1,8 @@
 // From https://www.remlab.net/op/futex-misc.shtml
 //TODO: improve implementation
 
-use crate::platform::{types::*, Pal, Sys};
 use super::AtomicLock;
+use crate::platform::{types::*, Pal, Sys};
 use core::sync::atomic::Ordering;
 
 pub struct Semaphore {
@@ -29,7 +29,7 @@ impl Semaphore {
                 value,
                 value - 1,
                 Ordering::Acquire,
-                Ordering::Relaxed
+                Ordering::Relaxed,
             ) {
                 Ok(ok) => return,
                 Err(err) => {
diff --git a/tests/Makefile b/tests/Makefile
index 815911acb095116eab7a75674c15248f866ec7ac..240d88188fa2743073f64d2b1de56d34f7e8f758 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -12,6 +12,7 @@ EXPECT_NAMES=\
 	fcntl/create \
 	fcntl/fcntl \
 	fnmatch \
+	futimens \
 	libgen \
 	locale \
 	math \
@@ -22,18 +23,25 @@ EXPECT_NAMES=\
 	setjmp \
 	sigaction \
 	signal \
+	stdio/all \
+	stdio/buffer \
+	stdio/fgets \
 	stdio/fputs \
 	stdio/fread \
+	stdio/freopen \
 	stdio/fseek \
 	stdio/fwrite \
+	stdio/getc_unget \
 	stdio/mutex \
 	stdio/popen \
 	stdio/printf \
 	stdio/rename \
 	stdio/scanf \
+	stdio/setvbuf \
 	stdio/sprintf \
 	stdio/printf_space_pad \
 	stdio/ungetc_ftell \
+	stdio/ungetc_multiple \
 	stdio/fscanf_offby1 \
 	stdio/fscanf \
 	stdio/printf_neg_pad \
@@ -69,6 +77,7 @@ EXPECT_NAMES=\
 	sys_mman \
 	time/asctime \
 	time/gmtime \
+	time/localtime \
 	time/macros \
 	time/mktime \
 	time/strftime \
@@ -82,6 +91,8 @@ EXPECT_NAMES=\
 	unistd/fork \
 	unistd/fsync \
 	unistd/ftruncate \
+	unistd/getopt \
+	unistd/getopt_long \
 	unistd/pipe \
 	unistd/rmdir \
 	unistd/sleep \
@@ -98,34 +109,20 @@ EXPECT_NAMES=\
 	wchar/wcsrchr \
 	wchar/wcsstr \
 	wchar/wcstod \
+	wchar/wcstok \
 	wchar/wcstol \
 	wchar/wcscasecmp \
 	wchar/wcsncasecmp \
+	wctype/towlower \
+	wctype/towupper
 	# TODO: Fix these
 	# mkfifo
 	# netdb/netdb \
 
-# issues with linking stdin, stdout, stderr
-STATIC_ONLY_NAMES=\
-	futimens \
-	stdio/all \
-	stdio/buffer \
-	stdio/fgets \
-	stdio/freopen \
-	stdio/getc_unget \
-	stdio/setvbuf \
-	stdio/ungetc_multiple \
-	time/localtime \
-	wchar/wcstok \
-	wctype/towlower \
-	wctype/towupper \
 # need to call fini in ld_so's _start
-STATIC_ONLY_NAMES+=\
-	destructor \
-# issues with linking optarg, optind etc.
-STATIC_ONLY_NAMES+=\
-	unistd/getopt \
-	unistd/getopt_long \
+STATIC_ONLY_NAMES=\
+	destructor
+
 
 DYNAMIC_ONLY_NAMES=\
 	dlfcn
@@ -205,9 +202,15 @@ FLAGS=\
 	-I .
 
 STATIC_FLAGS=\
-	../sysroot/lib/libc.a \
 	-static
 
+DYNAMIC_FLAGS=\
+	-Wl,--enable-new-dtags \
+	-Wl,-export-dynamic
+
+../sysroot:
+	$(MAKE) -C .. sysroot
+
 NATIVE_RELIBC?=0
 ifeq ($(NATIVE_RELIBC),0)
 FLAGS+=\
@@ -218,32 +221,24 @@ FLAGS+=\
 	../sysroot/lib/crti.o \
 	../sysroot/lib/crtn.o
 
-../sysroot:
-	$(MAKE) -C .. sysroot
-
-bins_static/%: %.c ../sysroot
-	mkdir -p "$$(dirname "$@")"
-	$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
-
 SYSROOT_LIB=$(shell realpath ../sysroot/lib/)
 
-DYNAMIC_FLAGS=\
+STATIC_FLAGS+=\
+	$(SYSROOT_LIB)/libc.a
+
+DYNAMIC_FLAGS+=\
 	-Wl,-dynamic-linker=$(SYSROOT_LIB)/ld64.so.1 \
-	-Wl,--enable-new-dtags \
-	-Wl,-rpath=$(SYSROOT_LIB) \
-	-Wl,-export-dynamic \
+	-Wl,-rpath=$(SYSROOT_LIB):\$$ORIGIN \
 	-L $(SYSROOT_LIB) \
 	-lc
 
-bins_dynamic/%: %.c ../sysroot
-	mkdir -p "$$(dirname "$@")"
-	$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)
-else
-bins_static/%: %.c
+DEPS=../sysroot
+endif
+
+bins_static/%: %.c $(DEPS)
 	mkdir -p "$$(dirname "$@")"
 	$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
 
-bins_dynamic/%: %.c
+bins_dynamic/%: %.c $(DEPS)
 	mkdir -p "$$(dirname "$@")"
-	$(CC) "$<" -o "$@" $(FLAGS)
-endif
+	$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)
diff --git a/tests/futimens.c b/tests/futimens.c
index 78e7f4c96b123555cbc21ebf2c50eafb489b4ea3..820e936a4ae99f5b4e2e1329f11d53cbbf3377a8 100644
--- a/tests/futimens.c
+++ b/tests/futimens.c
@@ -12,7 +12,7 @@ int main(int argc, char** argv) {
   char temp[] = "/tmp/stattest-XXXXXX";
   const char file[] = "/mkfifo_fifo";
   int len = sizeof(temp) + sizeof(int);
-  char* path = malloc(len * sizeof(char));
+  char* path = calloc(len, sizeof(char));
 
   if (path == NULL) {
     fprintf(stderr, "Could not allocate: %s\n", strerror(errno));