The C compiler generates wrong assembler code for functions with __attribute__ ((interrupt ("IRQ"))). Link register lr in interrupt function is decremented two times before it is loaded back to the program counter pc. It is decremented at the beginning of interrupt routime (sub lr, lr, #4) and again at the end (subs pc, lr, #4). It should be decremented only once. Such a bug was also reported previously (ID 16634, ID 25428). Here is the complete example:
PROGRAM bug.c: void function( void ) { volatile unsigned int *a; a = (unsigned int *)2000; *a = 1; *a = 0; } void IRQ_Handler( void ) __attribute__ ((interrupt ("IRQ"))); void IRQ_Handler( void ) { volatile unsigned int s, *a; a = (unsigned int *)2500; s = *a; function(); } COMPILATION OUTPUT: arm-4.1.1-eabi-gcc -v -save-temps -Wall -c -O -o bug.o bug.c Using built-in specs. Target: arm-none-eabi Configured with: ./configure --target=arm-none-eabi --program-prefix=arm-4.1.1-eabi- Thread model: single gcc version 4.1.1 /usr/local/packages/arm411/bin/../libexec/gcc/arm-none-eabi/4.1.1/cc1 -E -quiet -v -iprefix /usr/local/packages/arm411/bin/../lib/gcc/arm-none-eabi/4.1.1/ -D__USES_INITFINI__ bug.c -Wall -O -fpch-preprocess -o bug.i ignoring nonexistent directory "/usr/local/packages/arm411/bin/../lib/gcc/arm-none-eabi/4.1.1/../../../../arm-none-eabi/sys-include" ignoring nonexistent directory "/usr/local/lib/gcc/arm-none-eabi/4.1.1/include" ignoring nonexistent directory "/usr/local/lib/../arm-none-eabi/sys-include" ignoring nonexistent directory "/usr/local/lib/../arm-none-eabi/include" #include "..." search starts here: #include <...> search starts here: /usr/local/packages/arm411/bin/../lib/gcc/arm-none-eabi/4.1.1/include /usr/local/packages/arm411/bin/../lib/gcc/arm-none-eabi/4.1.1/../../../../arm-none-eabi/include End of search list. /usr/local/packages/arm411/bin/../libexec/gcc/arm-none-eabi/4.1.1/cc1 -fpreprocessed bug.i -quiet -dumpbase bug.c -auxbase-strip bug.o -O -Wall -version -o bug.s GNU C version 4.1.1 (arm-none-eabi) compiled by GNU C version 4.1.1 20060525 (Red Hat 4.1.1-1). GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=128878 Compiler executable checksum: 8b248e68ff58c0b76da33bbc4bade307 /usr/local/packages/arm411/bin/../lib/gcc/arm-none-eabi/4.1.1/../../../../arm-none-eabi/bin/as -meabi=4 -o bug.o bug.s ASSEMBLER OUTPUT: .file "bug.c" .text .align 2 .global function .type function, %function function: @ Function supports interworking. @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. @ lr needed for prologue mov r3, #0 mov r2, #1 str r2, [r3, #2000] str r3, [r3, #2000] bx lr .size function, .-function .align 2 .global IRQ_Handler .type IRQ_Handler, %function IRQ_Handler: @ Interrupt Service Routine. @ args = 0, pretend = 0, frame = 8 @ frame_needed = 0, uses_anonymous_args = 0 sub lr, lr, #4 stmfd sp!, {r0, r1, r2, r3, ip, lr} sub sp, sp, #8 mov r3, #0 ldr r3, [r3, #2500] str r3, [sp, #4] bl function add sp, sp, #8 ldmfd sp!, {r0, r1, r2, r3, ip, lr} subs pc, lr, #4 .size IRQ_Handler, .-IRQ_Handler .ident "GCC: (GNU) 4.1.1" Best regards, Jurij Kotar -- Summary: Bug in generation of interrupt function code for ARM processor Product: gcc Version: 4.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: jurij dot kotar at gmail dot com GCC build triplet: i386-redhat-linux GCC host triplet: i386-redhat-linux GCC target triplet: arm-none-eabi http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27859