Bug 17226 - ld --gc-sections segfaults on sparc-linux
Summary: ld --gc-sections segfaults on sparc-linux
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.25
: P2 normal
Target Milestone: 2.25
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-08-03 11:50 UTC by Mikael Pettersson
Modified: 2014-08-05 01:40 UTC (History)
1 user (show)

See Also:
Host:
Target: sparc*-linux
Build:
Last reconfirmed:


Attachments
gcsec-1.s from GCC's testsuite (393 bytes, text/plain)
2014-08-03 11:50 UTC, Mikael Pettersson
Details
proposed patch (330 bytes, patch)
2014-08-03 20:19 UTC, Mikael Pettersson
Details | Diff
counter-proposal patch (274 bytes, patch)
2014-08-03 23:08 UTC, Alan Modra
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mikael Pettersson 2014-08-03 11:50:46 UTC
Created attachment 7737 [details]
gcsec-1.s from GCC's testsuite

GCC's gcc/testsuite/gcc.dg/special/gcsec-1.c fails on sparc-linux because it causes ld to segfault.  This is reproducible both natively on sparc-linux and with cross toolchains hosted on x86_64-linux.  Occurs with (at least) binutils 2.25 (HEAD), 2.24, and 2.23.2.  Occurs with both 32 and 64-bit sparc targets.

To reproduce natively on sparc-linux, do sth like:

> gcc -m32 -c gcsec-1.s
> ld -m elf32_sparc -static -relax -o a.out /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/sparcv9-brewer-linux/4.7.4/crtbeginT.o gcsec-1.o --gc-sections --start-group /usr/lib/libc.a /usr/lib/gcc/sparcv9-brewer-linux/4.7.4/libgcc.a /usr/lib/gcc/sparcv9-brewer-linux/4.7.4/libgcc_eh.a --end-group /usr/lib/gcc/sparcv9-brewer-linux/4.7.4/crtend.o /usr/lib/crtn.o
Segmentation fault

Running the above in gdb shows:

Program received signal SIGSEGV, Segmentation fault.
0xf7f2ec2c in _bfd_sparc_elf_gc_sweep_hook (abfd=0x15ce98, info=0x9bc28 <link_info>, sec=0x16f418, relocs=<optimized out>) at elfxx-sparc.c:2003
2003                      if (local_got_refcounts[r_symndx] > 0)
Missing separate debuginfos, use: debuginfo-install glibc-2.17-2.bl17.bl.2.sparcv9 libgcc-4.7.4-10.bl17.bl.2.sparcv9 zlib-1.2.5-7.bl17.sparcv9
(gdb) list
1998                    case R_SPARC_GOTDATA_OP_HIX22:
1999                    case R_SPARC_GOTDATA_OP_LOX10:
2000                      break;
2001
2002                    default:
2003                      if (local_got_refcounts[r_symndx] > 0)
2004                        local_got_refcounts[r_symndx]--;
2005                      break;
2006                    }
2007                }
(gdb) bt
#0  0xf7f2ec2c in _bfd_sparc_elf_gc_sweep_hook (abfd=0x15ce98, info=0x9bc28 <link_info>, sec=0x16f418, relocs=<optimized out>) at elfxx-sparc.c:2003
#1  0xf7f5e264 in elf_gc_sweep (info=0x9bc28 <link_info>, abfd=0xa9618) at elflink.c:11936
#2  bfd_elf_gc_sections (abfd=0xa9618, info=0x9bc28 <link_info>) at elflink.c:12199
#3  0x00028e58 in lang_gc_sections () at ldlang.c:6401
#4  lang_process () at ldlang.c:6744
#5  0x00013b04 in main (argc=19, argv=0xffffd2b4) at ./ldmain.c:386
(gdb) print local_got_refcounts
$1 = (bfd_signed_vma *) 0x0

Removing the --gc-sections option allows the link to succeed.

To reproduce with a cross toolchain, do sth like:

> sparc64-unknown-linux-gcc -m32 -c gcsec-1.s
> sparc64-unknown-linux-ld -m elf32_sparc -static -relax -o a.out /home/mikpe/pkgs/linux-x86_64/cross-sparc64/usr/lib/crt1.o /home/mikpe/pkgs/linux-x86_64/cross-sparc64/usr/lib/crti.o /home/mikpe/pkgs/linux-x86_64/cross-sparc64/lib/gcc/sparc64-unknown-linux/4.8.3/32/crtbeginT.o gcsec-1.o --gc-sections --start-group /home/mikpe/pkgs/linux-x86_64/cross-sparc64/usr/lib/libc.a /home/mikpe/pkgs/linux-x86_64/cross-sparc64/lib/gcc/sparc64-unknown-linux/4.8.3/32/libgcc.a --end-group /home/mikpe/pkgs/linux-x86_64/cross-sparc64/lib/gcc/sparc64-unknown-linux/4.8.3/32/crtend.o /home/mikpe/pkgs/linux-x86_64/cross-sparc64/usr/lib/crtn.o
Segmentation fault

The cross toolchain was built with binutils-2.24, gcc-4.8.3, Linux 3.13 kernel headers, and glibc-2.19.

I've tried to make the test case standalone, but simply stubbing out the references to libc makes the segfault go away.
Comment 1 Mikael Pettersson 2014-08-03 20:19:47 UTC
Created attachment 7738 [details]
proposed patch

It seems that the majority of the elf backends in bfd do a NULL check before dereferencing local_got_refcounts in their gc_sweep_hook functions.

I don't know if there's a fundamental reason why the sparc backend doesn't do a NULL check in this context, but adding a NULL check fixes this test case with no visible regressions (tested 2.25 HEAD, 2.24, and 2.23.2 in cross environments, tested 2.23.2 natively).
Comment 2 Alan Modra 2014-08-03 23:08:30 UTC
Created attachment 7739 [details]
counter-proposal patch

There shouldn't be any need to test local_got_refcounts for NULL, if gc_sweep_hook logic exactly matches check_relocs, and by inspection there's a typo that probably is the cause of this bug.
Comment 3 Mikael Pettersson 2014-08-04 19:10:00 UTC
Thanks Alan, your patch also fixes the bug.  Tested with crosses hosted on x86_64-linux, and natively on sparc64-linux: no regressions.
Comment 4 Sourceware Commits 2014-08-05 01:39:47 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gdb and binutils".

The branch, master has been updated
       via  7833fb7b8e4d0c75138ef715935a5040bc9b2e78 (commit)
      from  02eb0a49bceb35e4b0503e6ffc11e85151dbc571 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

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

commit 7833fb7b8e4d0c75138ef715935a5040bc9b2e78
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Aug 5 10:49:54 2014 +0930

    Fix PR17226, ld --gc-sections segfaults on sparc-linux
    
    	PR ld/17226
    	* elfxx-sparc.c (_bfd_sparc_elf_gc_sweep_hook): Typo fix.

-----------------------------------------------------------------------

Summary of changes:
 bfd/ChangeLog     |    5 +++++
 bfd/elfxx-sparc.c |    2 +-
 2 files changed, 6 insertions(+), 1 deletions(-)
Comment 5 Alan Modra 2014-08-05 01:40:29 UTC
Fixed mainline.