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 }