From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686) Gecko/20030610 Galeon/1.3.7 Description of problem: When compiling net/ipv4/ipvs/ip_vs_core.c in linux 2.6.0-test3 (with user-mode linux patch, ARCH=um), wrong code is generated for the function ip_vs_in(). The preprocessed file is attached, and the assembly can be generated with gcc -O2 -fno-strict-aliasing -fomit-frame-pointer -S -o out.s out.i The relevent part of the generated assembly code are as follows: ip_vs_in: pushl %ebp pushl %edi pushl %esi pushl %ebx subl $24, %esp movl 48(%esp), %ebp movl (%ebp), %esi movl 36(%esi), %ebx movzbl 9(%ebx), %eax pushl %eax call ip_vs_proto_get xorl %edx, %edx cmpb $0, 114(%esi) movl %eax, %edi jne .L378 cmpl $loopback_dev, 24(%esi) je .L378 .L377: testl %edx, %edx movl $1, %eax jne .L374 cmpb $1, 9(%ebx) je .L428 .L380: [snip] .L374: addl $12, %esp popl %ebx popl %esi popl %edi popl %ebp ret .p2align 2,,3 [snip] .L378: movl $1, %edx jmp .L377 When the path .L378->.L377->.L374 is followed (corresponding to taking the first "if" and return in the C function), it is obvious that %esp had a net decrease by 16, so the function will return to the wrong spot. I have not tried rawhide, but gcc-ssa-3.5ssa-0.20030617.24 generates correct code using the same options. Version-Release number of selected component (if applicable): gcc-3.2.2-5 How reproducible: Always Steps to Reproduce: 1. Download the attached file, decompress as out.i 2. Run "gcc -O2 -fno-strict-aliasing -fomit-frame-pointer -S -o out.s out.i" with gcc-3.2.2-5. 3. Search for "ip_vs_in:" in out.s and observe the results. Actual Results: The wrong code as shown above, crashing the final program. Expected Results: Correct code. %esp should not change between function entry and exit. Additional info:
Created attachment 93781 [details] Preprocessed test case, bzip2'd out.i attached here.
Reduced into: /* { dg-do run } */ /* { dg-options "-O2 -fomit-frame-pointer" } */ /* { dg-options "-O2 -fomit-frame-pointer -march=i386" { target i?86-*-* } } */ extern void abort (void); extern void exit (int); struct S { int *a; unsigned char *b, c; }; int v; void foo (unsigned short x) { } int bar (struct S **x, int *y) { *y = 25; return 0; } int baz (struct S **x) { struct S *y = *x; unsigned char *a = y->b; foo (*a); if (__builtin_expect (y->c != 0 || y->a == &v, 0)) return 1; if (__builtin_expect (*a == 1, 0)) { int a, b = bar (x, &a); if (a) return b; } return 0; } int main (void) { struct S a, *b = &a; unsigned char c; __builtin_memset (b, 0, sizeof (a)); a.a = &v; a.b = &c; if (baz (&b) != 1) abort (); exit (0); } Seems to be broken on gcc-3_2-rhl8-branch and fixed on gcc-3_3-rhl-branch.
http://gcc.gnu.org/ml/gcc-patches/2003-08/msg01618.html