How to pass arguments to a method loaded from a static library in CPP

淺唱寂寞╮ 提交于 2019-12-04 15:40:49

Functions never have null addresses, so dlsym on a function name (or actually on any name defined in C++ or C) cannot be NULL without failing:

hello_t say_hello = (hello_t) dlsym(handle, "say_hello");
if (!say_hello) {
    cerr<<"Cannot load symbol 'say_hello': "<<dlerror()<<endl;
    exit(EXIT_FAILURE);
};

And dlopen(3) is documented to dynamically load only dynamic libraries (not static ones!). This implies shared objects (*.so) in ELF format. Read Drepper's paper How To Use Shared Libraries

I believe you might have found a bug in dlopen (see also its POSIX dlopen specification); it should fail for a static library hello.a; it is always used on position independent shared libraries (like hello.so).

You should dlopen only position independent code shared objects compiled with

g++ -Wall -O -shared -fPIC hello.cpp -o hello.so 

or if you have several C++ source files:

g++ -Wall -O -fPIC src1.cc -c -o src1.pic.o
g++ -Wall -O -fPIC src2.cc -c -o src2.pic.o
g++ -shared src1.pic.o src2.pic.o -o yourdynlib.so

you could remove the -O optimization flag or add -g for debugging or replace it with -O2 if you want.

and this works extremely well: my MELT project (a domain specific language to extend GCC) is using this a lot (generating C++ code, forking a compilation like above on the fly, then dlopen-ing the resulting shared object). And my manydl.c example demonstrates that you can dlopen a big lot of (different) shared objects on Linux (typically millions, and hundred of thousands at least). Actually the limitation is the address space.

BTW, you should not dlopen something having a main function, since main is by definition defined in the main program calling (perhaps indirectly) dlopen.

Also, order of arguments to g++ matters a lot; you should compile the main program with

g++ -Wall -rdynamic say_hello.cpp -ldl -o say_hello 

The -rdynamic flag is required to let the loaded plugin (hello.so) call functions from inside your say_hello program.

For debugging purposes always pass -Wall -g to g++ above.

BTW, you could in principle dlopen a shared object which don't have PIC (i.e. was not compiled with -fPIC); but it is much better to dlopen some PIC shared object.

Read also the Program Library HowTo and the C++ dlopen mini-howto (because of name mangling).


example

File helloshared.cc (my tiny plugin source code in C++) is

#include <iostream>
#include <string.h>
using namespace std;
extern "C" void say_hello(const char* name) {
    cout << __FILE__ << ":" << __LINE__ << " hello " 
         <<  name << "!" << endl;
}

and I am compiling it with:

g++ -Wall -fPIC -g -shared helloshared.cc -o hello.so


The main program is in file mainhello.cc :

#include <iostream>
#include <string>
#include <dlfcn.h>
#include <stdlib.h>
using namespace std;
int main() {
    cout << __FILE__ << ":" << __LINE__ << " starting." << endl;
    void* handle = dlopen("./hello.so", RTLD_LAZY);
    if (!handle) {
        cerr << "dlopen failed:" << dlerror() << endl;
        exit(EXIT_FAILURE);
    };
    // signature of loaded function
    typedef void hello_sig_t(const char*);
    void* hello_ad = dlsym(handle,"say_hello");
    if (!hello_ad) {
        cerr << "dlsym failed:" << dlerror() << endl;
        exit(EXIT_FAILURE);
    }
    hello_sig_t* fun = reinterpret_cast<hello_sig_t*>(hello_ad);
    fun("from main");
    fun = NULL; hello_ad = NULL;
    dlclose(handle);
    cout << __FILE__ << ":" << __LINE__ << " ended." << endl;
    return 0;
}

which I compile with

g++ -Wall -rdynamic -g mainhello.cc -ldl -o mainhello


Then I am running ./mainhello with the expected output:

mainhello.cc:7 starting.
helloshared.cc:5 hello from main!
mainhello.cc:24 ended.


Please notice that the signature hello_sig_t in mainhello.cc should be compatible (homomorphic, i.e. the same as) with the function say_hello of the helloshared.cc plugin, otherwise it is undefined behavior (and you probably would have a SIGSEGV crash).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!