目前尚不完全清楚英特尔正在做出何种区分,或者为什么做出这种区分是有用的1。看起来 Invalid 仅用于将 #UD(非法指令错误)的操作码,这就是他们使用 N.E. 的原因。即使在没有其他方法使用该操作数大小对指令进行编码的情况下。
N.E. ...它可能代表其他模式下一系列有效指令的一部分
这是有道理的,如果他们说“在 this 模式下”,我认为与他们的文档相匹配。例如0x1F 是 not a valid opcode or prefix in 64-bit mode,但在其他模式下意味着 pop ds。
脚注 1:当然,无法保证#UD 出现故障 - 未来 CPU 上的未来 ISA 扩展可能会将未使用的操作码重新用于 64-位模式,有效地将 Invalid 更改为 N.E. (面向未来的#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 也是可编码的,但不能使用 that 操作码。
同样,inc r/m64 被列为 N.E.对于兼容/传统模式;即它仅在长模式下可用,通过 REX 前缀。
pop 在一张表中有这两种类型的示例:
- 不再有任何方法可以对任何操作数大小执行
pop ds(或 ES/SS),并且这些操作码被释放以供将来使用,因此它在 64 位模式下是“无效的”。 (除了一些未记录的/早期的 8086 之外,pop cs 从未有效;只有像 retf 这样将 CS:[ER]IP 设置在一起的东西,而不仅仅是 CS。)
-
pop fs 和 GS 可以使用 16 位或 64 位操作数大小完成,但不能使用 32 位,所以
"0F A1 POP FS ... 将栈顶弹出到 FS;将栈指针递增 32 位"
表的行有 N.E.对于 64 位模式,对兼容/旧版有效。而 ... 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 操作数大小前缀确实可以像往常一样使 push/pop 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。不是堆栈或分支操作我猜 AMD 决定它更多操作数大小一致,默认为 64 位。)