在Mac OS X上的共享库中隐藏符号 [英] Hiding symbols in a shared library on Mac OS X

查看:226
本文介绍了在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).

我们的应用程序由几个动态(共享)库和许多使用它们的可执行文件组成.出于多种原因,共享库之一覆盖了newdelete运算符.在Mac OS X(和Linux)上,默认情况下会导出所有符号,包括重载的newdelete运算符. 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

这些是我们覆盖并希望隐藏的所有newdelete变体.我们通过执行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 and operator 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