Reputation: 732
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
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