では、GS の用途は何ですか?
x86_64 Linux カーネルは、システム コール用のカーネル空間スタックを効率的に取得する方法として GS レジスタを使用します。
GS レジスタは、CPU ごとの領域のベース アドレスを格納します。カーネル空間スタックを取得するには、entry_SYSCALL_64 で
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
PER_CPU_VAR を展開すると、次のようになります:
movq %gs:cpu_current_top_of_stack, %rsp
実際に fs:0
に答えるには 質問:x86_64 ABI では fs:0
が必要です fs
が「指す」アドレスを含む 自体。つまり、fs:-4
fs:0 - 4
に保存されている値をロードします . fs
が指すアドレスを簡単に取得できないため、この機能が必要です。 カーネルコードを介さずに。アドレスを fs:0
に格納する したがって、スレッド ローカル ストレージの操作がはるかに効率的になります。
スレッド ローカル変数のアドレスを取得すると、この動作を確認できます。
static __thread int test = 0;
int *f(void) {
return &test;
}
int g(void) {
return test;
}
にコンパイル
f:
movq %fs:0, %rax
leaq -4(%rax), %rax
retq
g:
movl %fs:-4, %eax
retq
i686 は同じことを行いますが、%gs
を使用します . aarch64 では、アドレスは tls レジスタ自体から読み取ることができるため、これは必要ありません。
x86-64 には 3 つの TLS エントリがあり、そのうちの 2 つは FS と GS を介してアクセスできます。FS は glibc によって内部的に使用されます (IA32 では明らかに FS は Wine によって使用され、GS は glibc によって使用されます)。
glibc は TLS エントリ ポイントを struct pthread
にします スレッド化のための内部構造が含まれています。 glibc は通常 struct pthread
を参照します。 pd
の変数 、おそらく pthread 記述子 .
x86-64 では、struct pthread
tcbhead_t
で始まる (これはアーキテクチャに依存します。マクロ TLS_DTV_AT_TP
を参照してください) と TLS_TCB_AT_TP
)。このスレッド制御ブロック ヘッダー、AFAIU には、スレッドが 1 つしかない場合でも必要なフィールドがいくつか含まれています。 DTV は動的スレッド ベクトルであり、dlopen()
を介してロードされた DSO の TLS ブロックへのポインタが含まれています。 . TCB の前後には、(プログラムの) ロード時にリンクされた実行可能ファイルと DSO 用の静的 TLS ブロックがあります。 TCB と DTV については、Ulrich Drepper の TLS ドキュメントでかなり詳しく説明されています (第 3 章の図を参照してください)。