This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug target/12637] New: GCC 3.3.1 ARM. Using "interrupt" keyword causes local variables to be corrupted when calling a function from an interrupt handler.
- From: "hugh dot okeeffe at ashling dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 16 Oct 2003 11:08:23 -0000
- Subject: [Bug target/12637] New: GCC 3.3.1 ARM. Using "interrupt" keyword causes local variables to be corrupted when calling a function from an interrupt handler.
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
PLEASE REPLY TO gcc-bugzilla@gcc.gnu.org ONLY, *NOT* gcc-bugs@gcc.gnu.org.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12637
Summary: GCC 3.3.1 ARM. Using "interrupt" keyword causes local
variables to be corrupted when calling a function from
an interrupt handler.
Product: gcc
Version: 3.3.1
Status: UNCONFIRMED
Severity: critical
Priority: P1
Component: target
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: hugh dot okeeffe at ashling dot com
CC: gcc-bugs at gcc dot gnu dot org
GCC build triplet: arm-elf-gcc
GCC host triplet: arm-elf-gcc
GCC target triplet: arm-elf-gcc
As an example to highlight this problem, I have the following two functions
within an application.
void ExternalInterrupt1(void) __attribute__ ((interrupt ("IRQ"))) ;
void ExternalInterrupt2(void);
void ExternalInterrupt1(void)
{
unsigned long ulValue;
ulValue = 0x11223344;
MyFunction(1,2,3,4,5,6);
}
void ExternalInterrupt2(void)
{
unsigned long ulValue;
ulValue = 0x11223344;
MyFunction(1,2,3,4,5,6);
}
These are compiled with "arm-elf-gcc -c -O0 -g -mlittle-endian" and
linked "arm-elf-ld -O0 -g -L /cygdrive/C/PFARM/gnuarm/
arm-elf/lib/ -L /cygdrive/C/PFARM/gnuarm/lib/gcc-lib/arm-elf/3.3.1/ -lc -lgcc -
T ./arm.ln --cref" using GNU v3.3.1
The assembler listing for these functions are as follows....
void ExternalInterrupt1(void)
{
40000444: e52dc004 str ip, [sp, -#4]!
40000448: e1a0c00d mov ip, sp
4000044c: e92dd80f stmdb sp!, {r0, r1, r2, r3, fp, ip, lr, pc}
40000450: e24cb004 sub fp, ip, #4 ; 0x4
40000454: e24dd00c sub sp, sp, #12 ; 0xc
unsigned long ulValue;
ulValue = 0x11223344;
40000458: e59f3030 ldr r3, [pc, #48] ; 40000490
<ExternalInterrupt1+0x4c>
4000045c: e50b3028 str r3, [fp, -#40]
MyFunction(1,2,3,4,5,6);
40000460: e3a03005 mov r3, #5 ; 0x5
40000464: e58d3000 str r3, [sp]
40000468: e3a03006 mov r3, #6 ; 0x6
4000046c: e58d3004 str r3, [sp, #4]
40000470: e3a00001 mov r0, #1 ; 0x1
40000474: e3a01002 mov r1, #2 ; 0x2
40000478: e3a02003 mov r2, #3 ; 0x3
4000047c: e3a03004 mov r3, #4 ; 0x4
40000480: ebffffe6 bl 40000420 <MyFunction>
}
40000484: e91b680f ldmdb fp, {r0, r1, r2, r3, fp, sp, lr}
40000488: e8bd1000 ldmia sp!, {ip}
4000048c: e25ef004 subs pc, lr, #4 ; 0x4
40000490: 11223344 teqne r2, r4, asr #6
40000494 <ExternalInterrupt2>:
void ExternalInterrupt2(void)
{
40000494: e1a0c00d mov ip, sp
40000498: e92dd800 stmdb sp!, {fp, ip, lr, pc}
4000049c: e24cb004 sub fp, ip, #4 ; 0x4
400004a0: e24dd00c sub sp, sp, #12 ; 0xc
unsigned long ulValue;
ulValue = 0x11223344;
400004a4: e59f3028 ldr r3, [pc, #40] ; 400004d4
<ExternalInterrupt2+0x40>
400004a8: e50b3010 str r3, [fp, -#16]
MyFunction(1,2,3,4,5,6);
400004ac: e3a03005 mov r3, #5 ; 0x5
400004b0: e58d3000 str r3, [sp]
400004b4: e3a03006 mov r3, #6 ; 0x6
400004b8: e58d3004 str r3, [sp, #4]
400004bc: e3a00001 mov r0, #1 ; 0x1
400004c0: e3a01002 mov r1, #2 ; 0x2
400004c4: e3a02003 mov r2, #3 ; 0x3
400004c8: e3a03004 mov r3, #4 ; 0x4
400004cc: ebffffd3 bl 40000420 <MyFunction>
}
400004d0: e91ba800 ldmdb fp, {fp, sp, pc}
400004d4: 11223344 teqne r2, r4, asr #6
When using the "interrupt" keyword, the problem occurs on the call
to "MyFunction". When the parameters are being pushed onto
the stack, the "ulValue" local variable gets corrupted. In the function where
the "interrupt" keyword is not used, this
corruption does not happen.
The assembler code analysis has shown the following.
Without using the interrupt keyword (and with the stack pointer at 0x4000F000
on entry to the function):
===============================================================================
=========================
1. Backup the SP into IP
2. Store 0x4 registers on to the stack. SP is now at 0x4000EFF0
3. Subtract 0x4 from the IP value and store the result into FP. FP is now
0x4000EFFC
4. Subtract 0xC from the SP value and store the result into SP. SP is now
0x4000EFE4.
5. Load the value 0x11223344 into r3.
6. Store the value in r3 into the location 0x4000EFEC
Note that with the above, the registers (in step 2) are stored from 0x4000EFF0
to 0x4000EFFC. The ulLocalValue is stored at
0x4000EFEC. The addresses 0x4000EFE4 & 0x4000EFE8 are unused on the stack. And
finally the SP is now pointing to 0x4000EFE4.
Using the interrupt keyword (and with the stack pointer at 0x4000F000 after
the first instruction in the function):
===============================================================================
====================================
1. Backup the SP into IP
2. Store 0x8 registers on to the stack. SP is now at 0x4000EFE0
3. Subtract 0x4 from the IP value and store the result into FP. FP is now
0x4000EFFC
4. Subtract 0xC from the SP value and store the result into SP. SP is now
0x4000EFD4.
5. Load the value 0x11223344 into r3.
6. Store the value in r3 into the location 0x4000EFD4
Note that with the above, the registers (in step 2) are stored from 0x4000EFE0
to 0x4000EFFC. The ulLocalValue is stored at
0x4000EFD4. The addresses 0x4000EFDC & 0x4000EFD8 are unused on the stack. And
finally the SP is now pointing to 0x4000EFD4.
However the ulLocalValue is now at the same location as the stack pointer and
is primed for destruction.
Following the previous non-interrupt example, it would have been expected that
the compiler would have put the ulLocalValue
into 0x4000EFDC. Therefore, intead of the "str r3, [fp, -#40]", it should
have been a "str r3, [fp, -#32]"