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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6611346/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:58:48  来源:igfitidea点击:

How are the fs/gs registers used in Linux AMD64?

linuxassemblyarchitecturex86x86-64

提问by TheRealNeo

On the x86-64 architecture, two registers have a special purpose: FS and GS. In linux 2.6.*, the FS register seem to be used to store thread-local information.

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

  • Is that correct?
  • What is stored at fs:0? Is there any C structure that describe this content?
  • What is then the use of GS?
  • 那是对的吗?
  • fs:0 存储了什么?是否有任何描述此内容的 C 结构?
  • 那么GS有什么用呢?

采纳答案by ninjalj

In x86-64 there are 3 TLS entries, two of them accesible via FS and GS, FS is used internally by glibc (in IA32 apparently FS is used by Wine and GS by glibc).

在 x86-64 中有3 个 TLS 条目,其中两个可通过FS 和 GS 访问,FS 由 glibc 内部使用(在 IA32 中,Wine显然使用FS,glibc 使用 GS)。

Glibc makes its TLS entry point to a struct pthreadthat contains some internal structures for threading. Glibc usually refers to a struct pthreadvariable as pd, presumably for pthread descriptor.

Glibc 将其 TLS 入口点指向struct pthread包含一些用于线程处理的内部结构的 。Glibc 通常将一个struct pthread变量称为 as pd,大概用于pthread 描述符

On x86-64, struct pthreadstarts with a tcbhead_t(this depends on the architecture, see the macros TLS_DTV_AT_TPand TLS_TCB_AT_TP). This Thread Control Block Header, AFAIU, contains some fields that are needed even when there is a single thread. The DTV is the Dynamic Thread Vector, and contains pointers to TLS blocks for DSOs loaded via dlopen(). Before or after the TCB there is a static TLS block for the executable and DSOs linked at (program's) load time. The TCB and DTV are explained pretty well in Ulrich Drepper's TLS document(look for the diagrams in chapter 3).

在 x86-64 上,struct pthread以 a 开头tcbhead_t(这取决于体系结构,请参阅宏TLS_DTV_AT_TPTLS_TCB_AT_TP)。这个线程控制块头 AFAIU 包含一些字段,即使只有一个线程也需要这些字段。DTV 是动态线程向量,包含指向通过dlopen(). 在 TCB 之前或之后,有一个静态 TLS 块,用于在(程序)加载时链接的可执行文件和 DSO。TCB 和 DTV 在Ulrich Drepper 的 TLS 文档中得到了很好的解释(查找第 3 章中的图表)。

回答by MuhKarma

To actually answer your fs:0question: The x86_64 ABI requires that fs:0contains the address "pointed to" by fsitself. That is, fs:-4loads the value stored at fs:0 - 4. This feature is necessary because you cannot easily get the address pointed to by fswithout going through kernel code. Having the address stored at fs:0thus makes working with thread local storage much more efficient.

实际回答您的fs:0问题:x86_64 ABI 要求fs:0包含fs自身“指向”的地址。也就是说,fs:-4加载存储在 的值fs:0 - 4。这个特性是必要的,因为fs不通过内核代码就不能轻易得到指向的地址。将地址存储在fs:0使得使用线程本地存储的效率更高。

You can see this in action when you take the address of a thread local variable:

当您获取线程局部变量的地址时,您可以看到这一点:

static __thread int test = 0;

int *f(void) {
    return &test;
}

int g(void) {
    return test;
}

compiles to

编译为

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

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

i686 does the same but with %gs. On aarch64 this is not necessary because the address can be read from the tls register itself.

i686 执行相同的操作,但使用%gs. 在 aarch64 上,这不是必需的,因为可以从 tls 寄存器本身读取地址。

回答by firo

What is then the use of GS?

那么GS有什么用呢?

x86_64 Linux kernel uses GS register as a efficiency way to acquire kernel space stack for system calls.

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

GS register stores the base address for per-cpu area. To acquire the kernel space stack, in entry_SYSCALL_64

GS 寄存器存储每个 CPU 区域的基地址。获取内核空间栈,在entry_SYSCALL_64

movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp

After expanding PER_CPU_VAR, we get the following:

扩展 PER_CPU_VAR 后,我们得到以下内容:

movq    %gs:cpu_current_top_of_stack, %rsp