共有ライブラリをリンクする際のシンボルの可視性を制限する
-
10-07-2019 - |
質問
一部のプラットフォームでは、共有ライブラリの外部シンボルのリストをリンカーに提供することが義務付けられています。ただし、ほとんどのunixishシステムでは必要ありません。すべての非静的シンボルはデフォルトで使用可能です。
私の理解では、GNUツールチェーンはオプションで、明示的に宣言されたシンボルだけに可視性を制限できるということです。 GNU ldを使用してどのように達成できますか?
解決
GNU ld
はELFプラットフォームでそれを行うことができます。
リンカーバージョンスクリプトを使用して行う方法は次のとおりです。
/* foo.c */
int foo() { return 42; }
int bar() { return foo() + 1; }
int baz() { return bar() - 1; }
gcc -fPIC -shared -o libfoo.so foo.c && nm -D libfoo.so | grep ' T '
デフォルトでは、すべてのシンボルがエクスポートされます:
0000000000000718 T _fini
00000000000005b8 T _init
00000000000006b7 T bar
00000000000006c9 T baz
00000000000006ac T foo
bar()
と baz()
のみをエクスポートするとします。 「バージョンスクリプト」を作成します; libfoo.version
:
FOO {
global: bar; baz; # explicitly list symbols to be exported
local: *; # hide everything else
};
リンカーに渡します:
gcc -fPIC -shared -o libfoo.so foo.c -Wl,--version-script=libfoo.version
エクスポートされたシンボルを見る:
nm -D libfoo.so | grep ' T '
00000000000005f7 T bar
0000000000000609 T baz
他のヒント
それを行う最も簡単な方法は、gccオプションに -fvisibility = hidden
を追加し、コード内でいくつかのシンボルを明示的に公開することです( __ attribute __((visibility(&quot ; default")))
)。ドキュメントこちらを参照してください。
ldリンカスクリプトによってそれを達成する方法があるかもしれませんが、私はそれについてあまり知りません。
エクスポートされた関数を呼び出したり、エクスポートされたグローバルを使用するために生成されたコードは、エクスポートされていないものよりも効率が低くなります。関連する間接レベルが余分にあります。これは、コンパイル時にエクスポートされる可能性のあるすべての関数に適用されます。 gccは、後でリンカースクリプトによってエクスポートされない関数に対して、追加の間接性を生成します。したがって、可視性属性を使用すると、リンカスクリプトよりも優れたコードが生成されます。
libtoolを使用している場合、Employed Russianの回答によく似た別のオプションがあります。
彼の例を使用すると、次のようになります:
cat export.sym
bar
baz
次に、次のオプションを指定してlibtoolを実行します。
libtool -export-symbols export.sym ...
-export-symbolsを使用する場合、デフォルトではすべてのシンボルはエクスポートされず、export.sym内のシンボルのみがエクスポートされることに注意してください(したがって、このアプローチではlibfoo.versionの" local:*"行が実際に暗黙的です) 。