例如,给定一个十六进制: 83 E4 F0
通过查看英特尔开发人员手册,我可以弄清楚这83
意味着. 看着,我可以解码源/目标寄存器是 SP 或 ESP。and
FO
-16
E4
因此,我可以得出结论,十六进制表示要么and $-16, %ESP
要么and $-16, %SP
。但是,在手册中,这两者都被列为83 /4 ib
.
我怎样才能区分这两者?
例如,给定一个十六进制: 83 E4 F0
通过查看英特尔开发人员手册,我可以弄清楚这83
意味着. 看着,我可以解码源/目标寄存器是 SP 或 ESP。and
FO
-16
E4
因此,我可以得出结论,十六进制表示要么and $-16, %ESP
要么and $-16, %SP
。但是,在手册中,这两者都被列为83 /4 ib
.
我怎样才能区分这两者?
正如哈罗德所说,默认操作数大小未在指令中编码,但取决于当前处理器模式。
在实模式和 16 位保护模式下,默认操作数大小为 16 位,因此83 E4 F0
解码为and $-16, %sp
.
在 32 位模式下,操作数大小默认为 32 位,所以它是and $-16, %esp
.
在 x64 模式下,大多数指令再次默认为 32 位操作数大小(分支和间接使用堆栈的指令除外,例如推送、弹出、调用和返回),因此它再次解码为and $-16, %esp
.
可以使用前缀覆盖默认操作数大小。例如,前缀 66h 在 32 位和 16 位操作数大小之间切换,因此66 83 E4 F0
解码为and $-16, %esp
16 位模式和and $-16, %sp
32 位或 64 位模式。要获得 64 位操作数大小,您需要使用设置了 W 位的REX 前缀,因此48 83 E4 F0
解码为and $-16, %rsp
(但仅限于 64 位模式!)。
在保护模式下,只能是 32 位版本,16 位和 64 位版本都需要前缀大小覆盖字节,在这种情况下,16 位版本需要 0x66 前缀覆盖,所以你得到66:83 E4 F0
. 英特尔在 AND 的描述中明确说明了这一点:
在 64 位模式下,指令的默认操作大小为 32 位。
以及 066H 的参考,第 2.2.1 章:
操作数大小覆盖前缀允许程序在 16 位和 32 位操作数大小之间切换。任何一种尺寸都可以是默认值;使用前缀选择非默认大小。