From 04ea2f9397e5cf978af8cd5c6309d0ea52554e7f Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 7 Mar 2020 23:27:25 +0200 Subject: [PATCH 1/3] Refactor Linker::Link This patch does basically two things: - First make `global` variable not public, And make it accessable via a function `get_sym`. - Isolate the procedure that collect global symbols into single function that does that and call it `collect_syms`. The motivation of this patch is the second one where this procedure is extended, thus it needs a seamless way to access those symbols --- src/header/dlfcn/mod.rs | 6 +-- src/ld_so/linker.rs | 91 ++++++++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 36 deletions(-) diff --git a/src/header/dlfcn/mod.rs b/src/header/dlfcn/mod.rs index d5b53db5fb..cc10390c07 100644 --- a/src/header/dlfcn/mod.rs +++ b/src/header/dlfcn/mod.rs @@ -108,9 +108,9 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m eprintln!("dlsym: linker_ptr: {:p}", tcb.linker_ptr); let linker = (&*tcb.linker_ptr).lock(); - if let Some(global) = linker.globals.get(symbol_str) { - eprintln!("dlsym({:p}, {}) = 0x{:x}", handle, symbol_str, *global); - *global as *mut c_void + if let Some(global) = linker.get_sym(symbol_str) { + eprintln!("dlsym({:p}, {}) = 0x{:x}", handle, symbol_str, global); + global as *mut c_void } else { eprintln!("dlsym: symbol not found"); ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index dd39611280..fe98fae5f7 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -38,7 +38,7 @@ pub struct Linker { // Used by link /// Global symbols - pub globals: BTreeMap, + globals: BTreeMap, /// Loaded library in-memory data mmaps: BTreeMap, verbose: bool, @@ -129,6 +129,37 @@ impl Linker { } } + fn collect_syms(elf: &Elf, mmap: &[u8], verbose: bool) -> Result> { + let mut globals = BTreeMap::new(); + for sym in elf.dynsyms.iter() { + if sym.st_bind() == sym::STB_GLOBAL && sym.st_value != 0 { + if let Some(name_res) = elf.dynstrtab.get(sym.st_name) { + let name = name_res?; + let value = mmap.as_ptr() as usize + sym.st_value as usize; + if verbose { + println!(" global {}: {:x?} = {:#x}", &name, sym, value); + } + globals.insert(name.to_string(), value); + } + } + } + return Ok(globals); + } + + pub fn get_sym(&self, name: &str) -> Option { + if let Some(value) = self.globals.get(name) { + if self.verbose { + println!(" sym {} = {:#x}", name, value); + } + Some(*value) + } else { + if self.verbose { + println!(" sym {} = undefined", name); + } + None + } + } + pub fn link(&mut self, primary_opt: Option<&str>) -> Result> { let elfs = { let mut elfs = BTreeMap::new(); @@ -179,7 +210,7 @@ impl Linker { } } program_header::PT_TLS => { - if self.verbose{ + if self.verbose { println!(" load tls {:#x}: {:x?}", vsize, ph); } tls_size += vsize; @@ -221,18 +252,8 @@ impl Linker { if self.verbose { println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len()); } - // Locate all globals - for sym in elf.dynsyms.iter() { - if sym.st_bind() == sym::STB_GLOBAL && sym.st_value != 0 { - if let Some(name_res) = elf.dynstrtab.get(sym.st_name) { - let name = name_res?; - let value = mmap.as_ptr() as usize + sym.st_value as usize; - // println!(" global {}: {:x?} = {:#x}", name, sym, value); - self.globals.insert(name.to_string(), value); - } - } - } - + let globals = Linker::collect_syms(&elf, &mmap, self.verbose)?; + self.globals.extend(globals.into_iter()); self.mmaps.insert(elf_name.to_string(), mmap); } @@ -242,7 +263,7 @@ impl Linker { } else { None }; - if self.verbose{ + if self.verbose { println!("tcb {:x?}", tcb_opt); } // Copy data @@ -331,14 +352,20 @@ impl Linker { ); } if Some(*elf_name) == primary_opt { - tls_ranges.insert(elf_name.to_string(), (self.tls_index_offset, tcb_master.range())); + 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()), + ( + self.tls_index_offset + tcb_masters.len(), + tcb_master.range(), + ), ); tcb_masters.push(tcb_master); } @@ -360,10 +387,6 @@ impl Linker { // Perform relocations, and protect pages for (elf_name, elf) in elfs.iter() { - let mmap = match self.mmaps.get_mut(*elf_name) { - Some(some) => some, - None => continue, - }; if self.verbose { println!("link {}", elf_name); } @@ -379,10 +402,6 @@ impl Linker { // rel // ); - let a = rel.r_addend.unwrap_or(0) as usize; - - let b = mmap.as_mut_ptr() as usize; - let s = if rel.r_sym > 0 { let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(format!( "missing symbol for relocation {:?}", @@ -396,18 +415,20 @@ impl Linker { "missing name for symbol {:?}", sym )))??; - - if let Some(value) = self.globals.get(name) { - // println!(" sym {}: {:x?} = {:#x}", name, sym, value); - *value - } else { - // println!(" sym {}: {:x?} = undefined", name, sym); - 0 - } + self.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) { + 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 { @@ -473,6 +494,10 @@ impl Linker { prot |= sys_mman::PROT_WRITE; } + let mmap = match self.mmaps.get_mut(*elf_name) { + Some(some) => some, + None => continue, + }; let res = unsafe { let ptr = mmap.as_mut_ptr().add(vaddr); if self.verbose { From c2488b509484817e6e6ac39981aedaf5706a7cb8 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 7 Mar 2020 23:31:14 +0200 Subject: [PATCH 2/3] Running ./fmt.sh These files needs formating by the auto formatter and It keeps popping up every time I format my own code. --- src/header/unistd/mod.rs | 3 ++- src/ld_so/tcb.rs | 6 +----- src/platform/redox/socket.rs | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 3b15fd7e31..449128ab43 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -5,7 +5,8 @@ use core::{convert::TryFrom, mem, ptr, slice}; use crate::{ c_str::CStr, header::{ - errno, fcntl, limits, stdlib::getenv, sys_ioctl, sys_time, sys_utsname, termios, time::timespec, + errno, fcntl, limits, stdlib::getenv, sys_ioctl, sys_time, sys_utsname, termios, + time::timespec, }, platform::{self, types::*, Pal, Sys}, }; diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index 3b71ebfaad..3a30308882 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -2,11 +2,7 @@ use alloc::boxed::Box; use core::{mem, ops::Range, ptr, slice}; use goblin::error::{Error, Result}; -use crate::{ - header::sys_mman, - ld_so::linker::Linker, - sync::mutex::Mutex, -}; +use crate::{header::sys_mman, ld_so::linker::Linker, sync::mutex::Mutex}; use super::PAGE_SIZE; diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index 80eb515e8b..fd875c7635 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -215,7 +215,7 @@ impl PalSocket for Sys { *error = 0; return 0; - }, + } _ => (), }, _ => (), From 4860ab12fa7120b35a36fec33b16fd6624f5d549 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 7 Mar 2020 23:56:08 +0200 Subject: [PATCH 3/3] Resolve Both strong and weak symbols This patch keep 2 lists, one for strong symbols and one for weak symbols. First it will check for the symbol to be resolved in the strong symbols' list, if it is not there it will then check in the weak symbol list. --- src/ld_so/linker.rs | 47 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index fe98fae5f7..8486451460 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -39,6 +39,8 @@ pub struct Linker { // Used by link /// Global symbols globals: BTreeMap, + /// Weak symbols + weak_syms: BTreeMap, /// Loaded library in-memory data mmaps: BTreeMap, verbose: bool, @@ -51,6 +53,7 @@ impl Linker { library_path: library_path.to_string(), objects: BTreeMap::new(), globals: BTreeMap::new(), + weak_syms: BTreeMap::new(), mmaps: BTreeMap::new(), verbose, tls_index_offset: 0, @@ -129,21 +132,43 @@ impl Linker { } } - fn collect_syms(elf: &Elf, mmap: &[u8], verbose: bool) -> Result> { + fn collect_syms( + elf: &Elf, + mmap: &[u8], + verbose: bool, + ) -> Result<(BTreeMap, BTreeMap)> { let mut globals = BTreeMap::new(); + let mut weak_syms = BTreeMap::new(); for sym in elf.dynsyms.iter() { - if sym.st_bind() == sym::STB_GLOBAL && sym.st_value != 0 { - if let Some(name_res) = elf.dynstrtab.get(sym.st_name) { - let name = name_res?; - let value = mmap.as_ptr() as usize + sym.st_value as usize; + let bind = sym.st_bind(); + if sym.st_value == 0 || ![sym::STB_GLOBAL, sym::STB_WEAK].contains(&bind) { + continue; + } + let name: String; + let value: usize; + if let Some(name_res) = elf.dynstrtab.get(sym.st_name) { + name = name_res?.to_string(); + value = mmap.as_ptr() as usize + sym.st_value as usize; + } else { + continue; + } + match sym.st_bind() { + sym::STB_GLOBAL => { if verbose { println!(" global {}: {:x?} = {:#x}", &name, sym, value); } - globals.insert(name.to_string(), value); + globals.insert(name, value); } + sym::STB_WEAK => { + if verbose { + println!(" weak {}: {:x?} = {:#x}", &name, sym, value); + } + weak_syms.insert(name, value); + } + _ => unreachable!(), } } - return Ok(globals); + return Ok((globals, weak_syms)); } pub fn get_sym(&self, name: &str) -> Option { @@ -152,6 +177,11 @@ impl Linker { 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); + } + Some(*value) } else { if self.verbose { println!(" sym {} = undefined", name); @@ -252,8 +282,9 @@ impl Linker { if self.verbose { println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len()); } - let globals = Linker::collect_syms(&elf, &mmap, self.verbose)?; + 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); }