The assembler instructions gcc generates for a 'goto' statement only respect
the low 16 bits of the destination address by default (or in when using PIC in
general). This causes the program to jump to the wrong location and soon
thereafter segfault. The -mno-explicit-relocs seems to work around this
problem, but is no solution for a PIC compilation.

This problem appears in both:
Using built-in specs.
Target: mips-unknown-linux-gnu
Configured with: ../gcc/configure --prefix=/home/terpstra/gcc.bin
--enable-languages=c
Thread model: posix
gcc version 4.4.4 (GCC) 

and:
Using built-in specs.
Target: mips-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.4-3'
--with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared
--enable-multiarch --enable-linker-build-id --with-system-zlib
--libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls
--enable-clocale=gnu --enable-libstdcxx-debug --disable-libssp
--enable-targets=all --enable-checking=release --build=mips-linux-gnu
--host=mips-linux-gnu --target=mips-linux-gnu
Thread model: posix
gcc version 4.4.4 (Debian 4.4.4-3) 

However, I've been having related problems since as far back as gcc-3.4 (at
least). The gcc-snapshot in debian also does not resolve this issue. Sometimes
different compiler versions and/or optimization flags cause compilation to
succeed. I presume this is because the jump offsets fit into 16 bits with
different optimization choices. I've seen a related problem where gcc -fPIC
creates invalid assembler that with 'branch out of range' .s files. However,
first I'll see if this bug being fixed resolves the other.

I've included an example C program which can produce the buggy assembler.
Compile with:
<gcc> -std=gnu99 -O0 -fno-common -fno-strict-aliasing -fomit-frame-pointer -w
-S mlyacc.6.preprocessed-nolines.c -g -o bug.s

The problem assembler comes from the goto on line 2928:
   goto leaveChunk; 
... when tracing with gdb execution should resume on line 33861, however it
instead jumps to line 2749:

Inspecting the generated assembler:
        .loc 1 2928 0
        .set    noat
        lw      $1,%got($L894)($28)
        nop
        addiu   $1,$1,%lo($L894) 
        jr      $1
... it is easy to see that the correct label (L894) is used as destination.
However, only the low 16 bits of the address are used.

When compiled with -mno-explicit-relocs, the assembler reads as:
        .loc 1 2928 0
        .set    noat
        la      $1,$L894         #
        jr      $1   
... which works. Modifying the -mexplicit-relocs version (gcc default) to use
'la' instead of the PIC %got results in correct program execution.


-- 
           Summary: gcc produces bad MIPS jumps (in large C files)
           Product: gcc
           Version: 4.4.4
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: wesley at terpstra dot ca
 GCC build triplet: mips-unknown-linux-gnu
  GCC host triplet: mips-unknown-linux-gnu
GCC target triplet: mips-unknown-linux-gnu


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44537

Reply via email to