From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13298 invoked by alias); 2 Dec 2007 20:28:19 -0000 Received: (qmail 13038 invoked by uid 22791); 2 Dec 2007 20:28:14 -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:28:06 +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 5F90C2DEF26 for ; Sun, 2 Dec 2007 20:27:55 +0000 (GMT) Received: from richard by firetop.home with local (Exim 4.63) (envelope-from ) id 1IyvPy-0007ea-6E for binutils@sourceware.org; Sun, 02 Dec 2007 20:27:58 +0000 From: Richard Sandiford To: binutils@sourceware.org Mail-Followup-To: binutils@sourceware.org, rsandifo@nildram.co.uk Subject: [PATCH 3/7] Fix --gc-sections for C++ MIPS ELF References: <87r6i4svjg.fsf@firetop.home> Date: Sun, 02 Dec 2007 20:28:00 -0000 In-Reply-To: <87r6i4svjg.fsf@firetop.home> (Richard Sandiford's message of "Sun\, 02 Dec 2007 20\:15\:15 +0000") Message-ID: <87eje4suy9.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/msg00003.txt.bz2 I imagine this might be the most controversial of the changes. _bfd_elf_get_eh_frame_sec_info currently has three loops: - The main parsing loop. It grows memory as needed and stores stores CIE offsets rather than CIE pointers in the FDEs' cie_inf fields. It decides on the fly whether to keep an FDE or not. - A pass over the CIEs. If a CIE is needed by at least one to-be-kept FDE, the pass tries to merge the CIE with one that is already in the global pool, adding a new CIE to the pool on failure. The pass also copies some information from the temporary CIE structure to the eh_cie_fde. - A loop over the to-be-kept entries that assigns final offsets. It also points each to-be-kept FDE at its final CIE. If we're going to parse .eh_frame earlier than we do now, we can't always discard FDEs and CIEs on the fly; we need a separate pass that lives _outside_ the parsing routines. And that in turn means that the parsing routines don't know for sure whether a CIE is needed or not. We could get around this by keeping the extended CIE information around and leaving the discard routines to merge CIEs, but I think it would be better to merge all CIEs upfront. Both approaches should give the same results: it's just a bookkeeping issue. Also, later patches need to construct chains of eh_cie_fde entries, so it would be better if we didn't dynamically grow the sec_info structure in the main parsing loop. This patch splits out the parsing code into a separate function with two loops: - A simple pass over the section contents to count the CIEs and FDEs. Once we know how many there are, we can allocate the necessary memory upfront. - The main parsing loop. It adds all CIEs to the global pool, if we're using such a pool, and uses a new eh_cie_fde u.cie.merged field to point to the representative of each CIE group. (We don't know at this stage whether we'll keep that representative or not.) It points each FDE's u.fde.cie_inf field at the _local_ CIE, so that later patches can use the same reloc cookie to mark CIEs and FDEs; the u.cie.merged field then points to the CIE's group representative. The EH discard routine then uses the cached section information. It also has two loops: - A pass over the FDEs to decide which we need to keep. - A loop over the to-be-kept entries that assigns final offsets. In the worst case, that's 4 O(n) loops rather than 3. However, the second of the original three loops only looked at CIEs, so it was probably less expensive than the other 6 loops in the average case. >From that point of view, this patch could slow things down. FWIW, the final patch in the series gets rid of offsets_adjusted, thus saving a pass over the .eh_frames there. I don't know if that's enough mitigation. The CIE marking code might look a little more convoluted than necessary. The idea is to make sure that we only look at u.cie.merged when removed == 1, which leads indirectly to the offsets_adjusted patch. The u.cie.merged comment gets better in a later patch (or so I hope). Richard bfd/ * 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. (_bfd_elf_begin_eh_frame_parsing): Declare. (_bfd_elf_parse_eh_frame): Declare. (_bfd_elf_end_eh_frame_parsing): Declare. * elf-eh-frame.c (_bfd_elf_begin_eh_frame_parsing): New function. (_bfd_elf_parse_eh_frame): New function, split out from _bfd_elf_discard_section_eh_frame. Make a first pass through the buffer to calculate the number of entries and CIEs. Allocate memory for them before the main loop. Replace current extended cie representation with a pair of pointers, one to the local eh_cie_fde and one to the full struct cie. Allocate a separate array of struct cies if not merging. Merge CIEs during the main loop and set up each u.cie.merged field. Point an FDE's cie_inf field directly at the local CIE. Initially assume that all entries should be removed. (_bfd_elf_end_eh_frame_parsing): New function. (_bfd_elf_discard_section_eh_frame): Assume that the section has already been parsed. Use a separate pass to mark entries that need to be kept. Use the u.cie.merged field to track a CIE's group representative. * elflink.c (bfd_elf_discard_info): Call _bfd_elf_parse_eh_frame before _bfd_elf_discard_section_eh_frame. Wrap loop with calls to _bfd_elf_begin_eh_frame_parsing and _bfd_elf_end_eh_frame_parsing. Index: bfd/elf-bfd.h =================================================================== *** bfd/elf-bfd.h 2007-12-02 17:01:08.000000000 +0000 --- bfd/elf-bfd.h 2007-12-02 17:21:33.000000000 +0000 *************** struct eh_cie_fde *** 266,274 **** { union { struct { ! /* The CIE that we have chosen to use for this FDE. */ struct eh_cie_fde *cie_inf; } fde; } u; unsigned int reloc_index; unsigned int size; --- 266,287 ---- { union { struct { ! /* If REMOVED == 1, this is the CIE that the FDE originally used. ! The CIE belongs to the same .eh_frame input section as the FDE. ! ! If REMOVED == 0, this is the CIE that we have chosen to use for ! 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; } fde; + struct { + /* In general, equivalent CIEs are grouped together, with one CIE + representing all the others in a group. If REMOVED == 0, + this CIE is the group representative. If REMOVED == 1, + following this pointer brings us "closer" to the CIE's group + representative, and reapplying always gives the representative. */ + struct eh_cie_fde *merged; + } cie; } u; unsigned int reloc_index; unsigned int size; *************** struct eh_frame_hdr_info *** 308,313 **** --- 321,328 ---- asection *hdr_sec; unsigned int fde_count, array_count; struct eh_frame_array_ent *array; + /* TRUE if all .eh_frames have been parsd. */ + bfd_boolean parsed_eh_frames; /* TRUE if .eh_frame_hdr should contain the sorted search table. We build it if we successfully read all .eh_frame input sections and recognize them. */ *************** #define _bfd_elf_minisymbol_to_symbol _b *** 1723,1728 **** --- 1738,1750 ---- extern void _bfd_elf_strtab_finalize (struct elf_strtab_hash *); + extern void _bfd_elf_begin_eh_frame_parsing + (struct bfd_link_info *info); + extern void _bfd_elf_parse_eh_frame + (bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *); + extern void _bfd_elf_end_eh_frame_parsing + (struct bfd_link_info *info); + extern bfd_boolean _bfd_elf_discard_section_eh_frame (bfd *, struct bfd_link_info *, asection *, bfd_boolean (*) (bfd_vma, void *), struct elf_reloc_cookie *); Index: bfd/elf-eh-frame.c =================================================================== *** bfd/elf-eh-frame.c 2007-12-02 17:01:08.000000000 +0000 --- bfd/elf-eh-frame.c 2007-12-02 17:03:27.000000000 +0000 *************** skip_non_nops (bfd_byte *buf, bfd_byte * *** 431,446 **** return last; } ! /* 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 ! deleted. */ ! bfd_boolean ! _bfd_elf_discard_section_eh_frame ! (bfd *abfd, struct bfd_link_info *info, asection *sec, ! bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), ! struct elf_reloc_cookie *cookie) { #define REQUIRE(COND) \ do \ --- 431,456 ---- return last; } ! /* Called before calling _bfd_elf_parse_eh_frame on every input bfd's ! .eh_frame section. */ ! void ! _bfd_elf_begin_eh_frame_parsing (struct bfd_link_info *info) ! { ! struct eh_frame_hdr_info *hdr_info; ! ! hdr_info = &elf_hash_table (info)->eh_info; ! if (!hdr_info->parsed_eh_frames && !info->relocatable) ! hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); ! } ! ! /* Try to parse .eh_frame section SEC, which belongs to ABFD. Store the ! information in the section's sec_info field on success. COOKIE ! describes the relocations in SEC. */ ! ! void ! _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, ! asection *sec, struct elf_reloc_cookie *cookie) { #define REQUIRE(COND) \ do \ *************** #define REQUIRE(COND) \ *** 448,492 **** goto free_no_table; \ while (0) ! bfd_byte *ehbuf = NULL, *buf; bfd_byte *last_fde; ! struct eh_cie_fde *ent, *this_inf; unsigned int hdr_length, hdr_id; struct extended_cie { ! struct cie cie; ! unsigned int offset; ! unsigned int usage_count; ! unsigned int entry; } *ecies = NULL, *ecie; ! unsigned int ecie_count = 0, ecie_alloced = 0; ! struct cie *cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; - unsigned int offset; unsigned int ptr_size; ! unsigned int entry_alloced; if (sec->size == 0) { /* This file does not contain .eh_frame information. */ ! return FALSE; } if (bfd_is_abs_section (sec->output_section)) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ ! return FALSE; } - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - - if (hdr_info->cies == NULL && !info->relocatable) - hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); - /* Read the frame unwind information from abfd. */ REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); --- 458,499 ---- goto free_no_table; \ while (0) ! bfd_byte *ehbuf = NULL, *buf, *end; bfd_byte *last_fde; ! struct eh_cie_fde *this_inf; unsigned int hdr_length, hdr_id; struct extended_cie { ! struct cie *cie; ! struct eh_cie_fde *local_cie; } *ecies = NULL, *ecie; ! unsigned int ecie_count; ! struct cie *cie, *local_cies = NULL, tmp_cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int ptr_size; ! unsigned int num_cies; ! unsigned int num_entries; ! ! htab = elf_hash_table (info); ! hdr_info = &htab->eh_info; ! if (hdr_info->parsed_eh_frames) ! return; if (sec->size == 0) { /* This file does not contain .eh_frame information. */ ! return; } if (bfd_is_abs_section (sec->output_section)) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ ! return; } /* Read the frame unwind information from abfd. */ REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); *************** #define REQUIRE(COND) \ *** 497,503 **** { /* Empty .eh_frame section. */ free (ehbuf); ! return FALSE; } /* If .eh_frame section size doesn't fit into int, we cannot handle --- 504,510 ---- { /* Empty .eh_frame section. */ free (ehbuf); ! return; } /* If .eh_frame section size doesn't fit into int, we cannot handle *************** #define REQUIRE(COND) \ *** 508,519 **** ->elf_backend_eh_frame_address_size (abfd, sec)); REQUIRE (ptr_size != 0); buf = ehbuf; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) ! + 99 * sizeof (struct eh_cie_fde)); REQUIRE (sec_info); ! entry_alloced = 100; #define ENSURE_NO_RELOCS(buf) \ REQUIRE (!(cookie->rel < cookie->relend \ --- 515,561 ---- ->elf_backend_eh_frame_address_size (abfd, sec)); REQUIRE (ptr_size != 0); + /* Go through the section contents and work out how many FDEs and + CIEs there are. */ buf = ehbuf; + end = ehbuf + sec->size; + num_cies = 0; + num_entries = 0; + while (buf != end) + { + num_entries++; + + /* Read the length of the entry. */ + REQUIRE (skip_bytes (&buf, end, 4)); + hdr_length = bfd_get_32 (abfd, buf - 4); + + /* 64-bit .eh_frame is not supported. */ + REQUIRE (hdr_length != 0xffffffff); + if (hdr_length == 0) + break; + + REQUIRE (skip_bytes (&buf, end, 4)); + hdr_id = bfd_get_32 (abfd, buf - 4); + if (hdr_id == 0) + num_cies++; + + REQUIRE (skip_bytes (&buf, end, hdr_length - 4)); + } + sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) ! + (num_entries - 1) * sizeof (struct eh_cie_fde)); REQUIRE (sec_info); ! ecies = bfd_zmalloc (num_cies * sizeof (*ecies)); ! REQUIRE (ecies); ! ! /* If we're not merging CIE entries (such as for a relocatable link), ! we need to have a "struct cie" for each CIE in this section. */ ! if (hdr_info->cies == NULL) ! { ! local_cies = bfd_zmalloc (num_cies * sizeof (*local_cies)); ! REQUIRE (local_cies); ! } #define ENSURE_NO_RELOCS(buf) \ REQUIRE (!(cookie->rel < cookie->relend \ *************** #define GET_RELOC(buf) \ *** 533,571 **** == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) ! for (;;) { char *aug; ! bfd_byte *start, *end, *insns, *insns_end; bfd_size_type length; unsigned int set_loc_count; - if (sec_info->count == entry_alloced) - { - sec_info = bfd_realloc (sec_info, - sizeof (struct eh_frame_sec_info) - + ((entry_alloced + 99) - * sizeof (struct eh_cie_fde))); - REQUIRE (sec_info); - - memset (&sec_info->entry[entry_alloced], 0, - 100 * sizeof (struct eh_cie_fde)); - entry_alloced += 100; - } - this_inf = sec_info->entry + sec_info->count; last_fde = buf; - if ((bfd_size_type) (buf - ehbuf) == sec->size) - break; - /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); hdr_length = bfd_get_32 (abfd, buf - 4); - /* 64-bit .eh_frame is not supported. */ - REQUIRE (hdr_length != 0xffffffff); - /* The CIE/FDE must be fully contained in this input section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size); end = buf + hdr_length; --- 575,596 ---- == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) ! buf = ehbuf; ! ecie_count = 0; ! while ((bfd_size_type) (buf - ehbuf) != sec->size) { char *aug; ! bfd_byte *start, *insns, *insns_end; bfd_size_type length; unsigned int set_loc_count; this_inf = sec_info->entry + sec_info->count; last_fde = buf; /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); hdr_length = bfd_get_32 (abfd, buf - 4); /* The CIE/FDE must be fully contained in this input section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size); end = buf + hdr_length; *************** #define GET_RELOC(buf) \ *** 594,612 **** /* CIE */ this_inf->cie = 1; ! if (ecie_count == ecie_alloced) { ! ecies = bfd_realloc (ecies, ! (ecie_alloced + 20) * sizeof (*ecies)); ! REQUIRE (ecies); ! memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies)); ! ecie_alloced += 20; } ! ! cie = &ecies[ecie_count].cie; ! ecies[ecie_count].offset = this_inf->offset; ! ecies[ecie_count++].entry = sec_info->count; cie->length = hdr_length; start = buf; REQUIRE (read_byte (&buf, end, &cie->version)); --- 619,637 ---- /* CIE */ this_inf->cie = 1; ! /* If we're merging CIEs, construct the struct cie in TMP_CIE; ! we'll enter it into the global pool later. Otherwise point ! CIE to one of the section-local cie structures. */ ! if (local_cies) ! cie = local_cies + ecie_count; ! else { ! cie = &tmp_cie; ! memset (cie, 0, sizeof (*cie)); } ! cie->cie_inf = this_inf; cie->length = hdr_length; + cie->output_sec = sec->output_section; start = buf; REQUIRE (read_byte (&buf, end, &cie->version)); *************** #define GET_RELOC(buf) \ *** 788,835 **** insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); } else { /* Find the corresponding CIE. */ unsigned int cie_offset = this_inf->offset + 4 - hdr_id; for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) ! if (cie_offset == ecie->offset) break; /* Ensure this FDE references one of the CIEs in this input section. */ REQUIRE (ecie != ecies + ecie_count); ! cie = &ecie->cie; ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); - if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) - /* This is a FDE against a discarded section. It should - be deleted. */ - this_inf->removed = 1; - else - { - if (info->shared - && (((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr - && cie->make_relative == 0) - || (cie->fde_encoding & 0xf0) == DW_EH_PE_aligned)) - { - /* If a shared library uses absolute pointers - which we cannot turn into PC relative, - don't create the binary search table, - since it is affected by runtime relocations. */ - hdr_info->table = FALSE; - (*info->callbacks->einfo) - (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" - " table being created.\n"), abfd, sec); - } - ecie->usage_count++; - hdr_info->fde_count++; - this_inf->u.fde.cie_inf = (void *) (ecie - ecies); - } - /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); --- 813,841 ---- insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); + + this_inf->make_relative = cie->make_relative; + this_inf->make_lsda_relative = cie->make_lsda_relative; + this_inf->per_encoding_relative + = (cie->per_encoding & 0x70) == DW_EH_PE_pcrel; } else { /* Find the corresponding CIE. */ unsigned int cie_offset = this_inf->offset + 4 - hdr_id; for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) ! if (cie_offset == ecie->local_cie->offset) break; /* Ensure this FDE references one of the CIEs in this input section. */ REQUIRE (ecie != ecies + ecie_count); ! cie = ecie->cie; ! this_inf->u.fde.cie_inf = ecie->local_cie; ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); *************** #define GET_RELOC(buf) \ *** 901,990 **** } } this_inf->fde_encoding = cie->fde_encoding; this_inf->lsda_encoding = cie->lsda_encoding; sec_info->count++; } elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; ! /* Look at all CIEs in this section and determine which can be ! removed as unused, which can be merged with previous duplicate ! CIEs and which need to be kept. */ ! for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) ! { ! if (ecie->usage_count == 0) ! { ! sec_info->entry[ecie->entry].removed = 1; ! continue; ! } ! ecie->cie.output_sec = sec->output_section; ! ecie->cie.cie_inf = sec_info->entry + ecie->entry; ! cie_compute_hash (&ecie->cie); ! if (hdr_info->cies != NULL) ! { ! void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie, ! ecie->cie.hash, INSERT); ! if (loc != NULL) ! { ! if (*loc != HTAB_EMPTY_ENTRY) ! { ! sec_info->entry[ecie->entry].removed = 1; ! ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf; ! continue; ! } ! *loc = malloc (sizeof (struct cie)); ! if (*loc == NULL) ! *loc = HTAB_DELETED_ENTRY; ! else ! memcpy (*loc, &ecie->cie, sizeof (struct cie)); ! } ! } ! ecie->cie.cie_inf->make_relative = ecie->cie.make_relative; ! ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative; ! ecie->cie.cie_inf->per_encoding_relative ! = (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel; } ! /* Ok, now we can assign new offsets. */ ! offset = 0; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) ! if (!ent->removed) { ! if (!ent->cie) { ! ecie = ecies + (bfd_hostptr_t) ent->u.fde.cie_inf; ! ent->u.fde.cie_inf = ecie->cie.cie_inf; } ent->new_offset = offset; offset += size_of_output_cie_fde (ent, ptr_size); } - /* Resize the sec as needed. */ sec->rawsize = sec->size; sec->size = offset; - - free (ehbuf); - if (ecies) - free (ecies); return offset != sec->rawsize; - - free_no_table: - (*info->callbacks->einfo) - (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), - abfd, sec); - if (ehbuf) - free (ehbuf); - if (sec_info) - free (sec_info); - if (ecies) - free (ecies); - hdr_info->table = FALSE; - return FALSE; - - #undef REQUIRE } /* This function is called for .eh_frame_hdr section after --- 907,1061 ---- } } + this_inf->removed = 1; this_inf->fde_encoding = cie->fde_encoding; this_inf->lsda_encoding = cie->lsda_encoding; + if (this_inf->cie) + { + /* We have now finished constructing the struct cie. */ + if (hdr_info->cies != NULL) + { + /* See if we can merge this CIE with an earlier one. */ + void **loc; + + cie_compute_hash (cie); + loc = htab_find_slot_with_hash (hdr_info->cies, cie, + cie->hash, INSERT); + REQUIRE (loc); + if (*loc == HTAB_EMPTY_ENTRY) + { + *loc = malloc (sizeof (struct cie)); + REQUIRE (*loc); + memcpy (*loc, cie, sizeof (struct cie)); + } + cie = (struct cie *) *loc; + } + this_inf->u.cie.merged = cie->cie_inf; + ecies[ecie_count].cie = cie; + ecies[ecie_count++].local_cie = this_inf; + } sec_info->count++; } + BFD_ASSERT (sec_info->count == num_entries); + BFD_ASSERT (ecie_count == num_cies); elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; + goto success; ! free_no_table: ! (*info->callbacks->einfo) ! (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), ! abfd, sec); ! hdr_info->table = FALSE; ! if (sec_info) ! free (sec_info); ! success: ! if (ehbuf) ! free (ehbuf); ! if (ecies) ! free (ecies); ! if (local_cies) ! free (local_cies); ! #undef REQUIRE ! } ! /* Finish a pass over all .eh_frame sections. */ ! ! void ! _bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info) ! { ! struct eh_frame_hdr_info *hdr_info; ! ! hdr_info = &elf_hash_table (info)->eh_info; ! if (hdr_info->cies != NULL) ! { ! htab_delete (hdr_info->cies); ! hdr_info->cies = NULL; } + hdr_info->parsed_eh_frames = 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 ! deleted. */ ! ! bfd_boolean ! _bfd_elf_discard_section_eh_frame ! (bfd *abfd, struct bfd_link_info *info, asection *sec, ! bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), ! struct elf_reloc_cookie *cookie) ! { ! struct eh_cie_fde *ent, *cie, *merged; ! struct eh_frame_sec_info *sec_info; ! struct eh_frame_hdr_info *hdr_info; ! unsigned int ptr_size, offset; ! ! sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; ! if (sec_info == NULL) ! return FALSE; ! ! hdr_info = &elf_hash_table (info)->eh_info; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) ! if (!ent->cie) { ! cookie->rel = cookie->rels + ent->reloc_index; ! BFD_ASSERT (cookie->rel < cookie->relend ! && cookie->rel->r_offset == ent->offset + 8); ! if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie)) { ! if (info->shared ! && (((ent->fde_encoding & 0xf0) == DW_EH_PE_absptr ! && ent->u.fde.cie_inf->make_relative == 0) ! || (ent->fde_encoding & 0xf0) == DW_EH_PE_aligned)) ! { ! /* If a shared library uses absolute pointers ! which we cannot turn into PC relative, ! don't create the binary search table, ! since it is affected by runtime relocations. */ ! hdr_info->table = FALSE; ! (*info->callbacks->einfo) ! (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" ! " table being created.\n"), abfd, sec); ! } ! ent->removed = 0; ! hdr_info->fde_count++; ! ! cie = ent->u.fde.cie_inf; ! if (cie->removed) ! { ! merged = cie->u.cie.merged; ! if (!merged->removed) ! /* We have decided to keep the group representative. */ ! ent->u.fde.cie_inf = merged; ! else if (merged->u.cie.merged != merged) ! /* We didn't keep the original group representative, ! but we did keep an alternative. */ ! ent->u.fde.cie_inf = merged->u.cie.merged; ! else ! { ! /* Make the local CIE represent the merged group. */ ! merged->u.cie.merged = cie; ! cie->removed = 0; ! } ! } } + } + + ptr_size = (get_elf_backend_data (sec->owner) + ->elf_backend_eh_frame_address_size (sec->owner, sec)); + offset = 0; + for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) + if (!ent->removed) + { ent->new_offset = offset; offset += size_of_output_cie_fde (ent, ptr_size); } sec->rawsize = sec->size; sec->size = offset; return offset != sec->rawsize; } /* This function is called for .eh_frame_hdr section after *************** _bfd_elf_discard_section_eh_frame_hdr (b *** 1001,1012 **** htab = elf_hash_table (info); hdr_info = &htab->eh_info; - if (hdr_info->cies != NULL) - { - htab_delete (hdr_info->cies); - hdr_info->cies = NULL; - } - sec = hdr_info->hdr_sec; if (sec == NULL) return FALSE; --- 1072,1077 ---- Index: bfd/elflink.c =================================================================== *** bfd/elflink.c 2007-12-02 17:01:03.000000000 +0000 --- bfd/elflink.c 2007-12-02 17:03:27.000000000 +0000 *************** bfd_elf_discard_info (bfd *output_bfd, s *** 11894,11899 **** --- 11894,11900 ---- || !is_elf_hash_table (info->hash)) return FALSE; + _bfd_elf_begin_eh_frame_parsing (info); for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) { if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) *************** bfd_elf_discard_info (bfd *output_bfd, s *** 11944,11949 **** --- 11945,11951 ---- if (eh != NULL && init_reloc_cookie_rels (&cookie, info, abfd, eh)) { + _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie); if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, bfd_elf_reloc_symbol_deleted_p, &cookie)) *************** bfd_elf_discard_info (bfd *output_bfd, s *** 11957,11962 **** --- 11959,11965 ---- fini_reloc_cookie (&cookie, abfd); } + _bfd_elf_end_eh_frame_parsing (info); if (info->eh_frame_hdr && !info->relocatable