次の単純な共有ライブラリ ソース コードを考えてみましょう。
ライブラリ.cpp:
static int global = 10;
int foo()
{
return global;
}
-fPIC
clangでオプションを指定してコンパイルすると、次のオブジェクト アセンブリが生成されます (x86-64):
foo(): # @foo()
push rbp
mov rbp, rsp
mov eax, dword ptr [rip + global]
pop rbp
ret
global:
.long 10 # 0xa
シンボルはライブラリ内で定義されているため、コンパイラは予想どおり PC 相対アドレッシングを使用しています。mov eax, dword ptr [rip + global]
ただし、外部リンケージを持つシンボルに変更static int global = 10;
すると、結果のアセンブリは次のようになります。int global = 10;
foo(): # @foo()
push rbp
mov rbp, rsp
mov rax, qword ptr [rip + global@GOTPCREL]
mov eax, dword ptr [rax]
pop rbp
ret
global:
.long 10 # 0xa
ご覧のとおり、コンパイラはグローバル オフセット テーブルを使用して間接レイヤーを追加しました。これは、シンボルが同じライブラリ (およびソース ファイル) 内で定義されているため、この場合はまったく不要に思えます。
シンボルが別の共有ライブラリで定義されている場合、GOT が必要になりますが、この場合は冗長に感じられます。コンパイラがまだこのシンボルを GOT に追加しているのはなぜですか?
注:この質問はこれに似ていると思いますが、詳細が不足しているため、回答は適切ではありませんでした.