5

Is there any condition where the return address is not pushed into stack during a function call in x86 architecture?

phuclv
  • 37,963
  • 15
  • 156
  • 475
balajimc55
  • 2,192
  • 2
  • 13
  • 15
  • If you want to do a function call without stack access you might (miss-)use the "syscall" or "sysenter" instructions. – Martin Rosenau Nov 13 '15 at 07:03
  • "During a function call": if you avoid the `call` instruction itself, you can tailcall with `jmp` which doesn't push anything. – Peter Cordes Apr 14 '21 at 04:59

1 Answers1

11

No. CALL will, by definition, push the return address onto the stack before jumping to the target address. That return address is EIP (or RIP) + sizeof(call instruction) (usually 5 bytes.)

Volume 2 of the Intel® 64 and IA-32 Architectures Software Developer’s Manual states that CALL:

Saves procedure linking information on the stack and branches to the called procedure specified using the target operand.

This includes:

  • Near Call — "A call to a procedure in the current code segment", where EIP is pushed onto the stack.
  • Far Call — "A call to a procedure located in a different segment than the current code segment", where CS, EIP are pushed onto the stack.

The alternative, not pushing a return address, is a JMP.

Every C compiler I'm familiar with will always implement function calls on x86 using a CALL instruction, with one exception: a tail call, which can be implemented with a JMP. This happens especially when one function returns the result of another function call. E.g.

int bar(int a, int b);

int foo(int a, int b)
{
    if (a < b)
       return 0;

    return bar(a, b);   // Will probably be:    jmp  bar
}
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • Does any compiler implement function calls (in C) using any means other than CALL - RET instructions in assembly (like JMP)? – balajimc55 Nov 13 '15 at 03:00
  • 1
    @balajimc55 If the function call is marked inline and/or the optimizer is turned on, the resulting assembly code may have the call instruction entirely removed and the body of the function (the one being called) placed right inside the function that was suppose to call it. – Michael Petch Nov 13 '15 at 03:34
  • @MichaelPetch Yes I'm aware about inline calls. I just wanted to know about case when the return instruction is not pushed in a regular function call! Jonathon's updated answer addresses my doubt precisely! – balajimc55 Nov 13 '15 at 05:22
  • 3
    When the called target is outside segment boundaries, an exception is raised and the return address is not pushed. – vitsoft Nov 13 '15 at 07:48
  • @vitsoft Valid point, but I was assuming the OP was referring to successful execution transfer. – Jonathon Reinhart Nov 13 '15 at 12:09
  • Another way to state this is "yes, it pushes RIP if it doesn't fault, which points at the *end* of the current instruction during its execution". RIP-relative addressing works the same way, like `mov eax, [rip+0]` loads bytes from the next instruction. But yes, it's not the same RIP value as before the instruction started, not the address of the call instruction. – Peter Cordes Dec 10 '22 at 15:12