2017-10-15 4185 views
6

我有一个工具生成的x86_64体系一些GNU汇编代码,并有以下说明:什么是callq指令?

movq %rsp, %rbp 
leaq str(%rip), %rdi 
callq puts 
movl $0, %eax 

我无法找到关于“callq”指令实际的文件。

我看过http://support.amd.com/TechDocs/24594.pdf这是“AMD64体系结构程序员手册第3卷:通用和系统指令”,但它们只描述CALL近和远指令。

我已经看过gnu assembler https://sourceware.org/binutils/docs/as/index.html的文档,但找不到详细说明它支持的说明。

我明白,它是一个函数的调用,但我想知道细节。我可以在哪里找到它们?

+0

我很好奇,@彼得,为什么你经常发表你的答案作为评论而不是答案。 – prl

+1

@prl:我这样做的时候,我认为他们可能是重复的,但我没有花时间去寻找重复目标。我会看看这个;如果它不是重复的,那么值得写出真实的答案。你说得对,我可以把它作为答案。 –

+2

@prl:我没有发现任何关于'callq'的具体问题。实际上有些非明显的东西可以说明分支和其他堆栈指令的默认操作数大小。这是一个新手问题,但实际上值得回应改变的是,如果我停止对所有不良行为表现出脾气暴躁的“我的代码不起作用,我什么都不知道”的问题。 –

回答

7

这只是call。如果您想查看英特尔/ AMD手册中的说明,请使用英特尔语法反汇编。

q操作数大小后缀在技术上适用(它推送64位返回地址并将RIP视为64位寄存器),但无法用指令前缀覆盖它。即calllcallw不能在64位模式下编码,所以它只是令人讨厌的是一些AT语法工具将其显示为callq而不是call。这当然也适用于retq

不同的工具在32位和64位模式下有所不同。 (Godbolt

  • GCC -S:总是call/ret。尼斯。
  • 铿-S:callq/retqcalll/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 $1pushq $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位模式下是固定的。

+1

我喜欢这种形式“持续烦人”。