I am trying to allow a shared library to call a function from the process that it is being loaded into. The library is written in C, the "kernel" in C++.
kernel.cpp:
#include <stdio.h>
#include <dlfcn.h>
typedef void(*func_t)();
extern "C" {
void test();
}
int main() {
char *error;
void *handle = dlopen("./library.so", RTLD_LAZY);
if((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
func_t init = (func_t)dlsym(handle, "init");
if((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
init();
return 0;
}
void test() {
fprintf(stderr, "test() called.\n");
}
library.c:
#include <stdio.h>
void test();
void init() {
fprintf(stderr, "init() called.\n");
test();
}
makefile:
all:
g++ -ldl kernel.cpp -o kernel
gcc -fpic -shared library.c -o library.so
./kernel
objdump -x kernel
SYMBOL TABLE:
...
000000000040088b g F .text 0000000000000024 test
Running the program, I get the following output:
init() called.
./kernel: symbol lookup error: ./library.so: undefined symbol: test
If I change dlopen to use RTLD_NOW, i get:
./library.so: undefined symbol: test
Why is the library having difficulty finding that symbol when it is clearly not mangled, sitting right there?
Symbols of an executable are not exported by default.
You need the -export-dynamic linker flag for linking the executable:
g++ -ldl -Wl,-export-dynamic kernel.C -o kernel
Quoting from the ld man page, which describes your exact scenario:
If you use "dlopen" to load a dynamic object which needs to refer
back to the symbols defined by the program, rather than some other
dynamic object, then you will probably need to use this option when
linking the program itself.