Felix Crazzolara
Felix Crazzolara

Reputation: 732

Providing symbol of linked shared library to shared library opened with dlopen

Consider the following files

# Makefile

all: libdyn.so libmain.so app

libdyn.so: libdyn.cpp
    g++ -fPIC -shared -o libdyn.so libdyn.cpp

libso.so: libso.cpp
    g++ -fPIC -shared -o libso.so libso.cpp

libmain.so: libmain.cpp libso.so
    g++ -Wl,--no-as-needed -fPIC -shared -o libmain.so libmain.cpp -ldl -L`pwd` -lso

app: main.cpp   g++ -o app main.cpp -ldl
    g++ -o app main.cpp -ldl
// libdyn.cpp

#include <iostream>

extern "C" {

extern void foo();

void bar() {
    std::cout << "Calling foo..." << std::endl;
    foo();
}

};
// libso.cpp

#include <iostream>

extern "C" {

void foo() {
    std::cout << "Hello from foo" << std::endl;
}

};
// libmain.cpp

#include <iostream>
#include <dlfcn.h>

int main_fun() {
    void* handle = dlopen("./libdyn.so", RTLD_LAZY);
    void (*bar_ptr)() = reinterpret_cast<void(*)()>(dlsym(handle, "bar"));
    std::cout << "Calling bar..." << std::endl;
    (*bar_ptr)();
    return 0;
}
// main.cpp

#include <iostream>
#include <dlfcn.h>

int main() {
    void* handle = dlopen("./libmain.so", RTLD_LAZY);
    int (*main_fun_ptr)() = reinterpret_cast<int(*)()>(dlsym(handle, "_Z8main_funv"));
    std::cout << "Calling main_fun..." << std::endl;
    (*main_fun_ptr)(); 
}

Calling ./app yields

Calling main_fun...
Calling bar...
Calling foo...
./app: symbol lookup error: ./libdyn.so: undefined symbol: foo

and ldd libmain.so yields

    linux-vdso.so.1 (0x00007ffd903f8000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe05cdb8000)
    libso.so (0x00007fe05cdb3000)
    libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe05cb99000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe05ca4a000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe05ca2f000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe05c83b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe05cddf000)

I don't understand why libdyn doesn't have access to foo. libmain links against libso, which provides foo and libdyn is loaded by libmain, so shouldn't foo then be found?

I am interested in solving this problem, however, there are a few constraints. As could be suspected, this is kind of a MWE for my real problem. In my application libmain.so is called using the Java Native Interface. Furthermore, only libmain is user code. libso and libdyn are external libraries that would be very difficult for me to recompile, but it would be doable. Lastly, there isn't a single foo function, but thousands and also global variables that must be shared in the way foo should be shared.

Upvotes: 1

Views: 204

Answers (1)

Lorinczy Zsigmond
Lorinczy Zsigmond

Reputation: 1910

In main.cpp, use open RTLD_GLOBAL in dlopen.

From the manual:

RTLD_GLOBAL
    The  symbols  defined by this shared object will be
    made available for symbol resolution
    of subsequently loaded shared objects.

Edit: alternatively, instead of linking libso.so as dependency into libmain.so, call dlopen from main_fun:

dlopen("libso.so", RTLD_LAZY|RTLD_GLOBAL)

Or perhaps from a shared-object-initializer:

static void init(void) __attribute__((constructor));
static void init(void) {
    fprintf(stderr, "libmain constructor %s running\n", __func__);
    if (!dlopen("libso.so", RTLD_LAZY|RTLD_GLOBAL)) {
        fprintf(stderr, "dlopen(\"libso.so\"): *** %s\n", dlerror());
        exit(1);
    }
}

Upvotes: 1

Related Questions