https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80848
Alexey Neyman <stilor at att dot net> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |stilor at att dot net
--- Comment #1 from Alexey Neyman <stilor at att dot net> ---
I have looked at this issue when the problem was reported in crosstool-NG
tracker [1]. The issue started with the commit 66035fd [2]; the link at [3]
explains in more detail the problem that commit tried to solve.
After that change, BFD trips over this check [4]:
724 if (hdr_length == 0)
725 {
726 /* A zero-length CIE should only be found at the end of
727 the section. */
728 REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size);
729 ENSURE_NO_RELOCS (buf);
730 sec_info->count++;
731 break;
732 }
The crtend.o generated by the build has the following in .eh_frame:
[[[[
alphaev4-unknown-linux-gnu-readelf -wf
.build/alphaev4-unknown-linux-gnu/buildtools/lib/gcc/alphaev4-unknown-linux-gnu/4.8.4/crtend.o
Contents of the .eh_frame section:
00000000 ZERO terminator
00000004 0000000000000010 00000000 CIE
Version: 1
Augmentation: "zR"
Code alignment factor: 4
Data alignment factor: -8
Return address column: 26
Augmentation data: 1b
DW_CFA_def_cfa_register: r30
DW_CFA_nop
00000018 0000000000000024 00000018 FDE cie=00000004
pc=0000000000000000..0000000000000070
DW_CFA_advance_loc: 20 to 0000000000000014
DW_CFA_def_cfa_offset: 32
DW_CFA_advance_loc: 12 to 0000000000000020
DW_CFA_offset: r9 at cfa-24
DW_CFA_advance_loc: 8 to 0000000000000028
DW_CFA_offset: r10 at cfa-16
DW_CFA_advance_loc: 8 to 0000000000000030
DW_CFA_offset: r26 at cfa-32
DW_CFA_advance_loc: 60 to 000000000000006c
DW_CFA_restore: r10
DW_CFA_restore: r9
DW_CFA_restore: r26
DW_CFA_def_cfa_offset: 0
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
]]]]
I.e., the zero terminator is indeed not the last record. GCC produces the
following assembly when compiling crtstuff.c into crtend.o (skipping irrelevant
parts):
[[[[
.section .eh_frame,"a",@progbits
.align 2
.type __FRAME_END__, @object
__FRAME_END__:
.zero 4
...
__do_global_ctors_aux:
$LFB9:
.cfi_startproc
ldah $29,0($27) !gpdisp!1
lda $29,0($29) !gpdisp!1
]]]]
That is, GCC generates both the explicit zero terminator as well as the CFI
instructions that make the assembler generate additional CIE/FDE records.
Adding -fno-asynchronous-unwind-tables and/or -fno-exceptions has no effect.
Adding -fno-dwarf2-cfi-insns makes GCC emit a second .eh_section fragment with
explicitly generated DWARF2 bytecode. In both cases, the result is an invalid
.eh_frame section with zero terminator record not being the last. In other
words, there is no way to prevent GCC from emitting any additional content into
the .eh_frame section, aside from the terminator.
- So, the question is, how should this be fixed?
- Was [2] a correct change to begin with?
- Should alpha (in addition to [2], or instead of [2]) implement a custom
"alpha_except_unwind_info" that will return UI_NONE if exceptions are disabled
(and then use that while compiling crtend.o)?
- Or if CFI is desired for __do_global_ctors_aux, perhaps compile this routine
separately into, say, crtend1.o; then compile the data-only section terminators
into crtend2.o; and then do a `ld -r` of both crtend[12].o into crtend.o?
[1] https://github.com/crosstool-ng/crosstool-ng/issues/719
[2]
https://github.com/gcc-mirror/gcc/commit/66035fd81f6fb8dff84e0c64d52ed041450fdebc
[3] https://gcc.gnu.org/ml/gcc-patches/2014-07/msg01680.html
[4]
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=bfd/elf-eh-frame.c;h=52ba9c62138bb7d2c8901d961ba322dbfe23e220;hb=HEAD#l724