我们如何在 16 位中使用 `e[]x` 而在 32 位中不使用 `r[]x`

Col*_*son 0 x86 assembly x86-64

那么在汇编中,如何e[]x在16位实模式下可以使用,而r[]x在32位模式下不能使用呢?例如:

BITS 16
mov bx, 1
mov eax, 2
Run Code Online (Sandbox Code Playgroud)

将在 IDA 中正确组装和反汇编(在 16 位模式下)。它可以工作,因为我之前已经反汇编了 Win2k 引导加载程序并找到了eax.

但是,为什么即使在无法访问的受保护模式下的 64 位处理器上也无法访问r[]x?

Fra*_*kH. 5

这样做的原因是 64 位模式在一个特定的地方改变了指令解码——即,启用用于指示 64 位操作数大小/将寄存器宽度扩展到 64 位/将寄存器使用扩展到“新” R8..R15寄存器的前缀字节。它们不同于“备用大小前缀” ( 0x66),后者是 x86 通用的(独立于 CPU 操作模式)并且如果在 16 位模式下将操作数/寄存器大小从 16 位更改为 32 位,反之亦然从 32 位更改为 16 位如果在32位模式。

所谓的REX前缀被编码为0x40..0x4f并且只有当 CPU 在 64 位模式下运行时才作为前缀有效。为什么呢 ?好吧 - 如前所述,改变了指令解码,这些操作码实际上映射到经典 x86中inc <reg>/ 的一字节版本dec <reg>。
这是可能的,因为在16位/ 32位指令集的模糊的-inc EAX可以是任一 0x40 或 0xff 0xc0。在 64 位模式下,指令解码器只接受0xff 0xc0这一点。另一方面,0x40如所示,成为REX前缀之一。

因此 - 这些 64 位操作数大小前缀在 16 位/32 位模式中不存在(它们是inc/dec操作然后...),因此 16 位/32 位 x86 代码无法声明“我想做一个 64 位操作” .

例如,这是一些具有不同操作数大小的指令的汇编/操作码:

      64bit 32bit option 1 32bit option 2 指令
================================================== ============
      fe c8 fe c8 -- 贴花
   66 ff c8 66 ff c8 66 48 dec ax
      ff c8 ff c8 48 dec eax
   48 ff c8 -- -- dec rax

如您所见,64 位不知道 的单字节版本dec eax,但它知道0x48作为(多个)指令前缀之一说“使其成为 64 位操作”。