Linux AMD64 中如何使用 fs/gs 寄存器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6611346/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How are the fs/gs registers used in Linux AMD64?
提问by TheRealNeo
On the x86-64 architecture, two registers have a special purpose: FS and GS. In linux 2.6.*, the FS register seem to be used to store thread-local information.
在 x86-64 架构上,有两个寄存器有特殊用途:FS 和 GS。在 linux 2.6.* 中,FS 寄存器似乎用于存储线程本地信息。
- Is that correct?
- What is stored at fs:0? Is there any C structure that describe this content?
- What is then the use of GS?
- 那是对的吗?
- fs:0 存储了什么?是否有任何描述此内容的 C 结构?
- 那么GS有什么用呢?
采纳答案by ninjalj
In x86-64 there are 3 TLS entries, two of them accesible via FS and GS, FS is used internally by glibc (in IA32 apparently FS is used by Wine and GS by glibc).
在 x86-64 中有3 个 TLS 条目,其中两个可通过FS 和 GS 访问,FS 由 glibc 内部使用(在 IA32 中,Wine显然使用FS,glibc 使用 GS)。
Glibc makes its TLS entry point to a struct pthread
that contains some internal structures for threading. Glibc usually refers to a struct pthread
variable as pd
, presumably for pthread descriptor.
Glibc 将其 TLS 入口点指向struct pthread
包含一些用于线程处理的内部结构的 。Glibc 通常将一个struct pthread
变量称为 as pd
,大概用于pthread 描述符。
On x86-64, struct pthread
starts with a tcbhead_t
(this depends on the architecture, see the macros TLS_DTV_AT_TP
and TLS_TCB_AT_TP
). This Thread Control Block Header, AFAIU, contains some fields that are needed even when there is a single thread. The DTV is the Dynamic Thread Vector, and contains pointers to TLS blocks for DSOs loaded via dlopen()
. Before or after the TCB there is a static TLS block for the executable and DSOs linked at (program's) load time. The TCB and DTV are explained pretty well in Ulrich Drepper's TLS document(look for the diagrams in chapter 3).
在 x86-64 上,struct pthread
以 a 开头tcbhead_t
(这取决于体系结构,请参阅宏TLS_DTV_AT_TP
和TLS_TCB_AT_TP
)。这个线程控制块头 AFAIU 包含一些字段,即使只有一个线程也需要这些字段。DTV 是动态线程向量,包含指向通过dlopen()
. 在 TCB 之前或之后,有一个静态 TLS 块,用于在(程序)加载时链接的可执行文件和 DSO。TCB 和 DTV 在Ulrich Drepper 的 TLS 文档中得到了很好的解释(查找第 3 章中的图表)。
回答by MuhKarma
To actually answer your fs:0
question: The x86_64 ABI requires that fs:0
contains the address "pointed to" by fs
itself. That is, fs:-4
loads the value stored at fs:0 - 4
. This feature is necessary because you cannot easily get the address pointed to by fs
without going through kernel code. Having the address stored at fs:0
thus makes working with thread local storage much more efficient.
实际回答您的fs:0
问题:x86_64 ABI 要求fs:0
包含fs
自身“指向”的地址。也就是说,fs:-4
加载存储在 的值fs:0 - 4
。这个特性是必要的,因为fs
不通过内核代码就不能轻易得到指向的地址。将地址存储在fs:0
使得使用线程本地存储的效率更高。
You can see this in action when you take the address of a thread local variable:
当您获取线程局部变量的地址时,您可以看到这一点:
static __thread int test = 0;
int *f(void) {
return &test;
}
int g(void) {
return test;
}
compiles to
编译为
f:
movq %fs:0, %rax
leaq -4(%rax), %rax
retq
g:
movl %fs:-4, %eax
retq
i686 does the same but with %gs
. On aarch64 this is not necessary because the address can be read from the tls register itself.
i686 执行相同的操作,但使用%gs
. 在 aarch64 上,这不是必需的,因为可以从 tls 寄存器本身读取地址。
回答by firo
What is then the use of GS?
那么GS有什么用呢?
x86_64 Linux kernel uses GS register as a efficiency way to acquire kernel space stack for system calls.
x86_64 Linux 内核使用 GS 寄存器作为为系统调用获取内核空间堆栈的有效方式。
GS register stores the base address for per-cpu area. To acquire the kernel space stack, in entry_SYSCALL_64
GS 寄存器存储每个 CPU 区域的基地址。获取内核空间栈,在entry_SYSCALL_64
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
After expanding PER_CPU_VAR, we get the following:
扩展 PER_CPU_VAR 后,我们得到以下内容:
movq %gs:cpu_current_top_of_stack, %rsp