如何在Linux AMD64中使用fs/gs寄存器?

The*_*Neo 35 architecture linux x86 assembly x86-64

在x86-64架构中,两个寄存器具有特殊用途:FS和GS.在linux 2.6.*中,FS寄存器似乎用于存储线程本地信息.

  • 那是对的吗?
  • 什么存储在fs:0?是否有描述此内容的C结构?
  • 那么GS的用途是什么?

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_TPTLS_TCB_AT_TP).该线程控制块头(AFAIU)包含一些即使存在单个线程也需要的字段.DTV是动态线程向量,包含指向通过加载的DSO的TLS块的指针dlopen().在TCB之前或之后,存在用于在(程序)加载时链接的可执行文件和DSO的静态TLS块.在Ulrich Drepper的TLS文档中很好地解释了TCB和DTV (在第3章中查找图表).

  • 在x86上win32使用FS来指向windows线程信息 - wine只是匹配它. (2认同)

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寄存器本身读取地址.


fir*_*iro 7

那么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)

  • 当然,它在“swapgs”之后执行此操作,将 gs 段基数设置为*内核的* GS 值,而不是用户空间的值。从用户空间进入时,“%gs”仍然是用户空间设置的!(`swapgs` 和 `syscall` 是由 AMD 设计的,可以像这样一起使用。) (9认同)