[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