diff options
-rw-r--r-- | bfd/ChangeLog | 21 | ||||
-rw-r--r-- | bfd/ecoff.c | 4 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 20 | ||||
-rw-r--r-- | bfd/elf-eh-frame.c | 59 | ||||
-rw-r--r-- | bfd/elflink.c | 117 | ||||
-rw-r--r-- | bfd/section.c | 3 |
6 files changed, 145 insertions, 79 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 54c909b..b1e840e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,26 @@ 2007-12-15 Richard Sandiford <rsandifo@nildram.co.uk> + * elf-bfd.h (eh_cie_fde): Add u.fde.next_for_section and + u.cie.gc_mark. + (bfd_elf_section_data): Add fde_list. + (elf_fde_list): New macro. + (elf_obj_tdata): Add eh_frame_section. + (elf_eh_frame_section): New macro. + (_bfd_elf_gc_mark_reloc): Remove last parameter. + (_bfd_elf_gc_mark_fdes): Declare. + * elf-eh-frame.c (_bfd_elf_get_eh_frame_sec_info): Chain the FDEs + for each input section. + (mark_entry, _bfd_elf_gc_mark_fdes): New functions. + * elflink.c (_bfd_elf_gc_mark_reloc): Remove is_eh parameter. + (_bfd_elf_gc_mark): Update call accordingly. Mark the relocations + againts the section's FDEs. Don't mark the bfd's elf_eh_frame_section. + (bfd_elf_gc_sections): Parse each input bfd's .eh_frame before + marking any input sections. Remove the current EH handling. + * section.c (bfd_section): Remove gc_mark_from_eh. + * ecoff.c (bfd_debug_section): Update initializer accordingly. + +2007-12-15 Richard Sandiford <rsandifo@nildram.co.uk> + * elf-bfd.h (eh_cie_fde): Add u.cie. Document how u.fde.cie_inf changes when removed == 0. (eh_frame_hdr_info): Add parsed_eh_frames. diff --git a/bfd/ecoff.c b/bfd/ecoff.c index 0bd4add..149df64 100644 --- a/bfd/ecoff.c +++ b/bfd/ecoff.c @@ -55,8 +55,8 @@ static asection bfd_debug_section = { /* name, id, index, next, prev, flags, user_set_vma, */ "*DEBUG*", 0, 0, NULL, NULL, 0, 0, - /* linker_mark, linker_has_input, gc_mark, gc_mark_from_eh, */ - 0, 0, 1, 0, + /* linker_mark, linker_has_input, gc_mark, */ + 0, 0, 1, /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */ 0, 0, 0, 0, /* has_gp_reloc, need_finalize_relax, reloc_done, */ diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index c91af27..f5fcc6f 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -273,6 +273,7 @@ struct eh_cie_fde the output FDE. The CIE's REMOVED field is also 0, but the CIE might belong to a different .eh_frame input section from the FDE. */ struct eh_cie_fde *cie_inf; + struct eh_cie_fde *next_for_section; } fde; struct { /* In general, equivalent CIEs are grouped together, with one CIE @@ -281,6 +282,9 @@ struct eh_cie_fde following this pointer brings us "closer" to the CIE's group representative, and reapplying always gives the representative. */ struct eh_cie_fde *merged; + + /* True if we have marked relocations associated with this CIE. */ + unsigned int gc_mark : 1; } cie; } u; unsigned int reloc_index; @@ -1243,6 +1247,10 @@ struct bfd_elf_section_data the linker. For the SHT_GROUP section, points at first member. */ asection *next_in_group; + /* The FDEs associated with this section. The u.fde.next_in_section + field acts as a chain pointer. */ + struct eh_cie_fde *fde_list; + /* A pointer used for various section optimizations. */ void *sec_info; }; @@ -1254,6 +1262,7 @@ struct bfd_elf_section_data #define elf_group_name(sec) (elf_section_data(sec)->group.name) #define elf_group_id(sec) (elf_section_data(sec)->group.id) #define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group) +#define elf_fde_list(sec) (elf_section_data(sec)->fde_list) #define elf_sec_group(sec) (elf_section_data(sec)->sec_group) #define xvec_get_elf_backend_data(xvec) \ @@ -1459,6 +1468,9 @@ struct elf_obj_tdata asection *elf_data_section; asection *elf_text_section; + /* A pointer to the .eh_frame section. */ + asection *eh_frame_section; + /* Whether a dyanmic object was specified normally on the linker command line, or was specified when --as-needed was in effect, or was found via a DT_NEEDED entry. */ @@ -1504,6 +1516,8 @@ struct elf_obj_tdata #define elf_dynversym(bfd) (elf_tdata(bfd) -> dynversym_section) #define elf_dynverdef(bfd) (elf_tdata(bfd) -> dynverdef_section) #define elf_dynverref(bfd) (elf_tdata(bfd) -> dynverref_section) +#define elf_eh_frame_section(bfd) \ + (elf_tdata(bfd) -> eh_frame_section) #define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals) #define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals) #define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms) @@ -2004,7 +2018,11 @@ extern asection *_bfd_elf_gc_mark_rsec extern bfd_boolean _bfd_elf_gc_mark_reloc (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn, - struct elf_reloc_cookie *, bfd_boolean); + struct elf_reloc_cookie *); + +extern bfd_boolean _bfd_elf_gc_mark_fdes + (struct bfd_link_info *, asection *, asection *, elf_gc_mark_hook_fn, + struct elf_reloc_cookie *); extern bfd_boolean _bfd_elf_gc_mark (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn); diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 63b6ba4..460112c 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -475,6 +475,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, unsigned int ptr_size; unsigned int num_cies; unsigned int num_entries; + elf_gc_mark_hook_fn gc_mark_hook; htab = elf_hash_table (info); hdr_info = &htab->eh_info; @@ -577,6 +578,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, buf = ehbuf; ecie_count = 0; + gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook; while ((bfd_size_type) (buf - ehbuf) != sec->size) { char *aug; @@ -821,6 +823,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, } else { + asection *rsec; + /* Find the corresponding CIE. */ unsigned int cie_offset = this_inf->offset + 4 - hdr_id; for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) @@ -836,6 +840,12 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); + /* Chain together the FDEs for each section. */ + rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); + REQUIRE (rsec && rsec->owner == abfd); + this_inf->u.fde.next_for_section = elf_fde_list (rsec); + elf_fde_list (rsec) = this_inf; + /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); @@ -976,6 +986,55 @@ _bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info) hdr_info->parsed_eh_frames = TRUE; } +/* Mark all relocations against CIE or FDE ENT, which occurs in + .eh_frame section SEC. COOKIE describes the relocations in SEC; + its "rel" field can be changed freely. */ + +static bfd_boolean +mark_entry (struct bfd_link_info *info, asection *sec, + struct eh_cie_fde *ent, elf_gc_mark_hook_fn gc_mark_hook, + struct elf_reloc_cookie *cookie) +{ + for (cookie->rel = cookie->rels + ent->reloc_index; + cookie->rel < cookie->relend + && cookie->rel->r_offset < ent->offset + ent->size; + cookie->rel++) + if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, cookie)) + return FALSE; + + return TRUE; +} + +/* Mark all the relocations against FDEs that relate to code in input + section SEC. The FDEs belong to .eh_frame section EH_FRAME, whose + relocations are described by COOKIE. */ + +bfd_boolean +_bfd_elf_gc_mark_fdes (struct bfd_link_info *info, asection *sec, + asection *eh_frame, elf_gc_mark_hook_fn gc_mark_hook, + struct elf_reloc_cookie *cookie) +{ + struct eh_cie_fde *fde, *cie, *merged; + + for (fde = elf_fde_list (sec); fde; fde = fde->u.fde.next_for_section) + { + if (!mark_entry (info, eh_frame, fde, gc_mark_hook, cookie)) + return FALSE; + + /* At this stage, all cie_inf fields point to local CIEs, so we + can use the same cookie to refer to them. */ + cie = fde->u.fde.cie_inf; + merged = cie->u.cie.merged; + if (!merged->u.cie.gc_mark) + { + merged->u.cie.gc_mark = 1; + if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie)) + return FALSE; + } + } + return TRUE; +} + /* This function is called for each input file before the .eh_frame section is relocated. It discards duplicate CIEs and FDEs for discarded functions. The function returns TRUE iff any entries have been diff --git a/bfd/elflink.c b/bfd/elflink.c index 4201e28..31c9de9 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -11137,15 +11137,13 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, /* COOKIE->rel describes a relocation against section SEC, which is a section we've decided to keep. Mark the section that contains - the relocation symbol. IS_EH is true if the mark comes from - .eh_frame. */ + the relocation symbol. */ bfd_boolean _bfd_elf_gc_mark_reloc (struct bfd_link_info *info, asection *sec, elf_gc_mark_hook_fn gc_mark_hook, - struct elf_reloc_cookie *cookie, - bfd_boolean is_eh) + struct elf_reloc_cookie *cookie) { asection *rsec; @@ -11154,8 +11152,6 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info, { if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour) rsec->gc_mark = 1; - else if (is_eh) - rsec->gc_mark_from_eh = 1; else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) return FALSE; } @@ -11172,8 +11168,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info, elf_gc_mark_hook_fn gc_mark_hook) { bfd_boolean ret; - bfd_boolean is_eh; - asection *group_sec; + asection *group_sec, *eh_frame; sec->gc_mark = 1; @@ -11185,8 +11180,10 @@ _bfd_elf_gc_mark (struct bfd_link_info *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) + eh_frame = elf_eh_frame_section (sec->owner); + if ((sec->flags & SEC_RELOC) != 0 + && sec->reloc_count > 0 + && sec != eh_frame) { struct elf_reloc_cookie cookie; @@ -11195,8 +11192,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info, else { for (; cookie.rel < cookie.relend; cookie.rel++) - if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, - &cookie, is_eh)) + if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie)) { ret = FALSE; break; @@ -11204,6 +11200,22 @@ _bfd_elf_gc_mark (struct bfd_link_info *info, fini_reloc_cookie_for_section (&cookie, sec); } } + + if (ret && eh_frame && elf_fde_list (sec)) + { + struct elf_reloc_cookie cookie; + + if (!init_reloc_cookie_for_section (&cookie, info, eh_frame)) + ret = FALSE; + else + { + if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame, + gc_mark_hook, &cookie)) + ret = FALSE; + fini_reloc_cookie_for_section (&cookie, eh_frame); + } + } + return ret; } @@ -11469,6 +11481,25 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) return TRUE; } + /* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section + at the .eh_frame section if we can mark the FDEs individually. */ + _bfd_elf_begin_eh_frame_parsing (info); + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *sec; + struct elf_reloc_cookie cookie; + + sec = bfd_get_section_by_name (sub, ".eh_frame"); + if (sec && init_reloc_cookie_for_section (&cookie, info, sec)) + { + _bfd_elf_parse_eh_frame (sub, info, sec, &cookie); + if (elf_section_data (sec)->sec_info) + elf_eh_frame_section (sub) = sec; + fini_reloc_cookie_for_section (&cookie, sec); + } + } + _bfd_elf_end_eh_frame_parsing (info); + /* Apply transitive closure to the vtable entry usage info. */ elf_link_hash_traverse (elf_hash_table (info), elf_gc_propagate_vtable_entries_used, @@ -11508,68 +11539,6 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) if (bed->gc_mark_extra_sections) bed->gc_mark_extra_sections(info, gc_mark_hook); - /* ... again for sections marked from eh_frame. */ - for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) - { - asection *o; - - if (bfd_get_flavour (sub) != bfd_target_elf_flavour) - continue; - - /* Keep .gcc_except_table.* if the associated .text.* (or the - associated .gnu.linkonce.t.* if .text.* doesn't exist) is - marked. This isn't very nice, but the proper solution, - splitting .eh_frame up and using comdat doesn't pan out - easily due to needing special relocs to handle the - difference of two symbols in separate sections. - Don't keep code sections referenced by .eh_frame. */ -#define TEXT_PREFIX ".text." -#define TEXT_PREFIX2 ".gnu.linkonce.t." -#define GCC_EXCEPT_TABLE_PREFIX ".gcc_except_table." - for (o = sub->sections; o != NULL; o = o->next) - if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0) - { - if (CONST_STRNEQ (o->name, GCC_EXCEPT_TABLE_PREFIX)) - { - char *fn_name; - const char *sec_name; - asection *fn_text; - unsigned o_name_prefix_len , fn_name_prefix_len, tmp; - - o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX); - sec_name = o->name + o_name_prefix_len; - fn_name_prefix_len = strlen (TEXT_PREFIX); - tmp = strlen (TEXT_PREFIX2); - if (tmp > fn_name_prefix_len) - fn_name_prefix_len = tmp; - fn_name - = bfd_malloc (fn_name_prefix_len + strlen (sec_name) + 1); - if (fn_name == NULL) - return FALSE; - - /* Try the first prefix. */ - sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name); - fn_text = bfd_get_section_by_name (sub, fn_name); - - /* Try the second prefix. */ - if (fn_text == NULL) - { - sprintf (fn_name, "%s%s", TEXT_PREFIX2, sec_name); - fn_text = bfd_get_section_by_name (sub, fn_name); - } - - free (fn_name); - if (fn_text == NULL || !fn_text->gc_mark) - continue; - } - - /* If not using specially named exception table section, - then keep whatever we are using. */ - if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) - return FALSE; - } - } - /* ... and mark SEC_EXCLUDE for those that go. */ return elf_gc_sweep (abfd, info); } diff --git a/bfd/section.c b/bfd/section.c index 4ee6c89..11ce0d6 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -357,9 +357,8 @@ CODE_FRAGMENT . output sections that have an input section. *} . unsigned int linker_has_input : 1; . -. {* Mark flags used by some linker backends for garbage collection. *} +. {* Mark flag used by some linker backends for garbage collection. *} . unsigned int gc_mark : 1; -. unsigned int gc_mark_from_eh : 1; . . {* The following flags are used by the ELF linker. *} . |