Bug 21181 - All executables segfault when linked with -z,now on Alpha.
Summary: All executables segfault when linked with -z,now on Alpha.
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.28
: P2 normal
Target Milestone: 2.28
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-02-18 08:02 UTC by Michael Cree
Modified: 2017-02-20 11:10 UTC (History)
5 users (show)

See Also:
Host:
Target: alpha
Build:
Last reconfirmed: 2017-02-20 00:00:00


Attachments
Fix (1.19 KB, patch)
2017-02-20 07:32 UTC, Alan Modra
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Cree 2017-02-18 08:02:13 UTC
Recent regression seen first with binutils Debian version 2.27.90.20170124-2.  All executables compiled with -z,now for Alpha target segfault when run.

Debugging with gdb on a bad executable showed that the program entered _start, then jumped to _PROCEDURE_LINKAGE_TABLE, which loads CPU register t12 with the first entry of the GOT which is null, and jumps indirect via t12 which is null, hence segfault.

Comparing an executable built with a working linker (Debian version 2.27-8)
and one compiled with a recent broken linker revealed this difference in the dynamic section between the good and the bad executable:

-  RELA                 0x0000000120000380
+  RELA                 0x00000001200003b0

objdump -s shows that for both executables the .rela.plt section is
at 0x120000380 and the .init section is at 0x1200003b0, so we see in
the bad executable the dynamic section RELA entry is not the address
of a relocation table, but is pointing to the .init section.

A simple edit of one byte in the bad executable (changing the RELA entry to be 0x0000000120000380) leads to a working executable.
Comment 1 Alan Modra 2017-02-20 05:47:47 UTC
I think this was very likely triggered by my elf_backend_dtrel_excludes_plt change, git commit 64f52338e9.  Architectures other than alpha are likely to be affected too, if you can manage to create a binary with plt dynamic relocs but no other dynamic relocs, and DT_RELA/DT_RELASZ are emitted.

I'm guessing that all the bad -z now binaries have DT_RELASZ zero, which would mean that the value of DT_RELA should not matter.  Except that it does, due to a glibc bug.  See glibc/elf/dynamic_link.h _ELF_DYNAMIC_DO_RELOC and note what happens during processing of DT_PLTREL with DT_RELA/DT_RELASIZ as you describe.  No PLT reloc processing for you!

It's also a bug that alpha ld emits DT_RELA/DT_RELASZ when DT_RELASZ is zero.
Comment 2 Michael Cree 2017-02-20 07:15:32 UTC
Yes, RELASZ is set to zero in executables linked with -z,now (the example below from a simple "Hello World!" program):

Dynamic Section:
  NEEDED               libc.so.6.1
  INIT                 0x00000001200003b0
  FINI                 0x00000001200006f0
  INIT_ARRAY           0x0000000120011de8
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000120011df0
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000120000290
  STRTAB               0x0000000120000318
  SYMTAB               0x00000001200002b8
  STRSZ                0x000000000000003d
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000120012000
  PLTRELSZ             0x0000000000000030
  PLTREL               0x0000000000000007
  JMPREL               0x0000000120000380
  0x70000000           0x0000000000000001
  RELA                 0x00000001200003b0
  RELASZ               0x0000000000000000
  RELAENT              0x0000000000000018
  FLAGS                0x0000000000000008
  FLAGS_1              0x0000000000000001
  VERNEED              0x0000000120000360
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x0000000120000356
Comment 3 Alan Modra 2017-02-20 07:32:53 UTC
Created attachment 9838 [details]
Fix

This should cure the problem.  Please test.
Comment 4 Michael Cree 2017-02-20 09:32:19 UTC
Tested patch against binutils debian version 2.27.90.20170218.  It fixes the problem!  Executables linked with -z,now work.

But, did you mean for RELA/RELASZ still to be emitted?  objdump -p reveals in the new exectuable:

Dynamic Section:
  NEEDED               libc.so.6.1
  INIT                 0x00000001200003b0
  FINI                 0x00000001200006e0
  INIT_ARRAY           0x0000000120011de8
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000120011df0
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000120000290
  STRTAB               0x0000000120000318
  SYMTAB               0x00000001200002b8
  STRSZ                0x000000000000003d
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000120012000
  PLTRELSZ             0x0000000000000030
  PLTREL               0x0000000000000007
  JMPREL               0x0000000120000380
  0x70000000           0x0000000000000001
  RELA                 0x0000000000000000
  RELASZ               0x0000000000000000
  RELAENT              0x0000000000000018
  FLAGS                0x0000000000000008
  FLAGS_1              0x0000000000000001
  VERNEED              0x0000000120000360
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x0000000120000356
Comment 5 Alan Modra 2017-02-20 10:05:29 UTC
I have another patch to remove DT_RELA etc.
Comment 6 cvs-commit@gcc.gnu.org 2017-02-20 10:32:45 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit 644877806ec0024d1df1dc29249b8e610202147b
Author: Alan Modra <amodra@gmail.com>
Date:   Mon Feb 20 17:20:45 2017 +1030

    Alpha executables segfault when linked with -z,now
    
    	PR 21181
    	* elflink.c (bfd_elf_final_link): Make DT_REL/DT_RELA zero
    	if DT_RELSZ/DT_RELASZ is zero.
Comment 7 cvs-commit@gcc.gnu.org 2017-02-20 10:51:41 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=499345cc67f44f27d7490d4c8996d3f9b5f76b1f

commit 499345cc67f44f27d7490d4c8996d3f9b5f76b1f
Author: Alan Modra <amodra@gmail.com>
Date:   Mon Feb 20 17:20:45 2017 +1030

    Alpha executables segfault when linked with -z,now
    
    	PR 21181
    	* elflink.c (bfd_elf_final_link): Make DT_REL/DT_RELA zero
    	if DT_RELSZ/DT_RELASZ is zero.
Comment 8 Alan Modra 2017-02-20 10:57:02 UTC
Fixed master and 2.28 branch
Comment 9 John Paul Adrian Glaubitz 2017-02-20 11:10:20 UTC
(In reply to Alan Modra from comment #8)
> Fixed master and 2.28 branch

Thanks a lot. The 2.28 backport means that the next update of the binutils package in Debian will pull the patch in automatically.