In Intel's manual for Intel 64 and IA-32 instruction set section 3.1.1.5, it introduces 64/32-bit mode column in the instruction summary table.
For 64-bit mode support, it says:
- I - Not supported
- N.E. - Indicates an instruction syntax is not encodable in 64-bit mode (it may represent part of a sequence of valid instructions in other modes
What is the difference between an instruction is not encodable in 64-bit mode, and an instruction is not supported in 64-bit mode?
It's not totally clear exactly what distinction Intel is making, or why it's useful to make that distinction1. It looks like Invalid is only used for opcodes that will #UD (illegal instruction fault), which is why they use N.E. even in cases where there's no other way to encode the instruction with that operand-size.
N.E. ... it may represent part of a sequence of valid instructions in other modes
This would make sense and I think match their docs if they said "in this mode". e.g. 0x1F
is not a valid opcode or prefix in 64-bit mode, but in other modes means pop ds
.
Footnote 1: Of course there's no future-proof guarantee of faulting with #UD - a future ISA extension on future CPUs could repurpose unused opcodes for something in 64-bit mode, effectively changing Invalid to N.E. (The future-proof way to #UD is the 0F 0B
opcode, documented as ud2
)
An example of Invalid is aam
(immediate division) in 64-bit mode: there's no encoding of the instruction at all in that mode, and the opcode is unused.
An example of N.E. is the inc r32
short form 0x40+rd which 64-bit mode repurposed (along with 0x48+rd dec
) as REX prefixes. inc eax
is also encodeable, but not with that opcode.
Similarly, inc r/m64
is listed as N.E. for compat/legacy mode; i.e. it's only available in long mode, via a REX prefix.
pop
has examples of both kinds in one table:
pop ds
(or ES/SS) with any operand-size, and those opcodes are freed up for future use, so it's "invalid" in 64-bit mode. (pop cs has never been valid, except for some undocumented / early 8086; only stuff like retf which sets CS:[ER]IP together not just CS.)pop fs
and GS can be done with 16-bit or 64-bit operand-size, but not 32-bit, so the0F A1 POP FS
... Pop top of stack into FS; increment stack pointer by 32 bits"pop r32
and pop r/m32
are both listed as N.E. for 64-bit mode, not invalid, despite the fact that there's no way to encode pop eax
or pop dword [rdi]
in that mode. So it's looking like Invalid is about the opcode, not the instruction.
(Even a REX.W=0 doesn't override the operand size to 32-bit for opcodes where the default is 64, but a 66
operand-size prefix does work as usual to make push/pop 16-bit. This is despite the "description" text saying operand-size may be overridden by REX.W - that seems to be talking about instructions in general, as implied by the current code-segment's D flag.)
Perhaps because 64-bit mode can still pop the other 2 sizes (64 or 16-bit) with the same opcode? Or the other 2 sizes of r/m with pop? e.g. pop ax
and pop word [rdi]
are valid in 64-bit mode along with pop rax
of course.
This is consistent with how they listed pop ds
.
I wondered whether movsxd r64, r/m32
would be Invalid or N.E. in 16/32-bit mode, because the same opcode has a different meaning outside of 64-bit mode (ARPL r,r/m16 - http://ref.x86asm.net/coder32.html#x63).
But instead it's only N.E. for 32-bit mode and movsxd r32, r/m32
is listed as "valid" for both modes! That has to be a bug because it's obviously wrong. Opcode 63
in compat/legacy mode is ARPL. (Which is listed as N.E. (64) / Valid (32), and whose Operation section mentions movsxd for 64-bit mode.) So N.E. would match their pattern of using that for things which mean something else but don't fault.
(Real-world assemblers like NASM and YASM reject movsxd eax, ecx
even in 64-bit mode; they want a 64-bit destination, refusing to let you use it as a worse mov eax, ecx
even though that is possible in machine code, but Intel's manual discourages that. movsxd
unfortunately needs a REX prefix to serve its only purpose: sign-extend 32 to 64. Not being a stack or branch op I guess AMD decided it was more consistent for the operand-size to default to 64-bit.)