链接共享库时限制符号的可见性
-
10-07-2019 - |
题
某些平台要求您向链接器提供共享库的外部符号列表。但是,在大多数不需要的unixish系统上:默认情况下,所有非静态符号都可用。
我的理解是GNU工具链可以选择性地将可见性限制为显式声明的符号。如何使用GNU ld实现这一目标?
解决方案
GNU ld
可以在ELF平台上实现。
以下是如何使用链接器版本脚本执行此操作:
/* foo.c */
int foo() { return 42; }
int bar() { return foo() + 1; }
int baz() { return bar() - 1; }
gcc -fPIC -shared -o libfoo.so foo.c && nm -D libfoo.so | grep ' T '
默认情况下,导出所有符号:
0000000000000718 T _fini
00000000000005b8 T _init
00000000000006b7 T bar
00000000000006c9 T baz
00000000000006ac T foo
假设您只想导出bar()
和baz()
。创建<!>“版本脚本<!>”; libfoo.version
:
FOO {
global: bar; baz; # explicitly list symbols to be exported
local: *; # hide everything else
};
将其传递给链接器:
gcc -fPIC -shared -o libfoo.so foo.c -Wl,--version-script=libfoo.version
观察导出的符号:
nm -D libfoo.so | grep ' T '
00000000000005f7 T bar
0000000000000609 T baz
其他提示
我认为最简单的方法是将-fvisibility=hidden
添加到gcc选项中,并明确地在代码中公开一些符号(通过__attribute__((visibility("default")))
)。请参阅此处文档。
可能有一种方法可以通过ld链接器脚本实现这一点,但我对此并不了解。
为调用任何导出函数或使用任何导出的全局变量而生成的代码效率低于未导出的函数。涉及额外的间接水平。这适用于在编译时间可能导出的任何函数。 gcc仍然会为稍后由链接描述文件导出的函数产生额外的间接。因此,使用visibility属性将产生比链接器脚本更好的代码。
如果您使用libtool,还有另一个选项,就像Employed Russian的回答一样。
使用他的例子,它将是:
cat export.sym
bar
baz
然后使用以下选项运行libtool:
libtool -export-symbols export.sym ...
请注意,使用-export-symbols时,默认情况下不会导出所有符号,只导出export.sym中的符号(因此libfoo.version中的<!> quot; local:* <!> \ n>行是实际上隐含在这种方法中。)
不隶属于 StackOverflow