Bug 22706 - bfd/elf32-sh.c fails asserts without additional information: sh4-unknown-linux-gnu-ld: BFD assertion fail bfd/elf32-sh.c:5171
Summary: bfd/elf32-sh.c fails asserts without additional information: sh4-unknown-linu...
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.30
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-01-14 00:10 UTC by Sergei Trofimovich
Modified: 2018-07-30 13:07 UTC (History)
5 users (show)

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


Attachments
binutils-gdb-sh4-better-errors.patch (466 bytes, patch)
2018-07-24 22:45 UTC, Sergei Trofimovich
Details | Diff
bug.S (237 bytes, text/x-asm)
2018-07-24 22:45 UTC, Sergei Trofimovich
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sergei Trofimovich 2018-01-14 00:10:02 UTC
Attempted to build glibc for sh4-unknown-linux-gnu target and got the following errors:

LANG=C bash -x ./trigger-linker-system.sh 
+ sh4-unknown-linux-gnu-ld -plugin /usr/libexec/gcc/sh4-unknown-linux-gnu/6.4.0/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/sh4-unknown-linux-gnu/6.4.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccvxcoL0.res --sysroot=/usr/sh4-unknown-linux-gnu -m shlelf_linux -static -o /tmp/portage/cross-sh4-unknown-linux-gnu/glibc-9999/work/build-default-sh4-unknown-linux-gnu-nptl/elf/sln -L/usr/lib/gcc/sh4-unknown-linux-gnu/6.4.0 -L/usr/lib/gcc/sh4-unknown-linux-gnu/6.4.0/../../../../sh4-unknown-linux-gnu/lib -L/usr/sh4-unknown-linux-gnu/lib -L/usr/sh4-unknown-linux-gnu/usr/lib -O1 --as-needed --hash-style=gnu /tmp/portage/cross-sh4-unknown-linux-gnu/glibc-9999/work/build-default-sh4-unknown-linux-gnu-nptl/csu/crt1.o /tmp/portage/cross-sh4-unknown-linux-gnu/glibc-9999/work/build-default-sh4-unknown-linux-gnu-nptl/csu/crti.o /usr/lib/gcc/sh4-unknown-linux-gnu/6.4.0/crtbeginT.o /tmp/portage/cross-sh4-unknown-linux-gnu/glibc-9999/work/build-default-sh4-unknown-linux-gnu-nptl/elf/sln.o /tmp/portage/cross-sh4-unknown-linux-gnu/glibc-9999/work/build-default-sh4-unknown-linux-gnu-nptl/elf/static-stubs.o --start-group /tmp/portage/cross-sh4-unknown-linux-gnu/glibc-9999/work/build-default-sh4-unknown-linux-gnu-nptl/libc.a -lgcc --end-group /usr/lib/gcc/sh4-unknown-linux-gnu/6.4.0/crtend.o /tmp/portage/cross-sh4-unknown-linux-gnu/glibc-9999/work/build-default-sh4-unknown-linux-gnu-nptl/csu/crtn.o
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.29.1 p3) 2.29.1 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.29.1-r1/work/binutils-2.29.1/bfd/elf32-sh.c:5171
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.29.1 p3) 2.29.1 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.29.1-r1/work/binutils-2.29.1/bfd/elf32-sh.c:5174
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.29.1 p3) 2.29.1 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.29.1-r1/work/binutils-2.29.1/bfd/elf32-sh.c:5176
...

The trigger issue here is likely glibc's lack of support gcc built as --enable-default-pie but binutils ld error messages are not informative enough to understand what is wrong with the code.

It's caused by BFD_ASSERT calls at:
    https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=bfd/elf32-sh.c;h=9fa363615ddbb7629628b7fe500df93d0a27a8b0;hb=HEAD#l5141

I suggest changing calls like
    BFD_ASSERT ((insn & 0xff00) == 0xd000);
to something like
    if ((insn & 0xff00) != 0xd000)
      _bfd_error_handler
        /* xgettext:c-format */
        (_("%B(%A+%#Lx): unexpected instruction %04X (expected 0xd0??, ?)"),
         input_bfd, input_section, offset, insn);
That way error message would be:
ld/ld-new: libc.a(sched_yield.o)(.text+0x3a): unexpected instruction A005 (expected 0xd0??, mov.l)
ld/ld-new: libc.a(sched_yield.o)(.text+0x3c): unexpected instruction E0FF (expected 0x0?12, stc)
ld/ld-new: libc.a(sched_yield.o)(.text+0x3e): unexpected instruction 0009 (expected 0x0?ce, mov.l)

It will help tweaking glibc.
Comment 1 Nick Clifton 2018-02-06 17:42:40 UTC
Hi Sergei,

  Is there any chance that you could upload a reproducible testcase
  (object files + libraries + linker command line).  This would make
  investigating the problem a lot easier.

Cheers
  Nick
