This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [patch,PE-COFF,head+2.22] Don't generate bogus base relocs in .eh_frame of DLLs.
- From: Ozkan Sezer <sezeroz at gmail dot com>
- To: binutils at sourceware dot org
- Cc: dave dot korn dot cygwin at gmail dot com
- Date: Wed, 5 Oct 2011 09:16:00 +0300
- Subject: Re: [patch,PE-COFF,head+2.22] Don't generate bogus base relocs in .eh_frame of DLLs.
> 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
>
>
>
>Index: ld/pe-dll.c
>===================================================================
>RCS file: /cvs/src/src/ld/pe-dll.c,v
>retrieving revision 1.138
>diff -p -u -r1.138 pe-dll.c
>--- ld/pe-dll.c 16 Sep 2011 01:15:19 -0000 1.138
>+++ ld/pe-dll.c 25 Sep 2011 12:59:34 -0000
>@@ -1395,6 +1395,16 @@ generate_reloc (bfd *abfd, struct bfd_li
> else if (!blhe || blhe->type != bfd_link_hash_defined)
> continue;
> }
>+ /* Nor for Dwarf FDE references to discarded sections. */
>+ else if (bfd_is_abs_section (sym->section->output_section))
>+ {
>+ /* These are the same section names that
>+ _bfd_elf_default_action_discarded chooses to discard
>+ relocs against. */
>+ if (!strcmp (s->name, ".eh_frame")
>+ || !strcmp (s->name, ".gcc_except_table"))
>+ continue;
>+ }
>
> reloc_data[total_relocs].vma = sec_vma + relocs[i]->address;
>
This patch still isn't in. Is it not needed any more?
--
O.S.