私のアプリは、静的な初期化コードを含むライブラリを dlopens します。他のすべてのライブラリは同じことを行い、以前は正常にロードされていましたが、別のライブラリから関数を呼び出すと、これは死んでしまいます。これは次のようなものです:
0x12311 <-- bad address
_static_initialization_0 <-- function call
....
dlopen
これで、逆アセンブリでの関数呼び出しは次のようになります
call _Z6MyFuncRA37_Kc@plt
ただし、この呼び出しは無効なアドレス 0x12311 を呼び出すことになります。つまり、PLT エントリが間違ったアドレスを取得します。
この問題は、問題のライブラリがサードパーティのものである可能性が非常に高いです。つまり、他のライブラリに依存しているにもかかわらず、ビルド済みのバイナリ形式で提供されている可能性があります。先週、大幅な最適化を行い、多くのヘッダーなどを変更しました。PLT が間違っている関数 MyFunc は、大規模な最適化変更を行った (別の) ライブラリにあります。
これはどのように可能ですか?正確な質問は次のとおりです。
- PLTミスマッチを引き起こすメカニズムは何ですか
- プリコンパイルされたライブラリに触れずに修正する方法はありますか-再構築されたバージョンを入手できるためオプションですが、なぜクラッシュするのかまだ興味があります
また、同じアプリが -O2 最適化でコンパイルすると正常に動作します。これは、私が奇妙と呼んでいるものです (バイナリ ライブラリはどちらの場合も同じです)。
PS ubuntu 12.04 x86_64 ですが、アプリは i386 です。
更新: LD_DEBUG をチェックするためのコメント (何らかの理由で削除された) の提案は良かったです。
10272: /media/EXT/work/build32/bin/libMyLib.so: error:
symbol lookup error: undefined symbol: omp_set_num_threads (fatal)
そして、 libMyLib.so シンボルのバインドを停止しますが、失敗していないバージョンでは他のシンボルのバインドを続けます。しかし、その後実行を継続して親ライブラリをロードしようとする理由がわかりません。実際には、スキームは次のとおりです。
libA -> libB -> libMyLib
libMyLib は (上記の LD_DEBUG 出力で示されているように) 失敗するため、それと libB を完全に (!) スキップし、libA シンボルのバインドを続行します。障害のないバージョンは、libMyLib シンボルを完全にロードし、次に libB シンボル、次に libA シンボルをロードします。
率直に言って、ldバグのように見えます。
最適化されたバージョンが機能する理由については、omp_ メソッドは実際には必要なく、リンカーの最適化によってスローされるため、実行時に必ず見つかると思います。
libC の omp_ シンボルが見つからなかった後の LD_DEBUG=all ログに表示される内容は次のとおりです。
19225: symbol=omp_set_num_threads; lookup in file=/usr/lib/i386-linux-gnu/libXdmcp.so.6 [0]
19225: /media/EXT/Work/libC.so: error: symbol lookup error: undefined symbol: omp_set_num_threads (fatal)
19225:
19225: file=/media/EXT/libA.so [0]; destroying link map
19225:
19225: file=/media/EXT/libA.so [0]; dynamically loaded by /media/EXT/libX.so [0]
19225: file=/media/EXT/libA.so [0]; generating link map
19225: dynamic: 0xf2fdb764 base: 0xf2f81000 size: 0x00064a28
19225: entry: 0xf2f8ffd0 phdr: 0xf2f81034 phnum: 7
19225:
19225: checking for version `GCC_3.0' in file /lib/i386-linux-gnu/libgcc_s.so.1 [0] required by file /media/EXT/libA.so [0]
... few more checking
19225: object=/media/EXT/libA.so [0]
19225: scope 0: bin/mainapp /lib/i386-linux-gnu/libpthread.so.0 /media/EXT/libX.so ...
19225: scope 1:...
19225:
19225:
19225: relocation processing: /media/EXT/libA.so
19225: symbol=_ZTVN10__cxxabiv117__class_type_infoE; lookup in file=bin/mainapp [0]
19225: symbol=_ZTVN10__cxxabiv117__class_type_infoE; lookup in file=/lib/i386-linux-gnu/libpthread.so.0 [0]
19225: symbol=_ZTVN10__cxxabiv117__class_type_infoE; lookup in file=/media/EXT/libX.so [0]
19225: binding file /media/EXT/libA.so [0] to /media/EXT/libX.so [0]: normal symbol `_ZTVN10__cxxabiv117__class_type_infoE'
... here it continues to bind libA symbols, and after finishing that
19225:
19225:
19225: calling init: /media/EXT/libC.so
19225:
初期化されていない libC.so モジュールに対して init を呼び出します。
(libX.so は dlopen を呼び出す基本モジュールであり、他のすべてのライブラリで使用される基本的なメソッドも含まれています。)
libA のリンク マップを破棄した後、再度生成されたことがログに示されます。ローダーが libA をロードし続けるのか、今回は libB/libC を気にせずにゼロから開始するのかわかりません。まあ、libC に対して init が呼び出されるまでは、いずれにしても libB/libC を無視します。