Bug 17366

Summary: gold can't handle a crt1.o with an .eh_frame
Product: binutils Reporter: Rafael Ávila de Espíndola <rafael>
Component: goldAssignee: Cary Coutant <ccoutant>
Severity: normal CC: amodra, ian, jan
Priority: P2    
Version: unspecified   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Rafael Ávila de Espíndola 2014-09-09 23:02:49 UTC
I noticed that gold's exception_static_test test was failing on my machine (fedora 20 x86_64).

The link line is

gcctestdir/ld --build-id --no-add-needed --hash-style=gnu -m elf_x86_64 -static -o exception_static_test /usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.3/crtbeginT.o -Lgcctestdir -L/usr/lib/gcc/x86_64-redhat-linux/4.8.3 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../.. exception_test_main.o exception_test_1.o exception_test_2.o -ldl -lz -lstdc++ -lm --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-redhat-linux/4.8.3/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crtn.o

To see the problem run:
 readelf -aW exception_static_test  | grep -i eh_frame

On my system the output is

  [16] .eh_frame         PROGBITS        00000000004b60d8 0b60d8 00f5ec 00   A  0   0  8
   00     .note.ABI-tag .note.gnu.build-id .rela.plt .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini .rodata .gcc_except_table .stapsdt.base __libc_subfreeres __libc_atexit __libc_thread_subfreeres .eh_frame 
     2: 00000000004c56c0     0 OBJECT  LOCAL  DEFAULT   16 __EH_FRAME_BEGIN__

note how __EH_FRAME_BEGIN__ points to the *end* of .eh_frame.

with bfd ld I get

 [15] .eh_frame         PROGBITS        00000000004b5d08 0b5d08 00f524 00   A  0   0  8
   00     .note.ABI-tag .note.gnu.build-id .rela.plt .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini .rodata .stapsdt.base __libc_subfreeres __libc_atexit __libc_thread_subfreeres .eh_frame .gcc_except_table 
   261: 00000000004b5d38     0 OBJECT  LOCAL  DEFAULT   15 __EH_FRAME_BEGIN__

The difference of 0x30 from the start is accounted by the .eh_frame of  crt1.o:

$ readelf -SW /lib64/crt1.o | grep .eh_frame
  [ 5] .eh_frame         PROGBITS        0000000000000000 000090 000030 00   A  0   0  8
Comment 1 Rafael Ávila de Espíndola 2014-09-10 00:57:54 UTC
For what it is worth, crt1.o has an .eh_frame because of

Comment 2 Cary Coutant 2014-09-10 19:59:26 UTC
See the discussion starting at:


and continuing into April:


Gold is optimizing the .eh_frame data, then throwing the optimized result into the output section at a point corresponding to where it saw the first .eh_frame section that it could optimize. This is a perfectly reasonable thing to do, and it makes no sense that the open bracket symbol is defined crtbeginT.o, which comes after crt1.o in the link order. When crt1.o has no .eh_frame data, everything works because the optimized data will get inserted following crtbeginT.o.

Gnu ld likely handles this by not optimizing the .eh_frame data when --eh-frame-hdr is not passed in, so everything appears in link order. It's still doing the wrong thing, though, as the data in crt1.o still comes before the __EH_FRAME_BEGIN__ symbol.

The proper solution would be to move the __EH_FRAME_BEGIN__ symbol into a file that actually does come before any .eh_frame data.

*** This bug has been marked as a duplicate of bug 14675 ***
Comment 3 Alan Modra 2014-09-11 00:00:27 UTC
GNU ld optimises .eh_frame without --eh-frame-hdr.  The only real difference between GNU gold and GNU ld is that GNU ld doesn't lose track of where __EH_FRAME_BEGIN__ was defined.

I agree that __EH_FRAME_BEGIN__ is defined in the wrong object file, and one fix for this bug is to ask people to provide sane input to ld/gold.  Another fix might be to have the linker define its own __EH_FRAME_BEGIN__ symbol, ignoring the bad user input.