在Mac OS X上的共享库中隐藏符号 [英] Hiding symbols in a shared library on Mac OS X
问题描述
我们一直在各种平台(Linux,Windows,Mac OS X)上构建大型开源软件 ,32位和64位)持续了数年之久.但是,最近,Mac OS X版本(64位)停止正常工作,并开始随机崩溃.或多或少与我们的构建机器上的Mac OS X从10.7更新到10.8.2(但编译器工具链没有改变,它仍然是llvm-gcc 4.2.1).
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. Lately however, the Mac OS X build (64-bit) stopped working correctly and started to crash randomly. 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).
我们的应用程序由几个动态(共享)库和许多使用它们的可执行文件组成.出于多种原因,共享库之一覆盖了new
和delete
运算符.在Mac OS X(和Linux)上,默认情况下会导出所有符号,包括重载的new
和delete
运算符. Mac OS X上的崩溃似乎与向一个内存子系统(不是我们的内存子系统)分配一些内存,然后通过我们自己的(且不兼容的)delete
实现释放了内存有关.
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. On Mac OS X (and Linux), all symbols are exported by default, including our overloaded new
and delete
operators. 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.
最明智的解决方案似乎是防止重载的运算符对共享库的用户可见.这可以通过两种方式完成:用__attribute__((visibility("hidden")))
标记运算符,或使用-unexported_symbols_list
链接器命令行选项以防止某些符号被导出.不幸的是,第一个解决方案不起作用:gcc发出警告,指出已以不同的方式声明了运算符(在<new>
中),因此该属性将被忽略.根据我在各地的阅读,第二种解决方案似乎是解决此问题的正确方法.但是由于某些原因,我们无法使其正常工作.
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. 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. 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.
在链接共享库时,我们将-Wl,-unexported_symbols_list unexported_symbols_list.txt
选项传递给g ++,该选项又应传递给ld. unexported_symbols_list.txt
文件包含以下符号列表:
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. The unexported_symbols_list.txt
file contains the following list of symbols:
__ZdaPv
__ZdaPvRKSt9nothrow_t
__ZdlPv
__ZdlPvRKSt9nothrow_t
__ZdlPvS_
__Znam
__ZnamRKSt9nothrow_t
__Znwm
__ZnwmPv
__ZnwmRKSt9nothrow_t
这些是我们覆盖并希望隐藏的所有new
和delete
变体.我们通过执行nm libappleseed.dylib
然后使用c++filt
取消符号名称来找到这些符号.
These are all the variations of new
and delete
that we override and want to be hidden. We found these symbols by doing nm libappleseed.dylib
then unmangling the symbol names using c++filt
.
这是CMake生成的链接libappeseed.dylib
的命令行:
Here's the command line generated by CMake to link 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 [...]
不幸的是,尽管我们付出了所有努力,但这些符号似乎仍然存在(如nm所示).
知道我们在做什么错吗? 还有其他方法可以尝试吗?
Any idea what we are doing wrong? Is there another approach that we could try?
2012年12月19日更新:
Apple的以下技术说明很好地涵盖了我们的问题和假定的解决方案:
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").
指向相关源代码的指针:
Pointers to relevant source code:
-
operator new
和operator delete
覆盖: dllvisibility.h
operator new
andoperator delete
overrides: allocator.cpp- Macros to control symbol visibility in the shared library: dllvisibility.h
使用-fvisibility=hidden
构建libappleseed.dylib并运行strip -x libappleseed.dylib
之后,nm
的输出片段:
Fragment of nm
's output after building libappleseed.dylib with -fvisibility=hidden
and running strip -x libappleseed.dylib
:
...
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
...
推荐答案
您应该使用-fvisibility=hidden
进行构建,然后仅导出所需的内容.在这里阅读:
You should be building with -fvisibility=hidden
and then export only what you want. Have a read here:
http://gcc.gnu.org/wiki/Visibility
它也解释了-fvisibility-inlines-hidden
.许多大型库(例如Qt)都利用了这一点.好处是相当可观的.
It also explains -fvisibility-inlines-hidden
. Many large libraries (Qt, for example) make use of this. The benefits are quite substantial.
这篇关于在Mac OS X上的共享库中隐藏符号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!