问题描述
在Intel's manual for Intel 64 and IA-32 instruction set部分3.1.1.5中,它在指令汇总表中引入了64/32位模式列。
对于 64 位模式支持,它说:
- I - 不支持
- 东北- 表示指令语法在 64 位模式下不可编码(它可能代表其他模式下有效指令序列的一部分
一条指令在 64 位模式下不可编码和一条指令在 64 位模式下不支持有什么区别?
解决方法
目前尚不完全清楚英特尔正在做出什么区别,或者做出这种区别为何有用1。看起来 Invalid 仅用于将#UD(非法指令错误)的操作码,这就是他们使用 N.E.即使在没有其他方法来编码具有该操作数大小的指令的情况下。
东北...它可能代表其他模式
中有效指令序列的一部分这是有道理的,如果他们说“在这个模式下”,我认为匹配他们的文档。例如0x1F
是 not a valid opcode or prefix in 64-bit mode,但在其他模式下表示 pop ds
。
脚注 1:当然,没有未来证明#UD 出现故障的保证 - 未来 CPU 上的未来 ISA 扩展可以将未使用的操作码重新用于 64-位模式,有效地将 Invalid 变为 NE (面向未来的#UD 方法是the 0F 0B
opcode,documented as ud2
)
Invalid 的一个例子是 64 位模式下的 aam
(立即除法):在该模式下根本没有指令的编码,并且操作码未使用。
NE 的一个例子是 inc r32
short form 0x40+rd,64 位模式将其(连同 0x48+rd dec
)重新用作 REX 前缀。 inc eax
也是可编码的,但不能使用 那个 操作码。
同样,inc r/m64
被列为 N.E.对于兼容/传统模式;即它仅在长模式下可用,通过 REX 前缀。
pop
在一张表中包含这两种类型的示例:
- 不再有任何方法可以使用任何操作数大小来执行
pop ds
(或 ES/SS),并且这些操作码被释放以供将来使用,因此它在 64 位模式下是“无效的”。 (pop cs 从未有效,除了一些未记录的/早期 8086;只有像 retf 这样的东西将 CS:[ER]IP 设置在一起,而不仅仅是 CS。) -
pop fs
和 GS 可以使用 16 位或 64 位操作数大小完成,但不能使用 32 位,因此
"0F A1 POP FS
... 将栈顶弹出到 FS;将栈指针增加 32 位"
表的一行有 N.E.对于 64 位模式,对 compat/legacy 有效。而 ... by 64 bits 行是相反的,对 64 有效,对 32 无效。(有趣的是,当 RSP 以字节为单位时,他们写的是“by 64 bits”而不是“by 8”,不是位。)
pop r32
和 pop r/m32
都列为 N.E.对于 64 位模式,并非无效,尽管在该模式下无法对 pop eax
或 pop dword [rdi]
进行编码。 所以看起来 Invalid 是关于操作码,而不是指令。
(对于默认为 64 的操作码,即使 REX.W=0 也不会将操作数大小覆盖为 32 位,但是 66
操作数大小前缀确实像往常一样工作以进行推送/弹出16 位。尽管“描述”文本说操作数大小可能被 REX.W 覆盖 - 这似乎是在谈论一般指令,正如当前代码段的 D 标志所暗示的那样。)
也许是因为 64 位模式仍然可以使用相同的操作码弹出其他 2 种大小(64 位或 16 位)?或者其他 2 种尺寸的 r/m 带流行音乐?例如pop ax
和 pop word [rdi]
在 64 位模式下有效,当然还有 pop rax
。
这与他们列出 pop ds
的方式一致。
我想知道 movsxd r64,r/m32
是 Invalid 还是 N.E.在 16/32 位模式下,因为相同的操作码在 64 位模式之外具有不同的含义(ARPL r,r/m16 - http://ref.x86asm.net/coder32.html#x63)。
但它只是 N.E.对于 32 位模式,movsxd r32,r/m32
对于这两种模式都被列为“有效”! 这一定是一个错误,因为它显然是错误的。兼容/传统模式下的操作码 63
是 ARPL。 (被列为 N.E. (64) / Valid (32),其操作部分提到 movsxd 用于 64 位模式。)所以 N.E.将匹配他们将其用于具有其他含义但没有错的事物的模式。
(现实世界的汇编器,如 NASM 和 YASM,即使在 64 位模式下也拒绝 movsxd eax,ecx
;他们想要一个 64 位目标,拒绝让您将其用作更糟的 mov eax,ecx
,即使那样 在机器代码中是可能的,但英特尔的手册不鼓励这样做。不幸的是,movsxd
需要一个 REX 前缀来满足其唯一目的:将 32 符号扩展到 64。不是堆栈或分支操作 I猜测 AMD 决定将操作数大小默认为 64 位更加一致。)