1

「CreateObject」以外の機能を公開しないライブラリがあります。それにもかかわらず、それらの関数はすべて間接的に呼び出されるため、パフォーマンス レポートでは、最大 1.65% の時間が __i686.get_pc_thunk.bx に費やされていることがわかります。関数 (クラス メソッド) は 1 億 6000 万回呼び出され、共有ライブラリの内部にあり、公開されていません。

再配置なしで内部メソッドをコンパイルできるかどうか、つまり、相対オフセットなどを使用できるかどうか疑問に思います。

gcc は 4.5.2 です

更新: 実際には、メイクファイルに残っている -O0 が原因だと思います。今は大したことではありませんが、プロファイラーの「ガベージ」が少なくなるので、-O0 でも同じことをしたいと思います。これを行う -O2 「本当の」オプションは何ですか。

更新 2: うーん、-O2 ではなく、おそらく --dynamic-list が pc_thunk のパフォーマンス ヒットを少し下げましたが、まだ残っています... そのため、--dynamic-list が本当に役立つかどうかさえわかりません。非表示のシンボルに間接サンクを含める必要がありますか?それは正しいですか?

更新 3: テスト プロジェクトを作成しました。内部ライブラリ関数の属性の可視性を非表示に設定し、gcc 4.7 および -O2 と LTO を有効にしてコンパイルし、内部関数を含めずに --dynamic-list をリンカーに渡しましたが、それでも呼び出しget_pc_thunk にはまだあります。

これはテスト共有ライブラリのコードです:

#include <stdio.h>

__attribute__((visibility("hidden"), noinline)) void lib1f2()
{
    puts("I should have PLT disabled");
}

void lib1f()
{
    puts("I'm lib1");
    lib1f2();
}

gdb では、lib1f2 内にまだサンクが表示されます。

面白いのは、 -fwhole-program lib1f2 を使用すると、メインの実行可能ファイルにインライン化されますが、サンクへのこの呼び出しまだ含まれていることです。

更新 4: OK に近づいています (私が愚かであることを理解するために)。プログラム (および上記のコード) は、単なる const 文字列であってもデータを使用するため、GOT 呼び出しが必要です。したがって、今の質問は次のとおりです。

  1. それでも、GOT のサンクを回避できますか?
  2. (関連) おそらく -fPIC なしでコンパイルする - 欠点は何ですか?
4

3 に答える 3

1

GCC可視性サポートに興味があるかもしれません

http://gcc.gnu.org/wiki/Visibility

すべてのシンボルを非公開にするには、-fvisibility=hiddenオプションを使用できます。また、CreateObjectメソッドをpublic using attribute((visibility( "default")))としてタグ付けすることを忘れないでください。

于 2012-12-03T14:01:19.200 に答える
1

1) それでも、GOT のサンクを回避できますか?

ないと思います。少なくとも i686 ではありません。問題は、コードが相対ジャンプを自動的に実行できることです...というか、間接ジャンプIIRCを除いて、x86のすべてのジャンプは相対です。一方、現在のプログラム カウンターに関連するデータにインデックスを付ける方法はありません。この問題は、x86_64 で実際に解決されています。これは、この場合に正確に使用できる新しい命令ポインター相対アドレッシングがあるためです。

gcc -fPIC -shared -O2 -flto でコンパイルされたテスト

32 ビットの場合:

00000530 <lib1f2.2321>:
push   %ebx
call   52b <__x86.get_pc_thunk.bx>
add    $0x1aca,%ebx
sub    $0x18,%esp
lea    -0x1a67(%ebx),%eax
mov    %eax,(%esp)
call   3f0 <puts@plt>
add    $0x18,%esp
pop    %ebx
ret
00000560 <lib1f>:
push   %ebx
call   52b <__x86.get_pc_thunk.bx>
add    $0x1a9a,%ebx
sub    $0x18,%esp
lea    -0x1a4c(%ebx),%eax
mov    %eax,(%esp)
call   3f0 <puts@plt>
add    $0x18,%esp
pop    %ebx
jmp    530 <lib1f2.2321>
nop

64 ビット

00000000000006b0 <lib1f2.2352>:
lea    0x2a(%rip),%rdi
jmpq   590 <puts@plt>

00000000000006c0 <lib1f>:
lea    0x35(%rip),%rdi
sub    $0x8,%rsp
callq  590 <puts@plt>
xor    %eax,%eax
add    $0x8,%rsp
jmp    6b0 <lib1f2.2352>

2) (関連) おそらく -fPIC なしでコンパイルする - 欠点は何ですか?

恥ずかしいことですが、ここで少し混乱していることを認めなければなりません。一目見ただけで、共有ライブラリは -fPIC でコンパイルすると失敗すると言ったでしょう。代わりに、次の 2 つのコマンドはどちらも機能します

gcc -fPIC -m32 -shared -O2 -flto test.c -o test.so
gcc -m32 -shared -O2 -flto test.c -o test.so

-fPIC 以外の場合、コードは get_pc_thunk を呼び出す必要もありません。秘訣は、動的ローダーが実行時にライブラリ コードを正しいアドレスでデータに修正することです。

ただし、これは問題です。サンクを回避することで速度が向上しましたが、共有ライブラリを実際に共有する機能が失われたためです。これは、オペレーティング システムが再配置を含むライブラリのすべてのコード ページに対して新しいコピーを作成する必要があるためです。一方、GOT を使用する場合は、GOT ページのみを複製する必要があるため、多くのアプリケーションが同じライブラリにリンクする場合のメモリ フットプリントが大幅に削減されます。

興味深いことに、64 ビット モードでは非 pic モードでライブラリをコンパイルすることはできず、次のコマンドは失敗します。

gcc -m64 -shared -O2 -flto test.c -o test.so

それでも、プロセッサが提供するコード相対アドレッシングのサポートがあるため、これは問題ではありません。

于 2012-12-06T22:08:04.373 に答える
0

関数、特に で可視性属性を使用しますhidden。あなたは定義するかもしれません

 #ifdef __GNUC__
  #define MODULE_VISIBILITY  __attribute__ ((visibility ("hidden")))
 #else
  #define MODULE_VISIBILITY
 #endif

次に、関数を宣言します

 extern void MODULE_VISIBILITY my_module_fun(int);

最近の (4.6 または 4.7) GCC コンパイラを使用すると、リンク時の最適化を使用してコンパイルおよびリンクすることもできCXX= g++ -fltoますMakefile

于 2012-12-03T13:57:12.873 に答える