arm-elf-gcc-3.2 seems to generate bad interrupt code when compiling w/o any optimizations. Gcc Version: arm-elf-gcc (GCC) 3.2 Compiling with: arm-elf-gcc -S -g -I. -mcpu=arm7dmi -Wall -save-temps timer_test.c yields the following asm code for an interrupt handler: timer2_int: .LFB3: .LM25: @ Interrupt Service Routine. @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, uses_anonymous_args = 0 str ip, [sp, #-4]! mov ip, sp .LCFI7: sub lr, lr, #4 stmfd sp!, {r2, r3, fp, ip, lr, pc} .LCFI8: sub fp, ip, #4 .LCFI9: .LM26: mvn r3, #3776 sub r3, r3, #15 mov r2, #0 str r2, [r3, #0] .LM27: ldmea fp, {r2, r3, fp, ip, pc}^ As you can see, the last line of this is bogus. It should not be LDMing from fp, but instead from sp. Compiling with: arm-elf-gcc -S -g -I. -O2 -mcpu=arm7dmi -Wall -save-temps timer_test.c fixes the problem: .LM49: @ Interrupt Service Routine. @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. stmfd sp!, {r2, r3} .LCFI2: .LM50: mov r2, #0 mvn r3, #3776 .LM51: @ lr needed for prologue .LM52: str r2, [r3, #-15] ldmfd sp!, {r2, r3} <--- This line is correct here. subs pc, lr, #4
Created attachment 4664 [details] Smaller C file showing the same problems.
Created attachment 4665 [details] bug.i, from compiling bug.c
Using the above attachment, you can see the problem compiling with: arm-elf-gcc -S -g -I. -mcpu=arm7dmi -Wall -save-temps bug.c vs. arm-elf-gcc -S -g -I. -Os -mcpu=arm7dmi -Wall -save-temps bug.c
On the mainline (20030806) I get this: str ip, [sp, #-4]! mov ip, sp stmfd sp!, {r3, fp, ip, lr, pc} sub fp, ip, #4 sub sp, sp, #4 mvn r3, #65280 sub r3, r3, #199 ldr r3, [r3, #0] str r3, [fp, #-20] ldmea fp, {r3, fp, sp, lr} ldmfd sp!, {ip} subs pc, lr, #4 But I think the load from fp is okay since fp is set above to fp-4, above that fp = ip, before the store to sp (which increments sp), ip = sp. The load is still there in the mainline. What do you think?
Subject: Re: arm-elf-gcc-3.2 generates wrong interrupt code w/o optimizations on All versions of gcc prior to 3.3.1 have known problems with interrupt code. R.
I would say that this instruction: ldmea fp, {r3, fp, sp, lr} is very bad. Restoring fp from fp? who knows what the value of fp would be. Also, the fact that after that you only have: ldmfd sp!, {ip} means that your stack pointer doesn't get restored to what it was at function entry. So after enough interrupts, your stack will be entirely gone. Oh, I have just cross-compiled gcc-3.3.1, and I have seen the same problem, even with the -Os and -O2 optimizations. If I am misinterpreting this assmbly please let me know, but it just looks bad to me.
Here's an analysis of the code you posted: lets say, on entry, sp = 0x1000 str ip, [sp, #-4]! @ ip -> [0xFFC], sp = 0xFFC mov ip, sp @ ip = 0xFFC stmfd sp!, {r3, fp, ip, lr, pc} @ r3 -> [0xFF8] @ fp -> [0xFF4] @ ip -> [0xFF0] @ lr -> [0xFEC] @ pc -> [0xFE8] @ sp = 0xFE8 sub fp, ip, #4 @ fp = 0xFF8 sub sp, sp, #4 @ sp = 0xFE4 mvn r3, #65280 sub r3, r3, #199 ldr r3, [r3, #0] str r3, [fp, #-20] ldmea fp, {r3, fp, sp, lr} @ r3 <- [0xFFC] @ fp <- [0x1000] (who knows what fp is at this point) @ sp <- ???? @ lr <- ???? ldmfd sp!, {ip} subs pc, lr, #4 So looking that that code, it seems horribly broken. And besides, there is no ^ operator after the ldm** operations, so the CPSR never gets restored. I don't think I want the rest of program executing in IRQ mode.
I realized I made a couple of mistakes: @ r3 -> [0xFF8] @ fp -> [0xFF4] @ ip -> [0xFF0] @ lr -> [0xFEC] @ pc -> [0xFE8] should be in reverse order: @ pc -> [0xFF8] @ lr -> [0xFF4] etc... And I think the example code has a typo. Did you mean: str r3, [fp, #-20]! instead of: str r3, [fp, #-20] In that case, offseting fp by -20 makes the ldmea make everything work out ok. But the ldmea still needs the ^ at the end
Thanks for you anlysis, the asm I copied was a direct copy of the outputed asm so this is still a problem (I do not read ARM asm that well), thanks.
Your analysis of the 3.3.1 generated code is invalid. You really should read up on how the ldm and stm instructions work. In particular how the instruction suffixes affect its behaviour.