CALL

The call instruction is used to transfer program control to a procedure or function. Before jumping to the target address, call automatically pushes the return address (the instruction pointer rip of the next instruction) onto the stack. This ensures that once the procedure finishes, the program knows where to resume execution. Essentially, call combines two steps—saving the return location and jumping to the procedure—making it a key instruction for structured programming in assembly.

OPERATIONS OF THE CALL INSTRUCTION

  1. it pushes the return address onto the stack so that the execution of the program can be continued after the function has successfully fulfilled its goal,

  2. it changes the instruction pointer (EIP) to the call destination and starting execution there.

64-BIT

student@nix-bow:~$ gdb -q bow64

Reading symbols from bow64...(no debugging symbols found)...done.
(gdb) disas main
 Dump of assembler code for function main:
   0x00000000000006bc <+0>: 	push   rbp                      # <---- 1. Stores previous EBP (caller’s base pointer)
   0x00000000000006bd <+1>: 	mov    rbp,rsp                  # <---- 2. Creates new stack frame (EBP = current SP)
   
   # Local variables are allocated by subtracting from rsp in 64-bit, or esp in 32-bit.
   0x00000000000006c0 <+4>: 	sub    rsp,0x10                 # <---- 3. Moves ESP to the top - # <---- 3. Allocates space for local variables (ESP moves down)
   0x00000000000006c4 <+8>:  	mov    DWORD PTR [rbp-0x4],edi
   0x00000000000006c7 <+11>:	mov    QWORD PTR [rbp-0x10],rsi
   0x00000000000006cb <+15>:	mov    rax,QWORD PTR [rbp-0x10]
   0x00000000000006cf <+19>:	add    rax,0x8
   0x00000000000006d3 <+23>:	mov    rax,QWORD PTR [rax]
   0x00000000000006d6 <+26>:	mov    rdi,rax
   0x00000000000006d9 <+29>:	call   0x68a <bowfunc>
   0x00000000000006de <+34>:	lea    rdi,[rip+0x9f]
   0x00000000000006e5 <+41>:	call   0x560 <puts@plt>
   0x00000000000006ea <+46>:	mov    eax,0x1
   0x00000000000006ef <+51>:	leave                           # <----  Restores old EBP and moves ESP back to base of frame
   0x00000000000006f0 <+52>:	ret                             # <----  Return from function
 End of assembler dump.
 
 * leave is equivalent to...which restores the caller’s frame and prepares for return.
    mov rsp, rbp
    pop rbp

32-BIT

PROCEDURE

SOURCE

VISUALIZATION

FUNCTION

Things to consider prior to calling a function. This is similar to calling a syscall. The only difference with syscalls is that we have to store the syscall number in rax, while we can call functions directly with call function. Furthermore, with syscall we don't have to worry about Stack Alignment.

PROCESS

POV: CALLER

  1. Save Registers on the stack (Caller Saved)

    1. push/pop

  2. Pass Function Arguments (like syscalls)

    1. identify the arguments required by printf

  3. Fix Stack Alignment

Before calling a function, the stack pointer (rsp) must be aligned to a 16-byte boundary, starting from the _start function. This alignment ensures efficient processor performance and prevents crashes in certain functions (e.g., in libc) that rely on this alignment. To maintain it, you may need to push 16 bytes (or a multiple) onto the stack before making a function call.

  1. Get Function's Return Value (in rax)

POV: CALLEE

  1. Saving Callee Saved registers (rbx and rbp)

  2. Get arguments from registers

  3. Align the Stack

  4. Return value in rax

The caller sets up necessary data before calling a function, and the callee (receiver) retrieves and uses that data. This setup and cleanup happen at the start and end of the function, known as the prologue and epilogue, which ensure the function can run without affecting the current stack or register state.

SOURCE

Last updated