diff --git a/src/header/dlfcn/mod.rs b/src/header/dlfcn/mod.rs index dcce6789ceaa1ebf2b7295941aebbd8ad240afb5..784a2b83c2b41bc72e7d2042176ee4729797340a 100644 --- a/src/header/dlfcn/mod.rs +++ b/src/header/dlfcn/mod.rs @@ -40,10 +40,11 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut //TODO support all sort of flags let filename = if cfilename.is_null() { - ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); - return ptr::null_mut(); + None } else { - str::from_utf8_unchecked(CStr::from_ptr(cfilename).to_bytes()) + Some(str::from_utf8_unchecked( + CStr::from_ptr(cfilename).to_bytes(), + )) }; let tcb = match Tcb::current() { @@ -60,31 +61,34 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut return ptr::null_mut(); } let mut linker = (&*tcb.linker_ptr).lock(); + let cbs_c = linker.cbs.clone(); let cbs = cbs_c.borrow(); let id = match (cbs.load_library)(&mut linker, filename) { Err(err) => { - eprintln!("dlopen: failed to load {}", filename); + eprintln!("dlopen: failed to load {:?}", filename); ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); return ptr::null_mut(); } Ok(id) => id, }; - if let Err(err) = (cbs.link)(&mut linker, None, None, Some(id)) { - (cbs.unload)(&mut linker, id); - eprintln!("dlopen: failed to link '{}': {}", filename, err); - ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); - return ptr::null_mut(); - }; + if let Some(fname) = filename { + if let Err(err) = (cbs.link)(&mut linker, None, None, Some(id)) { + (cbs.unload)(&mut linker, id); + eprintln!("dlopen: failed to link '{}': {}", fname, err); + ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); + return ptr::null_mut(); + }; - if let Err(err) = (cbs.run_init)(&mut linker, Some(id)) { - (cbs.unload)(&mut linker, id); - eprintln!("dlopen: failed to link '{}': {}", filename, err); - ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); - return ptr::null_mut(); - }; + if let Err(err) = (cbs.run_init)(&mut linker, Some(id)) { + (cbs.unload)(&mut linker, id); + eprintln!("dlopen: failed to link '{}': {}", fname, err); + ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); + return ptr::null_mut(); + }; + } id as *mut c_void } diff --git a/src/ld_so/callbacks.rs b/src/ld_so/callbacks.rs index d53f21561b0f52f43e579c2346d12d4931ae1c96..f0e851cbc7623b064d6bdaab23f98081a22bbf55 100644 --- a/src/ld_so/callbacks.rs +++ b/src/ld_so/callbacks.rs @@ -4,7 +4,7 @@ use goblin::error::Result; pub struct LinkerCallbacks { pub unload: Box<dyn Fn(&mut Linker, usize)>, - pub load_library: Box<dyn Fn(&mut Linker, &str) -> Result<usize>>, + pub load_library: Box<dyn Fn(&mut Linker, Option<&str>) -> Result<usize>>, pub link: Box<dyn Fn(&mut Linker, Option<&str>, Option<DSO>, Option<usize>) -> Result<Option<usize>>>, pub get_sym: Box<dyn Fn(&Linker, &str, Option<usize>) -> Option<Symbol>>, @@ -29,7 +29,7 @@ fn unload(linker: &mut Linker, libspace: usize) { linker.unload(libspace) } -fn load_library(linker: &mut Linker, name: &str) -> Result<usize> { +fn load_library(linker: &mut Linker, name: Option<&str>) -> Result<usize> { linker.load_library(name) } diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 3f6b4d4c46b0a67e8d87c563bef38a18aaf3348c..b83526d0cd7656a15f2aff9eff446e68706fdead 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -73,6 +73,8 @@ pub struct Linker { pub cbs: Rc<RefCell<LinkerCallbacks>>, } +const root_id: usize = 1; + impl Linker { pub fn new(ld_library_path: Option<String>, verbose: bool) -> Self { Self { @@ -82,7 +84,7 @@ impl Linker { verbose, tls_index_offset: 0, lib_spaces: BTreeMap::new(), - counter: 1, + counter: root_id + 1, cbs: Rc::new(RefCell::new(LinkerCallbacks::new())), } } @@ -175,13 +177,18 @@ impl Linker { 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); + pub fn load_library(&mut self, name: Option<&str>) -> Result<usize> { + match name { + Some(name) => { + 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); + } + None => return Ok(root_id), + } } 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) { @@ -270,11 +277,11 @@ impl Linker { pub fn get_sym(&self, name: &str, libspace: Option<usize>) -> Option<Symbol> { match libspace { + None | Some(root_id) => self.root.get_sym(name), Some(id) => { let lib = self.lib_spaces.get(&id)?; lib.get_sym(name) } - None => self.root.get_sym(name), } } @@ -290,6 +297,7 @@ impl Linker { pub fn run_fini(&self, libspace: Option<usize>) -> Result<()> { match libspace { + Some(root_id) => return Ok(()), Some(id) => { let lib = self.lib_spaces.get(&id).unwrap(); self.run_tree(&lib, &lib.dep_tree, ".fini_array") diff --git a/tests/Makefile b/tests/Makefile index 77113745eb66c3f1adcd5bffa27d23edd3089b95..e481ece6fa10759dba70207a2de0b75cedbe1365 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -129,6 +129,9 @@ STATIC_ONLY_NAMES+=\ unistd/getopt \ unistd/getopt_long \ +DYNAMIC_ONLY_NAMES=\ + dlfcn + # Binaries that may generate varied output NAMES=\ $(EXPECT_NAMES) \ @@ -159,9 +162,11 @@ NAMES=\ BINS=$(patsubst %,bins_static/%,$(NAMES)) BINS+=$(patsubst %,bins_static/%,$(STATIC_ONLY_NAMES)) BINS+=$(patsubst %,bins_dynamic/%,$(NAMES)) +BINS+=$(patsubst %,bins_dynamic/%,$(DYNAMIC_ONLY_NAMES)) EXPECT_BINS=$(patsubst %,bins_static/%,$(EXPECT_NAMES)) EXPECT_BINS+=$(patsubst %,bins_static/%,$(STATIC_ONLY_NAMES)) EXPECT_BINS+=$(patsubst %,bins_dynamic/%,$(EXPECT_NAMES)) +EXPECT_BINS+=$(patsubst %,bins_dynamic/%,$(DYNAMIC_ONLY_NAMES)) TEST_RUNNER?=sh -- @@ -228,6 +233,7 @@ DYNAMIC_FLAGS=\ -Wl,-dynamic-linker=$(SYSROOT_LIB)/ld64.so.1 \ -Wl,--enable-new-dtags \ -Wl,-rpath=$(SYSROOT_LIB) \ + -Wl,-export-dynamic \ -L $(SYSROOT_LIB) \ -lc diff --git a/tests/dlfcn.c b/tests/dlfcn.c new file mode 100644 index 0000000000000000000000000000000000000000..16729e1cec6c75580b1a6f9af7b04cb22f86cf70 --- /dev/null +++ b/tests/dlfcn.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> + + +int add(int a, int b) +{ + return a + b; +} + + +int main() +{ + void* handle = dlopen(NULL, RTLD_LAZY); + if (!handle) { + printf("dlopen(NULL) failed\n"); + exit(1); + } + int (*f)(int, int) = dlsym(handle, "add"); + if (!f) { + printf("dlsym(handle, add) failed\n"); + exit(2); + } + int a = 22; + int b = 33; + printf("add(%d, %d) = %d\n", a, b, f(a, b)); +} + diff --git a/tests/expected/dlfcn.stderr b/tests/expected/dlfcn.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/dlfcn.stdout b/tests/expected/dlfcn.stdout new file mode 100644 index 0000000000000000000000000000000000000000..36ae1185bdb1318e7a81ffb2951b7838b5339d54 --- /dev/null +++ b/tests/expected/dlfcn.stdout @@ -0,0 +1 @@ +add(22, 33) = 55