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