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

Viewed 47

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.

1 Answers

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);
    }
}
Related