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 ecx
和push 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
,不管汇编器选择什么宽度。
fs
和 gs
段寄存器但不是cs
、ds
、es
、ss
寄存器(这在 64 位模式下并不重要, 并且只能使用mov
读取,而不是push
,释放这些推送/弹出操作码以备将来使用)。
作为一个例外,段寄存器要么零扩展,要么以 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]
);
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 的唯一匹配项)。除了 fs 和 gs 之外的段寄存器在 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位代码?