2

在 x86 汇编中,为什么我们可以eRx在 16 位“实模式”下使用,但不能rRx在 32 位模式下使用?例如:

BITS 16
mov bx, 1
mov eax, 2

将正确组装和拆卸。它可以工作,因为我之前已经反汇编了 Win2k 引导加载程序并找到了对eax.

但是,为什么没有办法,即使在 64 位处理器上,在 32 位“保护模式”下,您也无法访问rRx

4

3 回答 3

7

原因是 64 位模式在一个特定位置更改指令解码 - 即启用用于指示 64 位操作数大小/将寄存器宽度扩展到 64 位/将寄存器使用扩展到“新” R8..R15寄存器的前缀字节。这些不同于“备用大小前缀” 0x66( 32位模式。

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

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

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

      64bit 32bit option 1 32bit option 2 指令
==================================================== ===========
      fe c8 fe c8 -- dec al
   66 ff c8 66 ff c8 66 48 十进制斧头
      ff c8 ff c8 48 dec eax
   48 ff c8 -- -- 德莱克斯

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

于 2012-08-20T09:23:39.533 回答
4

通过设计,CPU 设计,您无法在非 64 位模式下访问 64 位寄存器。

您也可以通过设计以 16 位模式访问 32 位寄存器。为此,您可以使用称为操作数大小前缀( 0x66) 和地址大小前缀( 0x67) 的特殊指令前缀。

在非 64 位模式下,没有特殊的指令前缀可以到达 64 位寄存器。

在 32 位模式下没有足够的操作码/前缀编码空间来添加它,不像 386 扩展 286 时有一些未使用的字节作为前缀。

0x4?在 64 位模式下指定 64 位操作数大小所需的REX 前缀是32 位和 16 位模式下的inc/指令。decAMD64 不得不改变一些字节的含义来为他们想要的前缀腾出空间。对 32 位模式的相同更改将与现有二进制文件不兼容。

于 2012-08-20T07:59:47.310 回答
1

好吧,如果您使用的是 80286,那么它将无法正常工作!您使用的计算机是 32 位 CPU,它同时具有 16 位和 32 位寄存器,但没有 64 位寄存器。它也适用于 64 位 cpu。

于 2012-08-20T01:18:21.963 回答