共享对象在主二进制文件中找不到符号,C++

14
我正在尝试为我编写的程序创建一种插件架构,而在我的首次尝试中遇到了问题。是否可以从共享对象中访问主可执行文件中的符号?我认为以下代码是可以的:
testlib.cpp:
void foo();
void bar() __attribute__((constructor));
void bar(){ foo(); }

testexe.cpp:

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

using namespace std;

void foo()
{
    cout << "dynamic library loaded" << endl;    
}

int main()
{
    cout << "attempting to load" << endl;
    void* ret = dlopen("./testlib.so", RTLD_LAZY);
    if(ret == NULL)
        cout << "fail: " << dlerror() << endl;
    else
        cout << "success" << endl;
    return 0;
}

编译环境:

g++ -fPIC -o testexe testexe.cpp -ldl
g++ --shared -fPIC -o testlib.so testlib.cpp

输出:

attempting to load
fail: ./testlib.so: undefined symbol: _Z3foov

显然,这是不行的。所以我有两个问题: 1)有没有办法使共享对象在加载自身的可执行文件时找到符号。 2)如果没有,那么使用插件的程序通常如何工作,以便能够在其程序内运行任意共享对象中的代码?

2个回答

20

尝试:

g++ -fPIC -rdynamic -o testexe testexe.cpp -ldl

如果没有使用-rdynamic(或类似的东西,比如-Wl,--export-dynamic),应用程序本身的符号将不会对动态链接可用。


2
根据https://gcc.gnu.org/onlinedocs/gcc-4.8.3/gcc/Link-Options.html,可以通过在gcc链接步骤中使用选项“-rdynamic”来实现相同的效果。 - Tom Barron
为什么要使用-fPIC呢?它创建的是可执行文件,而不是共享库。我认为-fPIC是多余的。 - Rick

1

来自The Linux Programming Interface:

42.1.6 访问主程序中的符号

假设我们使用dlopen()动态加载共享库,使用dlsym()获取该库中函数x()的地址,然后调用x()。如果x()又调用函数y(),那么y()通常会在程序加载的一个共享库中寻找。有时,我们希望x()调用主程序中实现的y()。(这类似于回调机制。)为了实现这一点,我们必须使主程序中的(全局范围)符号对动态链接器可用,通过使用链接程序时的––export–dynamic选项进行链接:

$ gcc -Wl,--export-dynamic main.c(加上其他选项和参数)

等价地,我们可以写成以下形式:

$ gcc -export-dynamic main.c

使用任意一种选项都允许动态加载的库访问主程序中的全局符号。

gcc –rdynamic选项和gcc –Wl,–E选项是–Wl,––export–dynamic的同义词。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接