For some time, Solaris 12 provides its own set of CRTs. Cf. https://gcc.gnu.org/ml/gcc-patches/2015-09/msg01638.html for some backgroup. When recently the __start_crt_compiler function in crt1.o was changed from [29] 0 0 FUNC WEAK D 0 UNDEF __start_crt_compiler to [29] 0 0 FUNC WEAK H 0 UNDEF __start_crt_compiler (i.e. hidden visibility), every single 64-bit executable started to die with SIGILL if linked with gld. Both 32-bit and /bin/ld are fine instead. Here's what I found: /usr/lib/sparcv9/crt1.o has __start_crt+0x64: 40 00 00 00 call +0x0 <__start_crt+0x64> Relocation Section: .rela.text index type offset value addend section symbol [20] R_SPARC_WPLT30 0xe4 0 0 .text __start_crt_compiler __start_crt starts at .text+0x80 [30] 0x80 0xa4 FUNC GLOB D 0 .text __start_crt [29] 0 0 FUNC WEAK H 0 UNDEF __start_crt_compiler When linking with /bin/ld, the resulting executable turns into: __start_crt+0x64: 40 00 00 00 call +0x0 <__start_crt+0x64> [76] 0x100000b80 0xa4 FUNC GLOB D 0 .text __start_crt [32] 0 0 FUNC LOCL H 0 ABS __start_crt_compiler while when I use gld instead, I get __start_crt+0x64: 7f ff fe 4f call -0x6c4 <0x100000000> [53] 0x100000660 0xa4 FUNC GLOB D 0 .text __start_crt Rainer
How is crt1.o testing that __start_crt_compiler is undefined? I'm talking about an "if (foo)" test used in a call to a weak function: if (foo) foo ();
> --- Comment #1 from Alan Modra <amodra at gmail dot com> --- > How is crt1.o testing that __start_crt_compiler is undefined? I'm talking > about an "if (foo)" test used in a call to a weak function: > if (foo) > foo (); You've got this (I'm attaching both the crt1.o and empty-ld and empty-gld executables for reference) in crt1.o: crt1.o: cc __start_crt+0x4c: 2f 00 00 00 sethi %hi(0x0), %l7 d0 __start_crt+0x50: f4 74 60 00 stx %i2, [%l1] d4 __start_crt+0x54: ac 1d e0 00 xor %l7, 0x0, %l6 d8 __start_crt+0x58: ea 5c 00 16 ldx [%l0 + %l6], %l5 dc __start_crt+0x5c: 02 c5 40 09 brz,pn %l5, +0x24 <__start_crt+0x80> ^ offsets (in hex) from the beginning of .text to allow matching with the relocs below. This is the if (__start_crt_compiler) __start_crt_compiler (); part ... e0 __start_crt+0x60: 91 3e 20 00 sra %i0, 0x0, %o0 e4 __start_crt+0x64: 40 00 00 00 call +0x0 <__start_crt+0x64> ... and here are the corresponding relocs. [17] R_SPARC_GOTDATA_OP_HIX22 0xcc 0 0 .text __start_crt_compiler [18] R_SPARC_GOTDATA_OP_LOX10 0xd4 0 0 .text __start_crt_compiler [19] R_SPARC_GOTDATA_OP 0xd8 0 0 .text __start_crt_compiler [20] R_SPARC_WPLT30 0xe4 0 0 .text __start_crt_compiler When single-stepping through this part of empty-ld (ld output), I find: __start_crt+0x4c: 2f 00 00 00 sethi %hi(0x0), %l7 __start_crt+0x50: f4 74 60 00 stx %i2, [%l1] __start_crt+0x54: ac 1d e0 08 xor %l7, 0x8, %l6 __start_crt+0x58: ea 5c 00 16 ldx [%l0 + %l6], %l5 __start_crt+0x5c: 02 c5 40 09 brz,pn %l5, +0x24 <__start_crt+0x80> __start_crt+0x60: 91 3e 20 00 sra %i0, 0x0, %o0 __start_crt+0x64: 40 00 00 00 call +0x0 <__start_crt+0x64> __start_crt+0x48: brnz,pn %l2, 0x100000b94 <__start_crt+0x54> (gdb) p/x $l2 $5 = 0xffffffff7ffffb08 __start_crt+0x4c: sethi %hi(0), %l7 __start_crt+0x54: xor %l7, 8, %l6 __start_crt+0x58: ldx [ %l0 + %l6 ], %l5 __start_crt+0x5c: brz,pn %l5, 0x100000bc0 <__start_crt+0x80> (gdb) p/x $l5 $4 = 0x0 I.e. __start_crt_compiler is 0 and the branch is taken, skipping the call. __start_crt+0x60: sra %i0, 0, %o0 __start_crt+0x80: sethi %hi(0x100000), %i3 On the other hand, with the gld-produced executable, I get __start_crt+0x4c: 2f 00 04 02 sethi %hi(0x100800), %l7 __start_crt+0x50: f4 74 60 00 stx %i2, [%l1] __start_crt+0x54: ac 1d fd f0 xor %l7, -0x210, %l6 __start_crt+0x58: aa 04 00 16 add %l0, %l6, %l5 __start_crt+0x5c: 02 c5 40 09 brz,pn %l5, +0x24 <__start_crt+0x80> __start_crt+0x60: 91 3e 20 00 sra %i0, 0x0, %o0 __start_crt+0x64: 7f ff fe 57 call -0x6a4 <0x100000000> __start_crt+0x48: brnz,pn %l2, 0x100000694 <__start_crt+0x54> (gdb) p/x $l2 $4 = 0xffffffff7ffff9d8 __start_crt+0x4c: sethi %hi(0x100800), %l7 __start_crt+0x54: xor %l7, -528, %l6 __start_crt+0x58: add %l0, %l6, %l5 __start_crt+0x5c: brz,pn %l5, 0x1000006c0 <__start_crt+0x80> (gdb) p/x $l5 $6 = 0x100000000 __start_crt+0x60: sra %i0, 0, %o0 __start_crt+0x64: call 0x100000000 I.e. __start_crt_compiler is non-NULL, the call is taken, but the destination is invalid, leading to the SIGILL. Rainer
Created attachment 9722 [details] input objects and executables
Created attachment 9724 [details] lightly tested fix It is a bug in optimisation of sequences loading addresses from the GOT. You can't convert a GOT indirect load to GOT relative when the relative offset is outside the range of possible sethi, xor values. This happens with -Ttext=0x100000000 which results in your gld testcase having _GLOBAL_OFFSET_TABLE_ = 0x100100a10. The relative offset to zero, the proper value for the undefined weak symbol, is too large.
The master branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=5b86074c4a84e32ca55a6c72c5fca45d97dc9374 commit 5b86074c4a84e32ca55a6c72c5fca45d97dc9374 Author: Alan Modra <amodra@gmail.com> Date: Mon Jan 2 22:06:28 2017 +1030 PR20989, sparc GOT sequence optimisation PR ld/20989 * elfxx-sparc.c (gdop_relative_offset_ok): New function. (_bfd_sparc_elf_relocate_section): Use it to validate GOT indirect to GOT pointer relative code edit.
The binutils-2_28-branch branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=567e353f0e5d192b04f6b79e73dc14c5a74983c5 commit 567e353f0e5d192b04f6b79e73dc14c5a74983c5 Author: Alan Modra <amodra@gmail.com> Date: Mon Jan 2 22:06:28 2017 +1030 PR20989, sparc GOT sequence optimisation PR ld/20989 * elfxx-sparc.c (gdop_relative_offset_ok): New function. (_bfd_sparc_elf_relocate_section): Use it to validate GOT indirect to GOT pointer relative code edit.
Fixed