繁体   English   中英

限制Linux静态库中的符号

[英]Restricting symbols in a Linux static library

我正在寻找限制导出到Linux静态库(存档)的C符号数量的方法。 我想将这些仅限于那些属于该库官方API的符号。 我已经使用'static'将大多数函数声明为static,但是这会将它们限制为文件范围。 我正在寻找一种限制图书馆范围的方法。

我可以使用Ulrich Drepper的“ 如何编写共享库”中的技术为共享库执行此操作,但我无法将这些技术应用于静态存档。 在他早期的图书馆设计良好实践论文中,他写道:

唯一的可能性是使用'ld -r'将需要某些内部资源的所有目标文件合并为一个,然后限制由此组合目标文件导出的符号。 GNU链接器可以选择执行此操作。

谁能帮助我发现这些选项可能是什么? 我在'strip -w -K prefix_ *'上取得了一些成功,但这感觉很野蛮。 理想情况下,我想要一个适用于GCC 3和4的解决方案。

谢谢!

对于使用GCC 3.x或4.x编译的代码,静态库无法执行您想要的操作。

如果您可以使用共享对象(库),GNU链接器将通过称为版本脚本的功能来执行您所需的操作。 这通常用于提供特定于版本的入口点,但是退化情况只是区分公共和私有符号而没有任何版本控制。 使用ld的--version-script =命令行选项指定版本脚本。

版本脚本的内容使得入口指向foo和bar为public并隐藏所有其他接口:

{ global: foo; bar; local: *; };

请参阅ld doc: http//sourceware.org/binutils/docs/ld/VERSION.html#VERSION

我是共享库的主要倡导者,这种限制全局变量可见性的能力是他们的伟大优点之一。

提供共享对象的更多优点但是为Solaris编写的文档(由Greg Nakhimovsky撰写的快乐记忆)位于http://developers.sun.com/solaris/articles/linker_mapfiles.html

我希望这有帮助。

我不相信GNU ld有任何这样的选择; Ulrich必须具有objcopy ,它有许多这样的选项: - --localize-hidden , - --localize-symbol=symbolname , - --localize-symbols=filename

--localize-hidden特别允许人们对暴露的符号进行非常精细的控制。 考虑:

int foo() { return 42; }
int __attribute__((visibility("hidden"))) bar() { return 24; }

gcc -c foo.c
nm foo.o
000000000000000b T bar
0000000000000000 T foo

objcopy --localize-hidden foo.o bar.o
nm bar.o
000000000000000b t bar
0000000000000000 T foo

因此bar()不再从对象中导出(即使它仍然存在并可用于调试)。 您也可以使用objcopy --strip-unneeded删除bar()

这个答案的优点将取决于您使用静态库的原因。 如果允许链接器稍后删除未使用的对象,那么我几乎无法添加。 如果它是为了组织的目的 - 最小化必须传递给链接应用程序的对象的数量 - 这种对Employed Russian的答案的扩展可能是有用的。

在编译时,可以使用以下命令设置编译单元中所有符号的可见性:

-fvisibility=hidden
-fvisibility=default

这意味着可以编译具有默认可见性的单个文件“interface.c”和具有隐藏可见性的大量实现文件,而无需注释源。 然后,可重定位链接将生成单个目标文件,其中非api函数被“隐藏”:

ld -r interface.o implementation0.o implementation1.o -o relocatable.o

现在可以对组合的目标文件进行objcopy:

objcopy --localize-hidden relocatable.o mylibrary.o

因此,我们有一个目标文件“library”或“module”,它只公开预期的API。


上述策略与链接时间优化适度地相互作用。 使用-flto编译并通过编译器将-r传递给链接器来执行可重定位链接:

gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o

使用objcopy像以前一样本地化隐藏的符号,然后最后一次调用链接器来剥离本地符号以及它可以在post-lto对象中找到的任何其他死代码。 遗憾的是,relocatable.o不太可能保留任何与lto相关的信息:

gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o

lto的当前实现在可重定位链接阶段期间似乎是活动的。 使用lto,隐藏的=>本地符号被最终的可重定位链接剥离。 没有lto,hidden => local符号在最终的可重定位链接中幸存下来。

lto的未来实现似乎可能通过可重定位链接阶段保留所需的元数据,但是目前可重定位链接的结果似乎是一个普通的旧目标文件。

这是对EmployedRussian和JonChesterfield的答案的改进,如果您同时生成动态和静态库,这可能会有所帮助。

从标准机制开始,用于在DSO中隐藏符号(lib的动态版本)。 使用-fvisibility=hidden编译所有文件。 在定义API的头文件中,更改要公开的类和函数的声明:

   #define DLL_PUBLIC __attribute__ ((visibility ("default")))
   extern DLL_PUBLIC int my_api_func(int);

详情请见此处 这适用于C和C ++。 这对于DSO来说已足够,但您需要为静态库添加以下构建步骤:

ld -r obj1.o obj2.o ... objn.o -o static1.o
objcopy --localize-hidden static1.o static2.o
ar -rcs mylib.a static2.o

ar步骤是可选的 - 您只需链接static2.o

我这样做的方法是使用INTERNAL标记不要导出的所有内容,包括保护所有.h文件,使用-DINTERNAL =编译dev版本,并使用包含所有其他库.c文件的单个.c文件编译发布版本with -DINTERNAL = static。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM