一、简介
1.1 C实现的异常处理
对于cortex-m处理器,可以将异常处理或ISR实现为普通的C程序/函数,为了深入了解这种机制,我们先来看一下C函数在ARM架构上是如何工作的。
用ARM架构的C编译器遵循ARM的一个名为AAPCS的规范。根据这份标准,C函数可以修改R0R3、R12、R14(LR)以及PSR。若C函数需要使用R4R11,就应该将这些寄存器保存到栈空间中,并且在函数结束前将它们恢复,如下图所示:
R0~R3、R12、LR以及PSR被称作调用者保存寄存器,若在函数调用后还需要使用这些寄存器的数值,在进行调用前,调用子程序的程序代码需要将这些寄存器的内容保存到内存中(如栈)。函数调用后不需要使用的寄存器数值则不用保存。
R4~R11为调用者保存寄存器,被调用的子程序或函数需要确保这些寄存器在函数结束时不会发生变化(与进入函数时的数值一样)。这些寄存器的数值可能会在函数执行过程中变化,不过需要在函数退出前将它们恢复为初始值。
若cortex-m处理器具有浮点单元,则浮点单元中的寄存器也有类似的需求:
S0~S15为调用者保存寄存器。
S16~S31为被调用者保存寄存器。
一般来说,函数调用将R0R3作为输入参数,R0则用作返回结果。若返回值为64位,则R1也会用于返回结果。要使C函数可以用作异常处理,异常机制需要在异常入口处自动保存R0R3、R12、LR以及PSR,并在异常退出时将它们恢复,这些都要由处理器硬件控制。这样,当返回到被中断的程序时,所有寄存器的数值都会和进入中断时相同。另外,与普通的C函数调用不同,返回地址PC的数值并没有存在在LR中(异常机制在进入异常时将EXC_RETURN代码放入了LR中,该数值将会在异常返回时用到),因此,异常流程也需要将返回地址保存。这样对于CORTEX-M3或不具有浮点单元的CORTEX-M4处理器,需要在异常处理期间保存的寄存器共有8个。对于具有浮点单元的cortex-m4处理器,若用到了浮点单元,则异常机制还需要保存S0 ~ S15 及FPSCR。CONTROL寄存器中FPCA位表示这一操作的执行情况。
1.2 栈帧
在异常入口处被压入栈空间的数据块为栈帧。对于cortex-M3或不具有浮点单元的cortex-m4处理器,栈帧都是8个字大小,对于具有浮点单元的cortex-m4,栈帧则可能是8或26个字。
AAPCS的另外一个要求为,栈指针的数值在函数入口和出口处应该是双字对齐的。因此,若在中断产生时栈帧未对齐到双字地址上,Cortex-m3和Cortex-m4处理器会自动插入一个字。这样可以保证栈指针位于异常处理的开始处。双字栈对齐特性是可编程的,若异常未完全符合AAPCS,则可以关闭该特性。
压栈的xPSR中的第9位表示栈指针的数值是否调整过。在下图中,栈指针为双字对齐的,因此就不会额外插入一个字,而且xPSR的第9位也为0。在双字栈对齐特性被关闭后,栈帧还是会保持这种方式的,只是栈指针的数值有可能未对齐到双字地址。
若使能了双字栈对齐特性&