ARM架构中为什么会有一个scratch寄存器?处理器是如何使用它的,也就是说这个寄存器的目的是什么?
来自Arm 架构过程调用标准:
临时寄存器 / Scratch 寄存器:用于在计算过程中存储一个中间值的寄存器(通常这些值在程序源代码中没有名称并具有有限的生命周期)。
如果您调用函数,函数调用后 Scratch 寄存器中的值可能已被更改。因此,函数调用者必须确保如果这些值仍然需要,它们需要保存。这些寄存器也称为调用者安全寄存器,与被调用者安全寄存器相对。被调用的函数会将后者保存。因此,如果需要临时存储值,则首先使用 Scratch 寄存器,因为无需事先保存它们。
void foo(void)
这样的例程甚至不需要r0,但是该例程可以在不保存它的情况下使用r0。调用foo()
的例程如果要保留r0,则必须保存r0。在这种情况下,r0-r3是短暂的寄存器或scratch registers。相比之下,如果要使用r4-r11,则必须将其保存(在堆栈上)。
r12或ip
通常不对汇编程序员有特殊意义,也可以视为scratch register。 r12
是scratch register,但原因不同于r0-r3。 r12
未用作参数寄存器,因此可以由序言代码(例程开始)使用。
如果您希望在“回溯”中使用您的例程,则可能会有其他限制。您可以使用伪操作.cantunwind
将您的例程标记为“不可回溯”的堆栈回溯。这不是ARM汇编器,而是ELF文件中的“元数据”。在这种情况下,您可以将r14(lr)用作已保存的寄存器;不是scratch.
在纯汇编项目中,所有寄存器都可以成为scratch registers。例如,启动处理器的初始代码通常不需要保存任何内容,并且所有寄存器都是scratch registers。一个例外可能是堆栈指针。
注意:一些系统会专门使用r9,但这很少见。一个例子可能是u-boot。r9从来不是scratch register。
参考资料