The generated code copies an argument to a local (new) stack frame before allocating that stack frame (adjusting the stack pointer), allowing an interrupt to corrupt that value. The argument is copied to memory, so that the argument's address can be passed to another function. As long as an interrupt doesn't occur within the 2 instruction window between copying the argument and adjusting the stack pointer, everything works fine.
Compiler command line: arm-elf-gcc -v -save-temps -c -mcpu=arm7tdmi -mbig-endian -Wall -Wpointer- arith -Wstrict-prototypes -Winline -Wundef -Woverloaded-virtual -g -O2 - ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fvtable-gc -finit- priority -D__ECOS -Wp,-MD,HPIDrv.tmp -o HPIDrv.o HPIDrv.c > HPIDrv.out 2>&1 Compiler output: Reading specs from /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/specs Configured with: ../../gcc-3.2.1/configure --prefix=/home/tools/gnu-3.2.1 -- target=arm-elf -v --enable-languages=c,c++ --with-gnu-as --with-gnu-ld --with- newlib --with-gxx-include-dir=/home/tools/gnu-3.2.1/arm-elf/include Thread model: single gcc version 3.2.1 /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/cpp0 -lang-c -v - iprefix /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/ -D__GNUC__=3 - D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=1 -D__GXX_ABI_VERSION=102 -D__ELF__ - D__ELF__ -D__OPTIMIZE__ -D__STDC_HOSTED__=1 -Acpu=arm -Amachine=arm - D__ARM_ARCH_4T__ -D__APCS_32__ -D__ARMEB__ -D__ELF__ -D__USES_INITFINI__ - D__arm__ -D__ECOS -MD HPIDrv.tmp HPIDrv.c -Wall -Wpointer-arith -Wstrict- prototypes -Winline -Wundef -Woverloaded-virtual HPIDrv.i GNU CPP version 3.2.1 (cpplib) (ARM/ELF) ignoring nonexistent directory "/home/tools/gnu-tools/arm-elf/sys-include" ignoring nonexistent directory "/home/tools/gnu-3.2.1/arm-elf/sys-include" ignoring duplicate directory "/home/tools/gnu-3.2.1/lib/gcc-lib/arm- elf/3.2.1/include" ignoring duplicate directory "/home/tools/gnu-3.2.1/arm-elf/include" #include "..." search starts here: #include <...> search starts here: /home/tools/gnu-tools/lib/gcc-lib/arm-elf/3.2.1/include /home/tools/gnu-tools/arm-elf/include /home/tools/gnu-3.2.1/include End of search list. /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/cc1 -fpreprocessed HPIDrv.i -quiet -dumpbase HPIDrv.c -mcpu=arm7tdmi -mbig-endian -g -O2 -Wall - Wpointer-arith -Wstrict-prototypes -Winline -Wundef -Woverloaded-virtual - version -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fvtable- gc -finit-priority -o HPIDrv.s GNU CPP version 3.2.1 (cpplib) (ARM/ELF) GNU C version 3.2.1 (arm-elf) compiled by GNU C version 3.2.2 20030222 (Red Hat Linux 3.2.2-5). HPIDrv.c:20: warning: conflicting types for built-in function `memset' /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/../../../../arm- elf/bin/as -EB -marm7tdmi -o HPIDrv.o HPIDrv.s HPIDrv.i file: # 1 "HPIDrv.c" # 1 "<built-in>" # 1 "<command line>" # 1 "HPIDrv.c" typedef unsigned char uint8; typedef unsigned short uint16; typedef void tHPIDrv; typedef struct hpi_info { tHPIDrv *HPIDrv; unsigned int CfgMask; uint16 ChannelID; } HPI_INFO; # 19 "HPIDrv.c" extern int diag_printf(const char *fmt, ...); extern void memset(void *, int, unsigned int); int HPIDrv_SendMessages(tHPIDrv *const pDrv, const uint16 Type, const uint16 ChannelID, const uint8 NumBlocks, const uint16 *const pSize, const uint16 *const *const ppData) { diag_printf("pDrv=0x%08X, Type=0x%04X, ChannelID=%d, NumBlocks=%d, Size=%d, pData=0x%08X\n", pDrv, Type, ChannelID, NumBlocks, *pSize, *ppData); return 0; } inline int HPIDrv_SendMessage(tHPIDrv *const pDrv, const uint16 Type, const uint16 ChannelID, const uint16 Size, const uint16 *const pData) { return HPIDrv_SendMessages(pDrv, Type, ChannelID, 1, &Size, &pData); } int testit(HPI_INFO *hpi) { typedef struct parm { uint16 a; uint16 b; uint16 c[8]; } parm_t; parm_t V42Parms; memset(&V42Parms, 0, sizeof(V42Parms)); if (HPIDrv_SendMessage(hpi->HPIDrv, 0x0800|0x0002, (hpi->CfgMask & 0x00000001)?0:hpi->ChannelID, sizeof(V42Parms)/sizeof(uint16), (uint16 *)&V42Parms) != 0) { return 0; } return 1; } Portion of HPIDrv.s file showing invalid code generation in HPIDrv_SendMessage () function: .Lfe2: .size testit,.Lfe2-testit .section .text.HPIDrv_SendMessage,"ax",%progbits .align 2 .global HPIDrv_SendMessage .type HPIDrv_SendMessage,function HPIDrv_SendMessage: .LFB3: .LSM25: @ args = 4, pretend = 0, frame = 4 @ frame_needed = 1, uses_anonymous_args = 0 mov ip, sp .LCFI8: stmfd sp!, {fp, ip, lr, pc} .LCFI9: mov r3, r3, asl #16 sub fp, ip, #4 .LCFI10: mov r3, r3, asr #16 sub lr, fp, #12 strh r3, [fp, #-14] @ movhi <-- This instruction is redundant .LSM26: mov r1, r1, asl #16 .LSM27: strh r3, [lr, #-2]! @ movhi <-- The 'Size' argument (register r3) is copied to the local stack frame here, BEFORE the stack frame is allocated (below). .LSM28: mov r2, r2, asl #16 .LSM29: sub sp, sp, #12 <-- Stack frame allocated. .LCFI11: .LSM30: add ip, fp, #4 .LSM31: .LSM32: mov r1, r1, lsr #16 mov r2, r2, lsr #16 mov r3, #1 str lr, [sp, #0] str ip, [sp, #4] bl HPIDrv_SendMessages ldmea fp, {fp, sp, pc} .LFE3: -- Summary: Improper code generation causes stack corruption Product: gcc Version: 3.2.1 Status: UNCONFIRMED Severity: critical Priority: P2 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: jay at systech dot com CC: gcc-bugs at gcc dot gnu dot org GCC host triplet: i386-redhat-linux GCC target triplet: arm-elf http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20182