Bug 22832 - internal error, aborting at ../../bfd/elflink.c:9710 in elf_link_output_extsym
Summary: internal error, aborting at ../../bfd/elflink.c:9710 in elf_link_output_extsym
Status: RESOLVED WONTFIX
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.30
: P2 normal
Target Milestone: 2.31
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-02-11 08:14 UTC by John Paul Adrian Glaubitz
Modified: 2018-03-31 12:35 UTC (History)
5 users (show)

See Also:
Host:
Target: sparc*-*-*
Build:
Last reconfirmed: 2018-02-11 00:00:00
Project(s) to access:
ssh public key:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description John Paul Adrian Glaubitz 2018-02-11 08:14:22 UTC
When cross-building the Rust compiler for sparc64-unknown-linux-gnu, the build fails with an internal binutils error:

error: linking with `sparc64-linux-gnu-gcc` failed: exit code: 1
  |
  = note: "sparc64-linux-gnu-gcc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-L" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/sparc64-unknown-linux-gnu/lib" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std0-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std1-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std10-7456b92f185380f18a6
46928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std11-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std12-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std13-7456
b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std14-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std15-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std2-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std3-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std4-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std5-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std6-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std7-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std8-7456b92f185380f18a646928cc900174.rs.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.std9-7456b92f185380f18a646928cc900174.rs.rcgu.o" "-o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/libstd-50a30754efc77185.so" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.crate.metadata.rcgu.o" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps/std-50a30754efc77185.crate.allocator.rcgu.o" "-Wl,-z,relro,-z,now" "-Wl,-O1" "-nodefaultlibs" "-L" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/deps" "-L" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/release/deps" "-L" "/srv/glaubitz/rust/rust/build/sparc64-unknown-linux-gnu/native/libbacktrace/.libs" "-L" "/srv/glaubitz/rust/rust/build/sparc64-unknown-linux-gnu/native/jemalloc/lib" "-L" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1-std/sparc64-unknown-linux-gnu/release/build/compiler_builtins-990f7637d0503f4e/out" "-L" "/srv/glaubitz/rust/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/sparc64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,--whole-archive" "-l" "backtrace" "-Wl,--no-whole-archive" "-Wl,-Bdynamic" "-l" "dl" "-l" "rt" "-l" "pthread" "-Wl,-Bstatic" "-Wl,--whole-archive" "/tmp/rustc.SObmSkbjz1fo/libpanic_unwind-4f85ba5d0e870e29.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.SObmSkbjz1fo/libunwind-c86c9565da689e14.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.SObmSkbjz1fo/liballoc_system-655151fba596847e.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.SObmSkbjz1fo/liblibc-b8f9bb8294d9a014.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.SObmSkbjz1fo/liballoc-513d34708cb20443.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.SObmSkbjz1fo/libstd_unicode-5211f032242a5357.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.SObmSkbjz1fo/libcore-e2f49b08d2bc06b5.rlib" "-Wl,--no-whole-archive" "/tmp/rustc.SObmSkbjz1fo/libcompiler_builtins-136e26942e0df602.rlib" "-Wl,-Bdynamic" "-l" "gcc_s" "-l" "c" "-l" "m" "-l" "rt" "-l" "pthread" "-l" "util" "-l" "util" "-shared" "-Wl,-rpath,$ORIGIN/../lib"
  = note: /usr/lib/gcc-cross/sparc64-linux-gnu/7/../../../../sparc64-linux-gnu/bin/ld: BFD (GNU Binutils for Debian) 2.30 internal error, aborting at ../../bfd/elflink.c:9710 in elf_link_output_extsym

          /usr/lib/gcc-cross/sparc64-linux-gnu/7/../../../../sparc64-linux-gnu/bin/ld: Please report this bug.

          collect2: error: ld returned 1 exit status

The issue is resolved immediately by downgrading to binutils 2.28.
Comment 1 H.J. Lu 2018-02-11 12:58:31 UTC
Please try master branch.  This may have been fixed by

commit a8735c82b8519d8b18915765ca983fc07154a17d
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Sat Feb 10 02:30:25 2018 +0100

    Fix GOT relocation overflow on SPARC.


commit c20c30f615756ddfccc4bb75c65ccfc1a399466e
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Tue Feb 6 18:15:56 2018 +0100

    Fix PR ld/22263 on SPARC.
    
    This is -fpie -pie generating dynamic relocations in the text section,
    simply because no TLS transitions are applied in PIE mode.  The meat
    of the patch is to turn calls to bfd_link_pic (info) in TLS-related code
    into !bfd_link_executable (info) and there are quite a lot of them.
