Linux AMD64 中如何使用 fs/gs 寄存器?
- 2024-10-11 08:36:00
- admin 原创
- 76
问题描述:
在 x86-64 架构上,有两个寄存器有特殊用途:FS 和 GS。在 linux 2.6.* 中,FS 寄存器似乎用于存储线程本地信息。
那正确吗?
fs:0 中存储了什么?是否有任何 C 结构描述此内容?
那么 GS 有什么用呢?
解决方案 1:
在 x86-64 中有3 个 TLS 条目,其中两个可通过FS 和 GS访问, FS 由 glibc 内部使用(在 IA32 中,显然FS 由 Wine 使用,而 GS 由 glibc 使用)。
Glibc 将其 TLS 入口点指向包含一些线程内部结构的 。Glibc 通常将变量struct pthread
称为,大概是pthread 描述符。struct pthread
`pd`
在 x86-64 上,struct pthread
以 开头tcbhead_t
(这取决于架构,请参阅宏TLS_DTV_AT_TP
和TLS_TCB_AT_TP
)。此线程控制块头(AFAIU)包含一些即使在单线程时也需要的字段。DTV 是动态线程向量,包含指向通过 加载的 DSO 的 TLS 块的指针。在 TCB 之前或之后,有一个静态 TLS 块,用于可执行文件和在(程序的)加载时链接的 DSO。TCB 和 DTV 在Ulrich Drepper 的 TLS 文档dlopen()
中得到了很好的解释(请查看第 3 章中的图表)。
解决方案 2:
实际回答您的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 寄存器本身读取地址。
解决方案 3:
那么 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
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件