Line 1... |
Line 1... |
/* .eh_frame section optimization.
|
/* .eh_frame section optimization.
|
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
|
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
Written by Jakub Jelinek <jakub@redhat.com>.
|
Written by Jakub Jelinek <jakub@redhat.com>.
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
Line 488... |
Line 488... |
htab = elf_hash_table (info);
|
htab = elf_hash_table (info);
|
hdr_info = &htab->eh_info;
|
hdr_info = &htab->eh_info;
|
if (hdr_info->parsed_eh_frames)
|
if (hdr_info->parsed_eh_frames)
|
return;
|
return;
|
|
|
if (sec->size == 0)
|
if (sec->size == 0
|
|
|| sec->sec_info_type != ELF_INFO_TYPE_NONE)
|
{
|
{
|
/* This file does not contain .eh_frame information. */
|
/* This file does not contain .eh_frame information. */
|
return;
|
return;
|
}
|
}
|
|
|
Line 775... |
Line 776... |
this_inf->u.cie.per_encoding_relative
|
this_inf->u.cie.per_encoding_relative
|
= (cie->per_encoding & 0x70) == DW_EH_PE_pcrel;
|
= (cie->per_encoding & 0x70) == DW_EH_PE_pcrel;
|
}
|
}
|
else
|
else
|
{
|
{
|
asection *rsec;
|
|
|
|
/* Find the corresponding CIE. */
|
/* Find the corresponding CIE. */
|
unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
|
unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
|
for (cie = local_cies; cie < local_cies + cie_count; cie++)
|
for (cie = local_cies; cie < local_cies + cie_count; cie++)
|
if (cie_offset == cie->cie_inf->offset)
|
if (cie_offset == cie->cie_inf->offset)
|
break;
|
break;
|
Line 792... |
Line 791... |
this_inf->make_relative = cie->cie_inf->make_relative;
|
this_inf->make_relative = cie->cie_inf->make_relative;
|
this_inf->add_augmentation_size
|
this_inf->add_augmentation_size
|
= cie->cie_inf->add_augmentation_size;
|
= cie->cie_inf->add_augmentation_size;
|
|
|
ENSURE_NO_RELOCS (buf);
|
ENSURE_NO_RELOCS (buf);
|
|
if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL)
|
|
{
|
|
asection *rsec;
|
|
|
REQUIRE (GET_RELOC (buf));
|
REQUIRE (GET_RELOC (buf));
|
|
|
/* Chain together the FDEs for each section. */
|
/* Chain together the FDEs for each section. */
|
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
|
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
|
/* RSEC will be NULL if FDE was cleared out as it was belonging to
|
/* RSEC will be NULL if FDE was cleared out as it was belonging to
|
Line 804... |
Line 807... |
{
|
{
|
REQUIRE (rsec->owner == abfd);
|
REQUIRE (rsec->owner == abfd);
|
this_inf->u.fde.next_for_section = elf_fde_list (rsec);
|
this_inf->u.fde.next_for_section = elf_fde_list (rsec);
|
elf_fde_list (rsec) = this_inf;
|
elf_fde_list (rsec) = this_inf;
|
}
|
}
|
|
}
|
|
|
/* Skip the initial location and address range. */
|
/* Skip the initial location and address range. */
|
start = buf;
|
start = buf;
|
length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
|
length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
|
REQUIRE (skip_bytes (&buf, end, 2 * length));
|
REQUIRE (skip_bytes (&buf, end, 2 * length));
|
Line 1131... |
Line 1135... |
struct eh_cie_fde *ent;
|
struct eh_cie_fde *ent;
|
struct eh_frame_sec_info *sec_info;
|
struct eh_frame_sec_info *sec_info;
|
struct eh_frame_hdr_info *hdr_info;
|
struct eh_frame_hdr_info *hdr_info;
|
unsigned int ptr_size, offset;
|
unsigned int ptr_size, offset;
|
|
|
|
if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
|
|
return FALSE;
|
|
|
sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info;
|
sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info;
|
if (sec_info == NULL)
|
if (sec_info == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
|
ptr_size = (get_elf_backend_data (sec->owner)
|
|
->elf_backend_eh_frame_address_size (sec->owner, sec));
|
|
|
hdr_info = &elf_hash_table (info)->eh_info;
|
hdr_info = &elf_hash_table (info)->eh_info;
|
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
|
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
|
if (ent->size == 4)
|
if (ent->size == 4)
|
/* There should only be one zero terminator, on the last input
|
/* There should only be one zero terminator, on the last input
|
file supplying .eh_frame (crtend.o). Remove any others. */
|
file supplying .eh_frame (crtend.o). Remove any others. */
|
ent->removed = sec->map_head.s != NULL;
|
ent->removed = sec->map_head.s != NULL;
|
else if (!ent->cie)
|
else if (!ent->cie)
|
{
|
{
|
|
bfd_boolean keep;
|
|
if ((sec->flags & SEC_LINKER_CREATED) != 0 && cookie->rels == NULL)
|
|
{
|
|
unsigned int width
|
|
= get_DW_EH_PE_width (ent->fde_encoding, ptr_size);
|
|
bfd_vma value
|
|
= read_value (abfd, sec->contents + ent->offset + 8 + width,
|
|
width, get_DW_EH_PE_signed (ent->fde_encoding));
|
|
keep = value != 0;
|
|
}
|
|
else
|
|
{
|
cookie->rel = cookie->rels + ent->reloc_index;
|
cookie->rel = cookie->rels + ent->reloc_index;
|
/* FIXME: octets_per_byte. */
|
/* FIXME: octets_per_byte. */
|
BFD_ASSERT (cookie->rel < cookie->relend
|
BFD_ASSERT (cookie->rel < cookie->relend
|
&& cookie->rel->r_offset == ent->offset + 8);
|
&& cookie->rel->r_offset == ent->offset + 8);
|
if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie))
|
keep = !(*reloc_symbol_deleted_p) (ent->offset + 8, cookie);
|
|
}
|
|
if (keep)
|
{
|
{
|
if (info->shared
|
if (info->shared
|
&& (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr
|
&& (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr
|
&& ent->make_relative == 0)
|
&& ent->make_relative == 0)
|
|| (ent->fde_encoding & 0x70) == DW_EH_PE_aligned))
|
|| (ent->fde_encoding & 0x70) == DW_EH_PE_aligned))
|
Line 1176... |
Line 1200... |
{
|
{
|
free (sec_info->cies);
|
free (sec_info->cies);
|
sec_info->cies = NULL;
|
sec_info->cies = NULL;
|
}
|
}
|
|
|
ptr_size = (get_elf_backend_data (sec->owner)
|
|
->elf_backend_eh_frame_address_size (sec->owner, sec));
|
|
offset = 0;
|
offset = 0;
|
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
|
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
|
if (!ent->removed)
|
if (!ent->removed)
|
{
|
{
|
ent->new_offset = offset;
|
ent->new_offset = offset;
|