https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81653
Bug ID: 81653
Summary: gcc configured with --enable-default-pie on SPARC
miscompiles hand-written .s 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 41884
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=41884&action=edit
Test case program, part 1
GCC, configured with --enable-default-pie on SPARC, miscompiles hand-written .s
files that happen to access global variables. The cause is that it passes the
option "-K PIC" to the assembler; the assembler then interprets the .s file
differently (by putting different relocations into the .o file). The resulting
executable does not work.
Test case: Find attached main.c and getter.s.
With a GCC not configured with --enable-default-pie:
$ gcc -m32 main.c getter.s
$ ./a.out
$ echo $?
42
With a GCC configured with --enable-default-pie:
$ gcc -m32 main.c getter.s
$ ./a.out
Segmentation fault
$ gdb a.out
(gdb) run
Starting program: /home/haible/a.out
Program received signal SIGSEGV, Segmentation fault.
0x700006c8 in getter ()
(gdb) disassemble getter
Dump of assembler code for function getter:
0x700006c0 <+0>: sethi %hi(0), %g1
0x700006c4 <+4>: or %g1, 0x10, %g1 ! 0x10
=> 0x700006c8 <+8>: ld [ %g1 ], %o0
0x700006cc <+12>: retl
0x700006d0 <+16>: nop
End of assembler dump.
(gdb) print $g1
$1 = 16
Details about this GCC version:
$ 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)
Analysis of the difference between that and this GCC:
1) The "as" invocation was
as -v -s -Av9a -32 -relax -o /tmp/cci9hbn2.o getter.s
and in this GCC version is
as -v -s -K PIC -Av9a -32 -relax -o /tmp/ccYeBhLa.o getter.s
2) The relocations in the object file:
That GCC:
$ gcc -m32 -c getter.s -o getter.o
$ objdump --disassemble --reloc getter.o
getter.o: file format elf32-sparc
Disassembly of section .text:
00000000 <getter>:
0: 03 00 00 00 sethi %hi(0), %g1
0: R_SPARC_HI22 variable
4: 82 10 60 00 mov %g1, %g1 ! 0 <getter>
4: R_SPARC_LO10 variable
8: d0 00 40 00 ld [ %g1 ], %o0
c: 81 c3 e0 08 retl
10: 01 00 00 00 nop
This GCC:
$ gcc -m32 -c getter.s -o getter.o
$ objdump --disassemble --reloc getter.o
getter.o: file format elf32-sparc
Disassembly of section .text:
00000000 <getter>:
0: 03 00 00 00 sethi %hi(0), %g1
0: R_SPARC_GOT22 variable
4: 82 10 60 00 mov %g1, %g1 ! 0 <getter>
4: R_SPARC_GOT10 variable
8: d0 00 40 00 ld [ %g1 ], %o0
c: 81 c3 e0 08 retl
10: 01 00 00 00 nop
As you can see, the assembler has inserted different relocations with "-K PIC"
than without.
3) The instructions in the linked a.out file:
That GCC:
$ objdump --disassemble a.out
00010480 <main>:
10480: 9d e3 bf a0 save %sp, -96, %sp
10484: 03 00 00 88 sethi %hi(0x22000), %g1
10488: 82 10 60 68 or %g1, 0x68, %g1 ! 22068 <variable>
1048c: 84 10 20 2a mov 0x2a, %g2
10490: c4 20 40 00 st %g2, [ %g1 ]
10494: 40 00 00 06 call 104ac <getter>
10498: 01 00 00 00 nop
1049c: 82 10 00 08 mov %o0, %g1
104a0: b0 10 00 01 mov %g1, %i0
104a4: 81 cf e0 08 rett %i7 + 8
104a8: 01 00 00 00 nop
000104ac <getter>:
104ac: 03 00 00 88 sethi %hi(0x22000), %g1
104b0: 82 10 60 68 or %g1, 0x68, %g1 ! 22068 <variable>
104b4: d0 00 40 00 ld [ %g1 ], %o0
104b8: 81 c3 e0 08 retl
104bc: 01 00 00 00 nop
This GCC:
$ objdump --disassemble a.out
00000680 <main>:
680: 9d e3 bf a0 save %sp, -96, %sp
684: 2f 00 00 46 sethi %hi(0x11800), %l7
688: ae 05 e1 74 add %l7, 0x174, %l7 ! 11974 <__FRAME_END__+0x111e4>
68c: 7f ff ff 85 call 4a0 <__sparc_get_pc_thunk.l7>
690: 01 00 00 00 nop
694: 03 00 00 00 sethi %hi(0), %g1
698: 82 18 60 9c xor %g1, 0x9c, %g1
69c: 82 05 c0 01 add %l7, %g1, %g1
6a0: 84 10 20 2a mov 0x2a, %g2
6a4: c4 20 40 00 st %g2, [ %g1 ]
6a8: 40 00 00 06 call 6c0 <getter>
6ac: 01 00 00 00 nop
6b0: 82 10 00 08 mov %o0, %g1
6b4: b0 10 00 01 mov %g1, %i0
6b8: 81 cf e0 08 return %i7 + 8
6bc: 01 00 00 00 nop
000006c0 <getter>:
6c0: 03 00 00 00 sethi %hi(0), %g1
6c4: 82 10 60 10 or %g1, 0x10, %g1 ! 10 <_init-0x3e4>
6c8: d0 00 40 00 ld [ %g1 ], %o0
6cc: 81 c3 e0 08 retl
6d0: 01 00 00 00 nop
6d4: 01 00 00 00 nop
6d8: 01 00 00 00 nop
6dc: 01 00 00 00 nop
You can see the effect: The 'getter' function no longer references 'variable'.