C, Rust, and loadable module

I have a small program in C with the following function:

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int version() {
    return 5;
}

int main() {
    printf("Using module lib from C:\n");
    void (*rust_function)();

    void* s = dlopen("libinc.so", RTLD_NOW);
    if (s == NULL) {
        fprintf(stderr, "can't load module\n");
        exit(-1);
    }

    rust_function = dlsym(s, "rust_function");
    rust_function();
    dlclose(s);
}

and the following code in rust

#[no_mangle]
pub extern "C" fn rust_function() {
    unsafe {
        let v = version();
        println!("Hello, world 4! v={:?}", v);
    }
}

extern "C" {
        pub fn version() -> ::std::os::raw::c_int;
}

The rust library is loaded automatically in C but the call to version does not work with this error:

Unable to load module /root/rust/rustlib/target/release/librustlib.so: 
DSO load failed /root/rust/rustlib/target/release/librustlib.so: 
undefined symbol: version

Any Idea ?

For us to help you, please include full code, including imports. Additionally, please format your code:

```rs
Your code goes here
```

I update the post, but the code except for C is complete

Your Rust program says it expects a version() function to be defined somewhere and is leaving it up to the loader at runtime (via dlopen()) to find the appropriate symbol from the *.so's dependend on by librustlib.so.

However, version() is defined in your C executable, and it looks like the way it was compiled means the loader will never consider your main executable when looking for the symbol.

Maybe you need to compile the C executable with -rdynamic like in this StackOverflow answer?

https://stackoverflow.com/questions/31192221/referencing-global-symbols-from-shared-library-loaded-with-dlopen

Usually for this type of thing you pass a function pointer around. So you pass it to the library, which calls back to the original.

Question: does this work with a dynamically loaded C library? I mean one where you dlopen and dlsym it as well. If it does, then that's one thing. But if it doesn't, then it's not a Rust problem per se (or not only that), it's (also) a linking problem.

You are right about -rdynamic.
Everything is good now

cc -o main main.c -rdynamic -ldl

The rust program:

#[no_mangle]
pub extern "C" fn rust_function() {
    unsafe {
		let v = version();
        println!("Hello, world 4! v={:?}", v);
    }
}


#[no_mangle]
extern "C" {
        fn version() -> ::std::os::raw::c_int;
}

The full C program:

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int version() {
    return 5;
}

int main() {
    printf("Using module lib from C:\n");
    void (*rust_function)();

    void* s = dlopen("libinc.so", RTLD_NOW);
    if (s == NULL) {
        fprintf(stderr, "can't load module\n");
        exit(-1);
    }

    rust_function = dlsym(s, "rust_function");
    rust_function();
    dlclose(s);
}
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.