This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug driver/81658] New: gcc configured with --enable-default-pie on SPARC produces buggy executable from working .o files
- From: "bruno at clisp dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Tue, 01 Aug 2017 21:37:40 +0000
- Subject: [Bug driver/81658] New: gcc configured with --enable-default-pie on SPARC produces buggy executable from working .o files
- Auto-submitted: auto-generated
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.