如何将全局寄存器变量关联到 %gs(或 %fs)?

How can I associate a global register variable to %gs (or %fs)?

在 x86_64 我正在玩一个不支持多线程的玩具 OS。

我尝试将两个 global register variables 关联到 %gs 和 %fs,这样:

register Foo* foo asm("gs");
register Bar* bar asm("fs");

但是 GCC 抱怨 "gs" 和 "fs" 不是有效的寄存器名称。

我尝试使用其他寄存器(例如 r12 和 r15)并编译。 我尝试使用 %gs 和 %fs,但编译错误仍然存​​在。

是否可以这样使用这些寄存器?
此外 I've read about issues with these registers 在 amd64 中,但我无法理解那里指出的问题:它是 GCC 错误还是在 amd64 中使用寄存器变量的问题?

一个 80386 兼容 CPU 有六个 段寄存器 命名为 cs、ds、ss、es、fs 和 gs。这些段寄存器用于称为 segmentation 的功能,基本上充当指向 段描述符 table、 的指针,其指针是隐式的添加到地址计算中。

这些段寄存器实际上不能用于保存任意数据,因为除了某些特定的方式(les 和朋友)将值加载到其中会导致加载无效值时出现异常。它们用于以下目的:

  • 段寄存器cs用于获取指令,ds用于获取数据,ss用于从堆栈获取数据(即相对于esp或ebp),es与某些指令结合使用,如scasb。在几乎每条带有内存操作数的指令中,您都可以覆盖地址解析所针对的段。
  • 改变cs用于操作系统在实模式、16位保护模式、32位保护模式和长模式之间切换。在 Windows 上,这也可以由应用程序完成(但不推荐)。改变cs是通过跳远或call来完成的。
  • OpenBSD 通过对 cs 设置长度限制来实现执行预防方案 (W^X),因此没有数据同时是 writable 和 executable。
  • 默认情况下从不使用 fs 和 gs 段,通常用于实现 thread-local storage。您可以使用 Linux 上的 arch_prctl 系统调用来设置与 fs 和 gs 关联的偏移量,但请记住,这样做会破坏 libc 对段描述符中存储的偏移量的期望 table 用于这些段描述符,可能会使 errno 等基本设施无法使用。
  • 在长模式(64位模式)下,整个分段机制不可用。 fs 和 gs 可以使用,但它们的值不会在段描述符 table 中查找,而是有两个特殊的寄存器,内核在其中存放一个偏移量,每当使用 fs 和 gs 时都会添加该偏移量。所有其他机制都不可用。

这是一个简化的描述,实际上有点复杂。