2021-10-25
This guide is part four of the series, X86–64 Assembly Language Program.
In the previous post of this series, we saw how to define and call functions in x86–64 Assembly.
Now I wanted to know how to provide arguments to a function and return values. In other words, when this is done in a higher-level language, how is it translated at the Assembly code level?
The answer is pretty straightforward. In x86–64 Assembly, there is a convention defining which registers should be used for the first argument, second argument, and so forth.
+-----------------+----------+
| Argument number | Register |
+-----------------+----------+
| Arg 1 | $ rdi |
| Arg 2 | $ rsi |
| Arg 3 | $ rdx |
| Arg 4 | $ rcx |
| Arg 5 | $ r8 |
| Arg 6 | $ r9 |
| Arg 7 | stack |
+-----------------+----------+
All further arguments are pushed onto the stack.
Return values are expected to be stored in the register $rax.
Here is an example of code that utilizes the conventional registers to pass arguments and results in order to print out the command-line arguments
section .data
section .text
global _start
_start:
call .getNumberOfArgs ; expects return value in $rax
mov rdi, rax
call .printNumberOfArgs ; expects value to be in 1st argument, i.e. $rdi
call .exit
.getNumberOfArgs:
pop rbx ; this is the address of the calling fxn. Remove it from the stack for a moment
pop rax ; get argc from stack
push rbx ; return address of calling fxn to stack
ret
; expects value to be in 1st argument, i.e. $rdi
.printNumberOfArgs:
pop rbx ; this is the address of the calling fxn. Remove it from the stack for a moment
add rdi, 48 ; convert number of args to ascii (only works if < 10)
push rdi ; push the ascii converted argc to stack
mov rsi, rsp ; store value of rsp, i.e. pointer to ascii argc to param2 of sys_write fxn
mov rdx, 8 ; param3 of sys_write fxn is the number of bits to print
push rbx ; return the address of the calling fxn to top of stack.
call .print
; clean up the number that was pushed onto the stack. Retaining the return address currently on top of stack
pop rbx
pop rcx
push rbx
ret
.print: ; print expects the calling location to be at the top of the stack
mov rax, 1
mov rdi, 1
syscall
ret ; return to location pointed to at top of stack
.exit:
mov rax, 60
mov rdi, 0
syscallThere are some additional well-defined calling conventions that are helpful to follow. See here.
I hope you enjoyed this article. To learn more, find the next part of this series here: Conditionals, Jumping, and Looping.