[patch,PE-COFF,head+2.22] Don't generate bogus base relocs in .eh_frame of DLLs.

Dave Korn dave.korn.cygwin@gmail.com
Sun Sep 25 18:05:00 GMT 2011


[ I'm back after a couple of months unexpected hiatus.  If there's anything
important that I've missed, please feel free to mail me off-list to draw my
attention to it.  ]

    Hi list,

  The latest release of the libstdc++ DLL for Cygwin breaks exception handling
if it is rebased away from its default address.  Debugging this shows that one
of the Dwarf-2 FDEs in the .eh_frame section gets mangled, which causes the
libgcc unwind code to get confused and fail to find the FDE for a given return
address from the stack frame, resulting in an early exit through terminate().

  It turns out that the FDE in question refers to an inline function, which
exists in one of the input object files linked to build the final DLL in a
COMDAT section.  When the COMDAT resolution picks a copy of the section from a
different object file, the .eh_frame FDE data contains a reloc that now points
to a discarded section.  This happens a lot because there's only one .eh_frame
section per object file that covers all the text sections, any one of which
might get discarded.

  The generic linker handles it just fine; it gets a value of zero against the
*ABS* section, resulting in a zero in the relocated section contents, and the
libgcc unwind code interprets a zero start address in an FDE to mean that the
FDE is discarded.  However the PE linker still goes and generates a base reloc
corresponding to the effectively-disregarded BFD reloc.  (PE DLLs are
pre-linked to assume they will be loaded at a chosen base address; if they end
up loaded elsewhere at runtime, the OS loader applies a set of PE-specific
relocations known as "base relocations".)  Thus when the DLL is rebased, the
start address field in the FDE gets written with the offset by which the DLL
is being rebased, and libgcc interprets this as an FDE for a PC range
somewhere in low or high memory (according to the direction in which the DLL
is rebased) and gets its internal list of memory regions in a twist.

  The attached patch is conservative; it checks just for BFD against symbols
from discarded input sections, and if the reloc itself is in an EH section it
doesn't generate a corresponding base reloc.  It doesn't cause any failures in
the ld testsuite, but then I don't think we have anything to verify base reloc
generation in there anyway, so I'm also running a GCC bootstrap and test cycle
using the patched binutils.  (I already checked that the libstdc++ DLL that it
builds omits the specific base relocs that were causing the problem and
handles exceptions just fine even after rebasing).  It'll probably be another
48 hours before the results from that are in, so this is advance warning for
Tristan; I'd like to get this into the 2.22 release so that it can be in the
next Cygwin binutils package.  Ok, Tristan?

ld/ChangeLog:

2011-09-25  Dave Korn  <dave.korn.cygwin@...

	* pe-dll.c (generate_reloc): Don't emit base reloc if underlying
	BFD reloc is from an EH section and refers to a discarded input
	COMDAT section.

    cheers,
      DaveK


-------------- next part --------------
A non-text attachment was scrubbed...
Name: no-base-relocs-against-discarded-sections-patch.diff
Type: text/x-c
Size: 878 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20110925/625d5e1f/attachment.bin>


More information about the Binutils mailing list