为什么SP(显然)存储在Cortex-M3上的异常条目中?

时间:2015-10-10 19:12:18

标签: c gcc assembly arm

我正在使用具有SysTick中断的TI LM3S811(较旧的Cortex-M3)以10Hz触发。这是ISR的主体:

void SysTick_Handler(void)
{
    __asm__ volatile("sub r4, r4, #32\r\n");
}

这会产生以下程序集,-O0-fomit-frame-pointergcc-4.9.3STKALIGN位为0,因此堆栈是4字节对齐的。

00000138 <SysTick_Handler>:
 138:   4668        mov r0, sp
 13a:   f020 0107   bic.w   r1, r0, #7
 13e:   468d        mov sp, r1
 140:   b401        push    {r0}
 142:   f1ad 0420   sub.w   r4, r4, #32
 146:   f85d 0b04   ldr.w   r0, [sp], #4
 14a:   4685        mov sp, r0
 14c:   4770        bx  lr
 14e:   bf00        nop

我不明白上面列表中r0发生了什么。具体做法是:

1)似乎我们正在清除SP的低3位并将其存储在堆栈中。那是保持8字节对齐吗?还是别的什么?

2)异常退出程序是否同样令人困惑。从我对ARM程序集的有限理解,它做了这样的事情:     SP = SP + 4; R0 = SP;

然后将其存储回SP。在这个阶段,这似乎取消了操纵。

3)为什么在无条件分支后(nop)有0x14E指令?

2 个答案:

答案 0 :(得分:1)

由于您使用的是-O0,因此您应该会遇到大量冗余且无用的代码。编译器工作的一般方式是生成代码,其中包含可能在程序中任何位置使用的所有内容的完整通用性,然后依赖优化器来消除不需要的内容。

  1. 是的,这是8字节对齐。它也分配一个堆栈帧来保存局部变量,即使你没有。
  2. 退出是相反的,取消分配堆栈框架。
  3. 最后的nop是在代码中保持4字节对齐,因为您可能希望在某些时候与非拇指代码链接。
  4. 如果启用优化,它将消除堆栈帧(因为它不需要),代码将变得更加简单。

答案 1 :(得分:0)

ARM过程调用标准和C ABI期望堆栈的8字节(64位)对齐。由于在按下/弹出单个字后可能会发生中断,因此无法保证堆栈在中断输入时正确对齐。

STKALIGN位(如果设置)(默认值)强制硬件通过有条件地将额外(虚拟)字推入堆栈来自动对齐堆栈。

函数的interrupt属性告诉gcc,OTOH堆栈可能是未对齐的,因此它会添加这个强制对齐的前/后同步。

所以,两者实际上都是一样的;一个是硬件,一个是软件。如果只能使用字对齐堆栈,则应从函数声明中删除interrupt属性并清除STKALIGN位。

确保这样一个“未对齐”的堆栈没有问题(我不指望任何问题,因为这是一个纯粹的32位CPU)。 OTOH,你应该保持原样,除非你真的需要保护额外的条件(!)时钟和单词(非常不可能)。

警告:根据“ARM体系结构参考手册”,不建议设置STKALIGN == 0。简而言之:不要将此位设置为0