我正在使用具有SysTick中断的TI LM3S811(较旧的Cortex-M3)以10Hz触发。这是ISR的主体:
void SysTick_Handler(void)
{
__asm__ volatile("sub r4, r4, #32\r\n");
}
这会产生以下程序集,-O0
和-fomit-frame-pointer
与gcc-4.9.3。 STKALIGN
位为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
指令?
答案 0 :(得分:1)
由于您使用的是-O0
,因此您应该会遇到大量冗余且无用的代码。编译器工作的一般方式是生成代码,其中包含可能在程序中任何位置使用的所有内容的完整通用性,然后依赖优化器来消除不需要的内容。
如果启用优化,它将消除堆栈帧(因为它不需要),代码将变得更加简单。
答案 1 :(得分:0)
ARM过程调用标准和C ABI期望堆栈的8字节(64位)对齐。由于在按下/弹出单个字后可能会发生中断,因此无法保证堆栈在中断输入时正确对齐。
STKALIGN
位(如果设置)(默认值)强制硬件通过有条件地将额外(虚拟)字推入堆栈来自动对齐堆栈。
函数的interrupt
属性告诉gcc,OTOH堆栈可能是未对齐的,因此它会添加这个强制对齐的前/后同步。
所以,两者实际上都是一样的;一个是硬件,一个是软件。如果只能使用字对齐堆栈,则应从函数声明中删除interrupt
属性并清除STKALIGN
位。
确保这样一个“未对齐”的堆栈没有问题(我不指望任何问题,因为这是一个纯粹的32位CPU)。 OTOH,你应该保持原样,除非你真的需要保护额外的条件(!)时钟和单词(非常不可能)。
警告:根据“ARM体系结构参考手册”,不建议设置STKALIGN == 0。简而言之:不要将此位设置为0
!