What is the calling convention for a syscall in a program that runs under the RISC-V pseudo-kernel (pk) or Linux?
Looking at the code generated by the riscv-gnu-toolchain the rules seem to be:
a7
a0
to a5
0
a0
Is this it?
Is it really necessary to zero-out the unused arguments?
What about register a6
? Can this be used for yet another sycall argument?
Example that calls the exit()
syscall:
li a0, 1 # argument that is used by the syscall
li a1, 0 # unused arguments
li a2, 0
li a3, 0
li a4, 0
li a5, 0
li a7, 93 # exit syscall number
Yes, this is basically it.
No, it isn't necessary to zero out the unused arguments. The zeroing out of unused arguments when using the riscv-gnu-toolchain (with the newlib C library) is just an artifact of the newlib sycall calling code. To keep it simple, the code has a single scall
(old name for ecall
) wrapper with 6 syscall arguments. Thus, the exit()
implementation just calls that wrapper with some additional zeroes.
As of 2020, the maximum number of syscall arguments in Linux is 6. The same goes for the pseudo-kernel. Thus, a6
is always unused.
Both Linux and pk supply the syscall number in a7
. And the syscall numbers used by pk follow the Linux standard.
The syscall(2) Linux man-page also summarizes the calling conventions on different architectures, including RISC-V. It specifies a1
as possibly used to return a second return value, but this doesn't match the code in glibc and newlib.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With