NASM 返回错误信息: "instruction not supported in 64-bit mode"
(或者对于 YASM, invalid size for operand 1
)
这些指令是 pop ecx
和 push ecx
。
我应该使用它们的替代指令还是有其他方法可以解决这个问题?
NASM 返回错误信息: "instruction not supported in 64-bit mode"
(或者对于 YASM, invalid size for operand 1
)
这些指令是 pop ecx
和 push ecx
。
我应该使用它们的替代指令还是有其他方法可以解决这个问题?
一般想法是在64位模式下,通常需要推送和弹出完整的寄存器,即64位寄存器。push
默认的操作数大小为64位,在32位操作数大小不可用的情况下。在x64上,每个PUSH指令是否都会推送8字节的倍数?(是的,除非您特别使用16位push,但32位不可用)。
在64位模式下,您不能推送32位寄存器; 相反,您可以推送和弹出包含您想要的32位值的整个64位寄存器,因此这是push rax
而不是push eax
。对于内存引用也是同理 - 您可以push qword ptr[rax]
,但不是push dword ptr[rax]
。
但是:即使在64位模式下,您仍然可以推送:
8或32位立即数扩展为64位; 这通常由汇编器自动处理为优化(如果您执行push 1
,它将使用最紧凑的编码进行编码,这将是6A01
,即具有imm8 操作数 )。无论汇编器选择哪种立即数的宽度,始终是64位推送,除非您明确指定push word 1
。
fs
和gs
段寄存器能够使用,但不包括cs
、ds
、es
和ss
寄存器(64位模式下无关紧要,只能使用mov
指令读取,而不能使用push
指令,这样便为将来的潜在使用释放了push/pop操作码)。
异常情况下,可以使用零扩展或16位移动指令将段寄存器的值推送到栈上(即栈上的其余48位保持不变)。这并不是什么大问题,因为pop fs
和pop gs
会丢弃这些额外的位。
您可以使用push low32
/mov dword [rsp+4], high32
进行push imm64
的模拟。或者使用mov r64, imm64
/push r64
;mov
指令(不是内存)是唯一可以使用64位立即数的x86-64指令。
使用16位操作数大小(前缀66h
),可以进行16位推送,将RSP调整2而不是8。但通常不要这样做,因为它会使堆栈错位,直到您进行16位弹出或者其他纠正。
push ax
)和内存引用(push word ptr[rax]
);push word 123
除非作为更宽的寄存器的一部分,否则8位寄存器无法在任何模式下进行推送,而32位push/pop在64位模式下不可用,即使有REX.W=0
前缀。
mov r64, imm64
(实际上,在 Intel 手册中的整个指令集描述中,它是唯一匹配 imm64 的指令)。除了 fs 和 gs 之外的段寄存器在 64 位模式下不再使用,因此它们不能被推送也就不足为奇了。 - Matteo Italiapush eax
的原因是,x64中push r64
的编码与x86中的push r32
的编码相同。也就是说,push reg
意味着将native_register_size
大小的寄存器推入堆栈。如果要改变这种情况,就需要扩展指令集。而x64已经有足够多的指令了。16/8位的push
已经存在,因此它们被保留为遗留指令。 - Johanpush r32
无法编码。我认为英特尔手册中的文本措辞暗示着REX.W=0
可以将操作数大小覆盖到32位而不是默认的64位,但表格(以及在真实CPU上的测试!)表明这并非如此;请参见此答案中的脚注,以了解情况的底部。 - Peter Cordes