使用Linaro gcc编译ARM GIC的中断处理程序时会出现奇怪的结果。
代码是:
void foo1(void) __attribute__(( interrupt("IRQ") ));
void foo2(void) __attribute__(( interrupt("IRQ") ));
void foo1() {
dummy();
return;
}
void foo2() {
return;
}
结果汇编代码:
foo1:
sub lr, lr, #4
push {r0, r1, r2, r3, r4, fp, ip, lr}
add fp, sp, #28
bl dummy
nop
sub sp, fp, #28
pop {r0, r1, r2, r3, r4, fp, ip, pc}^
foo2:
str fp, [sp, #-4]!
add fp, sp, #0
nop
sub sp, fp, #0
ldr fp, [sp], #4
subs pc, lr, #4
因此,如果有任何子程序,如果在处理程序代码和PUSH {lr} / POP {pc}中没有子程序,则SUBS用于从中断返回。
问题是SUBS自动从处理器IRQ模式切换到SVC模式,但POP {pc}没有。因此,应该使用SUBS,对于foo1,需要添加外部SUBS指令以从IRQ切换到SVC模式。
是功能还是错误?
有没有办法强制编译器每次都使用SUBS?
答案 0 :(得分:1)
我找不到参考资料,但是IIRC,pop {}
相当于LDM sp ..
。
对于LDM,ARM ARM(A4.1.22 LDM(3))声明:
^对于加载PC的LDM指令,这表示 当前模式的SPSR将复制到CPSR。
这就是生成的pop指令从SPSR恢复CPSR的原因,因此返回先前的CPU模式。