diff --git a/src/header/dlfcn/mod.rs b/src/header/dlfcn/mod.rs
index 8b4025f319e749818651241dcb361288d93fe51a..01fbe570c70097fe0040c7411c22c1efe13c7049 100644
--- a/src/header/dlfcn/mod.rs
+++ b/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,51 +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, None) {
-                //TODO
-                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]
@@ -91,38 +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, None) {
-            //TODO
-            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
 }
 
diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs
index 201e1434496e9d8ee83b322caed464e75ea17c24..20404788607025718c7d43829dd4ba5ba20240ab 100644
--- a/src/ld_so/linker.rs
+++ b/src/ld_so/linker.rs
@@ -85,7 +85,7 @@ impl Linker {
     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()) };
+                unsafe{sys_mman::munmap(mmap.as_mut_ptr() as *mut c_void, mmap.len())};
             }
         }
     }
@@ -250,7 +250,7 @@ impl Linker {
     pub fn run_fini(&self, libspace: Option<usize>) -> Result<()> {
         match libspace {
             Some(id) => {
-                let lib = self.lib_spaces.get(&id).unwrap().unwrap();
+                let lib = self.lib_spaces.get(&id).unwrap();
                 self.run_tree(&lib, &lib.dep_tree, ".fini_array")
             }
             None => {