29

Linux スタティック ライブラリ (アーカイブ) にエクスポートされる C シンボルの数を制限する方法を探しています。これらを、ライブラリの公式 API の一部であるシンボルのみに制限したいと思います。私はすでに「静的」を使用してほとんどの関数を静的として宣言していますが、これによりそれらがファイル スコープに制限されます。スコープをライブラリに制限する方法を探しています。

Ulrich Drepper のHow to Write Shared Librariesの手法を使用して共有ライブラリに対してこれを行うことができますが、これらの手法を静的アーカイブに適用することはできません。彼の以前のライブラリ設計のグッド プラクティスの論文で、彼は次のように書いています。

唯一の可能性は、「ld -r」を使用して特定の内部リソースを必要とするすべてのオブジェクト ファイルを 1 つに結合し、この結合されたオブジェクト ファイルによってエクスポートされるシンボルを制限することです。GNU リンカーには、まさにこれを行うためのオプションがあります。

これらのオプションが何であるかを発見するのを手伝ってくれる人はいますか? 「strip -w -K prefix_*」である程度成功しましたが、これは野蛮に感じます。理想的には、GCC 3 と 4 の両方で動作するソリューションが必要です。

ありがとう!

4

5 に答える 5

15

GNU ld にそのようなオプションがあるとは思いません。Ulrich は、 、、objcopyなどのオプションが多数ある を意味していたに違いありません。--localize-hidden--localize-symbol=symbolname--localize-symbols=filename

特に--localize-hidden、どのシンボルが公開されるかを非常に細かく制御できます。検討:

int foo() { return 42; }
int __attribute__((visibility("hidden"))) bar() { return 24; }

gcc -c foo.c
nm foo.o
000000000000000b T bar
0000000000000000 T foo

objcopy --localize-hidden foo.o bar.o
nm bar.o
000000000000000b t bar
0000000000000000 T foo

そのbar()ため、オブジェクトからエクスポートされなくなりました (まだ存在し、デバッグに使用できる場合でも)。bar()でまとめて削除することもできますobjcopy --strip-unneeded

于 2009-01-06T08:40:52.870 に答える
12

スタティック ライブラリは、GCC 3.x または 4.x でコンパイルされたコードに対して必要なことを実行できません。

共有オブジェクト (ライブラリ) を使用できる場合、GNU リンカはバージョン スクリプトと呼ばれる機能を使用して必要なことを行います。これは通常、バージョン固有のエントリ ポイントを提供するために使用されますが、縮退の場合は、バージョン管理なしでパブリック シンボルとプライベート シンボルを区別するだけです。バージョン スクリプトは、ld に対する --version-script= コマンド ライン オプションで指定されます。

エントリ ポイント foo と bar を公開し、他のすべてのインターフェイスを非表示にするバージョン スクリプトの内容:

{ global: foo; bar; local: *; };

次の ld ドキュメントを参照してください: http://sourceware.org/binutils/docs/ld/VERSION.html#VERSION

私は共有ライブラリを大いに支持しており、グローバルの可視性を制限できるこの機能は、共有ライブラリの大きな利点の 1 つです。

共有オブジェクトの利点をさらに提供するが、Solaris 用に書かれたドキュメント (幸せな思い出の Greg Nakhimovsky による) は、http: //developers.sun.com/solaris/articles/linker_mapfiles.html にあります。

これが役立つことを願っています。

于 2008-12-26T19:49:02.413 に答える
10

この回答のメリットは、静的ライブラリを使用する理由によって異なります。リンカーが未使用のオブジェクトを後でドロップできるようにする場合は、追加することはほとんどありません。アプリケーションをリンクするために渡す必要があるオブジェクトの数を最小限に抑えるという組織化の目的である場合、雇用されたロシア人の回答のこの拡張が役立つ場合があります。

コンパイル時に、コンパイル単位内のすべてのシンボルの可視性は、次を使用して設定できます。

-fvisibility=hidden
-fvisibility=default

これは、ソースに注釈を付けることなく、デフォルトの可視性で単一のファイル「interface.c」をコンパイルし、非表示の可視性で多数の実装ファイルをコンパイルできることを意味します。再配置可能なリンクは、API 以外の関数が「隠されている」単一のオブジェクト ファイルを生成します。

ld -r interface.o implementation0.o implementation1.o -o relocatable.o

結合されたオブジェクト ファイルは、objcopy を実行できるようになりました。

objcopy --localize-hidden relocatable.o mylibrary.o

したがって、目的の API のみを公開する単一のオブジェクト ファイル「ライブラリ」または「モジュール」があります。


上記の戦略は、リンク時間の最適化と適度に相互作用します。-flto を使用してコンパイルし、コンパイラを介してリンカーに -r を渡すことで、再配置可能なリンクを実行します。

gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o

以前のように objcopy を使用して非表示のシンボルをローカライズし、最後にリンカを呼び出して、ローカル シンボルと、lto 後のオブジェクトで検出された他のデッド コードを取り除きます。残念ながら、relocatable.o は lto 関連の情報を保持していない可能性があります。

gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o

lto の現在の実装は、再配置可能リンク段階でアクティブになっているように見えます。lto をオンにすると、hidden=>local シンボルが最後の再配置可能リンクによって削除されました。lto がなければ、hidden=>local シンボルは最終的な再配置可能なリンクを生き延びました。

lto の将来の実装では、再配置可能リンク ステージを通じて必要なメタデータを保持する可能性が高いようですが、現時点では、再配置可能リンクの結果は単純な古いオブジェクト ファイルのようです。

于 2015-05-12T07:50:00.500 に答える
0

私のやり方は、INTERNAL でエクスポートされないものすべてをマークし、すべての .h ファイルを保護し、開発ビルドを -DINTERNAL= でコンパイルし、リリース ビルドを他のすべてのライブラリ .c ファイルを含む単一の .c ファイルでコンパイルすることです。 -DINTERNAL=static を使用。

于 2008-12-26T17:09:01.113 に答える