0
votes

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?

1
Which specific Linaro release? (FWIW I don't see any problem with the crusty old 13.11 arm-linux-gnueabihf binaries to hand) Secondly, what compiler/assembler options are you passing? The question as-is looks like a simple misreading of the (correct) compiler-generated assembly, but your comments on the answer imply something else - please add a bit more detail to the question to clarify what exactly is going on here.Notlikethat
arm-eabi-gcc -mfloat-abi=softfp -march=armv7-a -mcpu=cortex-a9 -S -ffunction-sections -fdata-sections arm-eabi-gcc (Linaro GCC 5.3-2016.02) 5.3.1 20160113 The pop {r0, r1, r2, r3, r4, fp, ip, pc}^ is generated, but it is not correct. It seems it should be ldm sp!, {r0, r1, r2, r3, r4, fp, ip, pc}^Pavel Sh
The problem is known and fixed at branch 6 gcc.gnu.org/bugzilla/show_bug.cgi?id=70830Pavel Sh
So the other half of this particular problem must be an assembler which silently misassembles the pop {...}^ into pop {...} instead of raising an error. Good find - feel free to write up your own answer.Notlikethat

1 Answers

1
votes

I can't find out the reference, but IIRC, pop {} is equivalent to LDM sp ...

For LDM, the ARM ARM (A4.1.22 LDM (3)) states that:

^ For an LDM instruction that loads the PC, this indicates that the SPSR of the current mode is copied to the CPSR.

That is why the generated pop instruction restores the CPSR from the SPSR, hence returning in the previous CPU mode.