Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RISC-V ecall syscall calling convention on pk/Linux

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:

  • syscall number is passed in a7
  • syscall arguments are passed in a0 to a5
  • unused arguments are set to 0
  • return value is returned in 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
like image 702
maxschlepzig Avatar asked Jan 18 '20 12:01

maxschlepzig


1 Answers

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.

like image 136
maxschlepzig Avatar answered Sep 22 '22 06:09

maxschlepzig