assemblylinux-kernelsystem-callsriscvcalling-convention

Do RISC-V kernel-space calling conventions exist?


RISC-V user-space function calls calling conventions are clear to me. It's also clear that a0-a5 are used to pass arguments to kernel and a7 to store system call number before an ecall. What I can't find is some documentation about assumptions I can do after execution of ecall instruction.
The following lines are part of the output of objdump -d -M no-aliases libc.so.6 in the <__open64_nocancel> (glibc 2.35 on RISC-V Ubuntu 22, but the same thing happens on 2.37 and 2.39)

   ...
   ada12:       861a                    c.mv    a2,t1
   ada14:       00000073                ecall
   ada18:       77fd                    c.lui   a5,0xfffff
   ada1a:       02a7e963                bltu    a5,a0,ada4c <__open64_nocancel+0x7e>
   ada1e:       2501                    c.addiw a0,0
   ada20:       6722                    c.ldsp  a4,8(sp)
   ada22:       000e3783                ld      a5,0(t3)
   ...

As you can see the last instruction uses t3 as base address to access memory without being reinitialized after the ecall. My question is: what can I safely assume from this?
Can caller-saved registers from user-space calling conventions be safely used after ecall without saving and restoring the value across ecall? I know a0-a1 are used to store return values from the system call, but what about a2-a7? May I assume they are clobbered?

I was expecting that all temporary registers would be considered clobbered, but the given example makes me wonder about argument registers. Maybe that's different since they serve a specific purpose to the kernel.


Solution

  • Registers other than the return-value are unmodified by system-calls on Linux, except for a few special cases on some ISAs (like x86-64 syscall itself clobbers RCX and R11).

    The kernel system-call entry points save all user-space registers so ptrace (debugging) and other things that want a struct of the user-space regs can just work on a process that's blocked in a system call.


    The syscall(2) man page (https://man7.org/linux/man-pages/man2/syscall.2.html) has a table of register usage, with a note at the bottom:

    Note that these tables don't cover the entire calling convention - some architectures may indiscriminately clobber other registers not listed here.

    As far as I know, there aren't any extra clobbers for Linux's RISC-V system-call calling convention, just the return value in a0 (and a1 for 64-bit return values).