Verified Commit 086c8f67 authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Allow running linker more than once

parent 0a06388d
......@@ -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)
}
}
// 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
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment