I am using the GCC 4.1.1 ARM build for Cygwin from GNUARM.
$ arm-elf-gcc -v
Using built-in specs.
Target: arm-elf
Configured with: ../gcc-4.1.1/configure --target=arm-elf
--prefix=/g/gnuarm-4.1.1 --enable-interwork --enable-multilib --with-float=soft
--with-newlib --with-headers=../newlib-1.14.0/newlib/libc/include
--enable-languages=c,c++
Thread model: single
gcc version 4.1.1
In a certain situation, the compiler generates incorrect code for a function
which results in the stack pointer being restored to the wrong value on return
from the function, and the stack then becomes corrupted. The following code
demonstrates the bug:
void dummy_func() {
}
int test_func(void *p) {
dummy_func();
register int r;
register void *h;
if (p == 0) {
return 0;
}
//r = (int)h;
return r;
}
Save it as register_bug.c, and compile with:
$ arm-elf-gcc -mthumb -mtpcs-frame -S -mcpu=arm7tdmi -fno-builtin
-fno-exceptions -mlittle-endian -fomit-frame-pointer -o register_bug_nor.s
register_bug.c
Uncomment the commented-out line, and compile again:
$ arm-elf-gcc -mthumb -mtpcs-frame -S -mcpu=arm7tdmi -fno-builtin
-fno-exceptions -mlittle-endian -fomit-frame-pointer -o register_bug_r.s
register_bug.c
If you now diff the two assembly files, you will notice that uncommenting the
line results in the following lines being added near the start of the function:
+ mov r2, r8
+ push{r2, lr}
and near the end:
+ pop {r2}
+ mov r8, r2
As you can see, more registers are pushed than popped. This means that when the
stack pointer register is later restored from the stack (pop {r1, r2, r3}; mov
sp, r3) it gets the wrong value.
--
Summary: GCC generates incorrect code on ARM in certain case,
resulting in stack corruption
Product: gcc
Version: 4.1.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: awalbran at innaworks dot com
GCC target triplet: arm-elf
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34341