Search code examples
c++clinkerdlopen

dlopen cant find demangled symbols


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?


Solution

  • 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.