链接共享库时限制符号的可见性

有些平台要求您向链接器提供共享库的外部符号列表。 但是,在大多数unixish系统中,这是不必要的:默认情况下,所有非静态符号都将可用。

我的理解是,GNU工具链可以select性地将可见性限制在显式声明的符号上。 那怎么能用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() 。 创build一个“版本脚本” 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链接器脚本来完成,但是我不太了解。

生成的调用任何导出的函数或使用任何导出的全局variables的代码比那些没有导出的代码效率要低。 还有一个额外的间接水平涉及。 这适用于可能编译时导出的任何函数。 gcc仍然会为链接器脚本稍后未导出的函数生成额外的间接寻址。 因此,使用可见性属性将产生比链接器脚本更好的代码。

如果你使用的是libtool,还有另外一个select就像俄罗斯人的回答。

用他的例子,就是这样的:

 cat export.sym bar baz 

然后使用以下选项运行libtool:

 libtool -export-symbols export.sym ... 

请注意,在使用-export-symbols时,所有符号默认情况下都不会被导出,只有export.sym中的符号才会被导出(所以libfoo.version中的“local:*”行实际上是隐式的)。