Bug 23980 - powerpc64 ld segfault when linking libc on FreeBSD
Summary: powerpc64 ld segfault when linking libc on FreeBSD
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.32
: P2 normal
Target Milestone: 2.32
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-12-13 12:30 UTC by Alfredo Dal'Ava Júnior
Modified: 2018-12-18 00:30 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
write.pico and writev.pico crashing when linking with LD (2.74 KB, application/gzip)
2018-12-17 11:20 UTC, Alfredo Dal'Ava Júnior
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alfredo Dal'Ava Júnior 2018-12-13 12:30:25 UTC
ld (BFD) crash with Segmentation Fault when cross compiling FreeBSD libc on PowerPC64. The stack trace is:

Core was generated by `/usr/local/ld/usr/local/bin/ld --sysroot=/usr/obj/usr/src/powerpc.powerpc64/tmp'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000bf4fe7 in _bfd_elf_link_hash_hide_symbol (info=0x119d208 <link_info>, h=0xffffffffffffffff, force_local=1) at elflink.c:7522
7522	  if (h->type != STT_GNU_IFUNC)
(gdb) bt
#0  0x0000000000bf4fe7 in _bfd_elf_link_hash_hide_symbol (info=0x119d208 <link_info>, h=0xffffffffffffffff, force_local=1) at elflink.c:7522
#1  0x0000000000d5a1f8 in ppc64_elf_hide_symbol (info=0x119d208 <link_info>, h=0x804bd64e0, force_local=1) at elf64-ppc.c:6243
#2  0x0000000000bece39 in elf_link_add_object_symbols (abfd=0x8047d7a80, info=0x119d208 <link_info>) at elflink.c:5020
#3  0x0000000000be9b21 in bfd_elf_link_add_symbols (abfd=0x8047d7a80, info=0x119d208 <link_info>) at elflink.c:5741
#4  0x0000000000620145 in load_symbols (entry=0x801c0c990, place=0x7fffffff6270) at ldlang.c:3079
#5  0x0000000000624584 in open_input_bfds (s=0x801c0c990, mode=OPEN_BFD_NORMAL) at ldlang.c:3528
#6  0x00000000006236dc in lang_process () at ldlang.c:7382
#7  0x0000000000630879 in main (argc=1301, argv=0x7fffffff6518) at ./ldmain.c:440

On stack frame #1 (elf64-ppc.c:6243), second parameter &fh->elf seems to be invalid/unset (-1)


(gdb) frame 1
#1  0x0000000000d5a1f8 in ppc64_elf_hide_symbol (info=0x119d208 <link_info>, h=0x804bd64e0, force_local=1) at elf64-ppc.c:6243
6243		_bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
(gdb) p/x &fh
$2 = 0x7fffffff5b48
(gdb) p/x &fh->elf
$3 = 0xffffffffffffffff



(gdb) p *(struct ppc_link_hash_entry *)&fh
$12 = {elf = {root = {root = {next = 0xffffffffffffffff, string = 0x804bd64e0 "", hash = 4325052448}, type = 224, non_ir_ref_regular = 0, non_ir_ref_dynamic = 0, linker_def = 1, 
      ldscript_def = 0, rel_from_abs = 0, u = {undef = {next = 0x119d208 <link_info>, abfd = 0x7fffffff6180}, def = {next = 0x119d208 <link_info>, section = 0x7fffffff6180, 
          value = 12504633}, i = {next = 0x119d208 <link_info>, link = 0x7fffffff6180, warning = 0xbece39 <elf_link_add_object_symbols+13017> "\307\205\250\374\377\377"}, c = {
          next = 0x119d208 <link_info>, p = 0x7fffffff6180, size = 12504633}}}, indx = 0, dynindx = 140733193388032, got = {refcount = 140733193388032, offset = 140733193388032, 
      glist = 0x7fff00000000, plist = 0x7fff00000000}, plt = {refcount = 34439765800, offset = 34439765800, glist = 0x804c51f28, plist = 0x804c51f28}, size = 140737488313968, type = 184, 
    other = 94, target_internal = 255, ref_regular = 1, def_regular = 1, ref_dynamic = 1, def_dynamic = 1, ref_regular_nonweak = 1, dynamic_adjusted = 1, needs_copy = 1, needs_plt = 1, 
    non_elf = 1, versioned = versioned_hidden, forced_local = 1, dynamic = 1, mark = 1, non_got_ref = 1, dynamic_def = 1, ref_dynamic_nonweak = 1, pointer_equality_needed = 1, 
    unique_global = 1, protected_def = 1, start_stop = 1, is_weakalias = 1, dynstr_index = 140737488314052, u = {alias = 0x7fffffff5ec8, elf_hash_value = 140737488314056}, verinfo = {
      verdef = 0x7fffffff5e9c, vertree = 0x7fffffff5e9c}, u2 = {start_stop_section = 0x80128dd7f, vtable = 0x80128dd7f}}, u = {stub_cache = 0x801606228, next_dot_sym = 0x801606228}, 
  dyn_relocs = 0x87, oh = 0x7000, is_func = 0, is_func_descriptor = 0, fake = 0, adjust_done = 0, save_res = 0, non_zero_localentry = 0, tls_mask = 0 '\000'}
Comment 1 Alan Modra 2018-12-13 22:27:03 UTC
> #1  0x0000000000d5a1f8 in ppc64_elf_hide_symbol (info=0x119d208 <link_info>,
> h=0x804bd64e0, force_local=1) at elf64-ppc.c:6243

"p *(struct ppc_link_hash_entry *) h" might be useful here, if you can recreate the problem.

> #2  0x0000000000bece39 in elf_link_add_object_symbols (abfd=0x8047d7a80,
> info=0x119d208 <link_info>) at elflink.c:5020

Also, "p *abfd" here.  And "p abfd->filename" then (outside of gdb) report the output of "file" for this file.  There is some possibility you might be attempting to link in a non-ppc64 file somehow.

Another useful debug exercise would be to use "watch" on the h->oh field of the symbol involved here to see where it is being set to -1.
Comment 2 Alfredo Dal'Ava Júnior 2018-12-14 18:44:51 UTC
Alan,

(In reply to Alan Modra from comment #1)
> > #1  0x0000000000d5a1f8 in ppc64_elf_hide_symbol (info=0x119d208 <link_info>,
> > h=0x804bd64e0, force_local=1) at elf64-ppc.c:6243
> 
> "p *(struct ppc_link_hash_entry *) h" might be useful here, if you can
> recreate the problem.

(gdb) p *(struct ppc_link_hash_entry *) h
$1 = {elf = {root = {root = {next = 0x0, string = 0x804c47e5d "__libc_interposing", hash = 161532955}, type = bfd_link_hash_undefined, non_ir_ref_regular = 0, non_ir_ref_dynamic = 0, 
      linker_def = 0, ldscript_def = 0, rel_from_abs = 0, u = {undef = {next = 0x0, abfd = 0x8047d4940}, def = {next = 0x0, section = 0x8047d4940, value = 0}, i = {next = 0x0, 
          link = 0x8047d4940, warning = 0x0}, c = {next = 0x0, p = 0x8047d4940, size = 0}}}, indx = -1, dynindx = -1, got = {refcount = 0, offset = 0, glist = 0x0, plist = 0x0}, plt = {
      refcount = -1, offset = 18446744073709551615, glist = 0xffffffffffffffff, plist = 0xffffffffffffffff}, size = 0, type = 0, other = 2, target_internal = 0, ref_regular = 1, 
    def_regular = 0, ref_dynamic = 0, def_dynamic = 0, ref_regular_nonweak = 1, dynamic_adjusted = 0, needs_copy = 0, needs_plt = 0, non_elf = 0, versioned = unversioned, forced_local = 1, 
    dynamic = 0, mark = 0, non_got_ref = 0, dynamic_def = 0, ref_dynamic_nonweak = 0, pointer_equality_needed = 0, unique_global = 0, protected_def = 0, start_stop = 0, is_weakalias = 0, 
    dynstr_index = 0, u = {alias = 0x0, elf_hash_value = 0}, verinfo = {verdef = 0x0, vertree = 0x0}, u2 = {start_stop_section = 0x0, vtable = 0x0}}, u = {stub_cache = 0x0, 
    next_dot_sym = 0x0}, dyn_relocs = 0x100, oh = 0xffffffffffffffff, is_func = 1, is_func_descriptor = 1, fake = 0, adjust_done = 1, save_res = 1, non_zero_localentry = 1, 
  tls_mask = 255 '\377'}


> 
> > #2  0x0000000000bece39 in elf_link_add_object_symbols (abfd=0x8047d7a80,
> > info=0x119d208 <link_info>) at elflink.c:5020
> 
> Also, "p *abfd" here.  And "p abfd->filename" then (outside of gdb) report
> the output of "file" for this file.  There is some possibility you might be
> attempting to link in a non-ppc64 file somehow.

(gdb) p *abfd
$2 = {filename = 0x802621860 "write.pico", xvec = 0x4a4250 <powerpc_elf64_fbsd_vec>, iostream = 0x804b2a1d8, iovec = 0x463990 <cache_iovec>, lru_prev = 0x801c42000, lru_next = 0x8047d4940, 
  where = 2592, mtime = 0, id = 354, format = bfd_object, direction = read_direction, flags = 32785, cacheable = 1, target_defaulted = 0, opened_once = 1, mtime_set = 0, no_export = 0, 
  output_has_begun = 0, has_armap = 0, is_thin_archive = 0, selective_search = 0, is_linker_output = 0, is_linker_input = 1, plugin_format = bfd_plugin_unknown, lto_output = 0, 
  plugin_dummy_bfd = 0x0, origin = 0, proxy_origin = 0, section_htab = {table = 0x804c71910, newfunc = 0xb9cdf0 <bfd_section_hash_newfunc>, memory = 0x804a14380, size = 4051, count = 11, 
    entsize = 304, frozen = 0}, sections = 0x804c49028, section_last = 0x804c49c08, section_count = 11, archive_pass = 0, start_address = 0, outsymbols = 0x0, symcount = 0, 
  dynsymcount = 0, arch_info = 0x5456e0 <bfd_powerpc_archs>, arelt_data = 0x0, my_archive = 0x0, archive_next = 0x0, archive_head = 0x0, nested_archives = 0x0, link = {next = 0x0, 
    hash = 0x0}, tdata = {aout_data = 0x804c4d078, aout_ar_data = 0x804c4d078, coff_obj_data = 0x804c4d078, pe_obj_data = 0x804c4d078, xcoff_obj_data = 0x804c4d078, 
    ecoff_obj_data = 0x804c4d078, srec_data = 0x804c4d078, verilog_data = 0x804c4d078, ihex_data = 0x804c4d078, tekhex_data = 0x804c4d078, elf_obj_data = 0x804c4d078, 
    mmo_data = 0x804c4d078, sun_core_data = 0x804c4d078, sco5_core_data = 0x804c4d078, trad_core_data = 0x804c4d078, som_data = 0x804c4d078, hpux_core_data = 0x804c4d078, 
    hppabsd_core_data = 0x804c4d078, sgi_core_data = 0x804c4d078, lynx_core_data = 0x804c4d078, osf_core_data = 0x804c4d078, cisco_core_data = 0x804c4d078, versados_data = 0x804c4d078, 
    netbsd_core_data = 0x804c4d078, mach_o_data = 0x804c4d078, mach_o_fat_data = 0x804c4d078, plugin_data = 0x804c4d078, pef_data = 0x804c4d078, pef_xlib_data = 0x804c4d078, 
    sym_data = 0x804c4d078, any = 0x804c4d078}, usrdata = 0x801c09990, memory = 0x804a14360, build_id = 0x0}


(gdb) p abfd->filename
$3 = 0x802621860 "write.pico"


[root@FreeBSD-16G /usr/src]# file /usr/obj/usr/src/powerpc.powerpc64/lib/libc/write.pico
/usr/obj/usr/src/powerpc.powerpc64/lib/libc/write.pico: ELF 64-bit MSB relocatable, 64-bit PowerPC or cisco 7500, version 1 (FreeBSD), with debug_info, not stripped


> 
> Another useful debug exercise would be to use "watch" on the h->oh field of
> the symbol involved here to see where it is being set to -1.

I'm going to look forward for this, at this point libc package is linking 1281 objects but I could reproduce the segfault with just:

/usr/local/ld -shared -o test.so write.pico writev.pico

Apparently both files are PowerPC64:

root@FreeBSD-16G /usr/obj/usr/src/powerpc.powerpc64/lib/libc]# file write.pico
write.pico: ELF 64-bit MSB relocatable, 64-bit PowerPC or cisco 7500, version 1 (FreeBSD), with debug_info, not stripped
[root@FreeBSD-16G /usr/obj/usr/src/powerpc.powerpc64/lib/libc]# file writev.pico
writev.pico: ELF 64-bit MSB relocatable, 64-bit PowerPC or cisco 7500, version 1 (FreeBSD), with debug_info, not stripped

The *.pico where produced by "clang", so I wouldn't discard that a problem in the object file itself.
Comment 3 Alan Modra 2018-12-14 21:57:50 UTC
> I could reproduce the segfault with just:
> /usr/local/ld -shared -o test.so write.pico writev.pico

Excellent!  If you attach those two files I'll take a look at what is going on.
Comment 4 Alfredo Dal'Ava Júnior 2018-12-17 11:20:05 UTC
Created attachment 11467 [details]
write.pico and writev.pico crashing when linking with LD

With the files attached, I can reproduce the segmentation fault using the following command:

/usr/local/bin/ld -shared -o test.so write.pico writev.pico


Thank you!
Comment 5 Alan Modra 2018-12-17 12:50:20 UTC
I don't reproduce the crash with a x86_64-linux to powerpc64-freebsd binutils configured with
--disable-nls --enable-plugins --disable-gdb --disable-sim --disable-readline \
--disable-libdecnumber --target=powerpc64-freebsd

$ ld/ld-new -shared -o pr23980 write.pico writev.pico
ld/ld-new: write.pico: in function `write':
/usr/src/lib/libc/sys/write.c:49: undefined reference to `__libc_interposing'
ld/ld-new: /usr/src/lib/libc/sys/write.c:49: undefined reference to `__libc_interposing'
ld/ld-new: writev.pico: in function `writev':
/usr/src/lib/libc/sys/writev.c:50: undefined reference to `__libc_interposing'
ld/ld-new: /usr/src/lib/libc/sys/writev.c:50: undefined reference to `__libc_interposing'

$ ld/ld-new --version
GNU ld (GNU Binutils) 2.31.51.20181216

Incidentally, were you expecting write.pico and writev.pico to be big-endian ELFv2 object files?  On linux we generally use big-endian ELFv1 and little-endian ELFv2.  Not that there is any linker problem (that I'm aware of) with big-endian ELFv2.
Comment 6 Alfredo Dal'Ava Júnior 2018-12-17 13:13:01 UTC
(In reply to Alan Modra from comment #5)
> I don't reproduce the crash with a x86_64-linux to powerpc64-freebsd
> binutils configured with
> --disable-nls --enable-plugins --disable-gdb --disable-sim
> --disable-readline \
> --disable-libdecnumber --target=powerpc64-freebsd

Binutils was configured like this:
CXXFLAGS="-I/usr/local/include -g" CFLAGS="-I/usr/local/include -g" ./configure --enable-targets=all --enable-gold

> 
> $ ld/ld-new -shared -o pr23980 write.pico writev.pico
> ld/ld-new: write.pico: in function `write':
> /usr/src/lib/libc/sys/write.c:49: undefined reference to `__libc_interposing'
> ld/ld-new: /usr/src/lib/libc/sys/write.c:49: undefined reference to
> `__libc_interposing'
> ld/ld-new: writev.pico: in function `writev':
> /usr/src/lib/libc/sys/writev.c:50: undefined reference to
> `__libc_interposing'
> ld/ld-new: /usr/src/lib/libc/sys/writev.c:50: undefined reference to
> `__libc_interposing'
> 
> $ ld/ld-new --version
> GNU ld (GNU Binutils) 2.31.51.20181216

I just updated binutils again, crashing same way. It's now: 

ld --version
GNU ld (GNU Binutils)2.31.51.20181213


> Incidentally, were you expecting write.pico and writev.pico to be big-endian
> ELFv2 object files?  On linux we generally use big-endian ELFv1 and
> little-endian ELFv2.  Not that there is any linker problem (that I'm aware
> of) with big-endian ELFv2.

yes, I'm expecting both being big-endian ELFv2, (as it should be default for FreeBSD-PowerPC64 at some point and I'm doing some tests).

As reference, FreeBSD build system log shows the following:

clang -mabi=elfv2 -fuse-ld=/usr/local/bin/ld -target powerpc64-unknown-freebsd13.0-elfv2 --sysroot=/usr/obj/usr/src/powerpc.powerpc64/tmp -B/usr/local  -nodefaultlibs -Wl,--version-script=Version.map   -shared -Wl,-x -Wl,--fatal-warnings -Wl,--warn-shared-textrel  -o libc.so.7.full -Wl,-soname,libc.so.7  `NM='nm' NMFLAGS='' lorder
Comment 7 Alan Modra 2018-12-17 13:32:48 UTC
OK, my --enable-targets=all build reproduces the segfault.  I'll look into it tomorrow, it is getting late here in .au
Comment 8 Alfredo Dal'Ava Júnior 2018-12-17 21:20:27 UTC
looks like the issue occurs only when using the ld from a x86_64 host (cross compiling). 
Linking the attached files directly from a powerpc64 machine gives:

