diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs
index 86f65225e6d51f6a68fc0008743979998bd666be..2e61c045b643953896c636f6f68bf375d41dac99 100644
--- a/src/ld_so/linker.rs
+++ b/src/ld_so/linker.rs
@@ -6,7 +6,6 @@ use alloc::{
 };
 use core::{
     mem,
-    ops::Range,
     ptr,
     slice
 };
@@ -36,12 +35,16 @@ const PATH_SEP: char = ':';
 
 pub struct Linker {
     // Used by load
+    /// Library path to search when loading library by name
     library_path: String,
+    /// Loaded library raw data
     objects: BTreeMap<String, Box<[u8]>>,
+
     // Used by link
-    mmaps: BTreeMap<String, &'static mut [u8]>,
+    /// Global symbols
     globals: BTreeMap<String, usize>,
-    tls_ranges: BTreeMap<String, (usize, Range<usize>)>,
+    /// Loaded library in-memory data
+    mmaps: BTreeMap<String, &'static mut [u8]>,
 }
 
 impl Linker {
@@ -49,9 +52,8 @@ impl Linker {
         Self {
             library_path: library_path.to_string(),
             objects: BTreeMap::new(),
-            mmaps: BTreeMap::new(),
             globals: BTreeMap::new(),
-            tls_ranges: BTreeMap::new(),
+            mmaps: BTreeMap::new(),
         }
     }
 
@@ -82,9 +84,7 @@ impl Linker {
             //println!("{:#?}", elf);
 
             for library in elf.libraries.iter() {
-                if !self.objects.contains_key(&library.to_string()) {
-                    self.load_library(library)?;
-                }
+                self.load_library(library)?;
             }
         }
 
@@ -94,7 +94,9 @@ impl Linker {
     }
 
     pub fn load_library(&mut self, name: &str) -> Result<()> {
-        if name.contains('/') {
+        if self.objects.contains_key(name) {
+            Ok(())
+        } else if name.contains('/') {
             self.load(name, name)
         } else {
             let library_path = self.library_path.clone();
@@ -126,11 +128,14 @@ impl Linker {
         }
     }
 
-    pub fn link(&mut self, primary: &str) -> Result<usize> {
+    pub fn link(&mut self, primary_opt: Option<&str>) -> Result<Option<usize>> {
         let elfs = {
             let mut elfs = BTreeMap::new();
             for (name, data) in self.objects.iter() {
-                elfs.insert(name.as_str(), Elf::parse(&data)?);
+                // Skip already linked libraries
+                if ! self.mmaps.contains_key(&*name) {
+                    elfs.insert(name.as_str(), Elf::parse(&data)?);
+                }
             }
             elfs
         };
@@ -173,7 +178,7 @@ impl Linker {
                         program_header::PT_TLS => {
                             println!("  load tls {:#x}: {:x?}", vsize, ph);
                             tls_size += vsize;
-                            if *elf_name == primary {
+                            if Some(*elf_name) == primary_opt {
                                 tls_primary += vsize;
                             }
                         }
@@ -237,6 +242,7 @@ impl Linker {
             len: 0,
             offset: 0,
         });
+        let mut tls_ranges = BTreeMap::new();
         for (elf_name, elf) in elfs.iter() {
             let object = match self.objects.get(*elf_name) {
                 Some(some) => some,
@@ -312,13 +318,13 @@ impl Linker {
                             tcb_master.ptr, tcb_master.len, tcb_master.offset, valign,
                         );
 
-                        if *elf_name == primary {
-                            self.tls_ranges.insert(elf_name.to_string(), (0, tcb_master.range()));
+                        if Some(*elf_name) == primary_opt {
+                            tls_ranges.insert(elf_name.to_string(), (0, tcb_master.range()));
                             tcb_masters[0] = tcb_master;
                         } else {
                             tcb_master.offset -= tls_offset;
                             tls_offset += vsize;
-                            self.tls_ranges.insert(elf_name.to_string(), (tcb_masters.len(), tcb_master.range()));
+                            tls_ranges.insert(elf_name.to_string(), (tcb_masters.len(), tcb_master.range()));
                             tcb_masters.push(tcb_master);
                         }
                     }
@@ -383,7 +389,7 @@ impl Linker {
                     0
                 };
 
-                let (tm, t) = if let Some((tls_index, tls_range)) = self.tls_ranges.get(*elf_name) {
+                let (tm, t) = if let Some((tls_index, tls_range)) = tls_ranges.get(*elf_name) {
                     (*tls_index, tls_range.start)
                 } else {
                     (0, 0)
@@ -477,7 +483,7 @@ impl Linker {
 
             println!("entry {}", elf_name);
 
-            if *elf_name == primary {
+            if Some(*elf_name) == primary_opt {
                 entry_opt = Some(mmap.as_mut_ptr() as usize + elf.header.e_entry as usize);
             }
 
@@ -549,6 +555,6 @@ impl Linker {
             }
         }
 
-        entry_opt.ok_or(Error::Malformed(format!("missing entry for {}", primary)))
+        Ok(entry_opt)
     }
 }
diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs
index 2455c6378c9e6f4d17d43db637c96938f5b31d67..fbc27db84dfc44de7870e950fb59324ec0262375 100644
--- a/src/ld_so/start.rs
+++ b/src/ld_so/start.rs
@@ -1,9 +1,13 @@
 // Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs
 
-use crate::{c_str::CStr, header::unistd, platform::types::c_char};
+use crate::{
+    c_str::CStr,
+    header::unistd,
+    platform::types::c_char,
+    start::Stack,
+};
 
 use super::linker::Linker;
-use crate::start::Stack;
 
 #[no_mangle]
 pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
@@ -107,16 +111,22 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
         }
     }
 
-    match linker.link(&path) {
-        Ok(entry) => {
-            eprintln!("ld.so: entry '{}': {:#x}", path, entry);
-            //unistd::_exit(0);
-            entry
-        }
+    let entry = match linker.link(Some(&path)) {
+        Ok(ok) => match ok {
+            Some(some) => some,
+            None => {
+                eprintln!("ld.so: failed to link '{}': missing entry", path);
+                unistd::_exit(1);
+                loop {}
+            }
+        },
         Err(err) => {
             eprintln!("ld.so: failed to link '{}': {}", path, err);
             unistd::_exit(1);
             loop {}
         }
-    }
+    };
+
+    eprintln!("ld.so: entry '{}': {:#x}", path, entry);
+    entry
 }