PK/Linux 上的 RISC-V ecall 系统调用约定

max*_*zig 6 system-calls calling-convention riscv

在 RISC-V 伪内核 (pk) 或 Linux 下运行的程序中系统调用的调用约定是什么?

查看由 riscv-gnu-toolchain 生成的代码,规则似乎是:

  • 系统调用号被传入 a7
  • 系统调用参数被传递a0a5
  • 未使用的参数设置为 0
  • 返回值在 a0

是这个吗?

真的有必要将未使用的参数归零吗?

注册a6呢?这可以用于另一个 sycall 参数吗?

调用exit()系统调用的示例:

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
Run Code Online (Sandbox Code Playgroud)

max*_*zig 6

是的,基本上就是这样。

不,没有必要将未使用的参数归零。使用 riscv-gnu-toolchain(使用 newlib C 库)时将未使用的参数归零只是 newlib sycall 调用代码的一个工件。为简单起见,该代码有一个带有 6 个系统调用参数的单个scall(旧名称ecall)包装器。因此,exit()实现只是使用一些额外的零来调用该包装器

截至 2020 年,Linux 中系统调用参数最大数量为 6。伪内核也是如此。因此,a6始终未使用。

Linux 和 pk 都在a7. 并且 pk 使用的系统调用号遵循 Linux 标准。

系统调用(2) Linux手册页还总结了不同的架构,包括RISC-V的调用约定。它指定a1可能用于返回第二个返回值,但这与 glibc 和 newlib 中的代码不匹配。