这只是call
。如果您想查看英特尔/ AMD手册中的说明,请使用英特尔语法反汇编。
q
操作数大小后缀在技术上适用(它推送64位返回地址并将RIP视为64位寄存器),但无法用指令前缀覆盖它。即calll
和callw
不能在64位模式下编码,所以它只是令人讨厌的是一些AT语法工具将其显示为callq
而不是call
。这当然也适用于retq
。
不同的工具在32位和64位模式下有所不同。 (Godbolt)
- GCC -S:总是
call
/ret
。尼斯。
- 铿-S:
callq
/retq
和calll
/retl
。至少它一直很烦人。
objdump -d:callq
/retq
(显式64位)和call
/ret
(隐含于32位)。不一致和有点愚蠢,因为64位没有操作数大小的选择,但是32位。 (不是有用选择,虽然:callw
截断EIP到16位)
尽管在另一方面,默认的操作数大小(没有REX.W前缀)在64位模式最指令仍然是32.但是add $1, (%rdi)
需要操作数大小的后缀;如果没有任何暗示,汇编器将不会为你选择32位。 OTOH,push
暗含为pushq
,即使pushw $1
和pushq $1
都是可编码的(and usable in practice)在64位模式下。
从Intel的指令集REF手册(上面链接):
对于近呼叫绝对的,绝对是在通用寄存器或内存位置间接地指定的偏移量(r/m16,r/m32或r/m64)。 操作数大小属性决定了目标操作数的大小(16,32或64位)。在64位模式下,近端调用(和所有近端分支)的操作数大小被强制为64位。
for rel32 ...与绝对偏移量一样,操作数大小属性决定了目标操作数(16,32或64位)的大小。 在64位模式下,目标操作数将始终为64位,因为操作数大小在接近分支时被强制为64位。
在32位模式中,可以编码一个16位call rel16
该截断EIP到16位,或使用一个绝对的16位地址的call r/m16
。但是如手册所述,操作数大小在64位模式下是固定的。
我很好奇,@彼得,为什么你经常发表你的答案作为评论而不是答案。 – prl
@prl:我这样做的时候,我认为他们可能是重复的,但我没有花时间去寻找重复目标。我会看看这个;如果它不是重复的,那么值得写出真实的答案。你说得对,我可以把它作为答案。 –
@prl:我没有发现任何关于'callq'的具体问题。实际上有些非明显的东西可以说明分支和其他堆栈指令的默认操作数大小。这是一个新手问题,但实际上值得回应改变的是,如果我停止对所有不良行为表现出脾气暴躁的“我的代码不起作用,我什么都不知道”的问题。 –