[vox-tech] bug in gcc?
Peter Jay Salzman
vox-tech@lists.lugod.org
Thu, 19 Sep 2002 12:20:29 -0700
with gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-112)
norm.c:
int z;
int main(void)
{ z = 3;
z = z + 1;
return 0;
}
pete.c:
int z;
int main(void)
{
z = 3;
z = z + 1;
return 0;
}
compile the programs:
lifshitz.ucdavis.edu% gcc -g -W -Wall -o pete pete.c
lifshitz.ucdavis.edu% gcc -g -W -Wall -o norm norm.c
debug pete:
lifshitz.ucdavis.edu% gdb -quiet pete
(gdb) break main
Breakpoint 1 at 0x80483d3: file pete.c, line 5.
(gdb) l
1 int z;
2
3 int main(void)
4 {
5 z = 3; <--- break main
6 z = z + 1;
7 return 0;
8 }
debug norm:
lifshitz.ucdavis.edu% gdb -quiet norm
(gdb) break main
Breakpoint 1 at 0x80483dd: file norm.c, line 5.
(gdb) l
1 int z;
2
3 int main(void)
4 { z = 3;
5 z = z + 1; <--- break main
6 return 0;
7 }
gcc recognizes the first line of the function to be the line AFTER the
opening curly brace, whether or not there happens to be a C statement on
that line.
at first i thought maybe the compiler was optimizing the "z=3" line out
of existence. after all, z is fully deterministic in this code, and the
compiler can easily see that in such a simplistic program.
so i wrote another function and used something that gcc can't ignore: a
function call (to printf()):
elmo.c:
#include <stdio.h>
int z =3;
int main(void)
{ printf("z is %d\n", z);
return 0;
}
compile elmo:
lifshitz.ucdavis.edu% gcc -g -W -Wall -o elmo elmo.c
debug elmo:
lifshitz.ucdavis.edu% gdb elmo
(gdb) b main
Breakpoint 1 at 0x804841c: file elmo.c, line 7.
(gdb) l
1 #include <stdio.h>
2 int z =3;
3
4 int main(void)
5 { printf("z is %d\n", z);
6
7 return 0; <--- break main
8 }
this happens with locals too (when i first wrote this email, i thought
it didn't. apparently, this bug doesn't exist on debian sarge's gcc
2.95).
oscar.c:
int main(void)
{ int z = 3;
z = z + 1;
return 0;
}
compile oscar:
lifshitz.ucdavis.edu% gcc -g -W -Wall -o oscar oscar.c
debug oscar:
(gdb) break main
Breakpoint 1 at 0x80483dd: file oscar.c, line 3.
(gdb) l
1 int main(void)
2 { int z = 3;
3 z = z + 1; <--- break main
4 return 0;
5 }
looking at the assembly code:
lifshitz.ucdavis.edu% gcc -g -S norm.c
lifshitz.ucdavis.edu% gcc -g -S pete.c
norm.s: pete.s:
.globl main .globl main
.type main,@function .type main,@function
main: main:
.stabn 68,0,4,.LM1-main .stabn 68,0,4,.LM1-main
.LM1: .LM1:
pushl %ebp pushl %ebp
movl %esp, %ebp movl %esp, %ebp
movl $3, z .stabn 68,0,5,.LM2-main
.stabn 68,0,5,.LM2-main .LM2:
.LM2: movl $3, z
incl z .stabn 68,0,6,.LM3-main
.stabn 68,0,6,.LM3-main .LM3:
.LM3: incl z
movl $0, %eax .stabn 68,0,7,.LM4-main
.stabn 68,0,7,.LM4-main .LM4:
.LM4: movl $0, %eax
popl %ebp .stabn 68,0,8,.LM5-main
ret .LM5:
popl %ebp
ret
this shows that although the instructions are the same between norm and
pete, the debugging info is definitely different.
norm thinks that this is related to the following. consider the
following program. call is "ernie.s":
# sample program; does a (not very efficient) sort of the array x, using
# the algorithm (expressed in pseudo-C code notation):
# for each element x[i]
# find the smallest element x[j] among x[i+1], x[i+2], ...
# swap x[i] and x[j]
.equ xlength, 7
.data
x:
.long 1
.long 5
.long 2
.long 18
.long 25
.long 22
.long 4
.text
.globl _start
_start:
callinit:
call init # initialize needed registers
# register usage:
# EAX points to next place in sorted array to be determined
# ECX is the value currently in that spot
# EBX is our loop counter (number of remaining iterations)
# ESI points to the smallest element found via findmin
# EDI contains the value of that element
top: call findmin
mov (%eax), %ecx
# need to swap?
cmpl %ecx, %edi
jge nexti
call swap
nexti:
decl %ebx
jz done
addl $4, %eax
jmp top
done: movl %eax, %eax # dummy, just for running in debugger
init:
movl $x, %eax
movl $xlength, %ebx
decl %ebx
ret
findmin:
# register usage:
# EDX points to the current element to be compared
# EBP serves as our loop counter (number of remaining
# iterations)
# ECX used as scratch register (no conflict with "main")
movl $999999, %edi
movl %eax, %edx
addl $4, %edx
movl %ebx, %ebp
findminloop:
movl (%edx), %ecx
cmpl %ecx, %edi
js nextj
# we've found a new minimum
movl %edx, %esi
movl %ecx, %edi
nextj:
decl %ebp
jz donefindmin
addl $4, %edx
jmp findminloop
donefindmin:
# restore old EAX value
ret
swap:
movl %edi, (%eax)
movl %ecx, (%esi)
ret
assemble and link this program with:
p@satan% as --gstabs -o ernie.o ernie.s
p@satan% ld -o ernie ernie.o
oops!! last night, gcc and a bunch of other compiler related packages
got updated on sarge.
before last night, setting a breakpoint on _start or callinit resulted
in either a segfault for gdb or a breakpoint assigned the number "-1"
(instead of 1).
today, when i just checked, it seems to work. of course. i should've
posted this email last night. :)
anyway, i'm not sure what to make of all this. in the worst case
scenario, it seems like a minor sort of thing. but i'm curious whether
people think this is a bug or not.
pete
--
Fingerprint: B9F1 6CF3 47C4 7CD8 D33E 70A9 A3B9 1945 67EA 951D