ARM 过程调用标准中的 r12

r12 in the ARM Procedure Call Standard

为什么根据ARM Procedure Call Standard,r12指定为scratch register?它位于两组保留的寄存器之间:r4-r11 和 sp-lr-pc。为什么不将 r0-r4 设为临时的而保留所有其他内容?

AAPCS 指南的第 14、15 和 18 页 http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf 定义了 R12 的使用 过程调用临时寄存器 (IP)。链接器使用它来访问 Branch 和 Link (BL) 指令无法访问的 32 位地址 space。

请注意,ARM 具有 STMLDM 指令,它们以 increasing/decreasing 数字顺序存储和加载值。寄存器 R0-R3 用作参数和 return 值,如果需要则为 'caller-saved'。寄存器 R4-R8 是被调用者保存的寄存器(可能更多)。同样,R13-R15 是特殊寄存器。使用 R12 允许使用 LDM/STM 相当有效地访问寄存器组,因为您可能希望以不同的方式对待组(上下文保存、函数调用、信号等都有不同的要求)。

函数尾声和序言代码可能需要运行计算and/or保存值。为此需要一个暂存器。因此,给定 LDM/STM 和其他 ARM 寻址模式,临时寄存器不应中断连续序列。根据上下文和代码生成策略,您可能需要 save/restore 调用方和被调用方都保存寄存器。在 R4 休息不是一个好的选择。影响最小的自然中断是在被调用者和上层内部寄存器(PC、SP、LR)之间。请注意,R9-R11 可以是特殊寄存器,具体取决于先前 APCS 中的系统(静态基、堆栈范围和帧指针)。由于这些是可选的,在某些系统中,它们可能会按照 R4-R8 保存。

Why is r12 designated as scratch register according to the ARM Procedure Call Standard?

为什么 是一个非常棘手的问题。鉴于不使用连续寄存器来实现类似功能会使事情变得复杂。它也更容易记住,并且确实为某些 ARM 指令提供了更大的灵活性。此外,代码生成的实现可能更简单,因为您只需要保存上限即可了解被调用者保存的寄存器。一个目标是使函数 epilogue/prologue 尽可能快。这取决于功能和系统要求。希望为什么需要暂存器是显而易见的。如果没有多个堆栈保留,基于参数的可变大小数组将难以实现。某些代码(例如信号)可能依赖于 FP 在序言期间自动设置;即,您在设置了堆栈和帧指针的函数中,或者您不在中间。 IP (r12) 也可用于单板和其他链接技巧(PLT、GOT 等)。 R12 的选择允许某些系统将 R9-R11 用作被调用者保存的通用寄存器,而不会破坏任何类似寄存器的序列。


来自 APCS,

The ip register has a dedicated role only during function call; at other times it may be used as a scratch register.

(Aside: Conventionally, ip is used by compiler code generators as the/a local code generator temporary register).

不幸的是,APCS 已被 AAPCS 淘汰,因此 ARM 不再提供它(很难找到网络参考)。然而,它提供了对 ARM ABI 演变的洞察力。