在x86-64架构上,两个寄存器有一个特殊用途:FS和GS。在linux 2.6。*中,FS寄存器似乎用于存储线程本地信息。
答案 0 :(得分:37)
在x86-64中有3 TLS entries,其中两个可以通过FS and GS访问,FS由glibc内部使用(在IA32中显然是FS is used by Wine and GS by 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)包含一些即使存在单个线程也需要的字段。 DTV是动态线程向量,包含指向通过dlopen()
加载的DSO的TLS块的指针。在TCB之前或之后,存在用于在(程序)加载时链接的可执行文件和DSO的静态TLS块。 TCB和DTV在Ulrich Drepper's TLS document中得到了很好的解释(请参阅第3章中的图表)。
答案 1 :(得分:16)
要实际回答您的fs:0
问题:x86_64 ABI要求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
编译到
%gs
i686使用Conf.FilesLocation
做同样的事情。在aarch64上,这不是必需的,因为可以从tls寄存器本身读取地址。
答案 2 :(得分:2)
那么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