Red Hat Bugzilla – Bug 115881
ld mangles eh_frame (is too relaxed, causing bad fill)
Last modified: 2007-11-30 17:07:00 EST
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; Galeon)
Description of problem:
New versions of ld appear to have code which compresses .eh_frame
information by coalescing identical CIE's. Good idea. However,
sometimes when it does this, it takes an .eh_frame section which was
padded out to the appropriate alignment (e.g. 4) and removes material
from it which leaves it improperly padded. When this happens, ld
inserts *fill* bytes. But that's a problem in .eh_frame, because each
.eh_frame entry (CIE or FDE) knows its own length, and that length is
used to compute the address or offset of the next entry. Those
lengths know nothing about any *fill* bytes, are are not adjusted by
the code which coalesces CIE's. So, Dwarf consumers try to interpret
those *fill* bytes as the start of a CIE or FDE and get very confused.
gcc appears to be very careful always to pad its .eh_frame sections
out to a multiple of the alignment, so that no *fill* bytes can
interfere with the lengths in the FDE's. However, it seems to do this
on a per-object-file basis. That is, it doesn't make any effort to
pad out individual CIE's or FDE's. This is how the removal of a CIE
can cause the pad for a section which was correct to become incorrect.
This bug was found with a real-world example, but it was quite large.
So, I generated a tiny example that's just an ld invocation with no
object files required beyond what's in glibc. It creates a degenerate
program that probably wouldn't even run, but it's not meant to run,
only to illustrate this bug.
Version-Release number of selected component (if applicable):
Steps to Reproduce:
1. Execute "too_relaxed" script (included as attachment)
Actual Results: The MAP file produced by the link shows *fill* bytes
in the .eh_frame.
The readelf -wf invocation dies with a Memory Fault.
Expected Results: The MAP file should have no *fill* bytes in the
The readelf -wf invocation should not die.
This problem also is present in Fedora Core 1. I have found no
workaround as yet.
A quick & dirty fix in the binutils source would be, in
_bfd_elf_discard_section_eh_frame, after calling cie_compare(), simply
determine if the size of the CIE is a multiple of the alignment of the
.eh_frame section, and refuse to coalesce CIE's if their size is not a
multiple of the section's alignment.
A better fix would be, after removal of the CIE, to correct the pad,
using DW_CFA_nop's, and update the FDE lengths appropriately.
Created attachment 97716 [details]
An errata has been issued which should help the problem described in this bug report.
This report is therefore being closed with a resolution of ERRATA. For more information
on the solution and/or where to find the updated files, please follow the link below. You may reopen
this bug report if the solution does not work for you.