user905747
user905747

Reputation: 623

Using shared libraries with dlopen - shared object cannot find symbol exported by the loading program

So, I have a following example I'm trying to run.

header.h

extern "C" {
        void registerfunc();
};

main.cpp

#include "header.h"
#include <dlfcn.h>
#include <iostream>

using namespace std;

typedef void (*register_func)();

void registerfunc() {
    cout << "register func has been called" << endl;
}

int main() {
    void* lib_handle = dlopen("./test/test.so", RTLD_NOW | RTLD_GLOBAL);

    if(lib_handle == NULL){
            cout << "no such lib:" << dlerror() <<endl;
            return 0;
    }

    register_func reg = (register_func)dlsym(lib_handle, "test");

    if(reg == NULL){
            cout << "Cannot load symbol" <<  dlerror() << endl;;
    } else {
            reg();
    }
    return 0;
}

it is compiled with following makefile

all:
    g++ main.cpp -ldl

then, i want to use registerfunc from my own so, which is written in the following way:

main.h:

extern "C"
{
    void test();
};

main.cpp

#include "main.h"
#include "../header.h"

void test() {
    registerfunc();
}

Makefile:

all:
    g++ main.cpp -fPIC -shared -o test.so

When I compile it this way and run a.out (output of first main), I get:

 no such lib: ./test/test.so: undefined symbol: registerfunc

However, if i compile a.out and test.so using following commands:

a.out -> g++ -g -fPIC -shared main.cpp -ldl
test.so -> g++ -g main.cpp -fPIC -shared -o test.so ../a.out

then I'm getting a segmentation fault with following backtrace (gdb -ex run a.out):

0x0000000000000001 in ?? ()

That leaves me kinda stumped, as to how make test.so call something that is defined by it's callee. Could you, please, help?

Upvotes: 1

Views: 1519

Answers (1)

Employed Russian
Employed Russian

Reputation: 213879

You have at least three separate problems here:

  • The smaller one is that you have two files named main.cpp, and it's not entirely clear which command refers to which file in your question.

  • The bigger problem is that you are expecting test.so to bind to registerfunc in a.out, but the function is not exported from a.out unless some shared library participating in the link references that function, or you link with -Wl,--export-dynamic (which exports all functions). This is the real solution.

    You can see which functions are exported from your a.out with this command:

    nm -D a.out | grep ' T '

  • Finally, when you do this:

    a.out -> g++ -g -fPIC -shared main.cpp -ldl

    you are actually creating a shared library (named a.out), not an executable. Running such a shared library as if it were an executable leads to the crash you've observed.

Upvotes: 2

Related Questions