使用dlopen加载库时收到“未定义的符号”错误

23

我正在编写一些使用动态共享库作为插件的代码。

我的构建共享库的命令行如下:

cc -shared -fPIC -o module.so -g -Wall module.c

在这个模块中,我可以调用任何已经在主可执行文件中加载的共享库中的函数。

然而,我无法访问(导出的)可执行文件本身中的函数(我会收到“未定义符号”错误)。

我的 dlopen 调用如下:

void *handle = dlopen(plugin, RTLD_NOW);

请问有什么方法可以让我的模块回调到可执行文件,而不必将可执行文件的所有实用函数放在另一个共享库中吗?

3个回答

35

正确的解决方案是在主可执行文件的链接命令中添加-rdynamic。这将向ld添加适当的选项(当使用GNU ld时,该选项实际上是--export-dynamic)。

直接添加--export-dynamic技术上是不正确的:它是一个链接器选项,因此应该添加为-Wl,--export-dynamic或者-Wl,-E。这也比-rdynamic更不可移植(其他链接器具有等效选项,但选项本身不同)。


当使用Boost扩展时,此解决方案同样适用,因为Boost shared_library类在Linux上使用dlopen来加载库。 - Farrukh Arshad

8

我已经自己找到了答案。

我需要在主可执行文件的链接选项中添加--export-dynamic标志。

创建动态链接可执行文件时,将所有符号添加到动态符号表中。动态符号表是在运行时从动态对象可见的符号集。

如果您不使用此选项,则动态符号表通常仅包含那些由链接中提到的某些动态对象引用的符号。

如果您使用"dlopen"加载需要引用程序定义的符号而不是其他动态对象的动态对象,则在链接程序本身时可能需要使用此选项。


4
当我遇到同样的问题时,我只是采用了以下的解决方案。在加载任何插件之前,只需加载程序本身,将其符号添加到动态表中:
dlopen(NULL,RTLD_NOW|RTLD_GLOBAL);

我认为这个解决方案更好。原因是,它也可以解决同样的问题,如果你:
a)将程序(或第三方模块)链接(而不是在运行时)到共享库中,其中符号需要在动态表中;
b)无法使用 -rdynamic 标志重新编译该模块。

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