ric*_*chq 51 c assembly arm calling-convention function-call
自从我上次编写手臂汇编程序以来已经有一段时间了,我对细节有点生疏.如果我从arm调用C函数,我只需要担心保存r0-r3和lr,对吧?
如果C函数使用任何其他寄存器,它是否负责保存堆栈中的那些并恢复它们?换句话说,编译器会生成代码来为C函数执行此操作.
例如,如果我在汇编程序函数中使用r10,我不必将其值放在堆栈或内存中,并在C调用后弹出/恢复它,是吗?
这是针对arm-eabi-gcc 4.3.0.
Ces*_*arB 69
这取决于您正在编译的平台的ABI.在Linux上,有两个ARM ABI; 旧的和新的.AFAIK,新的(EABI)实际上是ARM的AAPCS.完整的EABI定义目前存在于ARM的信息中心.
被调用者必须保存被调用者保存寄存器(与调用者保存寄存器相对应,调用者保存寄存器); 所以,如果这是你正在使用的ABI,你不必在调用另一个函数之前保存r10(另一个函数负责保存它).
编辑:您使用的编译器没有区别; 特别是gcc可以配置为几个不同的ABI,甚至可以在命令行上进行更改.看着它生成的序言/结尾代码是不是有用的,因为它是专为每个功能和编译器可以使用保存的寄存器(例如,保存在它的函数的中间)的其他方式.
Pav*_*l P 24
要在NEON寄存器上添加缺少的信息:
从AAPCS,§5.1.1核心寄存器:
从AAPCS,§5.1.2.1VFP寄存器使用约定:
原帖:
arm-to-c-calling-convention-neon-registers-to-save
aus*_*len 19
对于64位ARM,A64(来自ARM 64位架构的过程调用标准)
A64指令集可以看到31个64位通用(整数)寄存器; 这些标记为r0-r30.在64位上下文中,这些寄存器通常使用名称x0-x30来表示 ; 在32位上下文中,寄存器通过使用w0-w30指定.另外,堆栈指针寄存器SP可以与有限数量的指令一起使用.
前8个寄存器r0-r7用于将参数值传递给子程序并从函数返回结果值.它们也可用于在例程中保存中间值(但通常仅用于子例程调用之间).
寄存器r16(IP0)和r17(IP1)可以被用作例程和它调用的任何子例程之间的临时寄存器.它们也可以在例程中用于在子例程调用之间保存中间值.
寄存器r18的作用是特定于平台的.如果平台ABI需要专用通用寄存器来承载进程间状态(例如,线程上下文),那么它应该使用该寄存器来实现该目的.如果平台ABI没有这样的要求,那么它应该使用r18作为附加的临时寄存器.平台ABI规范必须记录该寄存器的用法.
SIMD
ARM 64位架构还有另外32个寄存器v0-v31,可由SIMD和浮点运算使用.寄存器的确切名称将更改,表示访问的大小.
注意:与AArch32不同,在AArch64中,SIMD和浮点寄存器的128位和64位视图在较窄的视图中不会与多个寄存器重叠,因此q1,d1和s1都指向寄存器中的相同条目银行.
前8个寄存器v0-v7用于将参数值传递给子程序并从函数返回结果值.它们也可用于在例程中保存中间值(但通常仅用于子例程调用之间).
寄存器v8-v15必须由被调用者跨子例程调用保留; 其余寄存器(v0-v7,v16-v31)不需要保留(或应由调用者保留).另外,只需要保存存储在v8-v15中的每个值的底部64位; 调用者有责任保留更大的值.
CesarB和Pavel的答案提供了AAPCS的引用,但仍有未解决的问题.被叫方是否保存r9?r12怎么样?r14怎么样?此外,答案非常笼统,并不是所要求的arm-eabi工具链所特有的.这是一种实用的方法,可以找出哪些寄存器是被调用者保存的,哪些不是.
以下C代码包含内联汇编块,声称修改寄存器r0-r12和r14.编译器将生成代码以保存ABI所需的寄存器.
void foo() {
asm volatile ( "nop" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14");
}
Run Code Online (Sandbox Code Playgroud)
使用命令行arm-eabi-gcc-4.7 -O2 -S -o - foo.c
并为您的平台添加开关(-mcpu=arm7tdmi例如).该命令将在STDOUT上打印生成的汇编代码.它可能看起来像这样:
foo:
stmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
nop
ldmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
bx lr
Run Code Online (Sandbox Code Playgroud)
注意,编译器生成的代码保存并恢复r4-r11.编译器不保存r0-r3,r12.它恢复r14(别名lr)纯粹是偶然的,因为我从经验中知道退出代码也可以将保存的lr加载到r0然后执行"bx r0"而不是"bx lr".通过添加-mcpu=arm7tdmi -mno-thumb-interwork或使用-mcpu=cortex-m4 -mthumb我们获得略有不同的汇编代码,如下所示:
foo:
stmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
nop
ldmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
Run Code Online (Sandbox Code Playgroud)
同样,r4-r11被保存并恢复.但是r14(别名lr)没有恢复.
总结一下:
这至少适用于arm-eabi-gcc的默认值.存在可能影响结果的命令行开关(特别是-mabi开关).