Written in section .text, outside of the _start: block.
This is simmilar to C++, where we write our functions in the same part of the code as our int main() { }, but not actually inside!
They are even made in a simmilar way to the main:
global myFunction
funcName:
; some code here
retHowever, unlike C++, there are no parameters for functions, instead you just call it:
call myFunctionThen, how do you give it parameters?
By using certain registers!
If you take a look at the “Function Usage” column, each register has a specific purpose.
Consider the following code:
mov rdi, array ; pass by reference
mov sil, byte[length] ; pass by value
mov rdx, sum
mov rcx, max
call myFunction
; the return value will be in raxThe main four types of registers for functions are:
- Preserved/Saved: Registers should maintain their value by the end of the function. If possible, try to not use them. If you do, you must preserve them somehow (usually by pushing/popping them in the stack)
- Temporary: You can do whatever you want with them
- Argument: The arguments/paramters of the function
- Return: The return value
In order to preserve those registers, you can do the following:
global stats
stats:
; prologue
push rbp ; Preserves stack pointer
mov rbp, rsp ; Create new stack pointer
push r12 ; Callee saved variable
push r13 ; Callee saved variable
push r14 ; Callee saved variable
push r15 ; Callee saved variable
push rbx ; Callee saved variable
; some code here
; epilogue
pop rbx ; Callee saved variables
pop r15 ; Callee saved variables
pop r14 ; Callee saved variables
pop r13 ; Callee saved variables
pop r12 ; Callee saved variables
pop rbp ; Preserves stack pointer You do not need to push/pop registers you dont use.
Also, make sure you pop in the reverse order that you push.