This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: gc sections and .eh_frame
> None of the proposed solutions is right. If you take a look at a
> typical .eh_frame, you'll see relocs pointing at text sections and
> .gcc_except_table (or .rodata for broken ppc compilers). Changing
> garbage collection to process .rela.eh_frame thus runs into the problem
> of distinguishing the two types of reloc: You need to ignore the
> former, and mark sections for the latter.
That's exactly what I proposed in my last message, but I suggested passing a
parameter to _bfd_elf_gc_mark to make it "forget" code sections. It seems
autodetecting .eh_frame is more straightforward.
> Try the following totally untested patch.
>
> * elflink.c (_bfd_elf_gc_mark): Handle .eh_frame relocs specially..
> (bfd_elf_gc_sections): ..rather than totally ignoring .eh_frame.
> Don't recheck sections we have already marked.
I think it doesn't work (alone) either, because you unconditionally mark
all .gcc_except_table* sections, which themselves point to the functions.
In normal mode (i.e. with a non broken ppc compiler), we really need avoid
marking any sections referenced by .eh_frame, them being code or data. So I
think that, before invoking _bfd_elf_gc_mark on .eh_frame, we need to make
sure that it doesn't reference .gcc_except_table* sections. Hence the
attached patch.
* elflink.c (_bfd_elf_gc_mark): Don't mark code sections referenced
by .eh_frame.
(bfd_elf_gc_sections): Mark again the sections referenced by .eh_frame
if the EH tables are not in .gcc_except_table* sections.
--
Eric Botcazou
Index: elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.136.2.3
diff -u -p -r1.136.2.3 elflink.c
--- elflink.c 27 Apr 2005 16:47:24 -0000 1.136.2.3
+++ elflink.c 27 Jun 2005 11:47:06 -0000
@@ -8687,6 +8687,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *
gc_mark_hook_fn gc_mark_hook)
{
bfd_boolean ret;
+ bfd_boolean is_eh;
asection *group_sec;
sec->gc_mark = 1;
@@ -8699,6 +8700,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *
/* Look through the section relocs. */
ret = TRUE;
+ is_eh = strcmp (sec->name, ".eh_frame") == 0;
if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
{
Elf_Internal_Rela *relstart, *rel, *relend;
@@ -8771,7 +8773,11 @@ _bfd_elf_gc_mark (struct bfd_link_info *
rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
}
- if (rsec && !rsec->gc_mark)
+ if (rsec
+ && !rsec->gc_mark
+ /* elf-eh-frame.c knows how to discard orphaned FDEs so don't
+ mark code sections referenced by the .eh_frame section. */
+ && !(is_eh && (rsec->flags & SEC_CODE) != 0))
{
if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
rsec->gc_mark = 1;
@@ -9068,6 +9074,8 @@ bfd_elf_gc_sections (bfd *abfd, struct b
gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
+ bfd_boolean has_gcc_except_table = FALSE;
+ asection *eh_frame = NULL;
asection *o;
if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
@@ -9077,15 +9085,41 @@ bfd_elf_gc_sections (bfd *abfd, struct b
{
if (o->flags & SEC_KEEP)
{
- /* _bfd_elf_discard_section_eh_frame knows how to discard
- orphaned FDEs so don't mark sections referenced by the
- EH frame section. */
+ /* Marking all sections referenced by .eh_frame effectively
+ disables GC because FDEs contain relocs against both the
+ functions' code and exception table. So we mark none,
+ relying on elf-eh-frame.c to deal with the former type of
+ relocs (it will discard orphaned FDEs) and on the linker
+ script to deal with the latter type if necessary. */
if (strcmp (o->name, ".eh_frame") == 0)
- o->gc_mark = 1;
+ {
+ o->gc_mark = 1;
+ eh_frame = o;
+ }
else if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
}
- }
+
+#define GCC_EXCEPT_TABLE_PREFIX ".gcc_except_table"
+
+ /* Detect .gcc_except_table* sections in the input file. */
+ if (!has_gcc_except_table
+ && strncmp (o->name,
+ GCC_EXCEPT_TABLE_PREFIX,
+ strlen (GCC_EXCEPT_TABLE_PREFIX)) == 0)
+ has_gcc_except_table = TRUE;
+ }
+
+ /* If we have not detected .gcc_except_table* sections in the input
+ file, that can mean the target uses a specific section for the
+ EH tables. Play safe and let .eh_frame mark the non-code
+ sections it really needs, since we will presumably not be able
+ to do so explicitly via the linker script if necessary. */
+ if (eh_frame && !has_gcc_except_table)
+ {
+ if (!_bfd_elf_gc_mark (info, eh_frame, gc_mark_hook))
+ return FALSE;
+ }
}
/* ... and mark SEC_EXCLUDE for those that go. */