8

次の単純な共有ライブラリ ソース コードを考えてみましょう。

ライブラリ.cpp:

static int global = 10;

int foo()
{
    return global;
}

-fPICclangでオプションを指定してコンパイルすると、次のオブジェクト アセンブリが生成されます (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 に追加しているのはなぜですか?

注:この質問はこれに似ていると思いますが、詳細が不足しているため、回答は適切ではありませんでした.

4

2 に答える 2

0

ロスリッジの回答の詳細に加えて。

これは、外部と内部のリンケージです。その変数がなければstatic、外部リンケージがあるため、他の翻訳単位からアクセスできます。他の翻訳単位は、それを宣言してextern int global;アクセスできます。

リンケージ:

外部リンク。名前は、他の翻訳単位のスコープから参照できます。外部リンケージを持つ変数と関数には言語リンケージもあり、異なるプログラミング言語で記述された翻訳単位をリンクすることができます。

名前空間のスコープで宣言された次の名前のいずれも、名前空間が名前がないか、名前のない名前空間に含まれていない限り、外部リンケージを持ちます (C++11以上):

  • 上記にリストされていない変数と関数 (つまり、静的と宣言されていない関数、静的と宣言されていない名前空間スコープの非 const 変数、および extern と宣言された変数);
于 2019-04-09T18:49:25.553 に答える