Bug 20989 - Every 64-bit Solaris 12/SPARC executable dies with SIGILL
Summary: Every 64-bit Solaris 12/SPARC executable dies with SIGILL
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.27
: P2 normal
Target Milestone: 2.28
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-12-22 13:55 UTC by Rainer Orth
Modified: 2017-01-02 11:40 UTC (History)
0 users

See Also:
Host: sparc-sun-solaris2.12
Target: sparc-sun-solaris2.12
Build: sparc-sun-solaris2.12
Last reconfirmed:


Attachments
input objects and executables (5.24 KB, application/x-bzip)
2016-12-23 13:57 UTC, Rainer Orth
Details
lightly tested fix (495 bytes, patch)
2016-12-26 13:11 UTC, Alan Modra
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Rainer Orth 2016-12-22 13:55:14 UTC
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
Comment 1 Alan Modra 2016-12-22 23:15:31 UTC
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 2 Rainer Orth 2016-12-23 13:37:39 UTC
> --- 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
Comment 3 Rainer Orth 2016-12-23 13:57:33 UTC
Created attachment 9722 [details]
input objects and executables
Comment 4 Alan Modra 2016-12-26 13:11:59 UTC
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.
Comment 5 Sourceware Commits 2017-01-02 11:38:20 UTC
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.
Comment 6 Sourceware Commits 2017-01-02 11:39:22 UTC
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.
Comment 7 Alan Modra 2017-01-02 11:40:31 UTC
Fixed