什么是 callq 指令?
What is callq instruction?
我有一些由工具生成的 x86_64 架构的 gnu 汇编代码,其中有这些说明:
movq %rsp, %rbp
leaq str(%rip), %rdi
callq puts
movl [=10=], %eax
我找不到关于 "callq" 指令的实际文档。
我看过 http://support.amd.com/TechDocs/24594.pdf 也就是 "AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions" 但他们只描述了 CALL near 和 far 指令。
我查看了 gnu 汇编程序的文档 https://sourceware.org/binutils/docs/as/index.html,但找不到详细说明它支持的指令的部分。
我知道这是对函数的调用,但我想知道详情。我在哪里可以找到它们?
只是call
。如果您希望能够在 Intel/AMD 手册中查找说明,请使用 Intel 语法反汇编。
q
操作数大小后缀在技术上确实适用(它推送一个 64 位 return 地址并将 RIP 视为 64 位寄存器),但无法用指令前缀。即 calll
和 callw
在 64 位模式下不可编码,所以一些 AT&T 语法工具将其显示为 callq
而不是 call
只是令人讨厌。这当然也适用于 retq
。
不同的工具在 32 位和 64 位模式下是不同的。 (Godbolt)
- gcc -S:总是
call
/ret
。不错
- clang -S:
callq
/retq
和 calll
/retl
。至少它一直很烦人。
objdump -d: callq
/retq
(显式 64 位)和 call
/ret
(隐式 32 位) .不一致且有点愚蠢,因为 64 位无法选择操作数大小,但 32 位可以。 (不是 有用的 选择,但是:callw
将 EIP 截断为 16 位。)
尽管另一方面,大多数指令在64位模式下的默认操作数大小(没有REX.W前缀)仍然是32。但是add , (%rdi)
需要操作数大小后缀;如果没有任何暗示,汇编程序不会为您选择 32 位。 OTOH,push
是隐含的 pushq
,即使 pushw
和 pushq
在 64 位模式下都是可编码的(and usable in practice)。
来自英特尔的指令集参考手册(上面链接):
For a near call absolute, an absolute offset is specified indirectly in a general-purpose register or a memory location (r/m16, r/m32, or r/m64).
The operand-size attribute determines the size of the target operand (16, 32 or 64 bits). When in 64-bit mode, the operand size for near call (and all near branches) is forced to 64-bits.
for rel32 ... As with absolute offsets, the operand-size attribute determines the size of the target operand (16, 32, or 64 bits). In 64-bit mode the target operand will always be 64-bits because the operand size is forced to 64-bits for near branches.
在 32 位模式下,您可以编码将 EIP 截断为 16 位的 16 位 call rel16
,或使用绝对 16 位地址的 call r/m16
。但是正如手册所说,操作数大小在 64 位模式下是固定的。
callq 指的是共享 libraries/dynamic 库中的 relocatable 调用。这个想法是推 0,然后推符号进行搜索,然后调用一个函数,以便在第一次调用时搜索它。在程序的relocatable table中,在第一次调用函数时,替换掉对函数实际位置的调用。后续调用引用在 运行 时间创建的重定位 table。
我有一些由工具生成的 x86_64 架构的 gnu 汇编代码,其中有这些说明:
movq %rsp, %rbp
leaq str(%rip), %rdi
callq puts
movl [=10=], %eax
我找不到关于 "callq" 指令的实际文档。
我看过 http://support.amd.com/TechDocs/24594.pdf 也就是 "AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions" 但他们只描述了 CALL near 和 far 指令。
我查看了 gnu 汇编程序的文档 https://sourceware.org/binutils/docs/as/index.html,但找不到详细说明它支持的指令的部分。
我知道这是对函数的调用,但我想知道详情。我在哪里可以找到它们?
只是call
。如果您希望能够在 Intel/AMD 手册中查找说明,请使用 Intel 语法反汇编。
q
操作数大小后缀在技术上确实适用(它推送一个 64 位 return 地址并将 RIP 视为 64 位寄存器),但无法用指令前缀。即 calll
和 callw
在 64 位模式下不可编码,所以一些 AT&T 语法工具将其显示为 callq
而不是 call
只是令人讨厌。这当然也适用于 retq
。
不同的工具在 32 位和 64 位模式下是不同的。 (Godbolt)
- gcc -S:总是
call
/ret
。不错 - clang -S:
callq
/retq
和calll
/retl
。至少它一直很烦人。 objdump -d:
callq
/retq
(显式 64 位)和call
/ret
(隐式 32 位) .不一致且有点愚蠢,因为 64 位无法选择操作数大小,但 32 位可以。 (不是 有用的 选择,但是:callw
将 EIP 截断为 16 位。)尽管另一方面,大多数指令在64位模式下的默认操作数大小(没有REX.W前缀)仍然是32。但是
add , (%rdi)
需要操作数大小后缀;如果没有任何暗示,汇编程序不会为您选择 32 位。 OTOH,push
是隐含的pushq
,即使pushw
和pushq
在 64 位模式下都是可编码的(and usable in practice)。
来自英特尔的指令集参考手册(上面链接):
For a near call absolute, an absolute offset is specified indirectly in a general-purpose register or a memory location (r/m16, r/m32, or r/m64). The operand-size attribute determines the size of the target operand (16, 32 or 64 bits). When in 64-bit mode, the operand size for near call (and all near branches) is forced to 64-bits.
for rel32 ... As with absolute offsets, the operand-size attribute determines the size of the target operand (16, 32, or 64 bits). In 64-bit mode the target operand will always be 64-bits because the operand size is forced to 64-bits for near branches.
在 32 位模式下,您可以编码将 EIP 截断为 16 位的 16 位 call rel16
,或使用绝对 16 位地址的 call r/m16
。但是正如手册所说,操作数大小在 64 位模式下是固定的。
callq 指的是共享 libraries/dynamic 库中的 relocatable 调用。这个想法是推 0,然后推符号进行搜索,然后调用一个函数,以便在第一次调用时搜索它。在程序的relocatable table中,在第一次调用函数时,替换掉对函数实际位置的调用。后续调用引用在 运行 时间创建的重定位 table。