i386/x64 pop FS/GS 指令支持将 SP 增加 32 位或 64 位而不是 16 位的变体。它是干什么用的?

Wer*_*ner 8 x86 assembly x86-64 i386

根据英特尔® 64 位和 IA-32 架构软件开发人员手册第 2 卷,pop fs支持 3 种变体(同样适用于pop gs):

  • 将栈顶弹出到 FS;将堆栈指针增加 16 位。
  • 将栈顶弹出到 FS;将堆栈指针增加 32 位。(在兼容/腿部模式下可用)
  • 将栈顶弹出到 FS;将堆栈指针增加 64 位。(在 64 位模式下可用)

AMD64 文档操作pop没有明确描述堆栈指针会发生什么。我试图生成这些,似乎 gas 确实能识别它们(我认为它们需要 66h 前缀):

 80490d6:       0f a1                   pop    fs
 80490d8:       66 0f a1                popw   fs
 80490db:       0f a9                   pop    gs
 80490dd:       66 0f a9                popw   gs
Run Code Online (Sandbox Code Playgroud)

我正在为这些头疼。据我了解,FS 和 GS 寄存器是 16 位,我知道它们有一个隐藏部分,但我不希望pop指令能够操作这些对吗?有人可以解释这些变体的目的是什么吗?

fuz*_*fuz 9

在 32 位模式下,每个堆栈槽为 32 位。如果在压入段寄存器后必须将堆栈指针调整为 4 字节的倍数,那会很烦人,因此 CPU 提供了将段寄存器压入 4 字节堆栈槽的指令。

当以 32 位操作数大小压入段寄存器时,寄存器内容零扩展为双字。当它被弹出时,只有低两个字节被读入段寄存器。高两个字节再次被忽略。