nagisa / rust_libloading

Bindings around the platform's dynamic library loading primitives with greatly improved memory safety.
https://docs.rs/libloading
ISC License
1.22k stars 100 forks source link

How do you obtain a static symbol from the original program image? #147

Closed codecnotsupported closed 5 months ago

codecnotsupported commented 5 months ago

I'm trying to load a static symbol using libloading but it returns a IncompatibleSize error, yet I don't know why.

#[no_mangle]
static mut TEST_STATIC_2: u32 = 10;
fn main() {
    unsafe { TEST_STATIC_2 = 1 }; // Symbol gets stripped if unused.
    let library = libloading::os::unix::Library::this();
    let test_symbol = unsafe { library.get::<u32>(b"TEST_STATIC_2\0") }.unwrap();

    dbg!(test_symbol);
}

Results in

thread 'main' panicked at src/main.rs:7:89:
called `Result::unwrap()` on an `Err` value: IncompatibleSize
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

IncompatibleSize Enum isn't very descriptive: "requested type cannot possibly work". Looking at the code that generates the error: https://github.com/nagisa/rust_libloading/blob/dc8664fd23a34b16e240c1bd48acbe3596cb8eef/src/os/unix/mod.rs#L214 Which is https://github.com/nagisa/rust_libloading/blob/dc8664fd23a34b16e240c1bd48acbe3596cb8eef/src/util.rs#L28-L34 It checks if the requested value is the size of a *mut raw::c_void (A raw pointer)?

So you're required to put in a pointer-like type in Library::get? Changing it to &u32 seems to fix that issue. However now it can't find the symbol. Which is odd since objdump can find it.

SHELL: cargo r
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/testing`
thread 'main' panicked at src/main.rs:6:74:
called `Result::unwrap()` on an `Err` value: DlSym { desc: "target/debug/testing: undefined symbol: TEST_STATIC_2" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
SHELL: objdump ./target/debug/testing -x | grep -i TEST_
0000000000060008 g     O .data  0000000000000004              TEST_STATIC_2
SHELL: 
nagisa commented 5 months ago

IncompatibleSize Enum isn't very descriptive: "requested type cannot possibly work".

Fair enough.

However now it can't find the symbol. Which is odd since objdump can find it.

If you're on linux, you can run with the LD_DEBUG=all environment variable set. It'll show you what the loader is doing. Testing locally I see indications that it is attempting to inspect the binary for symbols. Why it won't find anything is going to be up to yourself to figure out, but most likely reason is that ld.so does not consider the binary DSO enough or the symbols sufficiently visible.

A relevant linker flag to look into may be --export-dynamic-symbol

codecnotsupported commented 5 months ago

Thanks, Adding

[build]
rustflags = ["-C", "link-args=-rdynamic"]

to .cargo/config resolves the issue. Relevant stackoverflow page: https://stackoverflow.com/questions/43712979/how-to-export-a-symbol-from-a-rust-executable