Comment 2 Eric Botcazou 2018-02-11 14:50:45 UTC
The GOT relocation issue I just fixed (on master, 2.30 and 2.29 branch) can have pretty much unpredictable results since it may cause memory corruption.  Please retry with updated sources containing the fix.
Comment 3 John Paul Adrian Glaubitz 2018-02-11 17:34:26 UTC
While the patch from a8735c82b8519d8b18915765ca983fc07154a17d was actually still missing and using a binutils with the patch actually fixed another build issue with rustc for me, this particular error is still present - even with binutils built and installed from git:

  = note: /usr/local/bin/ld: BFD (GNU Binutils) 2.30.51.20180211 internal error, aborting at elflink.c:9710 in elf_link_output_extsym
          
          /usr/local/bin/ld: Please report this bug.
          
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

error: Could not compile `std`.
Comment 4 Jessica Clarke 2018-02-13 01:53:14 UTC
So, after debugging this, the problem is as follows:

Rust is using LLVM with -integrated-as (at least effectively; it may well be using it as a library and setting the flag itself, but the point is that the lowered IR is fed straight into the object code backend rather than being serialised via assembly and then assembled separately). LLVM's SparcMCCodeEmitter::getCallTargetOpValue handles __tls_get_addr specially to not emit an R_SPARC_WDISP30/WPLT30, and somewhere else the R_SPARC_TLS_LDM_CALL gets emitted, but the important point is that __tls_get_addr is never added to the output object file's symbol table despite being the symbolic operand to the call instruction.

Thus, when linking one of these object files, that object file's hash table never pulls in the definition of __tls_get_addr, and so when _bfd_sparc_elf_check_relocs is called for an R_SPARC_TLS_LDM_CALL, it looks up __tls_get_addr, doesn't find it, and so an entry is created, since TRUE is passed to bfd_link_hash_lookup for create, but this entry has type bfd_link_hash_new, and this never changes.

So it seems to me there are two issues here:

1. LLVM should be emitting an entry for __tls_get_addr in its symbol table so it is made visible to the object file.

2. ld should gracefully handle this case. If this case is an error, it should instead be passing FALSE for create to bfd_link_hash_lookup, and if the result is NULL, printing an error; otherwise, if this case should work, something needs to implicitly pull in the symbol (and in theory LLVM doesn't need to change, though in practice it's best to do so anyway for compatibility).

I've talked specifically about local-dynamic here for simplicity, but global-dynamic has the same issue too.

Note that gold also falls foul of this, giving "gold: internal error in tls_get_addr_sym, at ../../gold/sparc.cc:391", though line 391 is "gold_assert(this->tls_get_addr_sym_);" which is much easier to debug!

Reproduction:

jrtc27@deb4g:~/tmp/22832$ cat 22832.c
__thread int x;
int f(void) { return x; }
jrtc27@deb4g:~/tmp/22832$ clang -integrated-as -o 22832.o -fPIC -c 22832.c
jrtc27@deb4g:~/tmp/22832$ readelf -Wrs 22832.o

Relocation section '.rela.text' at offset 0x138 contains 6 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000000008  0000000300000011 R_SPARC_PC22           0000000000000000 _GLOBAL_OFFSET_TABLE_ + 4
000000000000000c  0000000300000010 R_SPARC_PC10           0000000000000000 _GLOBAL_OFFSET_TABLE_ + 8
0000000000000014  0000000500000038 R_SPARC_TLS_GD_HI22    0000000000000000 x + 0
0000000000000018  0000000500000039 R_SPARC_TLS_GD_LO10    0000000000000000 x + 0
000000000000001c  000000050000003a R_SPARC_TLS_GD_ADD     0000000000000000 x + 0
0000000000000020  000000050000003b R_SPARC_TLS_GD_CALL    0000000000000000 x + 0

Symbol table '.symtab' contains 6 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 22832.c
     2: 0000000000000000     0 TLS     LOCAL  DEFAULT    4 .tbss
     3: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
     4: 0000000000000000    52 FUNC    GLOBAL DEFAULT    2 f
     5: 0000000000000000     4 TLS     GLOBAL DEFAULT    4 x
jrtc27@deb4g:~/tmp/22832$ ld -o lib22832.so -shared 22832.o
ld: BFD (GNU Binutils) 2.30.51.20180211 internal error, aborting at elflink.c:9710 in elf_link_output_extsym

ld: Please report this bug.

jrtc27@deb4g:~/tmp/22832$ gold -o lib22832.so -shared 22832.o
gold: internal error in tls_get_addr_sym, at ../../gold/sparc.cc:391
Comment 5 Eric Botcazou 2018-02-13 07:13:17 UTC
> Thus, when linking one of these object files, that object file's hash table
> never pulls in the definition of __tls_get_addr, and so when
> _bfd_sparc_elf_check_relocs is called for an R_SPARC_TLS_LDM_CALL, it looks
> up __tls_get_addr, doesn't find it, and so an entry is created, since TRUE
> is passed to bfd_link_hash_lookup for create, but this entry has type
> bfd_link_hash_new, and this never changes.
> 
> So it seems to me there are two issues here:
> 
> 1. LLVM should be emitting an entry for __tls_get_addr in its symbol table
> so it is made visible to the object file.
> 
> 2. ld should gracefully handle this case. If this case is an error, it
> should instead be passing FALSE for create to bfd_link_hash_lookup, and if
> the result is NULL, printing an error; otherwise, if this case should work,
> something needs to implicitly pull in the symbol (and in theory LLVM doesn't
> need to change, though in practice it's best to do so anyway for
> compatibility).

