Calling functions in x86 assembly
This is the fifth post about x86 assembly. In this post I will show how to call functions in x86 assembly.
Below is a simple program that has three functions besides main.
global main
extern printf
section .text
main:
mov rdi, 5
call times2
mov rdi, rax
call print_value
call exit
times2:
push rbp
mov rbp, rsp
mov rax, rdi
add rax, rax
mov rsp, rbp
pop rbp
ret
print_value:
push rbp
mov rbp, rsp
push rdi
mov rdi, fmt
pop rsi
mov rax, 0
call printf wrt ..plt
mov rsp, rbp
pop rbp
ret
exit:
mov rdi, 0 ; exit code 0
mov rax, 60 ; system call for exit
syscall
section .data
fmt: db "The value is %d", 10, 0
Passing values to functions
The code above is following the Linux 64-bit ABI where the first six arguments(integers and pointers) are passed through registers. You could also pass the arguments on the stack or hardcoded memory locations.
Function prologue and epilogue
The beginning and the end in the functions times2
and print_value
is called the function prologue and epilogue.
push rbp
mov rbp, rsp
...
mov rsp, rbp
pop rbp
ret
This a convention for preparing the stack for usage. The prologue creates a new stack frame for the called function and the epilogue restores the stack frame for the calling function.