7

サードパーティの静的ライブラリの関数を使用する共有ライブラリを作成したいと考えています。たとえばfoobarからlibfoobar.a. 私のメインアプリケーションもfooそのシンボルを使用しており、エクスポートすることを知っています。barしたがって、リンクしてコードサイズを節約し、「foo」を未解決のままにしたいだけです(メインアプリケーションによって提供されるため)。を含めるlibfoobar.aと、リンカーldは共有ライブラリに両方の関数を含めます。を含めないと、アプリケーション自体が にリンクしていないためlibfoobar.a、ライブラリは関数にアクセスできません。質問:barbar

  • 共有ライブラリを構築するときに特定のシンボルのみを解決するようにldに指示する方法はありますか?
  • 共有libfoobar.aライブラリに変わりますか?
  • barから関数を含むファイルを抽出libfoobar.aし、リンカー行でそれを指定しますか?
  • 心配する必要はありません。ランタイム ローダーはbarアプリケーションから使用するため、共有ライブラリ内の のコピーはbar読み込まれませんか?
4

3 に答える 3

4

以下の点は、私が提起した質問に答えようとするものです。

  • ldでは、静的ライブラリから特定のシンボルへのリンクを省略できないようです。--just-symbolsor --undefined(またはEXTERNリンカー スクリプト コマンド) を使用しても、 ldによるシンボルのリンクは妨げられません。
  • 静的ライブラリlibfoobar.aを共有ライブラリ libfoobar.so.1.0 に変換し、すべての可視シンボルをエクスポートします。--version-scriptおよびその他の方法を使用して、シンボルのサブセットのみをエクスポートすることもできます。

    ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archive

  • 管理しなければならない内部依存関係が存在する可能性があるため、アーカイブ メンバーを抽出するよりも、静的ライブラリのコピーからアーカイブ メンバーを削除する方が適切です。たとえば、すべてのシンボルをエクスポートすると仮定すると、メインの実行可能ファイルからマップ ファイルを生成できます。次に、実行可能ファイルがスタティック ライブラリのコピーから取得したすべてのアーカイブ メンバーを grep して、コピーから削除できます。したがって、DSO が静的ライブラリにリンクしている場合、同じシンボルが未解決のままになります。

  • オプションを使用して実行可能ファイルをコンパイルすると、メインの実行可能ファイルを DSO の共有ライブラリとして指定でき--pieます。DSO は、リンク コマンドでスタティック ライブラリの前にある場合、最初に実行可能ファイルにリンクします。注意点は、メインの実行可能ファイルがLD_LIBRARY_PATHまたはを介し​​て利用可能でなければならないということです-rpath。さらに、straceを使用すると、実行可能ファイルはライブラリの依存関係であるため、DSO のロード時に再度ロードされることがわかります。

    ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.a

  • 動的リンカーは、フラグを指定してdlopen()を呼び出さない限り、最初に実行可能ファイルのバージョンのfooを使用します。straceを使用すると、DSO 全体がmmap2()でメモリにマップされたファイルであることがわかります。ただし、ウィキペディアは、mmap について「特定の場所にアクセスした後、ディスクからの実際の読み取りは「遅延」方式で実行される」と主張しています。これが true の場合、重複したfooはロードされません。オーバーライドは、DSOが関数fooをエクスポートした場合にのみ発生することに注意してください。そうしないと、DSO がfooを呼び出すたびに、DSO に静的にリンクされた関数fooが使用されます。RTLD_DEEPBIND

結論として、mmap()が遅延読み取りを使用する場合、最善の解決策は、通常の方法で DSO をリンクし、残りは動的リンカーと Linux に任せることです。

于 2009-12-16T15:40:57.883 に答える
1

改訂されたより明確な質問に答えます。

通常、共有ライブラリのポイントは、複数のプログラムがそれに対してリンクできることです。したがって、必要な関数にメイン プログラムのシンボルを使用する最適化は、メイン プログラムが常にそのシンボルを (静的ライブラリなどを介して) 提供する場合にのみ機能します。これは通常、人々がやりたいことではありません。

それがいくつかの小さな機能である場合は、おそらくそのままにしておく必要があります。おそらく、関数のコードの 2 つのコピー (shlib に 1 つ、メイン プログラムに 1 つ) が作成されることになります。それらが小さい (または少なくとも大きくない) 場合、または頻繁に呼び出されず、パフォーマンスが重要でない場合、2 つのコピーを持つことによるコード サイズ/I キャッシュ ヒットは心配する必要はありません。(翻訳: 頭の中でそれを回避する方法がわからないので、時間をかけて調べたり、より複雑な Makefile を作成して回避したりしないかもしれません。)

静的ライブラリから何かを抽出するために ar をいじることに関するいくつかのコメントについては、私の他の回答を参照してください。要約: .a 内のさまざまな .o ファイル間の依存関係がわからないため、おそらく自明ではありません。

共有ライブラリに静的ライブラリから取り込んだシンボルをエクスポートさせることで、あなたが望んでいることを実行できるかもしれません。次に、メイン アプリをリンクするときに、リンカー コマンド ラインで静的ライブラリの前に共有ライブラリを配置します。ld は shlib で "foo" を見つけ、そのコピーを使用します (この再エクスポートのトリックが可能な場合) が、"bar" の場合は静的ライブラリからのコピーを含める必要があります。

ld --export-dynamic は、動的シンボル テーブル内のすべてのシンボルをエクスポートするために必要なものかもしれません。それを試してみてください。docs/man ページで「export」を検索します。「エクスポート」は、ライブラリでシンボルを可視化するための専門用語です。--export-all-symbols は i386 PE (windows DLL) セクションにあります。それ以外の場合は、おそらくうまくいくでしょう。

于 2009-12-07T21:16:37.537 に答える