AMDREX在开发 64 位 x86 扩展时需要一些空间来为前缀和其他一些新指令添加新的操作码。他们将一些操作码的含义更改为那些新指令。
其中一些指令只是现有指令的缩写形式,或者没有必要。PUSHA是受害者之一。目前尚不清楚他们为什么禁止PUSHA,但它似乎没有与任何新的指令操作码重叠。也许它们是保留的PUSHA和POPA操作码以供将来使用,因为它们是完全冗余的,不会更快,也不会在代码中出现足够频繁而无关紧要。
的顺序PUSHA是指令编码的顺序:eax, ecx, edx, ebx, esp, ebp, esi, edi. 请注意,它是多余的推esp!你需要知道esp才能找到它推送的数据!
如果您要从 64 位转换代码,那么PUSHA代码无论如何都不好,您需要更新它以将新寄存器推送到r8thru r15。xmm8您还需要通过保存和恢复更大的 SSE 状态xmm15。假设你要破坏它们。
如果中断处理程序代码只是一个转发到 C 代码的存根,则不需要保存所有寄存器。您可以假设 C 编译器将生成将保留rbx、rbp、rsi、rdi和r12thru的代码r15。您应该只需要保存和恢复rax, rcx,rdx和r8thru r11。(注意:在 Linux 或其他 System V ABI 平台上,编译器将保留rbx, rbp, r12- r15,您可以期待rsi并rdi破坏)。
段寄存器在长模式下没有任何值(如果被中断的线程在 32 位兼容模式下运行,您必须保留段寄存器,感谢 ughoavgfhw)。实际上,它们摆脱了长模式下的大部分分段,但FS仍保留给操作系统用作线程本地数据的基地址。寄存器值本身无关紧要, 和 的基数是通过 MSR 和 设置FS的。假设您不会使用,则无需担心,只需记住 C 代码访问的任何线程本地数据都可能使用任何随机线程的 TLS。请注意这一点,因为 C 运行时库将 TLS 用于某些功能(例如:strtok 通常使用 TLS)。GS0xC00001000xC0000101FS
将值加载到FSor GS(即使在用户模式下)将覆盖FSBASEor GSBASEMSR。由于某些操作系统GS用作“处理器本地”存储(它们需要一种方法来为每个 CPU 提供指向结构的指针),因此它们需要将其保存在不会因GS在用户模式下加载而受到破坏的地方。为了解决这个问题,为GSBASE寄存器保留了两个 MSR:一个是活动的,一个是隐藏的。在内核模式下,内核GSBASE保存在通常的GSBASEMSR 中,而用户模式库保存在另一个(隐藏)中GSBASEMSR。当上下文从内核模式切换到用户模式上下文时,以及保存用户模式上下文并进入内核模式时,上下文切换代码必须执行 SWAPGS 指令,该指令交换可见和隐藏GSBASEMSR 的值。由于内核GSBASE在用户模式下安全地隐藏在另一个 MSR 中,因此用户模式代码无法GSBASE通过将值加载到GS. 当 CPU 重新进入内核模式时,上下文保存代码将执行SWAPGS并恢复内核的GSBASE.