Skip to content
Snippets Groups Projects
Verified Commit 086c8f67 authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Allow running linker more than once

parent 0a06388d
No related branches found
No related tags found
No related merge requests found
...@@ -6,7 +6,6 @@ use alloc::{ ...@@ -6,7 +6,6 @@ use alloc::{
}; };
use core::{ use core::{
mem, mem,
ops::Range,
ptr, ptr,
slice slice
}; };
...@@ -36,12 +35,16 @@ const PATH_SEP: char = ':'; ...@@ -36,12 +35,16 @@ const PATH_SEP: char = ':';
pub struct Linker { pub struct Linker {
// Used by load // Used by load
/// Library path to search when loading library by name
library_path: String, library_path: String,
/// Loaded library raw data
objects: BTreeMap<String, Box<[u8]>>, objects: BTreeMap<String, Box<[u8]>>,
// Used by link // Used by link
mmaps: BTreeMap<String, &'static mut [u8]>, /// Global symbols
globals: BTreeMap<String, usize>, globals: BTreeMap<String, usize>,
tls_ranges: BTreeMap<String, (usize, Range<usize>)>, /// Loaded library in-memory data
mmaps: BTreeMap<String, &'static mut [u8]>,
} }
impl Linker { impl Linker {
...@@ -49,9 +52,8 @@ impl Linker { ...@@ -49,9 +52,8 @@ impl Linker {
Self { Self {
library_path: library_path.to_string(), library_path: library_path.to_string(),
objects: BTreeMap::new(), objects: BTreeMap::new(),
mmaps: BTreeMap::new(),
globals: BTreeMap::new(), globals: BTreeMap::new(),
tls_ranges: BTreeMap::new(), mmaps: BTreeMap::new(),
} }
} }
...@@ -82,9 +84,7 @@ impl Linker { ...@@ -82,9 +84,7 @@ impl Linker {
//println!("{:#?}", elf); //println!("{:#?}", elf);
for library in elf.libraries.iter() { 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 { ...@@ -94,7 +94,9 @@ impl Linker {
} }
pub fn load_library(&mut self, name: &str) -> Result<()> { 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) self.load(name, name)
} else { } else {
let library_path = self.library_path.clone(); let library_path = self.library_path.clone();
...@@ -126,11 +128,14 @@ impl Linker { ...@@ -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 elfs = {
let mut elfs = BTreeMap::new(); let mut elfs = BTreeMap::new();
for (name, data) in self.objects.iter() { 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 elfs
}; };
...@@ -173,7 +178,7 @@ impl Linker { ...@@ -173,7 +178,7 @@ impl Linker {
program_header::PT_TLS => { program_header::PT_TLS => {
println!(" load tls {:#x}: {:x?}", vsize, ph); println!(" load tls {:#x}: {:x?}", vsize, ph);
tls_size += vsize; tls_size += vsize;
if *elf_name == primary { if Some(*elf_name) == primary_opt {
tls_primary += vsize; tls_primary += vsize;
} }
} }
...@@ -237,6 +242,7 @@ impl Linker { ...@@ -237,6 +242,7 @@ impl Linker {
len: 0, len: 0,
offset: 0, offset: 0,
}); });
let mut tls_ranges = BTreeMap::new();
for (elf_name, elf) in elfs.iter() { for (elf_name, elf) in elfs.iter() {
let object = match self.objects.get(*elf_name) { let object = match self.objects.get(*elf_name) {
Some(some) => some, Some(some) => some,
...@@ -312,13 +318,13 @@ impl Linker { ...@@ -312,13 +318,13 @@ impl Linker {
tcb_master.ptr, tcb_master.len, tcb_master.offset, valign, tcb_master.ptr, tcb_master.len, tcb_master.offset, valign,
); );
if *elf_name == primary { if Some(*elf_name) == primary_opt {
self.tls_ranges.insert(elf_name.to_string(), (0, tcb_master.range())); tls_ranges.insert(elf_name.to_string(), (0, tcb_master.range()));
tcb_masters[0] = tcb_master; tcb_masters[0] = tcb_master;
} else { } else {
tcb_master.offset -= tls_offset; tcb_master.offset -= tls_offset;
tls_offset += vsize; 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); tcb_masters.push(tcb_master);
} }
} }
...@@ -383,7 +389,7 @@ impl Linker { ...@@ -383,7 +389,7 @@ impl Linker {
0 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) (*tls_index, tls_range.start)
} else { } else {
(0, 0) (0, 0)
...@@ -477,7 +483,7 @@ impl Linker { ...@@ -477,7 +483,7 @@ impl Linker {
println!("entry {}", elf_name); 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); entry_opt = Some(mmap.as_mut_ptr() as usize + elf.header.e_entry as usize);
} }
...@@ -549,6 +555,6 @@ impl Linker { ...@@ -549,6 +555,6 @@ impl Linker {
} }
} }
entry_opt.ok_or(Error::Malformed(format!("missing entry for {}", primary))) Ok(entry_opt)
} }
} }
// Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs // 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 super::linker::Linker;
use crate::start::Stack;
#[no_mangle] #[no_mangle]
pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize { 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 { ...@@ -107,16 +111,22 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
} }
} }
match linker.link(&path) { let entry = match linker.link(Some(&path)) {
Ok(entry) => { Ok(ok) => match ok {
eprintln!("ld.so: entry '{}': {:#x}", path, entry); Some(some) => some,
//unistd::_exit(0); None => {
entry eprintln!("ld.so: failed to link '{}': missing entry", path);
} unistd::_exit(1);
loop {}
}
},
Err(err) => { Err(err) => {
eprintln!("ld.so: failed to link '{}': {}", path, err); eprintln!("ld.so: failed to link '{}': {}", path, err);
unistd::_exit(1); unistd::_exit(1);
loop {} loop {}
} }
} };
eprintln!("ld.so: entry '{}': {:#x}", path, entry);
entry
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment