浏览代码

Add support for dlopen(NULL, ...)

Mateusz Tabaka 4 年之前
父节点
当前提交
c11aad71b8
共有 7 个文件被更改,包括 74 次插入27 次删除
  1. 20 16
      src/header/dlfcn/mod.rs
  2. 2 2
      src/ld_so/callbacks.rs
  3. 17 9
      src/ld_so/linker.rs
  4. 6 0
      tests/Makefile
  5. 28 0
      tests/dlfcn.c
  6. 0 0
      tests/expected/dlfcn.stderr
  7. 1 0
      tests/expected/dlfcn.stdout

+ 20 - 16
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
 }
 

+ 2 - 2
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)
 }
 

+ 17 - 9
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")

+ 6 - 0
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
 

+ 28 - 0
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));
+}
+

+ 0 - 0
tests/expected/dlfcn.stderr


+ 1 - 0
tests/expected/dlfcn.stdout

@@ -0,0 +1 @@
+add(22, 33) = 55