From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14314 invoked by alias); 2 Dec 2007 20:31:33 -0000 Received: (qmail 14305 invoked by uid 22791); 2 Dec 2007 20:31:31 -0000 X-Spam-Check-By: sourceware.org Received: from smtp.nildram.co.uk (HELO smtp.nildram.co.uk) (195.149.33.74) by sourceware.org (qpsmtpd/0.31) with ESMTP; Sun, 02 Dec 2007 20:31:25 +0000 Received: from firetop.home (85-211-136-23.dyn.gotadsl.co.uk [85.211.136.23]) by smtp.nildram.co.uk (Postfix) with ESMTP id 431D52DF413 for ; Sun, 2 Dec 2007 20:31:19 +0000 (GMT) Received: from richard by firetop.home with local (Exim 4.63) (envelope-from ) id 1IyvTG-0007fw-32 for binutils@sourceware.org; Sun, 02 Dec 2007 20:31:22 +0000 From: Richard Sandiford To: binutils@sourceware.org Mail-Followup-To: binutils@sourceware.org, rsandifo@nildram.co.uk Subject: [PATCH 4/7] Fix --gc-sections for C++ MIPS ELF References: <87r6i4svjg.fsf@firetop.home> Date: Sun, 02 Dec 2007 20:31:00 -0000 In-Reply-To: <87r6i4svjg.fsf@firetop.home> (Richard Sandiford's message of "Sun\, 02 Dec 2007 20\:15\:15 +0000") Message-ID: <87abossusl.fsf@firetop.home> User-Agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org X-SW-Source: 2007-12/txt/msg00004.txt.bz2 This is the main patch. The core routine is mark_entry, which "marks all relocations" against a CIE or FDE ("marking a relocation" being shorthand for "marking the section in which a relocation's symbol is defined"). The parsing routines now chain together the FDEs for each code section into a list, and a new routine called _bfd_elf_gc_mark_fdes marks all the FDEs for a particular code section. CIEs are marked when one their dependent FDEs is marked. FDEs are only marked once, when their associated section is marked, so there's no need for them to have a separate gc_mark field. However, CIEs might be processed many times, so a gc_mark field does seem appropriate there. bfd_elf_gc_sections tries to parse each input .eh_frame section. It stores the .eh_frame section in a new ELF bfd field called "eh_frame_section" on success, otherwise the .eh_frame section is marked like any other section would be. If eh_frame_section is nonnull, _bfd_elf_gc_mark marks all the FDEs associated with the section it is marking. It doesn't process the relocations in eh_frame_section itself. Richard bfd/ * 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. Index: bfd/elf-bfd.h =================================================================== --- bfd/elf-bfd.h 2007-12-02 17:21:33.000000000 +0000 +++ bfd/elf-bfd.h 2007-12-02 17:22:22.000000000 +0000 @@ -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 @@ #define elf_section_flags(sec) (elf_sect #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 @@ #define elf_dynsymtab(bfd) (elf_tdata(bf #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 void _bfd_elf_set_osabi (bfd * , 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); Index: bfd/elf-eh-frame.c =================================================================== --- bfd/elf-eh-frame.c 2007-12-02 17:03:27.000000000 +0000 +++ bfd/elf-eh-frame.c 2007-12-02 17:26:13.000000000 +0000 @@ -475,6 +475,7 @@ #define REQUIRE(COND) \ 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 @@ #define GET_RELOC(buf) \ 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 @@ #define GET_RELOC(buf) \ } 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 @@ #define GET_RELOC(buf) \ 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 bf 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 Index: bfd/elflink.c =================================================================== --- bfd/elflink.c 2007-12-02 17:03:27.000000000 +0000 +++ bfd/elflink.c 2007-12-02 17:22:00.000000000 +0000 @@ -11137,15 +11137,13 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_i /* 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_ { 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 * 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 * /* 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 * 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 * 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 b 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 b 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); } Index: bfd/section.c =================================================================== --- bfd/section.c 2007-12-02 16:52:51.000000000 +0000 +++ bfd/section.c 2007-12-02 17:21:41.000000000 +0000 @@ -357,9 +357,8 @@ typedef asection, section prototypes, Se . 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. *} . Index: bfd/ecoff.c =================================================================== --- bfd/ecoff.c 2007-12-02 16:52:51.000000000 +0000 +++ bfd/ecoff.c 2007-12-02 17:21:41.000000000 +0000 @@ -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, */