Is ra / x1 automatically preserved across calls?
No. The psABI marks ra as not preserved across calls; save it explicitly when it must survive a call.
ra is the return-address register in the RISC-V calling convention. Call-related instructions commonly place the next instruction address in ra, and returns use that address to go back to the caller; the psABI marks ra as not preserved across calls.
The psABI names x1 as ra for the return address. It is not callee-saved; code that needs it across a call must save it explicitly.
ra / x1 is the psABI return-address register. Call sequences commonly place the return address here; it is not preserved across calls, so non-leaf functions must save it explicitly.
jal / jalr write the next instruction address into ra unless rd is something else.
ret usually expands to jalr x0, 0(ra), so it depends on the address stored in ra.
If the function calls others, saving and restoring ra becomes this function's own responsibility.
addi sp, sp, -16
sd ra, 8(sp)
call foo # ra is overwritten; use sw/lw for 32-bit RV32 saves
ld ra, 8(sp)
addi sp, sp, 16
retNo. The psABI marks ra as not preserved across calls; save it explicitly when it must survive a call.
Because another call writes a new return address and overwrites the old value in ra.