What is callq instruction?

50,679

It's just call. Use Intel-syntax disassembly if you want to be able to look up instructions in the Intel/AMD manuals.

The q operand-size suffix does technically apply (it pushes a 64-bit return address and treats RIP as a 64-bit register), but there's no way to override it with instruction prefixes. i.e. calll and callw aren't encodeable in 64-bit mode, so it's just annoying that some AT&T syntax tools show it as callq instead of call. This of course applies to retq as well.

Different tools are different in 32 vs. 64-bit mode. (Godbolt)

  • gcc -S: always call/ret. Nice.
  • clang -S: callq/retq and calll/retl. At least it's consistently annoying.
  • objdump -d: callq/retq (explicit 64-bit) and call/ret (implicit for 32-bit). Inconsistent and kinda dumb because 64-bit has no choice of operand-size, but 32-bit does. (Not a useful choice, though: callw truncates EIP to 16 bits.)

    Although on the other hand, the default operand size (without a REX.W prefix) for most instructions in 64-bit mode is still 32. But add $1, (%rdi) needs an operand-size suffix; the assembler won't pick 32-bit for you if nothing implies one. OTOH, push is implicitly pushq, even though pushw $1 and pushq $1 are both encodeable (and usable in practice) in 64-bit mode.


From Intel's instruction-set ref manual (linked above):

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.

In 32-bit mode, you can encode a 16-bit call rel16 that truncates EIP to 16 bits, or a call r/m16 that uses an absolute 16-bit address. But as the manual says, the operand-size is fixed in 64-bit mode.

Share:
50,679

Related videos on Youtube

user10607
Author by

user10607

Updated on July 09, 2022

Comments

  • user10607
    user10607 almost 2 years

    I have some gnu assembler code for the x86_64 architecture generated by a tool and there are these instructions:

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

    I can not find actual documentation on the "callq" instruction.

    I have looked at http://support.amd.com/TechDocs/24594.pdf which is "AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions" but they only describe CALL near and far instructions.

    I have looked at documentation for gnu assembler https://sourceware.org/binutils/docs/as/index.html but could not find the section detailing the instructions it supports.

    I understand that its a call to a function, but I would like to know the details. Where can I find them?

    • Peter Cordes
      Peter Cordes over 6 years
      @prl: I didn't find any existing questions about callq specifically. And there is actually non-obvious stuff to say about default operand-sizes for branches and other stack instructions. This is a newbie question, but actually one that's worth answering for a change, if I stop being grumpy with all the bad "my code doesn't work and I don't know anything" questions.
  • Peter Cordes
    Peter Cordes almost 6 years
    You're describing the PLT, which Unix systems traditionally use for dynamic linking (macieira.org/blog/2012/01/…). That's optional: gcc -fno-plt does early binding, inlining an indirect callq *puts@GOT(%rip). The callq mnemonic doesn't imply use of the PLT, and is used even for calls between functions in the same file.