考虑以下C代码:
extern void dummy(void);
void foo1(void) __attribute__(( interrupt("IRQ") ));
void foo2(void) __attribute__(( interrupt("FIQ") ));
void foo1() {
dummy();
return;
}
void foo2() {
dummy();
return;
}
arm gnueabi gcc生成的代码基本上是这样的:
foo1:
sub lr, lr, #4
stmfd sp!, {r0, r1, r2, r3, ip, lr}
bl dummy
ldmfd sp!, {r0, r1, r2, r3, ip, pc}^
foo2:
sub lr, lr, #4
stmfd sp!, {r0, r1, r2, r3, r4, lr}
bl dummy
ldmfd sp!, {r0, r1, r2, r3, r4, pc}^
foo1的代码没有任何意外。保存r0-r3
和ip
,因为对虚拟的调用可能会改变其值。此外,在纠正lr
之后,它最终会被推送到pc中。这是相当标准的。
然而,foo2的代码令人惊讶。不需要保存ip
的值,因为它是一个库存寄存器。但是gcc保存r4
是令人惊讶的。
那为什么gcc会保存r4?我没有看到任何理由这样做,因为对假人的调用不会破坏这个寄存器。
答案 0 :(得分:1)
我怀疑它是为了确保EABI所需的8字节堆栈对齐。使用的实际寄存器无关紧要,它可能是r12或其他任何东西 - 它只用于额外的4字节调整。