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

Gia*_*sio 2 c assembly gcc x86-64

在x86_64上,我正在玩一个不支持多线程的玩具操作系统.

我尝试将两个全局寄存器变量关联到%gs和%fs,这样:

register Foo* foo asm("gs");
register Bar* bar asm("fs");
Run Code Online (Sandbox Code Playgroud)

但GCC抱怨"gs"和"fs"不是有效的注册名称.

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

这种方式可以使用这些寄存器吗?
此外,我已经阅读了 amd64中这些寄存器的问题,但是我无法理解那里指出的问题:它是一个GCC错误还是在amd64中使用寄存器变量的问题?

fuz*_*fuz 5

兼容80386的CPU有六个段寄存器,分别命名为cs,ds,ss,es,fs和gs.这些段寄存器用于称为分段的特征,并且基本上充当指向段描述符表的指针,其表达式隐含地添加在地址计算中.

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

  • 段寄存器cs在获取指令时使用,ds在获取数据时使用,ss在从堆栈中获取数据时(即相对于esp或ebp),es与某些指令(如scasb)一起使用.在几乎每个带有内存操作数的指令中,您都可以覆盖解析地址的段.
  • 更改cs用于在操作系统之间在实模式,16位保护模式,32位保护模式和长模式之间切换.在Windows上,这也可以由应用程序完成(但不建议这样做).通过远程跳转或呼叫来改变cs.
  • OpenBSD通过设置cs的长度限制来实现执行防止方案(W ^ X),这样就不会同时写入和执行任何数据.
  • fs和gs段在默认情况下从不使用,通常用于实现线程本地存储.您可以使用arch_prctlLinux上的系统调用设置与fs和gs相关联的偏移量,但请记住,这样做会破坏libc对这些段描述符的段描述符表中存储的偏移量的期望,并可能使基本设施成为可能如errno无法使用.
  • 在长模式(64位模式)下,整个分段机制不可用.可以使用fs和gs但是它们的值不会在段描述符表中查找,而是有两个特殊寄存器,其中内核存放一个偏移量,只要使用fs和gs就会添加该偏移量.所有其他机制都不可用.

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

  • 如上所述:在段描述符表中没有相应条目的情况下将值写入这些寄存器会导致异常.请参见段寄存器(包括fs和gs)作为MMU配置的一部分.你不能只是将它们用于任意目的,它们每个只能保存2个字节的数据.但是,您可以为TLS使用设置fs或gs,然后使用其描述符指向变量的内存区域.这称为线程本地存储,非常易于使用. (3认同)