This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH 3/7] Fix --gc-sections for C++ MIPS ELF
- From: Richard Sandiford <rsandifo at nildram dot co dot uk>
- To: binutils at sourceware dot org
- Date: Sun, 02 Dec 2007 20:27:58 +0000
- Subject: [PATCH 3/7] Fix --gc-sections for C++ MIPS ELF
- References: <87r6i4svjg.fsf@firetop.home>
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