1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027 |
- use alloc::{
- boxed::Box,
- collections::{BTreeMap, BTreeSet},
- rc::Rc,
- string::{String, ToString},
- vec::Vec,
- };
- use core::{
- cell::RefCell,
- mem::{size_of, swap, transmute},
- ptr, slice,
- };
- use goblin::{
- elf::{
- header::ET_DYN,
- program_header,
- r#dyn::{Dyn, DT_DEBUG, DT_RUNPATH},
- reloc, sym, Elf,
- },
- error::{Error, Result},
- };
- use crate::{
- c_str::CString,
- fs::File,
- header::{errno::STR_ERROR, fcntl, sys_mman, unistd},
- io::Read,
- platform::{errno, types::c_void},
- };
- use super::{
- access::accessible,
- callbacks::LinkerCallbacks,
- debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
- library::{DepTree, Library},
- tcb::{Master, Tcb},
- PAGE_SIZE,
- };
- #[cfg(target_os = "redox")]
- pub const PATH_SEP: char = ';';
- #[cfg(target_os = "linux")]
- pub const PATH_SEP: char = ':';
- pub struct DSO {
- pub name: String,
- pub base_addr: usize,
- pub entry_point: usize,
- }
- #[derive(Clone, Copy, Debug)]
- pub struct Symbol {
- pub value: usize,
- pub base: usize,
- pub size: usize,
- }
- impl Symbol {
- pub fn as_ptr(self) -> *mut c_void {
- (self.base + self.value) as *mut c_void
- }
- }
- pub struct Linker {
- // Used by load
- /// Library path to search when loading library by name
- default_library_path: String,
- ld_library_path: Option<String>,
- root: Library,
- verbose: bool,
- tls_index_offset: usize,
- lib_spaces: BTreeMap<usize, Library>,
- counter: usize,
- pub cbs: Rc<RefCell<LinkerCallbacks>>,
- }
- impl Linker {
- pub fn new(ld_library_path: Option<String>, verbose: bool) -> Self {
- Self {
- default_library_path: "/lib".to_string(),
- ld_library_path: ld_library_path,
- root: Library::new(),
- verbose,
- tls_index_offset: 0,
- lib_spaces: BTreeMap::new(),
- counter: 1,
- cbs: Rc::new(RefCell::new(LinkerCallbacks::new())),
- }
- }
- pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
- 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.root.dep_tree);
- }
- return Ok(());
- }
- 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 lib.cir_dep.contains(name) {
- return Err(Error::Malformed(format!(
- "Circular dependency: {} is a dependency of itself",
- name
- )));
- }
- let mut deps = DepTree::new(name.to_string());
- let mut data = Vec::new();
- lib.cir_dep.insert(name.to_string());
- let path_c = CString::new(path)
- .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
- {
- let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
- let mut file = File::open(&path_c, flags)
- .map_err(|err| Error::Malformed(format!("failed to open '{}': {}", path, err)))?;
- 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(), lib)?;
- lib.cir_dep.remove(name);
- Ok(deps)
- }
- fn load_data(
- &mut self,
- name: &str,
- data: Box<[u8]>,
- lib: &mut Library,
- ) -> Result<Vec<DepTree>> {
- let elf = Elf::parse(&data)?;
- //println!("{:#?}", elf);
- // search for RUNPATH
- lib.runpath = if let Some(dynamic) = elf.dynamic {
- let entry = dynamic.dyns.iter().find(|d| d.d_tag == DT_RUNPATH);
- match entry {
- Some(entry) => {
- let path = elf
- .dynstrtab
- .get(entry.d_val as usize)
- .ok_or(Error::Malformed("Missing RUNPATH in dynstrtab".to_string()))??;
- Some(path.to_string())
- }
- _ => None,
- }
- } else {
- None
- };
- let mut deps = Vec::new();
- for library in elf.libraries.iter() {
- if let Some(dep) = self._load_library(library, lib)? {
- deps.push(dep);
- }
- }
- let key = match elf.soname {
- Some(soname) => soname,
- _ => name,
- };
- if !lib.objects.contains_key(key) {
- lib.objects.insert(key.to_string(), data);
- }
- return Ok(deps);
- }
- 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, lib)?))
- } else {
- let mut paths = Vec::new();
- if let Some(ld_library_path) = &self.ld_library_path {
- paths.push(ld_library_path);
- }
- if let Some(runpath) = &lib.runpath {
- paths.push(runpath);
- }
- paths.push(&self.default_library_path);
- for part in paths.iter() {
- let path = if part.is_empty() {
- format!("./{}", name)
- } else {
- format!("{}/{}", part, name)
- };
- if self.verbose {
- println!("check {}", path);
- }
- if accessible(&path, unistd::F_OK) == 0 {
- return Ok(Some(self.load_recursive(name, &path, lib)?));
- }
- }
- Err(Error::Malformed(format!("failed to locate '{}'", name)))
- }
- }
- fn collect_syms(
- elf: &Elf,
- mmap: &[u8],
- verbose: bool,
- ) -> Result<(BTreeMap<String, Symbol>, BTreeMap<String, Symbol>)> {
- let mut globals = BTreeMap::new();
- let mut weak_syms = BTreeMap::new();
- for sym in elf.dynsyms.iter() {
- let bind = sym.st_bind();
- if sym.st_value == 0 || ![sym::STB_GLOBAL, sym::STB_WEAK].contains(&bind) {
- continue;
- }
- let name: String;
- let value: Symbol;
- if let Some(name_res) = elf.dynstrtab.get(sym.st_name) {
- name = name_res?.to_string();
- value = if is_pie_enabled(elf) {
- Symbol {
- base: mmap.as_ptr() as usize,
- value: sym.st_value as usize,
- size: sym.st_size as usize,
- }
- } else {
- Symbol {
- base: 0,
- value: sym.st_value as usize,
- size: sym.st_size as usize,
- }
- };
- } else {
- continue;
- }
- match sym.st_bind() {
- sym::STB_GLOBAL => {
- if verbose {
- println!(" global {}: {:x?} = {:p}", &name, sym, value.as_ptr());
- }
- globals.insert(name, value);
- }
- sym::STB_WEAK => {
- if verbose {
- println!(" weak {}: {:x?} = {:p}", &name, sym, value.as_ptr());
- }
- weak_syms.insert(name, value);
- }
- _ => unreachable!(),
- }
- }
- return Ok((globals, weak_syms));
- }
- pub fn get_sym(&self, name: &str, libspace: Option<usize>) -> Option<Symbol> {
- match libspace {
- Some(id) => {
- let lib = self.lib_spaces.get(&id)?;
- lib.get_sym(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 => self.run_tree(&self.root, &self.root.dep_tree, ".init_array"),
- }
- }
- 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_tree(&self, lib: &Library, root: &DepTree, tree_name: &str) -> Result<()> {
- for node in root.deps.iter() {
- self.run_tree(lib, node, tree_name)?;
- }
- if self.verbose {
- println!("running {} {}", tree_name, &root.name);
- }
- let (_, mmap) = match lib.mmaps.get(&root.name) {
- Some(some) => some,
- None => return Ok(()),
- };
- 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 {
- Ok(y) => y,
- _ => continue,
- },
- _ => continue,
- };
- if name == tree_name {
- 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) };
- }
- }
- }
- return Ok(());
- }
- 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
- }
- }
- }
- 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 mut skip_list = BTreeSet::new();
- let elfs = {
- let mut elfs = BTreeMap::new();
- for (name, data) in lib.objects.iter() {
- // Skip already linked libraries
- if !lib.mmaps.contains_key(&*name) && !self.root.mmaps.contains_key(&*name) {
- elfs.insert(name.as_str(), Elf::parse(&data)?);
- } else {
- skip_list.insert(name.as_str());
- }
- }
- elfs
- };
- // Load all ELF files into memory and find all globals
- let mut tls_primary = 0;
- let mut tls_size = 0;
- for (elf_name, elf) in elfs.iter() {
- if skip_list.contains(elf_name) {
- continue;
- }
- if self.verbose {
- println!("map {}", elf_name);
- }
- let object = match lib.objects.get(*elf_name) {
- Some(some) => some,
- None => continue,
- };
- // data for struct LinkMap
- let mut l_ld = 0;
- // Calculate virtual memory bounds
- let bounds = {
- let mut bounds_opt: Option<(usize, usize)> = None;
- for ph in elf.program_headers.iter() {
- let voff = ph.p_vaddr as usize % PAGE_SIZE;
- let vaddr = ph.p_vaddr as usize - voff;
- let vsize =
- ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
- match ph.p_type {
- program_header::PT_DYNAMIC => {
- l_ld = ph.p_vaddr;
- }
- program_header::PT_LOAD => {
- if self.verbose {
- println!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
- }
- if let Some(ref mut bounds) = bounds_opt {
- if vaddr < bounds.0 {
- bounds.0 = vaddr;
- }
- if vaddr + vsize > bounds.1 {
- bounds.1 = vaddr + vsize;
- }
- } else {
- bounds_opt = Some((vaddr, vaddr + vsize));
- }
- }
- program_header::PT_TLS => {
- if self.verbose {
- println!(" load tls {:#x}: {:x?}", vsize, ph);
- }
- tls_size += vsize;
- if Some(*elf_name) == primary_opt {
- tls_primary += vsize;
- }
- }
- _ => (),
- }
- }
- match bounds_opt {
- Some(some) => some,
- None => continue,
- }
- };
- if self.verbose {
- println!(" bounds {:#x}, {:#x}", bounds.0, bounds.1);
- }
- // Allocate memory
- let mmap = unsafe {
- let same_elf = if let Some(prog) = dso.as_ref() {
- if prog.name == *elf_name {
- true
- } else {
- false
- }
- } else {
- false
- };
- if same_elf {
- let addr = dso.as_ref().unwrap().base_addr;
- let size = if is_pie_enabled(&elf) {
- bounds.1
- } else {
- bounds.1 - bounds.0
- };
- // Fill the gaps i the binary
- let mut ranges = Vec::new();
- for ph in elf.program_headers.iter() {
- if ph.p_type == program_header::PT_LOAD {
- let voff = ph.p_vaddr as usize % PAGE_SIZE;
- let vaddr = ph.p_vaddr as usize - voff;
- let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE)
- * PAGE_SIZE;
- if is_pie_enabled(&elf) {
- ranges.push((vaddr, vsize));
- } else {
- ranges.push((vaddr - addr, vsize));
- }
- }
- }
- ranges.sort();
- let mut start = addr;
- for (vaddr, vsize) in ranges.iter() {
- if start < addr + vaddr {
- if self.verbose {
- println!("mmap({:#x}, {})", start, addr + vaddr - start);
- }
- let mut flags = sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE;
- if start != 0 {
- flags |= sys_mman::MAP_FIXED_NOREPLACE;
- }
- let ptr = sys_mman::mmap(
- start as *mut c_void,
- addr + vaddr - start,
- //TODO: Make it possible to not specify PROT_EXEC on Redox
- sys_mman::PROT_READ | sys_mman::PROT_WRITE,
- flags,
- -1,
- 0,
- );
- if ptr as usize == !0
- /* MAP_FAILED */
- {
- return Err(Error::Malformed(format!(
- "failed to map {}. errno: {}",
- elf_name, STR_ERROR[errno as usize]
- )));
- }
- if start as *mut c_void != ptr::null_mut() {
- assert_eq!(
- ptr, start as *mut c_void,
- "mmap must always map on the destination we requested"
- );
- }
- }
- start = addr + vaddr + vsize
- }
- sys_mman::mprotect(
- addr as *mut c_void,
- size,
- sys_mman::PROT_READ | sys_mman::PROT_WRITE,
- );
- _r_debug.insert_first(addr as usize, &elf_name, addr + l_ld as usize);
- (
- addr as usize,
- slice::from_raw_parts_mut(addr as *mut u8, size),
- )
- } else {
- let (start, end) = bounds;
- let size = end - start;
- if self.verbose {
- println!("mmap({:#x}, {})", start, size);
- }
- let mut flags = sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE;
- if start != 0 {
- flags |= sys_mman::MAP_FIXED_NOREPLACE;
- }
- let ptr = sys_mman::mmap(
- start as *mut c_void,
- size,
- //TODO: Make it possible to not specify PROT_EXEC on Redox
- sys_mman::PROT_READ | sys_mman::PROT_WRITE,
- flags,
- -1,
- 0,
- );
- if ptr as usize == !0
- /* MAP_FAILED */
- {
- return Err(Error::Malformed(format!(
- "failed to map {}. errno: {}",
- elf_name, STR_ERROR[errno as usize]
- )));
- }
- if start as *mut c_void != ptr::null_mut() {
- assert_eq!(
- ptr, start as *mut c_void,
- "mmap must always map on the destination we requested"
- );
- }
- ptr::write_bytes(ptr as *mut u8, 0, size);
- _r_debug.insert(ptr as usize, &elf_name, ptr as usize + l_ld as usize);
- (start, slice::from_raw_parts_mut(ptr as *mut u8, size))
- }
- };
- if self.verbose {
- println!(" mmap {:p}, {:#x}", mmap.1.as_mut_ptr(), mmap.1.len());
- }
- let (globals, weak_syms) = Linker::collect_syms(&elf, &mmap.1, self.verbose)?;
- lib.globals.extend(globals.into_iter());
- lib.weak_syms.extend(weak_syms.into_iter());
- lib.mmaps.insert(elf_name.to_string(), mmap);
- }
- // Allocate TLS
- let mut tcb_opt = if primary_opt.is_some() {
- Some(unsafe { Tcb::new(tls_size)? })
- } else {
- None
- };
- if self.verbose {
- println!("tcb {:x?}", tcb_opt);
- }
- // Copy data
- let mut tls_offset = tls_primary;
- let mut tcb_masters = Vec::new();
- // Insert main image master
- tcb_masters.push(Master {
- ptr: ptr::null_mut(),
- len: 0,
- offset: 0,
- });
- let mut tls_ranges = BTreeMap::new();
- for (elf_name, elf) in elfs.iter() {
- if skip_list.contains(elf_name) {
- continue;
- }
- let same_elf = if let Some(prog) = dso.as_ref() {
- if prog.name == *elf_name {
- true
- } else {
- false
- }
- } else {
- false
- };
- if same_elf {
- continue;
- }
- let object = match lib.objects.get(*elf_name) {
- Some(some) => some,
- None => continue,
- };
- let &mut (base_addr, ref mut mmap) = match lib.mmaps.get_mut(*elf_name) {
- Some(some) => some,
- None => continue,
- };
- if self.verbose {
- println!("load {}", elf_name);
- }
- // Copy data
- for ph in elf.program_headers.iter() {
- let voff = ph.p_vaddr as usize % PAGE_SIZE;
- let vaddr = ph.p_vaddr as usize - voff;
- let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
- match ph.p_type {
- program_header::PT_LOAD => {
- let obj_data = {
- let range = ph.file_range();
- match object.get(range.clone()) {
- Some(some) => some,
- None => {
- return Err(Error::Malformed(format!(
- "failed to read {:x?}",
- range
- )))
- }
- }
- };
- let mmap_data = {
- let range = ph.p_vaddr as usize - base_addr
- ..ph.p_vaddr as usize + obj_data.len() - base_addr;
- match mmap.get_mut(range.clone()) {
- Some(some) => some,
- None => {
- println!("mmap: {}", mmap.len());
- return Err(Error::Malformed(format!(
- "failed to write {:x?}",
- range
- )));
- }
- }
- };
- if self.verbose {
- println!(
- " copy {:#x}, {:#x}: {:#x}, {:#x}",
- vaddr,
- vsize,
- voff,
- obj_data.len()
- );
- }
- mmap_data.copy_from_slice(obj_data);
- }
- program_header::PT_TLS => {
- let valign = if ph.p_align > 0 {
- ((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align
- } else {
- ph.p_memsz
- } as usize;
- let mut tcb_master = Master {
- ptr: unsafe { mmap.as_ptr().add(ph.p_vaddr as usize - base_addr) },
- len: ph.p_filesz as usize,
- offset: tls_size - valign,
- };
- if self.verbose {
- println!(
- " tls master {:p}, {:#x}: {:#x}, {:#x}",
- tcb_master.ptr, tcb_master.len, tcb_master.offset, valign,
- );
- }
- if Some(*elf_name) == primary_opt {
- tls_ranges.insert(
- elf_name.to_string(),
- (self.tls_index_offset, tcb_master.range()),
- );
- tcb_masters[0] = tcb_master;
- } else {
- tcb_master.offset -= tls_offset;
- tls_offset += vsize;
- tls_ranges.insert(
- elf_name.to_string(),
- (
- self.tls_index_offset + tcb_masters.len(),
- tcb_master.range(),
- ),
- );
- tcb_masters.push(tcb_master);
- }
- }
- _ => (),
- }
- }
- }
- self.tls_index_offset += tcb_masters.len();
- // Set master images for TLS and copy TLS data
- if let Some(ref mut tcb) = tcb_opt {
- unsafe {
- tcb.set_masters(tcb_masters.into_boxed_slice());
- tcb.copy_masters()?;
- }
- }
- // Perform relocations, and protect pages
- for (elf_name, elf) in elfs.iter() {
- if skip_list.contains(elf_name) {
- continue;
- }
- if self.verbose {
- println!("link {}", elf_name);
- }
- // Relocate
- for rel in elf
- .dynrelas
- .iter()
- .chain(elf.dynrels.iter())
- .chain(elf.pltrelocs.iter())
- {
- // println!(" rel {}: {:x?}",
- // reloc::r_to_str(rel.r_type, elf.header.e_machine),
- // rel
- // );
- let symbol = if rel.r_sym > 0 {
- let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(format!(
- "missing symbol for relocation {:?}",
- rel
- )))?;
- let name =
- elf.dynstrtab
- .get(sym.st_name)
- .ok_or(Error::Malformed(format!(
- "missing name for symbol {:?}",
- sym
- )))??;
- lib.get_sym(name).or_else(|| self.root.get_sym(name))
- } else {
- None
- };
- let s = symbol
- .as_ref()
- .map(|sym| sym.as_ptr() as usize)
- .unwrap_or(0);
- let a = rel.r_addend.unwrap_or(0) as usize;
- let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
- Some(some) => some,
- None => continue,
- };
- let b = mmap.as_mut_ptr() as usize;
- let (tm, t) = if let Some((tls_index, tls_range)) = tls_ranges.get(*elf_name) {
- (*tls_index, tls_range.start)
- } else {
- (0, 0)
- };
- let ptr = if is_pie_enabled(&elf) {
- unsafe { mmap.as_mut_ptr().add(rel.r_offset as usize) }
- } else {
- rel.r_offset as *mut u8
- };
- let set_u64 = |value| {
- // println!(" set_u64 {:#x}", value);
- unsafe {
- *(ptr as *mut u64) = value;
- }
- };
- match rel.r_type {
- reloc::R_X86_64_64 => {
- set_u64((s + a) as u64);
- }
- reloc::R_X86_64_DTPMOD64 => {
- set_u64(tm as u64);
- }
- reloc::R_X86_64_DTPOFF64 => {
- if s != 0 {
- set_u64((s - b) as u64);
- } else {
- set_u64(s as u64);
- }
- }
- reloc::R_X86_64_GLOB_DAT | reloc::R_X86_64_JUMP_SLOT => {
- set_u64(s as u64);
- }
- reloc::R_X86_64_RELATIVE => {
- set_u64((b + a) as u64);
- }
- reloc::R_X86_64_TPOFF64 => {
- set_u64((s + a).wrapping_sub(t) as u64);
- }
- reloc::R_X86_64_IRELATIVE => (), // Handled below
- reloc::R_X86_64_COPY => unsafe {
- // TODO: Make this work
- let sym = symbol
- .as_ref()
- .expect("R_X86_64_COPY called without valid symbol");
- ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size as usize);
- },
- _ => {
- panic!(
- " {} unsupported",
- reloc::r_to_str(rel.r_type, elf.header.e_machine)
- );
- }
- }
- }
- // overwrite DT_DEBUG if exist in DYNAMIC segment
- // first we identify the location of DYNAMIC segment
- let mut dyn_start = None;
- let mut debug_start = None;
- for ph in elf.program_headers.iter() {
- if ph.p_type == program_header::PT_DYNAMIC {
- dyn_start = Some(ph.p_vaddr as usize);
- }
- }
- // next we identify the location of DT_DEBUG in .dynamic section
- if let Some(dynamic) = elf.dynamic.as_ref() {
- let mut i = 0;
- for entry in &dynamic.dyns {
- if entry.d_tag == DT_DEBUG {
- debug_start = Some(i as usize);
- break;
- }
- i += 1;
- }
- }
- if let Some(dyn_start_addr) = dyn_start {
- if let Some(i) = debug_start {
- let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
- Some(some) => some,
- None => continue,
- };
- let bytes: [u8; size_of::<Dyn>() / 2] =
- unsafe { transmute((&_r_debug) as *const RTLDDebug as usize) };
- let start = if is_pie_enabled(elf) {
- dyn_start_addr + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
- } else {
- dyn_start_addr + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
- - mmap.as_mut_ptr() as usize
- };
- mmap[start..start + size_of::<Dyn>() / 2].clone_from_slice(&bytes);
- }
- }
- // Protect pages
- for ph in elf.program_headers.iter() {
- if ph.p_type == program_header::PT_LOAD {
- let voff = ph.p_vaddr as usize % PAGE_SIZE;
- let vaddr = ph.p_vaddr as usize - voff;
- let vsize =
- ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
- let mut prot = 0;
- if ph.p_flags & program_header::PF_R == program_header::PF_R {
- prot |= sys_mman::PROT_READ;
- }
- // W ^ X. If it is executable, do not allow it to be writable, even if requested
- if ph.p_flags & program_header::PF_X == program_header::PF_X {
- prot |= sys_mman::PROT_EXEC;
- } else if ph.p_flags & program_header::PF_W == program_header::PF_W {
- prot |= sys_mman::PROT_WRITE;
- }
- let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
- Some(some) => some,
- None => continue,
- };
- let res = unsafe {
- let ptr = if is_pie_enabled(elf) {
- mmap.as_mut_ptr().add(vaddr)
- } else {
- vaddr as *const u8
- };
- if self.verbose {
- println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
- }
- sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
- };
- if res < 0 {
- return Err(Error::Malformed(format!("failed to mprotect {}", elf_name)));
- }
- }
- }
- }
- // Activate TLS
- if let Some(ref mut tcb) = tcb_opt {
- unsafe {
- tcb.activate();
- }
- }
- // Perform indirect relocations (necessary evil), gather entry point
- let mut entry_opt = None;
- for (elf_name, elf) in elfs.iter() {
- if skip_list.contains(elf_name) {
- continue;
- }
- let (_, mmap) = match lib.mmaps.get_mut(*elf_name) {
- Some(some) => some,
- None => continue,
- };
- if self.verbose {
- println!("entry {}", elf_name);
- }
- if Some(*elf_name) == primary_opt {
- if is_pie_enabled(&elf) {
- entry_opt = Some(mmap.as_mut_ptr() as usize + elf.header.e_entry as usize);
- } else {
- entry_opt = Some(elf.header.e_entry as usize);
- }
- }
- // Relocate
- for rel in elf
- .dynrelas
- .iter()
- .chain(elf.dynrels.iter())
- .chain(elf.pltrelocs.iter())
- {
- // println!(" rel {}: {:x?}",
- // reloc::r_to_str(rel.r_type, elf.header.e_machine),
- // rel
- // );
- let a = rel.r_addend.unwrap_or(0) as usize;
- let b = mmap.as_mut_ptr() as usize;
- let ptr = unsafe { mmap.as_mut_ptr().add(rel.r_offset as usize) };
- let set_u64 = |value| {
- // println!(" set_u64 {:#x}", value);
- unsafe {
- *(ptr as *mut u64) = value;
- }
- };
- if rel.r_type == reloc::R_X86_64_IRELATIVE {
- unsafe {
- let f: unsafe extern "C" fn() -> u64 = transmute(b + a);
- set_u64(f());
- }
- }
- }
- // Protect pages
- for ph in elf.program_headers.iter() {
- if let program_header::PT_LOAD = ph.p_type {
- let voff = ph.p_vaddr as usize % PAGE_SIZE;
- let vaddr = ph.p_vaddr as usize - voff;
- let vsize =
- ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
- let mut prot = 0;
- if ph.p_flags & program_header::PF_R == program_header::PF_R {
- prot |= sys_mman::PROT_READ;
- }
- // W ^ X. If it is executable, do not allow it to be writable, even if requested
- if ph.p_flags & program_header::PF_X == program_header::PF_X {
- prot |= sys_mman::PROT_EXEC;
- } else if ph.p_flags & program_header::PF_W == program_header::PF_W {
- prot |= sys_mman::PROT_WRITE;
- }
- let res = unsafe {
- let ptr = if is_pie_enabled(&elf) {
- mmap.as_mut_ptr().add(vaddr)
- } else {
- vaddr as *const u8
- };
- if self.verbose {
- println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
- }
- sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
- };
- if res < 0 {
- return Err(Error::Malformed(format!("failed to mprotect {}", elf_name)));
- }
- }
- }
- }
- unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
- _dl_debug_state();
- Ok(entry_opt)
- }
- }
- unsafe fn call_inits_finis(addr: usize) {
- let func = transmute::<usize, *const Option<extern "C" fn()>>(addr);
- (*func).map(|x| x());
- }
- fn is_pie_enabled(elf: &Elf) -> bool {
- if elf.header.e_type == ET_DYN {
- true
- } else {
- false
- }
- }
|