Bug 17639 - Malformed .eh_frame generated with LTO, gold and optimization enabled
Summary: Malformed .eh_frame generated with LTO, gold and optimization enabled
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: gold (show other bugs)
Version: 2.24
: P2 normal
Target Milestone: ---
Assignee: Cary Coutant
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-11-24 13:52 UTC by Peter Wu
Modified: 2014-11-26 00:18 UTC (History)
2 users (show)

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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Wu 2014-11-24 13:52:59 UTC
(originally reported at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64046)

While trying to track down a weird crash in libunwind, I found that the library I was debugging (libgudev-1.0.so.0.2.0) has a weird .eh_frame. I could minimize the problem to:

    echo 'int main(void) { return 0; }' > hello.c
    gcc -shared -Wl,-fuse-ld=gold -fPIC -flto -ffat-lto-objects -O2 hello.c -Wl,--gc-sections
    readelf --hex-dump=.eh_frame a.out | head -n5

Omitting any of the gcc options would result in a .eh_frame section that does not look odd. Output of readelf follows (note the leading 8 zeroes, and the warning about the invalid FDE length).

Hex dump of section '.eh_frame':
  0x000006b0 00000000 00000000 14000000 00000000 ................
  0x000006c0 017a5200 01781001 1b0c0708 90010000 .zR..x..........
  0x000006d0 c0feffff 1c000000 00000000 02000000 ................
  0x000006e0 00000000 00000000 24000000 34000000 ........$...4...
  0x000006f0 70feffff 30000000 000e1046 0e184a0f p...0......F..J.
  0x00000700 0b770880 003f1a3b 2a332422 00000000 .w...?.;*3$"....

Contents of the .eh_frame section:

00000000 ZERO terminator


00000004 ZERO terminator


00000008 0000000000000014 00000000 CIE
  Version:               1
  Augmentation:          "zR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:     1b

  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop
readelf: Warning: Invalid length 0xfffffec0 in FDE at 0x000020

00000020 00000000fffffec0 0000001c FDE cie=00000008 pc=00000000000006d8..00000000000006da
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_??? (User defined call frame op: 0x24)

This .eh_frame encoding looks strange to me as it does not conform to LSB 4.1[1] nor the AMD64 ABI document. It also trips up Wireshark's ELF dissector
(and apparently also readelf).

Linux x86_64
GCC versions 4.8.2-1ubuntu6 (Ubuntu 14.04) and 4.9.2-1 (Arch Linux).
binutils 2.24-8 (Arch Linux)

 [1]: https://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
 [2]: http://www.x86-64.org/documentation/abi.pdf
Comment 1 Peter Wu 2014-11-24 14:35:44 UTC
This bug breaks C++ exceptions too.

==> foo.cpp <==
#include <stdio.h>
void foo(int n) {
    puts("FOO");
    throw 42;
}

==> main.cpp <==
#include <stdio.h>
extern void foo(int x);
int main(void) {
    puts("calling foo");
    try {
        foo(1);
    } catch (int i) {
        printf("Caught %d\n", i);
    }
    puts("done with foo");

With ld.gold (-Wl,-fuse-ld=gold):
calling foo
FOO
Aborted

Without gold:
calling foo
FOO
Caught 42
done with foo
Comment 2 cvs-commit@gcc.gnu.org 2014-11-25 21:57:11 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  c924eb67e143722e4098d84c1cb91123a51c988f (commit)
      from  61e6682207163bfc02b2fc0c54c084cf8f2c5f10 (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=c924eb67e143722e4098d84c1cb91123a51c988f

commit c924eb67e143722e4098d84c1cb91123a51c988f
Author: Cary Coutant <ccoutant@google.com>
Date:   Tue Nov 25 13:55:42 2014 -0800

    Fix corrupted .eh_frame section with LTO and --gc-sections.
    
    When --gc-sections is turned on during an LTO link, the .eh_frame sections
    from deferred files are processed before those from the replacement files.
    As a result, the section end-cap from crtendS.o is placed ahead of
    the .eh_frame data from the replacement files. This patch fixes the bug
    by skipping the layout of the deferred sections during GC pass 2.
    
    gold/
    	PR gold/17639
    	* object.cc (Sized_relobj_file): Initialize is_deferred_layout_.
    	(Sized_relobj_file::do_layout): Handle deferred sections properly
    	during GC pass 1. Don't add reloc sections to deferred list twice.
    	* object.h (Sized_relobj_file::is_deferred_layout): New function.
    	(Sized_relobj_file::is_deferred_layout_): New data member.

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

Summary of changes:
 gold/ChangeLog |    9 +++++++++
 gold/object.cc |   20 ++++++++++++++------
 gold/object.h  |    7 +++++++
 3 files changed, 30 insertions(+), 6 deletions(-)
Comment 3 Cary Coutant 2014-11-25 22:00:47 UTC
Should be fixed on binutils trunk. If you'd like this backported to 2.25, let me know.
Comment 4 Peter Wu 2014-11-25 23:29:14 UTC
Verified with master (git commit c924eb67e143722e4098d84c1cb91123a51c988f).

The current binutils stable is 2.24 right? It would be nice if it available in the next version (2.25?). Thank you for the prompt response!
Comment 5 cvs-commit@gcc.gnu.org 2014-11-26 00:18:52 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, binutils-2_25-branch has been updated
       via  9ec85a27138aefcd3fc35ddbd7727f384fe299b1 (commit)
      from  bd30b2c856c9ae1fc3559d80fc8c8ccdf65e5fce (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=9ec85a27138aefcd3fc35ddbd7727f384fe299b1

commit 9ec85a27138aefcd3fc35ddbd7727f384fe299b1
Author: Cary Coutant <ccoutant@google.com>
Date:   Tue Nov 25 13:55:42 2014 -0800

    Fix corrupted .eh_frame section with LTO and --gc-sections.
    
    Backport from trunk:
    
    When --gc-sections is turned on during an LTO link, the .eh_frame sections
    from deferred files are processed before those from the replacement files.
    As a result, the section end-cap from crtendS.o is placed ahead of
    the .eh_frame data from the replacement files. This patch fixes the bug
    by skipping the layout of the deferred sections during GC pass 2.
    
    gold/
    	PR gold/17639
    	* object.cc (Sized_relobj_file): Initialize is_deferred_layout_.
    	(Sized_relobj_file::do_layout): Handle deferred sections properly
    	during GC pass 1. Don't add reloc sections to deferred list twice.
    	* object.h (Sized_relobj_file::is_deferred_layout): New function.
    	(Sized_relobj_file::is_deferred_layout_): New data member.

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

Summary of changes:
 gold/ChangeLog |    9 +++++++++
 gold/object.cc |   20 ++++++++++++++------
 gold/object.h  |    7 +++++++
 3 files changed, 30 insertions(+), 6 deletions(-)