Android异常分析基础之APCS(ARM程序调用标准) AArch64的体系架构
很多朋友在分析android tombstone异常的时候,面对一堆堆的寄存器数据,堆栈,往往不知道应该看些什么,怎么看。
今天,我们先从异常分析的基础开始,一步步的由函数调用标准,寄存器保存,堆栈结构,操作系统signal等来说明,具体描述到底对tombstone文件,应该如何理解,并获取其中有重要价值的信息。并由此得出我们的分析结论。
首先, 我们从理解ARM程序调用标准开始进入我们的异常分析。(以下以ARMv8的AArch64架构的APCS标准为例进行说明,关于ARMv7版本以下由于架构不同,这里就不再做具体说明了)
第一步: 思考以下,我们在代码实现的时候,往往由C或C++语言参考一个标准的程序调用。如下所示:
int function_callee(int a, double b, char c, short d)
{
printf("%d, %f, %c, %d", a, b, c, d);
return 0;
}int function_caller()
{
int aa = 3;
double bb = 6.6;
char cc = 'x';
short dd = 6;
function_callee(aa, bb, cc, dd);
}
那么,在真实的执行环境中,这些参数应该是如何传递的呢? 中间会用到那些内存区域? 这些变量是如何排布的?为什么有时候我们会遇到莫名其妙的我们的数据被踩踏的问题?
其实,这些就涉及到在二进制层面,程序是如何传递,控制整个程序的执行和转换的流程。也就是我们常说的 ABI (应用程序二进制接口)。 而APCS就是ARM的ABI中的一个部分,用来定义在二进制层面应用程序的函数之间如何控制,传递参数,以及怎么样使调用流程进行跳转的标准。
本节,我们先简单介绍ARMv8的AArch64体系架构,以帮助我们后续更好的理解APCS的实现
ARM的体系架构
特点
ARM是一套精简指令集架构(RISC)体系下的CPU架构。对应每个PE(处理单元,可简单的理解为一个CPU核心), 她具有如下的几个特点:
1: 有一组很大统一的寄存器组
2: load / store 架构,数据操作只能在寄存器中进行,无法直接对内存数据进行数据操作
3: 简化的地址模式, 所有的 load / store地址都来源自寄存器和指令域。
4: ARM支持SIMD(单指令多数据)和浮点运算指令。
5: AArch64向前兼容支持AArch32的指令操作
架构
1: AArch64提供了31个64位通用寄存器, 从X0 到 X30, 其中, X30用作程序链接寄存器(LR)
2: AArch64提供了一个程序计数寄存器(PC), 若干堆栈寄存器(SP),和若干异常链接寄存器(ELR) (这里的若干指的是,CPU的在不同的执行状态下,会使用不同的寄存器,但这些寄存器不同时可见)
3: AArch64提供了32个128位用来做 SIMD 和 浮点运算的寄存器, 从V0 到 V31
4: AArch64定义了一套单独的指令集
5: AArch64定义了高达四层的异常模式, 从EL0 到EL3, 来提供不同的CPU特权等级
6: AArch64支持高达64位的虚拟地址寻址
7: AArch64定义了一些处理器PE状态,由PSTATE控制
8: 定义了一组系统寄存器,使用的时候由这些系统寄存器的特权等级作为后缀来访问 (所谓系统寄存器,是用来提供架构中的控制和状态信息的寄存器,涉及到中断控制,内存映射等等)
本文地址:https://blog.csdn.net/u012843232/article/details/110261466