Search code examples
linuxmacosshared-librariesdylibdlsym

How to export symbols from POSIX shared library and load using dlopen, dlsym


We are using dlopen to read in a dynamic library on Mac OS X. Update: This is a posix problem, the same thing fails under cygwin.

First the compile. On cygwin:

extern "C" void foo() { }


g++ -shared foo.c -o libfoo.so
nm -D libfoo.so

displays no public symbols. This appears to be the problem. If I could make them public, nm -D should display them.

Using:

nm libfoo.so | grep foo

000000x0xx0x00x0x0  T _foo

you can see the symbol is there. In Linux, this does seem to work:

nm -D foo.so
0000000000201020 B __bss_start
                 w __cxa_finalize
0000000000201020 D _edata
0000000000201028 B _end
0000000000000608 T _fini
0000000000000600 T foo
                 w __gmon_start__
00000000000004c0 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses

However, even in Linux, we cannot seem to connect to the library. Here is the source code:

include

include

using namespace std;

int main() {
    void* so = dlopen("foo.so", RTLD_NOW);
    if (so = nullptr) {
        cerr << "Can't open shared library\n";
        exit(-1);
    }
    #if 0
    const void* sym = dlsym(so, "foo");
    if (sym == nullptr) {
        cout << "Symbol not found\n";
    }
    #endif
    dlclose(so);
}

If we remove the #ifdef, the above code prints "Symbol not found" but it crashes on the dlclose.

We tried exporting LD_LIBRARY_PATH=. just to see if the library cannot be reached. And the dlopen call seems to work in any case, the return is not nullptr.

So to summarize, the library does not seem to work on Mac and Cygwin. On Linux nm -D shows the symbol in the library, but the code to load the symbol does not work.


Solution

  • In your example, you wrote if (so = nullptr) {, which assigns nullptr to so, and the condition is always false. -Wall is a good idea when debugging!

    This alone explains why you can't load the symbol, but I also found that I needed to do dlopen("./foo.so", RTLD_NOW); because dlopen otherwise searches library paths, not the current directory.