Thanks for debugging this.  The irony is that I put TRUE precisely because I thought it would deal with such a case...  Given that Gold and ld agree, I think that the error is indeed on the LLVM side but you're right that ld should handle this more gracefully (it's not too bad either).

Do you want me to prepare a patch or do you intend to do it?
Comment 6 John Paul Adrian Glaubitz 2018-02-13 10:09:22 UTC
(In reply to James Clarke from comment #4)
> Note that gold also falls foul of this, giving "gold: internal error in
> tls_get_addr_sym, at ../../gold/sparc.cc:391", though line 391 is
> "gold_assert(this->tls_get_addr_sym_);" which is much easier to debug!

I'm actually getting the following internal error when trying to build firefox on sparc64 during some rust code compilation:

 1:32.84   = note: /srv/glaubitz/firefox/mozilla-central/obj-sparc64-unknown-linux-gnu/build/unix/gold/ld: internal error in sized_finalize_symbol, at ../../gold/symtab.cc:2937
 1:32.84           collect2: error: ld returned 1 exit status

Is this related?
Comment 7 Jessica Clarke 2018-02-14 02:58:55 UTC
(In reply to John Paul Adrian Glaubitz from comment #6)
> (In reply to James Clarke from comment #4)
> > Note that gold also falls foul of this, giving "gold: internal error in
> > tls_get_addr_sym, at ../../gold/sparc.cc:391", though line 391 is
> > "gold_assert(this->tls_get_addr_sym_);" which is much easier to debug!
> 
> I'm actually getting the following internal error when trying to build
> firefox on sparc64 during some rust code compilation:
> 
>  1:32.84   = note:
> /srv/glaubitz/firefox/mozilla-central/obj-sparc64-unknown-linux-gnu/build/
> unix/gold/ld: internal error in sized_finalize_symbol, at
> ../../gold/symtab.cc:2937
>  1:32.84           collect2: error: ld returned 1 exit status
> 
> Is this related?

Possibly, but I'd expect it to trigger an assertion failure in tls_get_addr_sym before that as with my test case. I suggest you open a new bug for this (and if you have debug symbols in that build, run it under gdb and `p *sym` to see what symbol it's having issues with).
Comment 8 Sourceware Commits 2018-02-15 14:58:43 UTC
The master branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e513bd38a6b91401947d90ba5f301f01d3991b8e

commit e513bd38a6b91401947d90ba5f301f01d3991b8e
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 15 15:55:11 2018 +0100

    PR ld/22832 on SPARC.
    
    The fix for PR ld/22727 on SPARC passed TRUE as the 'create' argument
    in the call to bfd_link_hash_lookup.  It turns out this was a bad idea
    because, if the symbol is created at this point, the link will abort
    later in elf_link_output_extsym.  This changes the TRUE into a FALSE
    and puts an assertion on the result of the call, making it easier to
    debug the issue; that's exactly in keeping with what Gold does.
    
    bfd/
    	* elfxx-sparc.c (_bfd_sparc_elf_check_relocs) <R_SPARC_TLS_GD_CALL>:
    	Pass FALSE instead of TRUE as 'create' argument to bfd_link_hash_lookup
    	and assert that the result of the call is not NULL.
Comment 9 Sourceware Commits 2018-02-15 15:04:05 UTC
The binutils-2_30-branch branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d31b3bc9174ca62d7527a63e6428718311faff9c

commit d31b3bc9174ca62d7527a63e6428718311faff9c
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 15 15:55:11 2018 +0100

    PR ld/22832 on SPARC.
    
    The fix for PR ld/22727 on SPARC passed TRUE as the 'create' argument
    in the call to bfd_link_hash_lookup.  It turns out this was a bad idea
    because, if the symbol is created at this point, the link will abort
    later in elf_link_output_extsym.  This changes the TRUE into a FALSE
    and puts an assertion on the result of the call, making it easier to
    debug the issue; that's exactly in keeping with what Gold does.
    
    bfd/
    	* elfxx-sparc.c (_bfd_sparc_elf_check_relocs) <R_SPARC_TLS_GD_CALL>:
    	Pass FALSE instead of TRUE as 'create' argument to bfd_link_hash_lookup
    	and assert that the result of the call is not NULL.
Comment 10 Eric Botcazou 2018-02-15 15:07:02 UTC
BFD adjusted, the assertion failure is now similar to that of Gold.