The*_*Neo 35 architecture linux x86 assembly x86-64
在x86-64架构中,两个寄存器具有特殊用途:FS和GS.在linux 2.6.*中,FS寄存器似乎用于存储线程本地信息.
nin*_*alj 37
在x86-64中有3个TLS条目,其中两个可通过FS和GS访问,FS由glibc内部使用(在IA32中,显然FS由Wine使用,而glibc使用FS).
Glibc使其TLS入口点struct pthread
包含一些用于线程的内部结构.Glibc通常指的是一个struct pthread
变量pd
,大概是对于pthread描述符.
在x86-64上,struct pthread
以a开头tcbhead_t
(这取决于体系结构,请参阅宏TLS_DTV_AT_TP
和TLS_TCB_AT_TP
).该线程控制块头(AFAIU)包含一些即使存在单个线程也需要的字段.DTV是动态线程向量,包含指向通过加载的DSO的TLS块的指针dlopen()
.在TCB之前或之后,存在用于在(程序)加载时链接的可执行文件和DSO的静态TLS块.在Ulrich Drepper的TLS文档中很好地解释了TCB和DTV (在第3章中查找图表).
Muh*_*rma 16
要真正回答你的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;
}
Run Code Online (Sandbox Code Playgroud)
编译成
f:
movq %fs:0, %rax
leaq -4(%rax), %rax
retq
g:
movl %fs:-4, %eax
retq
Run Code Online (Sandbox Code Playgroud)
i686做同样但有%gs
.在aarch64上,这不是必需的,因为可以从tls寄存器本身读取地址.
那么GS有什么用呢?
x86_64 Linux 内核使用 GS 寄存器作为获取系统调用的内核空间堆栈的有效方式。
GS 寄存器存储每个 cpu 区域的基地址。获取内核空间堆栈,在entry_SYSCALL_64中
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
Run Code Online (Sandbox Code Playgroud)
展开 PER_CPU_VAR 后,我们得到以下内容:
movq %gs:cpu_current_top_of_stack, %rsp
Run Code Online (Sandbox Code Playgroud)