c/1523: GCC 2.97 miscompiles with -fomit-frame-pointer

Andreas Franck afranck@gmx.de
Thu Dec 28 04:16:00 GMT 2000


>Number:         1523
>Category:       c
>Synopsis:       GCC 2.97 miscompiles with -fomit-frame-pointer
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    unassigned
>State:          open
>Class:          wrong-code
>Submitter-Id:   net
>Arrival-Date:   Thu Dec 28 04:16:00 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Andreas Franck
>Release:        2.97 20001222 (experimental)
>Organization:
private
>Environment:
System: Linux dg1kfa.ampr.org 2.4.0-test13-pre4 #3 Sat Dec 23 12:59:32 CET 2000 i686 unknown
Architecture: i686
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: ../gcc/configure --prefix=/usr --enable-shared --enable-threads
>Description:
When compiling the following code with -O2 -fomit-frame-pointer, GCC
miscompiles the main function: the local stack space is cleared
before func2 is called, thus overwriting the local tmp structure with
its address and the return address. Compiling without 
-fomit-frame-pointer leaves everything fine and working.

This only happens in this certain assembler situation, which I
reproduced from a very similar structure in linux-2.4.0-test12, which
therefore fails on booting when compiled with recent GCC snapshots.

GCC 2.95.2 compiles this fine, regardless of -fomit-frame-pointer.

I think it is unwise to assume a structure is no longer needed when
a pointer to it is passed to an assembler routine not explicitly
mentioning one of its members, so this should be fixed.

>How-To-Repeat:
Compile and run the following code with and without 
-fomit-frame-pointer on any Intel x86 platform:

struct mystruct {
        int member1;
        int member2;
};
 
void func1(struct mystruct* s)
{
        s->member1 = 1;
        s->member2 = 2;
}
 
void inline func2(struct mystruct* s)
{
        __asm__ __volatile__(
                "decl (%0)\n\t"         /* decrement member1 */
                "call func3\n\t"
                :/* no outputs */
                :"c" (s)                /* Base address of the structure */
                :"memory");             /* This asm modifies memory */
}
 
asm(
".align 4\n"
".globl func3\n"
"func3:\n\t"
        "pushl %ecx\n\t"        /* Push structure address as parameter */
        "call func4\n\t"
        "popl %ecx\n\t"         /* And get it back.. */
        "ret"
);
 
void func4(struct mystruct* s)
{
        if (s->member1)
                abort();
}
 
int main(void)
{
        struct mystruct tmp;
 
        func1(&tmp);
        func2(&tmp);
 
        return 0;
}                                                                               

>Fix:
	Change the assembler code in func2 to:
	
	__asm__ __volatile__(
		"decl %1\n\t"
		"call func3\n\t"
		:"=m" (s->member1)
		:"m" (s->member1), "c" (s)
		:"memory");

This additionally clobbers the structure members, which stops the
optimizer to think they are no longer needed.

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the Gcc-bugs mailing list