# src/binutils-gdb/ld/ld-new -shared -o test.so write.pico writev.pico 
src/binutils-gdb/ld/ld-new: write.pico: in function `write':
/usr/src/lib/libc/sys/write.c:49: undefined reference to `__libc_interposing'
src/binutils-gdb/ld/ld-new: /usr/src/lib/libc/sys/write.c:49: undefined reference to `__libc_interposing'
src/binutils-gdb/ld/ld-new: writev.pico: in function `writev':
/usr/src/lib/libc/sys/writev.c:50: undefined reference to `__libc_interposing'
src/binutils-gdb/ld/ld-new: /usr/src/lib/libc/sys/writev.c:50: undefined reference to `__libc_interposing'

# src/binutils-gdb/ld/ld-new --version
GNU ld (GNU Binutils)2.31.51.20181217

Thanks!
Comment 9 Alan Modra 2018-12-17 22:21:57 UTC
With an x86_64-linux --enable-targets=all ld.bfd, the output is assumed to be x86_64-elf64 absent a -m option saying otherwise on the command line.  (You should be passing -melf64ppc_fbsd.)  The segfault here is caused by the ppc64 backend not checking the type of the symbol table hash entries before using fields that are only present in a ppc_link_hash_entry.
Comment 10 cvs-commit@gcc.gnu.org 2018-12-17 22:34:47 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit 87469ba2d2fc953796c7bb64e535d3f283756048
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Dec 18 08:59:59 2018 +1030

    PR23980, powerpc64 ld segfault
    
    	PR 23980
    	* elf64-ppc.c (ppc64_elf_hide_symbol): Check hash table type
    	before referencing ppc64-only fields of hash entries.
