Does CALL instruction ALWAYS push the address pointed by EIP to stack?
Asked Answered
E

1

6

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

Eyeleen answered 13/11, 2015 at 2:50 Comment(2)
If you want to do a function call without stack access you might (miss-)use the "syscall" or "sysenter" instructions.Bremerhaven
"During a function call": if you avoid the call instruction itself, you can tailcall with jmp which doesn't push anything.Severen
C
12

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
}
Chino answered 13/11, 2015 at 2:54 Comment(6)
Does any compiler implement function calls (in C) using any means other than CALL - RET instructions in assembly (like JMP)?Eyeleen
@Eyeleen 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.Tranche
@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!Eyeleen
When the called target is outside segment boundaries, an exception is raised and the return address is not pushed.Leaved
@Leaved Valid point, but I was assuming the OP was referring to successful execution transfer.Chino
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.Severen

© 2022 - 2024 — McMap. All rights reserved.