在 C 函数调用的 ARM 汇编函数中注册用法
Register usage in ARM assembly function which is called by a C function
ARM 的 C 函数调用约定说:
- 调用者将在 r0-r3 中传递前 4 个参数。
- 调用者将在堆栈上传递任何额外参数。
- 调用者将从 r0 中获取 return 值。
我手写了一个C调用的汇编函数,原型相当于这样:
void s(void);
假设 C 函数 c()
调用 s()
.
因为 s()
没有参数,也没有 return 值。我相信编译器不会触及 r0-r3
来生成 c()
的调用序列来调用 s()
.
假设s()
将使用r0-r12
来完成它的功能。 c()
也可能会使用这些寄存器。
我不确定是否必须显式保存和恢复 s()
中触及的所有寄存器,比如说r0-r12
。这样的内存操作会耗费一些时间。
或者至少 r0-r3
我不必这样做?
来自 Procedure Call Standard for the Arm Architecture,第 6.1.1 节(第 19 页):
A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variantsthat designate r9 as v6)
所以是的,因为 r0-r3 是临时寄存器,所以在 s()
中使用它们之前不需要保存它们,但是你必须保存和恢复任何其他寄存器。
假设编译器符合 ARM ABI,然后声明 s()
如下:
extern void s(void);
应该足够了,并且编译器不应在调用 s()
之后发出依赖于 c()
函数中 r0-r3 先前值的代码(即 c()
应该保存r0-r3(如果需要,在调用 s()
之前恢复它们),因为这会破坏 ABI 合规性。
通常,在混合使用 C 和 asm 时,您永远不能对 C 代码使用的寄存器做出任何假设,除了调用约定保证会入栈的寄存器。在使用它们之前堆叠所有其他寄存器,然后再弹出它们。所有这些都取决于编译器在调用您的汇编程序函数时在内部做出和不做出的假设。
这里有一些有用的信息:Mixing C, C++, and Assembly Language
ARM 的 C 函数调用约定说:
- 调用者将在 r0-r3 中传递前 4 个参数。
- 调用者将在堆栈上传递任何额外参数。
- 调用者将从 r0 中获取 return 值。
我手写了一个C调用的汇编函数,原型相当于这样:
void s(void);
假设 C 函数 c()
调用 s()
.
因为 s()
没有参数,也没有 return 值。我相信编译器不会触及 r0-r3
来生成 c()
的调用序列来调用 s()
.
假设s()
将使用r0-r12
来完成它的功能。 c()
也可能会使用这些寄存器。
我不确定是否必须显式保存和恢复 s()
中触及的所有寄存器,比如说r0-r12
。这样的内存操作会耗费一些时间。
或者至少 r0-r3
我不必这样做?
来自 Procedure Call Standard for the Arm Architecture,第 6.1.1 节(第 19 页):
A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variantsthat designate r9 as v6)
所以是的,因为 r0-r3 是临时寄存器,所以在 s()
中使用它们之前不需要保存它们,但是你必须保存和恢复任何其他寄存器。
假设编译器符合 ARM ABI,然后声明 s()
如下:
extern void s(void);
应该足够了,并且编译器不应在调用 s()
之后发出依赖于 c()
函数中 r0-r3 先前值的代码(即 c()
应该保存r0-r3(如果需要,在调用 s()
之前恢复它们),因为这会破坏 ABI 合规性。
通常,在混合使用 C 和 asm 时,您永远不能对 C 代码使用的寄存器做出任何假设,除了调用约定保证会入栈的寄存器。在使用它们之前堆叠所有其他寄存器,然后再弹出它们。所有这些都取决于编译器在调用您的汇编程序函数时在内部做出和不做出的假设。
这里有一些有用的信息:Mixing C, C++, and Assembly Language