【问题标题】:Should temporary registers be saved before issuing an environment call?是否应该在发出环境调用之前保存临时寄存器?
【发布时间】:2026-01-26 11:45:02
【问题描述】:

在以下 RISC-V 汇编代码中:

...
#Using some temporary (t) registers
...

addi a7,zero,1 #Printint system call code
addi a0,zero,100
ecall

...

在使用ecall之前是否应该将任何临时(t)寄存器保存到堆栈中?当使用ecall 时,会发生异常,内核模式处于打开状态并从异常处理程序中执行代码。发生异常时会保存一些信息,例如 EPCCAUSE ,但是临时寄存器呢?出于安全原因,环境调用被认为不像过程,但它们看起来像。在这种情况下,过程调用约定是否仍然适用?

【问题讨论】:

    标签: system-calls calling-convention riscv rars-simulator


    【解决方案1】:

    您是正确的,硬件捕获了一些信息,例如epc(如果没有,则在将控制权转移到异常处理程序期间中断的 pc 将丢失)。

    不过,这就是硬件的全部作用——其余的取决于软件。在这里,RARS 为ecall 提供异常处理程序。

    RARS 文档状态(来自系统调用的帮助部分,这就是 MIPS 上的调用方式(RARS 来自 MARS)):

    寄存器内容不受系统调用的影响,除了下表中指定的结果寄存器。

    在帮助中这个引用下面是标记为“可用服务表”的ecall函数代码表,其中1是PrintInt

    是否应该在使用 ecall 之前将任何临时 (t) 寄存器保存到堆栈中?

    不,没有必要,$t 寄存器将不受ecall 的影响。

    这也意味着我们可以添加 ecalls 来进行 printf 样式的调试,而不用担心保留 $t 寄存器,这很好。但是,请记住这一点,我们通常可以避免将 $a0 和 $a7 用于我们自己的变量,因为放入 ecall 进行调试将需要这些寄存器。


    此外,您可以编写自己的异常处理程序,它不必遵循任何特定的参数传递甚至寄存器保存约定。

    【讨论】:

    • 这通常是正确的,不仅仅是在 RARS 中,对吧?寄存器不受影响的原因是因为处理程序的代码根本不使用它们?在环境调用中不遵循调用约定的真正原因是什么?
    最近更新 更多