64位模式不支持32位的PUSH和POP指令。

19

NASM 返回错误信息: "instruction not supported in 64-bit mode"
(或者对于 YASM, invalid size for operand 1

这些指令是 pop ecxpush ecx
我应该使用它们的替代指令还是有其他方法可以解决这个问题?


请展示您的代码,否则问题将无效。寻求调试帮助的问题(“为什么这段代码不起作用?”)必须在问题本身中包含所需的行为、具体问题或错误以及重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。 - phuclv
1个回答

30

一般想法是在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

  • fsgs段寄存器能够使用,但不包括csdsesss寄存器(64位模式下无关紧要,只能使用mov指令读取,而不能使用push指令,这样便为将来的潜在使用释放了push/pop操作码)。

    异常情况下,可以使用零扩展或16位移动指令将段寄存器的值推送到栈上(即栈上的其余48位保持不变)。这并不是什么大问题,因为pop fspop gs会丢弃这些额外的位。

您可以使用push low32/mov dword [rsp+4], high32进行push imm64的模拟。或者使用mov r64, imm64/push r64mov指令(不是内存)是唯一可以使用64位立即数的x86-64指令。


使用16位操作数大小(前缀66h),可以进行16位推送,将RSP调整2而不是8。但通常不要这样做,因为它会使堆栈错位,直到您进行16位弹出或者其他纠正。

  • 16位寄存器(push ax)和内存引用(push word ptr[rax]);
  • 带符号扩展的8位或16位立即数:push word 123

除非作为更宽的寄存器的一部分,否则8位寄存器无法在任何模式下进行推送,而32位push/pop在64位模式下不可用,即使有REX.W=0前缀


除了你可以推动r/m16和r/m64但不能推动r/m32之外,你可以推动imm8、imm16和imm32但不能推动imm64也很奇怪。而且你不能推动CS、DS、ES或SS,但你可以推动FS和GS。在我看来相当不一致。 - Rudy Velthuis
1
@RudyVelthuis:虽然有点混乱,但其中有一些条理。无法推送 imm64 与其余指令集中存在某种模式 - 我所知道的唯一接受 imm64 的指令是 mov r64, imm64(实际上,在 Intel 手册中的整个指令集描述中,它是唯一匹配 imm64 的指令)。除了 fsgs 之外的段寄存器在 64 位模式下不再使用,因此它们不能被推送也就不足为奇了。 - Matteo Italia
我理解这种“疯狂背后的方法”。但有时候会变得非常混乱。特别是你可以推送/弹出16位但不能推送/弹出32位项目的事实。 - Rudy Velthuis
3
你不能在x64中使用push eax的原因是,x64中push r64的编码与x86中的push r32的编码相同。也就是说,push reg意味着将native_register_size大小的寄存器推入堆栈。如果要改变这种情况,就需要扩展指令集。而x64已经有足够多的指令了。16/8位的push已经存在,因此它们被保留为遗留指令。 - Johan
@Johan:当查看带有操作码的指令表时,我明白了这一点。但是无论原因何在,它变得越来越令人困惑。 - Rudy Velthuis
@RudyVelthuis:同意;我发现在x86-64模式下,push r32无法编码。我认为英特尔手册中的文本措辞暗示着REX.W=0可以将操作数大小覆盖到32位而不是默认的64位,但表格(以及在真实CPU上的测试!)表明这并非如此;请参见此答案中的脚注,以了解情况的底部。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接