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

问题描述 投票:35回答:3

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

  • 那是对的吗?
  • 什么存储在fs:0?是否有描述此内容的C结构?
  • 那么GS的用途是什么?
linux assembly architecture x86 x86-64
3个回答
37
投票

在x86-64中有qazxsw poi,其中两个可通过qazxsw poi访问,FS由glibc内部使用(在IA32中显然是3 TLS entries)。

Glibc将其TLS入口指向包含一些内部结构的FS and GS。 Glibc通常将FS is used by Wine and GS by glibc变量称为struct pthread,大概是pthread描述符。

在x86-64上,struct pthreadpd开头(这取决于架构,请参阅宏struct pthreadtcbhead_t)。该线程控制块头(AFAIU)包含一些即使存在单个线程也需要的字段。 DTV是动态线程向量,包含指向通过TLS_DTV_AT_TP加载的DSO的TLS块的指针。在TCB之前或之后,存在用于在(程序)加载时链接的可执行文件和DSO的静态TLS块。在TLS_TCB_AT_TP中很好地解释了TCB和DTV(在第3章中查找图表)。


16
投票

要真正回答你的dlopen()问题:x86_64 ABI要求Ulrich Drepper's TLS document包含fs:0本身“指向”的地址。也就是说,fs:0加载存储在fs的值。此功能是必要的,因为您无法轻松获取fs:-4指向的地址而无需通过内核代码。将地址存储在fs:0 - 4可以更有效地处理线程本地存储。

获取线程局部变量的地址时,您可以看到此操作:

fs

编译成

fs:0

i686使用static __thread int test = 0; int *f(void) { return &test; } int g(void) { return test; } 做同样的事情。在aarch64上,这不是必需的,因为可以从tls寄存器本身读取地址。


2
投票

那么GS的用途是什么?

x86_64 Linux内核使用GS寄存器作为获取系统调用的内核空间堆栈的有效方法。

GS寄存器存储每个cpu区域的基址。要获取内核空间堆栈,请在entry_SYSCALL_64中

f:
    movq    %fs:0, %rax
    leaq    -4(%rax), %rax
    retq

g:
    movl    %fs:-4, %eax
    retq

扩展PER_CPU_VAR后,我们得到以下结果:

%gs
© www.soinside.com 2019 - 2024. All rights reserved.