There is a strange result while compiling Interrupt Handler for ARM GIC using Linaro gcc.
The code is:
void foo1(void) __attribute__(( interrupt("IRQ") ));
void foo2(void) __attribute__(( interrupt("IRQ") ));
void foo1() {
dummy();
return;
}
void foo2() {
return;
}
The result assembler code:
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
So, SUBS is used to return from interrupt if no subroutines inside handler code and PUSH{lr}/POP{pc} is used if there is any subroutine.
The problem is that SUBS automatically switch from processor IRQ mode to SVC mode, but POP{pc} does not. So, SUBS should be used and for foo1 it is necessary to add external SUBS instruction to switch from IRQ to SVC mode.
Is it feature or bug?
Is any way to force compiler to use SUBS everytime?
pop {r0, r1, r2, r3, r4, fp, ip, pc}^
is generated, but it is not correct. It seems it should beldm sp!, {r0, r1, r2, r3, r4, fp, ip, pc}^
– Pavel Shpop {...}^
intopop {...}
instead of raising an error. Good find - feel free to write up your own answer. – Notlikethat