Search code examples
cshared-librariesdlopendlsym

Referencing global symbols from shared library loaded with dlopen


I have a shared library which I want to access symbols from the main program. For example:

main.c

#include <stdio.h>

void bar(void) { puts("bar"); }

extern void foo(void);

int main(void) {
    foo();
    return 0;
}

foo.c

#include <stdio.h>

extern void bar(void);

void foo(void) {
    puts("foo");
    bar();
}

I compile and run like:

gcc -c -fpic foo.c
gcc -shared -o libfoo.so foo.o
gcc -L$(pwd) -o test main.c -lfoo
./test

And I get the output I expect:

foo
bar

However, I must use dlopen() and dlsym() because I want to have control over when the library is loaded. The changed files are:

main.c

#include <stdio.h>
#include <dlfcn.h>

void bar(void) { puts("bar"); }

int main(void) {
    void *handle = dlopen("./libfoo.so", RTLD_LAZY);
    void (*foo)(void) = (void(*)(void))dlsym(handle,"foo");
    foo();
    return 0;
}

foo.c

#include <stdio.h>
#include <dlfcn.h>

extern void bar(void);

void foo(void) {
    puts("foo");
    bar();
}

I instead compile and run with:

gcc -c -fpic foo.c
gcc -shared -o libfoo.so foo.o
gcc -o test main.c -ldl
./test

However, this time I get the output

foo
./test: symbol lookup error: ./libfoo.so: undefined symbol: bar

How can I reference symbols in the main program from libfoo?


Solution

  • You have to add the -rdynamic option when linking test:

    gcc -o test main.c -ldl -rdynamic
    

    From here:

    -rdynamic Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of dlopen or to allow obtaining backtraces from within a program.