私が取り組んでいる問題のあるケースで、Linuxボックスでのダイナミックリンカー/ローダーの動作を理解したいと思います。
クラッシュするコードはプラグイン (dlopen(libwrapper.so, RTLD_GLOBAL)) として読み込まれます。libwrapper.so は、実際の仕事をする別のプラグインをロードする単なる薄いレイヤーです。これらのプラグインには、P1 および P2 という名前を付けることができます。これらはそれぞれ、F と呼ばれる共通のライブラリに依存します (すべて非常に単純化されています)。
ラッパー (libwrapper.so) が導入され、RTLD_GLOBAL なしで Pn をロードできるようになりました。これは、このフラグを設定すると、Pn をロードする明らかなリンケージの問題が発生するためです (それらは同じ API を持っています)。ターゲット プラットフォームが古すぎるため、RTLD_DEEPBIND はオプションではありません。サポートされていません。
驚いたことに、この問題は P2 のロード時に F ライブラリに現れます (P1 が既にロード (および初期化) されており、F がその暗黙的な依存関係として存在する場合)。P2 が明示的にロードされた時点 (dlopen(libP2.so, RTLD_LOCAL | RTLD_NOW)) では、動的リンカーは問題を報告しませんが、F 内でコードを呼び出して F 内で定義されたいくつかの型インスタンスを (再び) インスタンス化すると、さまざまな場所でセグメンテーション違反が発生します ( 1 つがスキップされたり、コメントアウトされたりすると、別の場所でクラッシュします。そのため、より一般的な問題や誤解が疑われるため、問題となる可能性のあるコード パターンの調査に時間をかけませんでした)。インライン関数は使用されていません。コードは -Wl、-E、可視性のデフォルトでリンクされています。GCC は 3.4.4 です。F コードは非常に安定しており、スタンドアロン アプリ内またはプラグインの一部として過去に使用されていました。
F をスタティック ライブラリとしてリンクして、ダイナミック リンカの問題を回避しようと考えましたが、結果は同じです。
このトピックに関する私の見解:
- F をダイナミック ライブラリとしてリンクすると、ダイナミック リンカは P2 をロードする 2 回目に F を参照し、参照カウンタをインクリメントするだけで静的イニシャライザを呼び出さず (これは問題ありません)、再配置を行います (これも問題があるようです)。 .
- F をスタティック ライブラリとしてリンクすると、ダイナミック リンカーが F コードを P2 (P2F) の静的にリンクされた部分としてロードし、P2F 内で再配置を行います。ただし、「どういうわけか」F の一般的なシンボルは、P1F コード インスタンスで台無しになります。
コードを少なくとも機能させるための回避策に関する仮定:
- P1 ... Pn を単一の共有ライブラリ (単一のプラグイン) にリンクします。F が共有されているか静的であるかは問題ではありません。このようにして、再配置は一度だけ行われます。
トピックに関する私の見解が間違っている/単純化しすぎている/重要な部分が欠落しているなどのフィードバックをいただければ幸いです。これは、過去の既知の GCC / binutils バグですか?