mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-29 13:04:46 +08:00
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.
This commit is contained in:
parent
155eaaa031
commit
ca92cecbbe
@ -1,3 +1,30 @@
|
||||
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.
|
||||
(_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.
|
||||
|
||||
2007-12-15 Richard Sandiford <rsandifo@nildram.co.uk>
|
||||
|
||||
* elf-bfd.h (eh_cie_fde): Put cie_inf in a union. Add a reloc_index
|
||||
|
@ -266,9 +266,22 @@ struct eh_cie_fde
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
/* The CIE that we have chosen to use for this FDE. */
|
||||
/* 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;
|
||||
@ -308,6 +321,8 @@ struct eh_frame_hdr_info
|
||||
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. */
|
||||
@ -1723,6 +1738,13 @@ extern bfd_boolean _bfd_elf_strtab_emit
|
||||
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 *);
|
||||
|
@ -431,16 +431,26 @@ skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width,
|
||||
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. */
|
||||
/* Called before calling _bfd_elf_parse_eh_frame on every input bfd's
|
||||
.eh_frame section. */
|
||||
|
||||
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)
|
||||
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 \
|
||||
@ -448,45 +458,42 @@ _bfd_elf_discard_section_eh_frame
|
||||
goto free_no_table; \
|
||||
while (0)
|
||||
|
||||
bfd_byte *ehbuf = NULL, *buf;
|
||||
bfd_byte *ehbuf = NULL, *buf, *end;
|
||||
bfd_byte *last_fde;
|
||||
struct eh_cie_fde *ent, *this_inf;
|
||||
struct eh_cie_fde *this_inf;
|
||||
unsigned int hdr_length, hdr_id;
|
||||
struct extended_cie
|
||||
{
|
||||
struct cie cie;
|
||||
unsigned int offset;
|
||||
unsigned int usage_count;
|
||||
unsigned int entry;
|
||||
struct cie *cie;
|
||||
struct eh_cie_fde *local_cie;
|
||||
} *ecies = NULL, *ecie;
|
||||
unsigned int ecie_count = 0, ecie_alloced = 0;
|
||||
struct cie *cie;
|
||||
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 offset;
|
||||
unsigned int ptr_size;
|
||||
unsigned int entry_alloced;
|
||||
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 FALSE;
|
||||
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 FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
@ -497,7 +504,7 @@ _bfd_elf_discard_section_eh_frame
|
||||
{
|
||||
/* Empty .eh_frame section. */
|
||||
free (ehbuf);
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If .eh_frame section size doesn't fit into int, we cannot handle
|
||||
@ -508,12 +515,47 @@ _bfd_elf_discard_section_eh_frame
|
||||
->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)
|
||||
+ 99 * sizeof (struct eh_cie_fde));
|
||||
+ (num_entries - 1) * sizeof (struct eh_cie_fde));
|
||||
REQUIRE (sec_info);
|
||||
|
||||
entry_alloced = 100;
|
||||
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 \
|
||||
@ -533,39 +575,22 @@ _bfd_elf_discard_section_eh_frame
|
||||
== (bfd_size_type) ((buf) - ehbuf))) \
|
||||
? cookie->rel : NULL)
|
||||
|
||||
for (;;)
|
||||
buf = ehbuf;
|
||||
ecie_count = 0;
|
||||
while ((bfd_size_type) (buf - ehbuf) != sec->size)
|
||||
{
|
||||
char *aug;
|
||||
bfd_byte *start, *end, *insns, *insns_end;
|
||||
bfd_byte *start, *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;
|
||||
@ -594,19 +619,19 @@ _bfd_elf_discard_section_eh_frame
|
||||
/* CIE */
|
||||
this_inf->cie = 1;
|
||||
|
||||
if (ecie_count == ecie_alloced)
|
||||
/* 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
|
||||
{
|
||||
ecies = bfd_realloc (ecies,
|
||||
(ecie_alloced + 20) * sizeof (*ecies));
|
||||
REQUIRE (ecies);
|
||||
memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies));
|
||||
ecie_alloced += 20;
|
||||
cie = &tmp_cie;
|
||||
memset (cie, 0, sizeof (*cie));
|
||||
}
|
||||
|
||||
cie = &ecies[ecie_count].cie;
|
||||
ecies[ecie_count].offset = this_inf->offset;
|
||||
ecies[ecie_count++].entry = sec_info->count;
|
||||
cie->cie_inf = this_inf;
|
||||
cie->length = hdr_length;
|
||||
cie->output_sec = sec->output_section;
|
||||
start = buf;
|
||||
REQUIRE (read_byte (&buf, end, &cie->version));
|
||||
|
||||
@ -788,48 +813,29 @@ _bfd_elf_discard_section_eh_frame
|
||||
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->offset)
|
||||
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;
|
||||
cie = ecie->cie;
|
||||
this_inf->u.fde.cie_inf = ecie->local_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);
|
||||
@ -901,90 +907,155 @@ _bfd_elf_discard_section_eh_frame
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
htab_delete (hdr_info->cies);
|
||||
hdr_info->cies = NULL;
|
||||
}
|
||||
hdr_info->parsed_eh_frames = TRUE;
|
||||
}
|
||||
|
||||
/* Ok, now we can assign new offsets. */
|
||||
/* 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)
|
||||
{
|
||||
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
|
||||
@ -1001,12 +1072,6 @@ _bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
|
||||
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;
|
||||
|
@ -11894,6 +11894,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
|
||||
|| !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)
|
||||
@ -11944,6 +11945,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
|
||||
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))
|
||||
@ -11957,6 +11959,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
|
||||
|
||||
fini_reloc_cookie (&cookie, abfd);
|
||||
}
|
||||
_bfd_elf_end_eh_frame_parsing (info);
|
||||
|
||||
if (info->eh_frame_hdr
|
||||
&& !info->relocatable
|
||||
|
Loading…
Reference in New Issue
Block a user