简体   繁体   English

在Mac OS X上隐藏共享库中的符号

[英]Hiding symbols in a shared library on Mac OS X

We've been building a large open source software on a variety of platforms (Linux, Windows, Mac OS X, 32-bit and 64-bit) for several years without troubles. 多年来,我们一直在各种平台(Linux,Windows,Mac OS X,32位和64位)上构建大型开源软件 ,没有任何问题。 Lately however, the Mac OS X build (64-bit) stopped working correctly and started to crash randomly. 然而,最近Mac OS X版本(64位)停止正常工作并开始随机崩溃。 It more or less coincided with an update of Mac OS X on our build machine from 10.7 to 10.8.2 (but the compiler toolchain didn't change, it's still llvm-gcc 4.2.1). 它或多或少与我们的构建机器上从10.7到10.8.2的Mac OS X更新一致(但编译器工具链没有改变,它仍然是llvm-gcc 4.2.1)。

Our application is made of a couple of dynamic (shared) libraries and many executables using them. 我们的应用程序由几个动态(共享)库和许多使用它们的可执行文件组成。 One of the shared library overrides the new and delete operators for a variety of reasons. 由于各种原因,其中一个共享库会覆盖newdelete运算符。 On Mac OS X (and Linux), all symbols are exported by default, including our overloaded new and delete operators. 在Mac OS X(和Linux)上,默认情况下会导出所有符号,包括我们重载的newdelete运算符。 The crashes on Mac OS X seem related to some memory being allocated with one memory subsystem (not ours) then freed through our own (and incompatible) delete implementation. Mac OS X上的崩溃似乎与一些内存子系统(不是我们的)分配的内存相关,然后通过我们自己的(并且不兼容的) delete实现释放。

The sanest solution seems to be preventing the overloaded operators from being visible to the users of the shared library. 最安静的解决方案似乎是阻止重载的操作员对共享库的用户可见。 This can be accomplished in two ways: marking the operators with __attribute__((visibility("hidden"))) , or using the -unexported_symbols_list linker command line option to prevent some symbols from being exported. 这可以通过两种方式实现:使用__attribute__((visibility("hidden")))标记运算符,或使用-unexported_symbols_list链接器命令行选项来防止导出某些符号。 The first solution unfortunately doesn't work: gcc emits warnings saying that the operators have been declared differently (in <new> ) and thus the attributes will be ignored. 遗憾的是,第一个解决方案不起作用:gcc发出警告,说操作符声明不同(在<new> ),因此属性将被忽略。 From my readings in various places, the second solution seems to be the right one to this problem. 根据我在不同地方的阅读, 第二种解决方案似乎是解决这个问题的正确方法。 However for some reason we can't make it work . 但由于某种原因,我们无法使其发挥作用

When linking the shared library, we're passing the -Wl,-unexported_symbols_list unexported_symbols_list.txt option to g++, which in turns should be passed to ld. 当链接共享库时,我们将-Wl,-unexported_symbols_list unexported_symbols_list.txt选项传递给g ++,而g ++又应该传递给ld。 The unexported_symbols_list.txt file contains the following list of symbols: unexported_symbols_list.txt文件包含以下符号列表:

__ZdaPv
__ZdaPvRKSt9nothrow_t
__ZdlPv
__ZdlPvRKSt9nothrow_t
__ZdlPvS_
__Znam
__ZnamRKSt9nothrow_t
__Znwm
__ZnwmPv
__ZnwmRKSt9nothrow_t

These are all the variations of new and delete that we override and want to be hidden. 这些是我们覆盖并希望隐藏的newdelete所有变体。 We found these symbols by doing nm libappleseed.dylib then unmangling the symbol names using c++filt . 我们通过nm libappleseed.dylib找到这些符号,然后使用c++filt解开符号名称。

Here's the command line generated by CMake to link libappeseed.dylib : 这是CMake生成的链接libappeseed.dylib的命令行:

/usr/bin/g++  -g -Werror -dynamiclib -Wl,-headerpad_max_install_names -framework Cocoa -lcurl    -Werror -Wl,-unexported_symbols_list -Wl,unexported_symbols_list.txt -o ../mac-gcc4/appleseed/libappleseed.dylib [...]

Unfortunately, despite all our efforts it appears that the symbols remain (as nm shows). 不幸的是,尽管我们付出了很多努力,但似乎仍然存在符号(如nm所示)。

Any idea what we are doing wrong? 知道我们做错了什么吗? Is there another approach that we could try? 我们可以尝试另一种方法吗?


UPDATE Dec. 19, 2012: 更新2012年12月19日:

Our problem and the supposed solution are well covered in this technical note from Apple: http://developer.apple.com/library/mac/#technotes/tn2185/_index.html (section "Overriding new/delete"). Apple的技术说明中详细介绍了我们的问题和所谓的解决方案: http//developer.apple.com/library/mac/#technotes/tn2185/_index.html (“覆盖新/删除”部分)。

Pointers to relevant source code: 指向相关源代码的指针:

Fragment of nm 's output after building libappleseed.dylib with -fvisibility=hidden and running strip -x libappleseed.dylib : 使用-fvisibility=hidden并运行strip -x libappleseed.dylib构建libappleseed.dylib后, nm输出的片段:

...
00000000002a41b0 T __ZdaPv
00000000002a41f0 T __ZdaPvRKSt9nothrow_t
00000000002a4190 T __ZdlPv
00000000002a41d0 T __ZdlPvRKSt9nothrow_t
00000000002a4060 T __Znam
00000000002a4130 T __ZnamRKSt9nothrow_t
00000000002a3ff0 T __Znwm
00000000002a40d0 T __ZnwmRKSt9nothrow_t
...

You should be building with -fvisibility=hidden and then export only what you want. 你应该用-fvisibility=hidden构建,然后只导出你想要的东西。 Have a read here: 在这里阅读:

http://gcc.gnu.org/wiki/Visibility http://gcc.gnu.org/wiki/Visibility

It also explains -fvisibility-inlines-hidden . 它还解释了-fvisibility-inlines-hidden Many large libraries (Qt, for example) make use of this. 许多大型库(例如Qt)都使用它。 The benefits are quite substantial. 好处是相当可观的。

You may take a look at symbol maps/versioning (--version-script ld option) 您可以查看符号映射/版本控制(--version-script ld选项)

http://accu.org/index.php/journals/1372 http://accu.org/index.php/journals/1372

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

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