This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug driver/81658] New: gcc configured with --enable-default-pie on SPARC produces buggy executable from working .o files


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81658

            Bug ID: 81658
           Summary: gcc configured with --enable-default-pie on SPARC
                    produces buggy executable from working .o files
           Product: gcc
           Version: 6.4.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: driver
          Assignee: unassigned at gcc dot gnu.org
          Reporter: bruno at clisp dot org
  Target Milestone: ---

Created attachment 41886
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=41886&action=edit
tarball of object files

GCC, configured with --enable-default-pie on SPARC, links object files that
happen to access global variables in such a way that the resulting executable
is broken: it crashes when attempting to access the global variable.

Test case: Find attached a tarball with 4 object files. They were produced from
https://haible.de/bruno/gnu/libffcall-2.0-20170731.tar.gz on a Linux/sparc
machine with gcc 6.3.0 (that is NOT configured with --enable-default-pie). On
that machine:
$ gcc -m32 vacall-libapi.o vacall.o vacall-structcpy.o minitests.o
$ ./a.out
<lots of good output, succeeds>

Unpack the same tarball and link the same object files on a machine with a GCC
configured with --enable-default-pie:
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/sparc64-linux-gnu/6/lto-wrapper
Target: sparc64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.4.0-2'
--with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs
--enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-6 --program-prefix=sparc64-linux-gnu- --enable-shared
--enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext
--enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/
--enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes
--with-default-libstdcxx-abi=new --enable-gnu-unique-object
--disable-libquadmath --enable-plugin --enable-default-pie --with-system-zlib
--disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo
--with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-sparc64/jre --enable-java-home
--with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-sparc64
--with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-sparc64
--with-arch-directory=sparc64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar
--enable-objc-gc=auto --enable-multiarch --enable-targets=all
--with-cpu-32=ultrasparc --with-long-double-128 --enable-multilib
--enable-checking=release --build=sparc64-linux-gnu --host=sparc64-linux-gnu
--target=sparc64-linux-gnu
Thread model: posix
gcc version 6.4.0 20170724 (Debian 6.4.0-2) 

$ gcc -m32 vacall-libapi.o vacall.o vacall-structcpy.o minitests.o
$ ./a.out 
void f(void):
Segmentation fault

Using "gcc -v", I see that the link command is essentially
/usr/lib/gcc/sparc64-linux-gnu/6/collect2 --sysroot=/ --build-id --eh-frame-hdr
-m elf32_sparc -dynamic-linker /lib/ld-linux.so.2 -relax -pie -o a.out
/usr/lib32/Scrt1.o /usr/lib32/crti.o
/usr/lib/gcc/sparc64-linux-gnu/6/32/crtbeginS.o
-L/usr/lib/gcc/sparc64-linux-gnu/6/32 -L/usr/lib32 -L/lib32 -L/usr/lib32
-L/usr/lib/gcc/sparc64-linux-gnu/6 -L/usr/lib vacall-libapi.o vacall.o
vacall-structcpy.o minitests.o -lgcc --as-needed -lgcc_s --no-as-needed -lc
-lgcc --as-needed -lgcc_s --no-as-needed
/usr/lib/gcc/sparc64-linux-gnu/6/32/crtend.o /usr/lib32/crtn.o

If I execute it manually, the resulting a.out file crashes:
$ ./a.out 
void f(void):
Segmentation fault

But if I execute it manually without the "-pie" option, the resulting a.out
file works.
$ ./a.out
<lots of good output, succeeds>

The difference between the two is at the beginning of function vacall_receiver.
   0x5b48 <vacall_receiver>:    save  %sp, -144, %sp
   0x5b4c <vacall_receiver+4>:  sethi  %hi(0), %o0
   0x5b50 <vacall_receiver+8>:  sethi  %hi(0x1c400), %l7
   0x5b54 <vacall_receiver+12>: call  0x5b40
   0x5b58 <vacall_receiver+16>: add  %l7, 0xac, %l7     ! 0x1c4ac
   0x5b5c <vacall_receiver+20>: or  %o0, 0x180, %o0
   0x5b60 <vacall_receiver+24>: ld  [ %l7 + %o0 ], %o1
At the instruction
   ld  [ %l7 + %o0 ], %o1
the values are:
In the case that works:
   %l7 + %o0 = 0x32180 => loads the word 0x32b58 into %o1
   &vacall_function = 0x32b58
In the case that does not work:
   %l7 + %o0 = 0x70022180 => loads the word 0x700456b0 into %o1
   &vacall_function = 0x70022b58
   The value in memory is wrong! 0x700456b0 is too high by 0x22b58
   (strange coincidence of numbers - looks like a relocation has been applied
twice instead of just once)

When I set a watchpoint at that location, I see that it's modified only once:

(gdb) watch *(void**)0x70022180
Hardware watchpoint 1: *(void**)0x70022180
(gdb) run
Starting program: /home/haible/vacall/a.out 

Watchpoint 1: *(void**)0x70022180

Old value = (void *) 0x22b58
New value = (void *) 0x700456b0
elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=0, nrelative=<optimized
out>, relsize=<optimized out>, reladdr=<optimized out>, map=0xf7ffaa10)
    at do-rel.h:112
112     do-rel.h: No such file or directory.


I'm reporting this as a bug in GCC, because it's GCC which passes the option
'-pie' to the linker, and it is this option which causes the executable to be
non-functional.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]