Comment 2 Sergei Trofimovich 2018-07-23 22:17:44 UTC
I'm afraid I can't reproduce it on current toolchain versions as is (something was fixed): gcc-8.1.0, binutils-2.30, glibc-2.27

I'll try to craft relocations to point to invalid instructions to trigger the same uninformative assertion failures.
Comment 3 Sergei Trofimovich 2018-07-24 22:45:01 UTC
Created attachment 11150 [details]
binutils-gdb-sh4-better-errors.patch
Comment 4 Sergei Trofimovich 2018-07-24 22:45:38 UTC
Created attachment 11151 [details]
bug.S
Comment 5 Sergei Trofimovich 2018-07-24 22:47:21 UTC
Managed to craft an object file to trigger needed asserts.

As a bonus the test also causes out-of-bounds read access in ld and causes SIGSEGV:

    # cat bug.S
    # trying to trigger BFD_ASSERTs to make errors better:
    #   https://sourceware.org/PR22706
    # originally was found on toolchain that hits those asserts
    # and makes failures hard to discover
    
    .text
    .globl _start
    _start:
        .word 0
        .word 0
        .word 0
    
    .globl bar
    .hidden bar
    bar:
        .word 0
        .word 0
        .word 0
    
    .reloc _start, R_SH_TLS_LE_32, bar-5
    .reloc _start, R_SH_TLS_IE_32, bar-5
    .reloc _start, R_SH_TLS_GD_32, bar-5

Triggering (already patched binutils to produce nicer failures):

$ sh4-unknown-linux-gnu-as bug.S -o bug.o
$ sh4-unknown-linux-gnu-ld -m shlelf_linux -dynamic-linker /lib/ld-linux.so.2 -o bug.elf bug.o
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5156
sh4-unknown-linux-gnu-ld: bug.o(.text+0xfffffffffffffff6): unexpected instruction 0000 (expected 0xd0??, mov.l)
sh4-unknown-linux-gnu-ld: bug.o(.text+0xfffffffffffffff8): unexpected instruction 0021 (expected 0x0?12, stc)
sh4-unknown-linux-gnu-ld: bug.o(.text+0xfffffffffffffffa): unexpected instruction 0000 (expected 0x0?ce, mov.l)
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5115
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5126
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5128
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5130
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5132
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5134
sh4-unknown-linux-gnu-ld: BFD (Gentoo 2.30 p3) 2.30.0 assertion fail /tmp/portage-tmpdir/portage/cross-sh4-unknown-linux-gnu/binutils-2.30-r3/work/binutils-2.30/bfd/elf32-sh.c:5136
free(): invalid size
./do.sh: line 7: 17526 Aborted                 (core dumped) sh4-unknown-linux-gnu-ld -m shlelf_linux -dynamic-linker /lib/ld-linux.so.2 -o bug.elf bug.o

valgrind suggests SIGSEGV might be related to out-of-bounds write:

==22276== Invalid read of size 2
==22276==    at 0x4E790A0: bfd_getl16 (libbfd.c:505)
==22276==    by 0x4E91634: sh_elf_relocate_section (elf32-sh.c:5159)
==22276==    by 0x4EB870F: elf_link_input_bfd (elflink.c:10715)
==22276==    by 0x4EBA25E: bfd_elf_final_link (elflink.c:12033)
==22276==    by 0x1294CE: ldwrite (ldwrite.c:581)
==22276==    by 0x11202F: main (ldmain.c:456)
==22276==  Address 0x596b806 is 10 bytes before a block of size 12 alloc'd
==22276==    at 0x4C2CE6F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==22276==    by 0x4E78E81: bfd_malloc (libbfd.c:193)
==22276==    by 0x4EB9DE0: bfd_elf_final_link (elflink.c:11910)
==22276==    by 0x1294CE: ldwrite (ldwrite.c:581)
==22276==    by 0x11202F: main (ldmain.c:456)
Comment 6 Sourceware Commits 2018-07-30 12:59:25 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

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

commit a05b9f5e1eb8f01eea23eff3902fa57f1f28a4e1
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Jul 30 13:58:15 2018 +0100

    Prevent a seg-fault in the linker when trying to process SH object files with bogus relocs.
    
    	PR 22706
    	* elf32-sh.c (sh_elf_relocate_section): When processing
    	translation relocs, fail if the relocation offset is too small.
    	Replace BFD_ASSERTs with more helpful error messages.
Comment 7 Nick Clifton 2018-07-30 13:07:14 UTC
Hi Sergei,

  Thanks for the bug reproducer and the error message patch.  

  The problem happens because the relocs are intended to modify
  a specific code sequence, but they are being applied to the wrong
  code.  So I have extended your error message patch to replace
  some more  of the assertions with not just error messages, but also
  early failures so that the code does not go on to process the relocs
  incorrectly and then try to write to the wrong location.

Cheers
  Nick