64 位模式不支持 32 位 PUSH 和 POP 指令 [重复]

Posted

技术标签:

【中文标题】64 位模式不支持 32 位 PUSH 和 POP 指令 [重复]【英文标题】:64-bit mode does not support 32-bit PUSH and POP instructions [duplicate] 【发布时间】:2017-09-12 03:26:44 【问题描述】:

NASM 返回如下错误:“64 位模式不支持指令” (或使用 YASM,invalid size for operand 1

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

【问题讨论】:

显示您的代码,否则问题将无效。 Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers 【参考方案1】:

一般的想法是您通常推送和弹出完整的寄存器,即 64 位模式下的 64 位寄存器。 push 的默认操作数大小为 64 位,32 位操作数大小不可用。 Does each PUSH instruction push a multiple of 8 bytes on x64?(是的,除非您专门使用 16 位推送,但 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 操作数)。它是always a 64-bit push unless you explicitly specify push word 1,不管汇编器选择什么宽度。

fsgs 段寄存器但不是csdsesss 寄存器(这在 64 位模式下并不重要, 并且只能使用mov 读取,而不是push,释放这些推送/弹出操作码以备将来使用)。

作为一个例外,段寄存器要么扩展,要么以 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 位推送/弹出在 64 位模式下不可用,even with a REX.W=0 prefix。

【讨论】:

除了你可以推送 r/m16 和 r/m64 但不能推送 r/m32 之外,你可以推送 imm8、imm16 和 imm32 但不能推送 imm64 的事实也很奇怪。而且你不能推CS、DS、ES或SS,但你可以推FS和GS。非常不一致,IMO。 @RudyVelthuis:它相当不一致,尽管这种疯狂有一点方法。无法推送 imm64 与指令集的其余部分模糊一致 - 我所知道的唯一接受 imm64 的指令是 mov r64, imm64(实际上,它是英特尔手册中整个指令集描述中 imm64 的唯一匹配项)。除了 fsgs 之外的段寄存器在 64 位模式下不再使用,因此无法推送也就不足为奇了。 我理解“疯狂背后的方法”。但有时它会变得相当混乱。尤其是您可以推送/弹出 16 位但不能推送 32 位项目的事实。 @RudyVelthuis,您不能在 x64 中使用 push eax 的原因是 x64 中 push r64 的编码与 x86 中 push r32 的编码相同。 IE。 push reg 表示 push native_register_size。否则将需要扩展指令集。天知道 x64 已经有足够多的指令了。 16/8 位推送已经存在,因此保留为旧版。 @Johan:当查看带有操作码的指令表时,我明白这一点。但无论出于何种原因,它都会变得越来越令人困惑。

以上是关于64 位模式不支持 32 位 PUSH 和 POP 指令 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

为啥英特尔微处理器的 64 位模式不支持 MOV AH,1?

是否可以在支持Intel IA-32e模式的操作系统中运行16位代码?

为啥 .NET 不支持 32 位的 SSE(而 ryujit 64 位可以)而 Mono 支持 32 位和 64 位?

32位和64位有啥区别 32位和64位区别都有哪些

32位软件和64位软件有区别吗?

32位和64位的区别