一、什么是AAPCS?
旧时,ARM 过程调用标准叫做 APCS (ARM Procedure Call Standard),Thumb的过程调用标准为 TPCS。如今这两种叫法已经废弃,统一称作 AAPCS (Procedure Call Standard for the ARM Architecture)。
AAPCS 是 ARM ABI(Application Binary Interface) 接口文档的一份,它定义了:
- 对寄存器使用的限制。
- 使用栈的惯例。
- 在函数调用之间传递/返回参数。
- 可以被"回溯"的基于栈的结构的格式,用来提供从失败点到程序入口函数的列表,包括函数参数。
当前 ARM 官方已经通过 github 来维护相关文档,想获取最新的文档可以访问GitHub - ARM-software/abi-aa: Application Binary Interface for the Arm® Architecture
二、寄存器
调用者保存寄存器(caller saved registers)与被调用者保存寄存器(cellee-saved registers)
试想一下,在调用一个函数时,无论是调用者还是被调用者,都可能更新寄存器的值。假设调用者在%edx中存了一个整数值100,而被调用者也使用这个寄存器,并更新成了1000,于是悲剧就发生了。当过程调用完毕返回后,调用者再使用%edx的时候,值已经从100变成了1000,这几乎必将导致程序会错误的执行下去。因此,函数调用的前后系统应该保持不变。
- 在函数调用前,将所有被调用者所使用的寄存器都保存一遍。(通过栈)
- 在函数调用时,将所有用到的寄存器的值都先保留再使用(通过栈保存),并且在结束时恢复。
- 约定调用者保存,与被调用者保存,各保存各的。arm采用的这种方案,如下图所示:
https://www.zhihu.com/question/301000788
调用者保存寄存器(caller saved registers):R0~R3、R12、R14链接寄存器、程序状态寄存器PSR;
- 函数调用后还需使用的寄存器数值,需在调用前将其保存(到内存中 如栈);
- 函数调用后无需使用的寄存器数值则无需保存;
- 函数可以任意使用(修改)这些寄存器;
被调用者保存寄存器(cellee-saved registers):R4~R11;
- 被调用的子程序或函数需确保这些寄存器在函数结束时不会发生变化(与进入函数前相同);
- 若函数需要使用这些寄存器,则应将其保存(入栈),并在函数结束前将其恢复为初始值;
若处理器具有浮点单元,则其中的寄存器也有类似需求;
S0~S15:调用者保存寄存器;
S16~S31:被调用者保存寄存器;
三、参数传递&返回
参数传递:
- 参数不超过4个时使用寄存器R0~R3传递,否则超出部分则使用堆栈传递;
- 多字大小的输入参数通过多个连续的寄存器传递(如:R0+R1);
- 若系统中不包含浮点运算的硬件部件,浮点参数通过相应的规则转换为整数参数后传递;
参数返回:
- 32位以下的基本数据类型,通过寄存器R0返回;
- 返回结果为64位时,通过寄存器R0与R1返回;
- 返回结果为浮点数时,通过浮点运算不见的寄存器返回;
- 对于位数更多的结果,需要通过栈传递
四、使用栈惯例
sp指向最后一个压入的值,数据栈由高地址向低地址生长)类型,即满递减堆栈。
- 压栈PUSH:先让SP指针自减(空出内存),然后再存入数据
- 出栈POP:先读出SP指向的数据,然后再自减
ref:
ARM体系结构学习笔记:过程调用标准AAPC、 ARM32调用约定、ARM64调用约定_arm64 传参 结构体-CSDN博客
ARM软件逆向工程入门 01 - ARM调用约定(Calling Convention)_armv7函数调用约定-CSDN博客
ARM学习(17)ARM函数调用规则_arm bl call 调用函数-CSDN博客
ARM 过程调用标准 AAPCS 以及堆栈使用-CSDN博客
应用程序二进制接口(ABI) --- AAPCS(函数调用/中断上下文保护) - 流水灯 - 博客园
arm异常处理分析_arm指令异常-CSDN博客
ARM架构过程调用标准AAPCS-CSDN博客
FreeRTOS-ARM架构与程序的本质_freertos内核-CSDN博客
c语言函数调用规范-基于arm 分析_aapcs-CSDN博客
ARM体系结构学习笔记:过程调用标准AAPC、 ARM32调用约定、ARM64调用约定_arm64 传参 结构体-CSDN博客