Allow running linker more than once
This commit is contained in:
+24
-18
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+19
-9
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user