11

私たちは、さまざまなプラットフォーム (Linux、Windows、Mac OS X、32 ビットおよび 64 ビット) で大規模なオープン ソースソフトウェアを数年間問題なく構築してきました。しかし最近、Mac OS X ビルド (64 ビット) が正しく動作しなくなり、ランダムにクラッシュするようになりました。多かれ少なかれ、ビルド マシン上の Mac OS X が 10.7 から 10.8.2 に更新されたのとほぼ一致しました (ただし、コンパイラ ツールチェーンは変更されていません。まだ llvm-gcc 4.2.1 です)。

私たちのアプリケーションは、いくつかの動的 (共有) ライブラリと、それらを使用する多くの実行可能ファイルで構成されています。共有ライブラリの 1 つは、さまざまな理由でnewand演算子をオーバーライドします。Mac OS X (および Linux) では、オーバーロードされたand演算子deleteを含むすべてのシンボルがデフォルトでエクスポートされます。Mac OS X でのクラッシュは、一部のメモリが 1 つのメモリ サブシステム (当社のものではない) に割り当てられ、独自の (互換性のない)実装によって解放されることに関連しているようです。newdeletedelete

最も健全な解決策は、オーバーロードされた演算子が共有ライブラリのユーザーに表示されないようにすることです。これは 2 つの方法で実行できます。演算子を__attribute__((visibility("hidden")))でマークするか、-unexported_symbols_listリンカー コマンド ライン オプションを使用して一部のシンボルがエクスポートされないようにします。残念ながら、最初の解決策は機能しません。gcc は、演算子が ( で<new>) 異なる方法で宣言されているため、属性が無視されるという警告を発します。さまざまな場所での私の読書から、2 番目の解決策は、この問題に対する正しい解決策のようです。しかし、何らかの理由でそれを機能させることができません

共有ライブラリをリンクするとき、-Wl,-unexported_symbols_list unexported_symbols_list.txtオプションを g++ に渡します。これは、ld に渡す必要があります。このunexported_symbols_list.txtファイルには、次のシンボルのリストが含まれています。

__ZdaPv
__ZdaPvRKSt9nothrow_t
__ZdlPv
__ZdlPvRKSt9nothrow_t
__ZdlPvS_
__Znam
__ZnamRKSt9nothrow_t
__Znwm
__ZnwmPv
__ZnwmRKSt9nothrow_t

これらは、オーバーライドして隠したい とnewのすべてのバリエーションです。を使用してシンボル名を解読し、deleteこれらのシンボルを見つけました。nm libappleseed.dylibc++filt

リンクするために 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 [...]

残念ながら、あらゆる努力にもかかわらず、シンボルは残っているようです (nm が示すように)。

私たちが間違っていることは何か分かりますか?私たちが試すことができる別のアプローチはありますか?


2012 年 12 月 19 日更新:

私たちの問題と想定される解決策は、Apple のテクニカル ノートhttp://developer.apple.com/library/mac/#technotes/tn2185/_index.html (セクション「新規/削除のオーバーライド」) で詳しく説明されています。

関連するソース コードへのポインタ:

  • operator newおよびoperator deleteオーバーライド: allocator.cpp
  • 共有ライブラリでシンボルの可視性を制御するマクロ: dllvisibility.h

nmlibappleseed.dylib をビルドし-fvisibility=hiddenて実行した後の の出力のフラグメント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
...
4

2 に答える 2

7

ビルドしてから、必要-fvisibility=hiddenなものだけをエクスポートする必要があります。ここで読んでください:

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

も解説しています-fvisibility-inlines-hidden。多くの大規模なライブラリ (Qt など) はこれを利用しています。メリットはかなり大きいです。

于 2012-12-10T10:09:31.947 に答える
0

シンボル マップ/バージョン管理 (--version-script ld オプション) を確認できます。

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

于 2012-12-19T17:25:55.610 に答える