情景:
可执行文件通过dlopen在运行时加载共享对象。
共享对象引用一些实际编译为主可执行文件的符号(函数)。
如果我在链接可执行文件时将-dynamic添加到gcc,这样可以正常工作。
-rdynamic导出可执行文件的所有非静态符号。我的共享对象只需要少数几个。
问题:有没有办法实现-rdynamic的效果,但是限制了我知道共享对象需要的几个选择符号?
编辑:
至少有两个人误解了这个问题,所以我试着澄清一下:
这个问题是关于从主可执行文件中导出符号。
关于从动态库导出符号,这个问题不。
这是一个最小的例子:
func.h,公共头文件
#include <stdio.h>
void func(void);
main.c,主要可执行代码:
#include <dlfcn.h>
#include "func.h"
// this function is later called by plugin
void func(void) {
printf("func\n");
}
int main() {
void * plugin_lib = dlopen("./plugin.so", RTLD_NOW);
printf("dlopen -> %p, error: %s\n", plugin_lib, dlerror());
// find and call function "plugin" in plugin.so
void (*p)(void); // declares p as pointer to function
p = dlsym(plugin_lib, "plugin");
p();
return 0;
}
plugin.c,运行时加载的插件的代码:
#include "func.h"
void plugin()
{
printf("plugin\n");
func();
}
如果我用
编译$ gcc -o main main.c -ldl
$ gcc -shared -fPIC -o plugin.so plugin.c
然后无法加载plugin.so,因为它引用了无法解析的符号func:
$ ./main
dlopen -> (nil), error: ./plugin.so: undefined symbol: func
Segmentation fault (core dumped)
我可以通过使用-rdynamic编译来说服主可执行文件导出其所有全局符号:
$ gcc -rdynamic -o main main.c -ldl
$ ./main
dlopen -> 0x75e030, error: (null)
plugin
func
但这会使所有符号不必要地填充动态符号表。
(可以使用nm -D main
检查此动态符号表。)
问题是,如何只将“func”添加到主可执行文件的动态符号表中,而不是一切。
答案 0 :(得分:1)
不幸的是,对于可执行文件来说,实现这一目标更加困难。您需要生成要导出的符号列表,然后将-Wl,--dynamic-list=symfile.txt
添加到LDFLAGS
。
Here's example如何在Clang中完成它(以及here用于生成符号文件的脚本。)
答案 1 :(得分:0)
您可以使用GCC的visibility属性来执行此操作。
使用__attribute__ ((visibility ("default")))
标志声明导出所需的函数。然后编译整个库,将-fvisibility=hidden
参数传递给GCC。
有关此问题的完整说明,请参阅以下GCC documentation page。