|
@@ -1,11 +1,13 @@
|
|
|
use alloc::{
|
|
|
boxed::Box,
|
|
|
- collections::{BTreeMap, BTreeSet},
|
|
|
+ collections::BTreeMap,
|
|
|
+ rc::Rc,
|
|
|
string::{String, ToString},
|
|
|
vec::Vec,
|
|
|
};
|
|
|
use core::{
|
|
|
- mem::{size_of, transmute},
|
|
|
+ cell::RefCell,
|
|
|
+ mem::{size_of, swap, transmute},
|
|
|
ptr, slice,
|
|
|
};
|
|
|
use goblin::{
|
|
@@ -28,7 +30,9 @@ use crate::{
|
|
|
|
|
|
use super::{
|
|
|
access::access,
|
|
|
+ callbacks::LinkerCallbacks,
|
|
|
debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
|
|
|
+ library::{DepTree, Library},
|
|
|
tcb::{Master, Tcb},
|
|
|
PAGE_SIZE,
|
|
|
};
|
|
@@ -43,70 +47,53 @@ pub struct DSO {
|
|
|
pub base_addr: usize,
|
|
|
pub entry_point: usize,
|
|
|
}
|
|
|
-#[derive(Default, Debug)]
|
|
|
-pub struct DepTree {
|
|
|
- pub name: String,
|
|
|
- pub deps: Vec<DepTree>,
|
|
|
-}
|
|
|
|
|
|
-impl DepTree {
|
|
|
- fn new(name: String) -> DepTree {
|
|
|
- DepTree {
|
|
|
- name,
|
|
|
- deps: Vec::new(),
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
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
|
|
|
- /// Global symbols
|
|
|
- globals: BTreeMap<String, usize>,
|
|
|
- /// Weak symbols
|
|
|
- weak_syms: BTreeMap<String, usize>,
|
|
|
- /// Loaded library in-memory data
|
|
|
- mmaps: BTreeMap<String, &'static mut [u8]>,
|
|
|
+ root: Library,
|
|
|
verbose: bool,
|
|
|
tls_index_offset: usize,
|
|
|
- /// A set used to detect circular dependencies in the Linker::load function
|
|
|
- cir_dep: BTreeSet<String>,
|
|
|
- /// Each object will have its children callec once with no repetition.
|
|
|
- dep_tree: DepTree,
|
|
|
+ lib_spaces: BTreeMap<usize, Library>,
|
|
|
+ counter: usize,
|
|
|
+ pub cbs: Rc<RefCell<LinkerCallbacks>>,
|
|
|
}
|
|
|
|
|
|
impl Linker {
|
|
|
pub fn new(library_path: &str, verbose: bool) -> Self {
|
|
|
Self {
|
|
|
library_path: library_path.to_string(),
|
|
|
- objects: BTreeMap::new(),
|
|
|
- globals: BTreeMap::new(),
|
|
|
- weak_syms: BTreeMap::new(),
|
|
|
- mmaps: BTreeMap::new(),
|
|
|
+ root: Library::new(),
|
|
|
verbose,
|
|
|
tls_index_offset: 0,
|
|
|
- cir_dep: BTreeSet::new(),
|
|
|
- dep_tree: Default::default(),
|
|
|
+ lib_spaces: BTreeMap::new(),
|
|
|
+ counter: 1,
|
|
|
+ cbs: Rc::new(RefCell::new(LinkerCallbacks::new())),
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
|
|
|
- self.dep_tree = self.load_recursive(name, path)?;
|
|
|
+ let mut lib: Library = Library::new();
|
|
|
+ swap(&mut lib, &mut self.root);
|
|
|
+ lib.dep_tree = self.load_recursive(name, path, &mut lib)?;
|
|
|
+ swap(&mut lib, &mut self.root);
|
|
|
if self.verbose {
|
|
|
- println!("Dep tree: {:#?}", self.dep_tree);
|
|
|
+ println!("Dep tree: {:#?}", self.root.dep_tree);
|
|
|
}
|
|
|
return Ok(());
|
|
|
}
|
|
|
-
|
|
|
- fn load_recursive(&mut self, name: &str, path: &str) -> Result<DepTree> {
|
|
|
+ pub fn unload(&mut self, libspace: usize) {
|
|
|
+ if let Some(lib) = self.lib_spaces.remove(&libspace) {
|
|
|
+ for (_, mmap) in lib.mmaps {
|
|
|
+ unsafe { sys_mman::munmap(mmap.as_mut_ptr() as *mut c_void, mmap.len()) };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fn load_recursive(&mut self, name: &str, path: &str, lib: &mut Library) -> Result<DepTree> {
|
|
|
if self.verbose {
|
|
|
println!("load {}: {}", name, path);
|
|
|
}
|
|
|
- if self.cir_dep.contains(name) {
|
|
|
+ if lib.cir_dep.contains(name) {
|
|
|
return Err(Error::Malformed(format!(
|
|
|
"Circular dependency: {} is a dependency of itself",
|
|
|
name
|
|
@@ -115,7 +102,7 @@ impl Linker {
|
|
|
|
|
|
let mut deps = DepTree::new(name.to_string());
|
|
|
let mut data = Vec::new();
|
|
|
- self.cir_dep.insert(name.to_string());
|
|
|
+ lib.cir_dep.insert(name.to_string());
|
|
|
let path_c = CString::new(path)
|
|
|
.map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
|
|
|
|
|
@@ -127,32 +114,45 @@ impl Linker {
|
|
|
file.read_to_end(&mut data)
|
|
|
.map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
|
|
|
}
|
|
|
- deps.deps = self.load_data(name, data.into_boxed_slice())?;
|
|
|
- self.cir_dep.remove(name);
|
|
|
+ deps.deps = self.load_data(name, data.into_boxed_slice(), lib)?;
|
|
|
+ lib.cir_dep.remove(name);
|
|
|
Ok(deps)
|
|
|
}
|
|
|
|
|
|
- pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result<Vec<DepTree>> {
|
|
|
+ fn load_data(
|
|
|
+ &mut self,
|
|
|
+ name: &str,
|
|
|
+ data: Box<[u8]>,
|
|
|
+ lib: &mut Library,
|
|
|
+ ) -> Result<Vec<DepTree>> {
|
|
|
let elf = Elf::parse(&data)?;
|
|
|
//println!("{:#?}", elf);
|
|
|
let mut deps = Vec::new();
|
|
|
for library in elf.libraries.iter() {
|
|
|
- if let Some(dep) = self.load_library(library)? {
|
|
|
+ if let Some(dep) = self._load_library(library, lib)? {
|
|
|
deps.push(dep);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- self.objects.insert(name.to_string(), data);
|
|
|
+ lib.objects.insert(name.to_string(), data);
|
|
|
|
|
|
return Ok(deps);
|
|
|
}
|
|
|
|
|
|
- pub fn load_library(&mut self, name: &str) -> Result<Option<DepTree>> {
|
|
|
- if self.objects.contains_key(name) {
|
|
|
+ pub fn load_library(&mut self, name: &str) -> Result<usize> {
|
|
|
+ let mut lib = Library::new();
|
|
|
+ self._load_library(name, &mut lib)?;
|
|
|
+ let ret = self.counter;
|
|
|
+ self.lib_spaces.insert(ret, lib);
|
|
|
+ self.counter += 1;
|
|
|
+ return Ok(ret);
|
|
|
+ }
|
|
|
+ fn _load_library(&mut self, name: &str, lib: &mut Library) -> Result<Option<DepTree>> {
|
|
|
+ if lib.objects.contains_key(name) || self.root.objects.contains_key(name) {
|
|
|
// It should be previously resolved so we don't need to worry about it
|
|
|
Ok(None)
|
|
|
} else if name.contains('/') {
|
|
|
- Ok(Some(self.load_recursive(name, name)?))
|
|
|
+ Ok(Some(self.load_recursive(name, name, lib)?))
|
|
|
} else {
|
|
|
let library_path = self.library_path.clone();
|
|
|
for part in library_path.split(PATH_SEP) {
|
|
@@ -176,7 +176,7 @@ impl Linker {
|
|
|
};
|
|
|
|
|
|
if access {
|
|
|
- return Ok(Some(self.load_recursive(name, &path)?));
|
|
|
+ return Ok(Some(self.load_recursive(name, &path, lib)?));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -227,40 +227,51 @@ impl Linker {
|
|
|
return Ok((globals, weak_syms));
|
|
|
}
|
|
|
|
|
|
- pub fn get_sym(&self, name: &str) -> Option<usize> {
|
|
|
- if let Some(value) = self.globals.get(name) {
|
|
|
- if self.verbose {
|
|
|
- println!(" sym {} = {:#x}", name, value);
|
|
|
- }
|
|
|
- Some(*value)
|
|
|
- } else if let Some(value) = self.weak_syms.get(name) {
|
|
|
- if self.verbose {
|
|
|
- println!(" sym {} = {:#x}", name, value);
|
|
|
+ pub fn get_sym(&self, name: &str, libspace: Option<usize>) -> Option<usize> {
|
|
|
+ match libspace {
|
|
|
+ Some(id) => {
|
|
|
+ let lib = self.lib_spaces.get(&id)?;
|
|
|
+ lib.get_sym(name)
|
|
|
}
|
|
|
- Some(*value)
|
|
|
- } else {
|
|
|
- if self.verbose {
|
|
|
- println!(" sym {} = undefined", name);
|
|
|
+ None => self.root.get_sym(name),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn run_init(&self, libspace: Option<usize>) -> Result<()> {
|
|
|
+ match libspace {
|
|
|
+ Some(id) => {
|
|
|
+ let lib = self.lib_spaces.get(&id).unwrap();
|
|
|
+ self.run_tree(&lib, &lib.dep_tree, ".init_array")
|
|
|
}
|
|
|
- None
|
|
|
+ None => self.run_tree(&self.root, &self.root.dep_tree, ".init_array"),
|
|
|
}
|
|
|
}
|
|
|
- pub fn run_init(&self) -> Result<()> {
|
|
|
- self.run_init_tree(&self.dep_tree)
|
|
|
+
|
|
|
+ pub fn run_fini(&self, libspace: Option<usize>) -> Result<()> {
|
|
|
+ match libspace {
|
|
|
+ Some(id) => {
|
|
|
+ let lib = self.lib_spaces.get(&id).unwrap();
|
|
|
+ self.run_tree(&lib, &lib.dep_tree, ".fini_array")
|
|
|
+ }
|
|
|
+ None => {
|
|
|
+ //TODO we first need to deinitialize all the loaded libraries first!
|
|
|
+ self.run_tree(&self.root, &self.root.dep_tree, ".fini_array")
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- fn run_init_tree(&self, root: &DepTree) -> Result<()> {
|
|
|
+ fn run_tree(&self, lib: &Library, root: &DepTree, tree_name: &str) -> Result<()> {
|
|
|
for node in root.deps.iter() {
|
|
|
- self.run_init_tree(node)?;
|
|
|
+ self.run_tree(lib, node, tree_name)?;
|
|
|
}
|
|
|
if self.verbose {
|
|
|
- println!("init {}", &root.name);
|
|
|
+ println!("running {} {}", tree_name, &root.name);
|
|
|
}
|
|
|
- let mmap = match self.mmaps.get(&root.name) {
|
|
|
+ let mmap = match lib.mmaps.get(&root.name) {
|
|
|
Some(some) => some,
|
|
|
None => return Ok(()),
|
|
|
};
|
|
|
- let elf = Elf::parse(self.objects.get(&root.name).unwrap())?;
|
|
|
+ let elf = Elf::parse(lib.objects.get(&root.name).unwrap())?;
|
|
|
for section in &elf.section_headers {
|
|
|
let name = match elf.shdr_strtab.get(section.sh_name) {
|
|
|
Some(x) => match x {
|
|
@@ -269,7 +280,7 @@ impl Linker {
|
|
|
},
|
|
|
_ => continue,
|
|
|
};
|
|
|
- if name == ".init_array" {
|
|
|
+ if name == tree_name {
|
|
|
let addr = if is_pie_enabled(&elf) {
|
|
|
mmap.as_ptr() as usize + section.vm_range().start
|
|
|
} else {
|
|
@@ -283,52 +294,42 @@ impl Linker {
|
|
|
return Ok(());
|
|
|
}
|
|
|
|
|
|
- pub fn run_fini(&self) -> Result<()> {
|
|
|
- self.run_fini_tree(&self.dep_tree)
|
|
|
- }
|
|
|
-
|
|
|
- fn run_fini_tree(&self, root: &DepTree) -> Result<()> {
|
|
|
- if self.verbose {
|
|
|
- println!("init {}", &root.name);
|
|
|
- }
|
|
|
- let mmap = match self.mmaps.get(&root.name) {
|
|
|
- Some(some) => some,
|
|
|
- None => return Ok(()),
|
|
|
- };
|
|
|
- let elf = Elf::parse(self.objects.get(&root.name).unwrap())?;
|
|
|
- for section in &elf.section_headers {
|
|
|
- let name = match elf.shdr_strtab.get(section.sh_name) {
|
|
|
- Some(x) => match x {
|
|
|
- Ok(y) => y,
|
|
|
- _ => continue,
|
|
|
- },
|
|
|
- _ => continue,
|
|
|
- };
|
|
|
- if name == ".fini_array" {
|
|
|
- let addr = if is_pie_enabled(&elf) {
|
|
|
- mmap.as_ptr() as usize + section.vm_range().start
|
|
|
- } else {
|
|
|
- section.vm_range().start
|
|
|
- };
|
|
|
- for i in (0..section.sh_size).step_by(8) {
|
|
|
- unsafe { call_inits_finis(addr + i as usize) };
|
|
|
- }
|
|
|
+ pub fn link(
|
|
|
+ &mut self,
|
|
|
+ primary_opt: Option<&str>,
|
|
|
+ dso: Option<DSO>,
|
|
|
+ libspace: Option<usize>,
|
|
|
+ ) -> Result<Option<usize>> {
|
|
|
+ match libspace {
|
|
|
+ Some(id) => {
|
|
|
+ let mut lib = self.lib_spaces.remove(&id).unwrap();
|
|
|
+ let res = self._link(primary_opt, dso, &mut lib);
|
|
|
+ self.lib_spaces.insert(id, lib);
|
|
|
+ res
|
|
|
+ }
|
|
|
+ None => {
|
|
|
+ let mut lib = Library::new();
|
|
|
+ swap(&mut lib, &mut self.root);
|
|
|
+ let res = self._link(primary_opt, dso, &mut lib);
|
|
|
+ swap(&mut lib, &mut self.root);
|
|
|
+ res
|
|
|
}
|
|
|
}
|
|
|
- for node in root.deps.iter() {
|
|
|
- self.run_fini_tree(node)?;
|
|
|
- }
|
|
|
- return Ok(());
|
|
|
}
|
|
|
|
|
|
- pub fn link(&mut self, primary_opt: Option<&str>, dso: Option<DSO>) -> Result<Option<usize>> {
|
|
|
+ pub fn _link(
|
|
|
+ &mut self,
|
|
|
+ primary_opt: Option<&str>,
|
|
|
+ dso: Option<DSO>,
|
|
|
+ lib: &mut Library,
|
|
|
+ ) -> Result<Option<usize>> {
|
|
|
unsafe { _r_debug.state = RTLDState::RT_ADD };
|
|
|
_dl_debug_state();
|
|
|
let elfs = {
|
|
|
let mut elfs = BTreeMap::new();
|
|
|
- for (name, data) in self.objects.iter() {
|
|
|
+ for (name, data) in lib.objects.iter() {
|
|
|
// Skip already linked libraries
|
|
|
- if !self.mmaps.contains_key(&*name) {
|
|
|
+ if !lib.mmaps.contains_key(&*name) && !self.root.mmaps.contains_key(&*name) {
|
|
|
elfs.insert(name.as_str(), Elf::parse(&data)?);
|
|
|
}
|
|
|
}
|
|
@@ -342,7 +343,7 @@ impl Linker {
|
|
|
if self.verbose {
|
|
|
println!("map {}", elf_name);
|
|
|
}
|
|
|
- let object = match self.objects.get(*elf_name) {
|
|
|
+ let object = match lib.objects.get(*elf_name) {
|
|
|
Some(some) => some,
|
|
|
None => continue,
|
|
|
};
|
|
@@ -478,9 +479,9 @@ impl Linker {
|
|
|
println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len());
|
|
|
}
|
|
|
let (globals, weak_syms) = Linker::collect_syms(&elf, &mmap, self.verbose)?;
|
|
|
- self.globals.extend(globals.into_iter());
|
|
|
- self.weak_syms.extend(weak_syms.into_iter());
|
|
|
- self.mmaps.insert(elf_name.to_string(), mmap);
|
|
|
+ lib.globals.extend(globals.into_iter());
|
|
|
+ lib.weak_syms.extend(weak_syms.into_iter());
|
|
|
+ lib.mmaps.insert(elf_name.to_string(), mmap);
|
|
|
}
|
|
|
|
|
|
// Allocate TLS
|
|
@@ -515,12 +516,12 @@ impl Linker {
|
|
|
if same_elf {
|
|
|
continue;
|
|
|
}
|
|
|
- let object = match self.objects.get(*elf_name) {
|
|
|
+ let object = match lib.objects.get(*elf_name) {
|
|
|
Some(some) => some,
|
|
|
None => continue,
|
|
|
};
|
|
|
|
|
|
- let mmap = match self.mmaps.get_mut(*elf_name) {
|
|
|
+ let mmap = match lib.mmaps.get_mut(*elf_name) {
|
|
|
Some(some) => some,
|
|
|
None => continue,
|
|
|
};
|
|
@@ -653,14 +654,15 @@ impl Linker {
|
|
|
"missing name for symbol {:?}",
|
|
|
sym
|
|
|
)))??;
|
|
|
- self.get_sym(name).unwrap_or(0)
|
|
|
+ lib.get_sym(name)
|
|
|
+ .unwrap_or(self.root.get_sym(name).unwrap_or(0))
|
|
|
} else {
|
|
|
0
|
|
|
};
|
|
|
|
|
|
let a = rel.r_addend.unwrap_or(0) as usize;
|
|
|
|
|
|
- let mmap = match self.mmaps.get_mut(*elf_name) {
|
|
|
+ let mmap = match lib.mmaps.get_mut(*elf_name) {
|
|
|
Some(some) => some,
|
|
|
None => continue,
|
|
|
};
|
|
@@ -741,7 +743,7 @@ impl Linker {
|
|
|
}
|
|
|
if let Some(dyn_start_addr) = dyn_start {
|
|
|
if let Some(i) = debug_start {
|
|
|
- let mmap = match self.mmaps.get_mut(*elf_name) {
|
|
|
+ let mmap = match lib.mmaps.get_mut(*elf_name) {
|
|
|
Some(some) => some,
|
|
|
None => continue,
|
|
|
};
|
|
@@ -778,7 +780,7 @@ impl Linker {
|
|
|
prot |= sys_mman::PROT_WRITE;
|
|
|
}
|
|
|
|
|
|
- let mmap = match self.mmaps.get_mut(*elf_name) {
|
|
|
+ let mmap = match lib.mmaps.get_mut(*elf_name) {
|
|
|
Some(some) => some,
|
|
|
None => continue,
|
|
|
};
|
|
@@ -811,7 +813,7 @@ impl Linker {
|
|
|
// Perform indirect relocations (necessary evil), gather entry point
|
|
|
let mut entry_opt = None;
|
|
|
for (elf_name, elf) in elfs.iter() {
|
|
|
- let mmap = match self.mmaps.get_mut(*elf_name) {
|
|
|
+ let mmap = match lib.mmaps.get_mut(*elf_name) {
|
|
|
Some(some) => some,
|
|
|
None => continue,
|
|
|
};
|
|
@@ -898,7 +900,7 @@ impl Linker {
|
|
|
}
|
|
|
}
|
|
|
unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
|
|
|
- //_dl_debug_state();
|
|
|
+ _dl_debug_state();
|
|
|
Ok(entry_opt)
|
|
|
}
|
|
|
}
|