Comment 11 Alan Modra 2018-12-17 22:41:51 UTC
Fixed.
Comment 12 cvs-commit@gcc.gnu.org 2018-12-18 00:30:19 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit 7af5d5c4dda26ac36ee2ff42af8f39a10382cc41
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Dec 18 09:20:06 2018 +1030

    PR23980, assertion fail
    
    All of the backend relocate_section functions that interpret reloc
    numbers assuming the input file is of the expected type (ie. same as
    output or very similar) really ought to be checking input file type.
    Not many do, and those that do currently just assert.  This patch
    replaces the assertion with a more graceful exit.
    
    	PR 23980
    	* elf32-i386.c (elf_i386_relocate_section): Exit with wrong format
    	error rather than asserting input file is as expected.
    	* elf32-s390.c (elf_s390_relocate_section): Likewise.
    	* elf32-sh.c (sh_elf_relocate_section): Likewise.
    	* elf32-xtensa.c (elf_xtensa_relocate_section): Likewise.
    	* elf64-ppc.c (ppc64_elf_relocate_section): Likewise.
    	* elf64-s390.c (elf_s390_relocate_section): Likewise.
    	* elf64-x86-64.c (elf_x86_64_relocate_section): Likewise.
    	* elf32-ppc.c (ppc_elf_relocate_section): Exit with wrong format
    	error if input file is not ppc32 ELF.