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

Kon*_*nko 9 assembly x86-64 nasm

NASM返回如下错误:"在64位模式下不支持指令",我无法弄清楚要做什么.

主题说明pop ecxpush ecx说明.我可以使用什么代替它们,还是有其他方法来解决这个问题?

Mat*_*lia 19

一般的想法是你通常推送和弹出完整的寄存器,即64位模式的64位寄存器. push默认操作数大小为64位,32位操作数大小不可用. 每个PUSH指令是否在x64上推送8个字节的倍数?(是的,除非您专门使用16位推送,但32位不可用).

你不能在64位模式下推送32位寄存器; 相反,你可以推送和弹出包含你想要的32位值的整个64位寄存器,这样就可以push raxpush eax.对于内存引用也是如此 - 你可以push qword ptr[rax],但不是push dword ptr[rax].

但是:即使在64位模式下,您仍然可以推送:

  • 8或32位立即标志扩展到64; 这通常由汇编程序自动处理为优化(如果你这样做push 1,将使用最紧凑的编码对其进行编码6A01,即使用imm8操作数).除非您明确指定push word 1,否则始终是64位推送,无论汇编程序选择何种宽度.

  • fsgs段寄存器 而不是所述cs,ds,es,ss寄存器(其不是在64位模式下重要的是,并且只可以与被读取mov,而不是push,释放那些潜在的未来使用压入/弹出操作码).

    作为一个例外,段寄存器是扩展或在16位移动的情况下被压入堆栈(即堆栈中的另一个48位未被修改); 这是不是真的太大的问题,因为pop fspop gs刚丢弃这些额外的比特.

您可以push imm64使用push low32/ 模拟一个mov dword [rsp+4], high32.或者用mov r64, imm64/ push r64; mov注册(不是内存)是唯一可以立即采用64位的x86-64指令.


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

  • 16位寄存器(push ax)和存储器引用(push word ptr[rax]);
  • 8位符号扩展或16位立即.

8位寄存器不能在任何模式下被推送(除了作为更宽寄存器的一部分),并且即使使用REX.W=0前缀,32位也不能在64位模式下使用.

  • @RudyVelthuis,你不能在x64中推送eax`的原因是x64中`push r64`的编码与x86中`push r32`的编码相同.即`push reg`意味着`push native_register_size`.否则就需要扩展指令集.天知道x64已经有足够的指令了.16/8位推送已经存在,因此这些保留为遗留. (3认同)