1,6 → 1,5 |
/* .eh_frame section optimization. |
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, |
2012 Free Software Foundation, Inc. |
Copyright (C) 2001-2015 Free Software Foundation, Inc. |
Written by Jakub Jelinek <jakub@redhat.com>. |
|
This file is part of BFD, the Binary File Descriptor library. |
41,10 → 40,12 |
bfd_vma augmentation_size; |
union { |
struct elf_link_hash_entry *h; |
bfd_vma val; |
struct { |
unsigned int bfd_id; |
unsigned int index; |
} sym; |
unsigned int reloc_index; |
} personality; |
asection *output_sec; |
struct eh_cie_fde *cie_inf; |
unsigned char per_encoding; |
unsigned char lsda_encoding; |
230,11 → 231,13 |
&& c1->augmentation_size == c2->augmentation_size |
&& memcmp (&c1->personality, &c2->personality, |
sizeof (c1->personality)) == 0 |
&& c1->output_sec == c2->output_sec |
&& (c1->cie_inf->u.cie.u.sec->output_section |
== c2->cie_inf->u.cie.u.sec->output_section) |
&& c1->per_encoding == c2->per_encoding |
&& c1->lsda_encoding == c2->lsda_encoding |
&& c1->fde_encoding == c2->fde_encoding |
&& c1->initial_insn_length == c2->initial_insn_length |
&& c1->initial_insn_length <= sizeof (c1->initial_instructions) |
&& memcmp (c1->initial_instructions, |
c2->initial_instructions, |
c1->initial_insn_length) == 0) |
254,6 → 257,7 |
cie_compute_hash (struct cie *c) |
{ |
hashval_t h = 0; |
size_t len; |
h = iterative_hash_object (c->length, h); |
h = iterative_hash_object (c->version, h); |
h = iterative_hash (c->augmentation, strlen (c->augmentation) + 1, h); |
262,12 → 266,15 |
h = iterative_hash_object (c->ra_column, h); |
h = iterative_hash_object (c->augmentation_size, h); |
h = iterative_hash_object (c->personality, h); |
h = iterative_hash_object (c->output_sec, h); |
h = iterative_hash_object (c->cie_inf->u.cie.u.sec->output_section, h); |
h = iterative_hash_object (c->per_encoding, h); |
h = iterative_hash_object (c->lsda_encoding, h); |
h = iterative_hash_object (c->fde_encoding, h); |
h = iterative_hash_object (c->initial_insn_length, h); |
h = iterative_hash (c->initial_instructions, c->initial_insn_length, h); |
len = c->initial_insn_length; |
if (len > sizeof (c->initial_instructions)) |
len = sizeof (c->initial_instructions); |
h = iterative_hash (c->initial_instructions, len, h); |
c->hash = h; |
return h; |
} |
445,18 → 452,111 |
return encoding | DW_EH_PE_pcrel; |
} |
|
/* Called before calling _bfd_elf_parse_eh_frame on every input bfd's |
.eh_frame section. */ |
/* Examine each .eh_frame_entry section and discard those |
those that are marked SEC_EXCLUDE. */ |
|
void |
_bfd_elf_begin_eh_frame_parsing (struct bfd_link_info *info) |
static void |
bfd_elf_discard_eh_frame_entry (struct eh_frame_hdr_info *hdr_info) |
{ |
unsigned int i; |
for (i = 0; i < hdr_info->array_count; i++) |
{ |
if (hdr_info->u.compact.entries[i]->flags & SEC_EXCLUDE) |
{ |
unsigned int j; |
for (j = i + 1; j < hdr_info->array_count; j++) |
hdr_info->u.compact.entries[j-1] = hdr_info->u.compact.entries[j]; |
|
hdr_info->array_count--; |
hdr_info->u.compact.entries[hdr_info->array_count] = NULL; |
i--; |
} |
} |
} |
|
/* Add a .eh_frame_entry section. */ |
|
static void |
bfd_elf_record_eh_frame_entry (struct eh_frame_hdr_info *hdr_info, |
asection *sec) |
{ |
if (hdr_info->array_count == hdr_info->u.compact.allocated_entries) |
{ |
if (hdr_info->u.compact.allocated_entries == 0) |
{ |
hdr_info->frame_hdr_is_compact = TRUE; |
hdr_info->u.compact.allocated_entries = 2; |
hdr_info->u.compact.entries = |
bfd_malloc (hdr_info->u.compact.allocated_entries |
* sizeof (hdr_info->u.compact.entries[0])); |
} |
else |
{ |
hdr_info->u.compact.allocated_entries *= 2; |
hdr_info->u.compact.entries = |
bfd_realloc (hdr_info->u.compact.entries, |
hdr_info->u.compact.allocated_entries |
* sizeof (hdr_info->u.compact.entries[0])); |
} |
|
BFD_ASSERT (hdr_info->u.compact.entries); |
} |
|
hdr_info->u.compact.entries[hdr_info->array_count++] = sec; |
} |
|
/* Parse a .eh_frame_entry section. Figure out which text section it |
references. */ |
|
bfd_boolean |
_bfd_elf_parse_eh_frame_entry (struct bfd_link_info *info, |
asection *sec, struct elf_reloc_cookie *cookie) |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
unsigned long r_symndx; |
asection *text_sec; |
|
hdr_info = &elf_hash_table (info)->eh_info; |
hdr_info->merge_cies = !info->relocatable; |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
|
if (sec->size == 0 |
|| sec->sec_info_type != SEC_INFO_TYPE_NONE) |
{ |
return TRUE; |
} |
|
if (sec->output_section && 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 TRUE; |
} |
|
if (cookie->rel == cookie->relend) |
return FALSE; |
|
/* The first relocation is the function start. */ |
r_symndx = cookie->rel->r_info >> cookie->r_sym_shift; |
if (r_symndx == STN_UNDEF) |
return FALSE; |
|
text_sec = _bfd_elf_section_for_symbol (cookie, r_symndx, FALSE); |
|
if (text_sec == NULL) |
return FALSE; |
|
elf_section_eh_frame_entry (text_sec) = sec; |
if (text_sec->output_section |
&& bfd_is_abs_section (text_sec->output_section)) |
sec->flags |= SEC_EXCLUDE; |
|
sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME_ENTRY; |
elf_section_data (sec)->sec_info = text_sec; |
bfd_elf_record_eh_frame_entry (hdr_info, sec); |
return TRUE; |
} |
|
/* 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. */ |
487,8 → 587,6 |
|
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
if (hdr_info->parsed_eh_frames) |
return; |
|
if (sec->size == 0 |
|| sec->sec_info_type != SEC_INFO_TYPE_NONE) |
563,10 → 661,13 |
|
/* FIXME: octets_per_byte. */ |
#define ENSURE_NO_RELOCS(buf) \ |
REQUIRE (!(cookie->rel < cookie->relend \ |
while (cookie->rel < cookie->relend \ |
&& (cookie->rel->r_offset \ |
< (bfd_size_type) ((buf) - ehbuf)) \ |
&& cookie->rel->r_info != 0)) |
< (bfd_size_type) ((buf) - ehbuf))) \ |
{ \ |
REQUIRE (cookie->rel->r_info == 0); \ |
cookie->rel++; \ |
} |
|
/* FIXME: octets_per_byte. */ |
#define SKIP_RELOCS(buf) \ |
632,7 → 733,6 |
|
cie->cie_inf = this_inf; |
cie->length = hdr_length; |
cie->output_sec = sec->output_section; |
start = buf; |
REQUIRE (read_byte (&buf, end, &cie->version)); |
|
733,7 → 833,7 |
|
/* For shared libraries, try to get rid of as many RELATIVE relocs |
as possible. */ |
if (info->shared |
if (bfd_link_pic (info) |
&& (get_elf_backend_data (abfd) |
->elf_backend_can_make_relative_eh_frame |
(abfd, info, sec))) |
762,20 → 862,22 |
cie->fde_encoding = DW_EH_PE_absptr; |
|
initial_insn_length = end - buf; |
if (initial_insn_length <= sizeof (cie->initial_instructions)) |
{ |
cie->initial_insn_length = initial_insn_length; |
memcpy (cie->initial_instructions, buf, initial_insn_length); |
} |
memcpy (cie->initial_instructions, buf, |
initial_insn_length <= sizeof (cie->initial_instructions) |
? initial_insn_length : sizeof (cie->initial_instructions)); |
insns = buf; |
buf += initial_insn_length; |
ENSURE_NO_RELOCS (buf); |
|
if (hdr_info->merge_cies) |
if (!bfd_link_relocatable (info)) |
{ |
/* Keep info for merging cies. */ |
this_inf->u.cie.u.full_cie = cie; |
this_inf->u.cie.per_encoding_relative |
= (cie->per_encoding & 0x70) == DW_EH_PE_pcrel; |
} |
} |
else |
{ |
/* Find the corresponding CIE. */ |
800,7 → 902,8 |
REQUIRE (GET_RELOC (buf)); |
|
/* 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, NULL); |
/* RSEC will be NULL if FDE was cleared out as it was belonging to |
a discarded SHT_GROUP. */ |
if (rsec) |
816,6 → 919,16 |
length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); |
REQUIRE (skip_bytes (&buf, end, 2 * length)); |
|
SKIP_RELOCS (buf - length); |
if (!GET_RELOC (buf - length) |
&& read_value (abfd, buf - length, length, FALSE) == 0) |
{ |
(*info->callbacks->minfo) |
(_("discarding zero address range FDE in %B(%A).\n"), |
abfd, sec); |
this_inf->u.fde.cie_inf = NULL; |
} |
|
/* Skip the augmentation size, if present. */ |
if (cie->augmentation[0] == 'z') |
REQUIRE (read_uleb128 (&buf, end, &length)); |
905,8 → 1018,9 |
|
elf_section_data (sec)->sec_info = sec_info; |
sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME; |
if (hdr_info->merge_cies) |
if (!bfd_link_relocatable (info)) |
{ |
/* Keep info for merging cies. */ |
sec_info->cies = local_cies; |
local_cies = NULL; |
} |
916,7 → 1030,7 |
(*info->callbacks->einfo) |
(_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), |
abfd, sec); |
hdr_info->table = FALSE; |
hdr_info->u.dwarf.table = FALSE; |
if (sec_info) |
free (sec_info); |
success: |
927,17 → 1041,89 |
#undef REQUIRE |
} |
|
/* Finish a pass over all .eh_frame sections. */ |
/* Order eh_frame_hdr entries by the VMA of their text section. */ |
|
void |
static int |
cmp_eh_frame_hdr (const void *a, const void *b) |
{ |
bfd_vma text_a; |
bfd_vma text_b; |
asection *sec; |
|
sec = *(asection *const *)a; |
sec = (asection *) elf_section_data (sec)->sec_info; |
text_a = sec->output_section->vma + sec->output_offset; |
sec = *(asection *const *)b; |
sec = (asection *) elf_section_data (sec)->sec_info; |
text_b = sec->output_section->vma + sec->output_offset; |
|
if (text_a < text_b) |
return -1; |
return text_a > text_b; |
|
} |
|
/* Add space for a CANTUNWIND terminator to SEC if the text sections |
referenced by it and NEXT are not contiguous, or NEXT is NULL. */ |
|
static void |
add_eh_frame_hdr_terminator (asection *sec, |
asection *next) |
{ |
bfd_vma end; |
bfd_vma next_start; |
asection *text_sec; |
|
if (next) |
{ |
/* See if there is a gap (presumably a text section without unwind info) |
between these two entries. */ |
text_sec = (asection *) elf_section_data (sec)->sec_info; |
end = text_sec->output_section->vma + text_sec->output_offset |
+ text_sec->size; |
text_sec = (asection *) elf_section_data (next)->sec_info; |
next_start = text_sec->output_section->vma + text_sec->output_offset; |
if (end == next_start) |
return; |
} |
|
/* Add space for a CANTUNWIND terminator. */ |
if (!sec->rawsize) |
sec->rawsize = sec->size; |
|
bfd_set_section_size (sec->owner, sec, sec->size + 8); |
} |
|
/* Finish a pass over all .eh_frame_entry sections. */ |
|
bfd_boolean |
_bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info) |
{ |
struct eh_frame_hdr_info *hdr_info; |
unsigned int i; |
|
hdr_info = &elf_hash_table (info)->eh_info; |
hdr_info->parsed_eh_frames = TRUE; |
|
if (info->eh_frame_hdr_type != COMPACT_EH_HDR |
|| hdr_info->array_count == 0) |
return FALSE; |
|
bfd_elf_discard_eh_frame_entry (hdr_info); |
|
qsort (hdr_info->u.compact.entries, hdr_info->array_count, |
sizeof (asection *), cmp_eh_frame_hdr); |
|
for (i = 0; i < hdr_info->array_count - 1; i++) |
{ |
add_eh_frame_hdr_terminator (hdr_info->u.compact.entries[i], |
hdr_info->u.compact.entries[i + 1]); |
} |
|
/* Add a CANTUNWIND terminator after the last entry. */ |
add_eh_frame_hdr_terminator (hdr_info->u.compact.entries[i], NULL); |
return 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. */ |
977,7 → 1163,7 |
/* 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; |
if (!cie->u.cie.gc_mark) |
if (cie != NULL && !cie->u.cie.gc_mark) |
{ |
cie->u.cie.gc_mark = 1; |
if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie)) |
1027,8 → 1213,12 |
{ |
bfd_boolean per_binds_local; |
|
/* Work out the address of personality routine, either as an absolute |
value or as a symbol. */ |
/* Work out the address of personality routine, or at least |
enough info that we could calculate the address had we made a |
final section layout. The symbol on the reloc is enough, |
either the hash for a global, or (bfd id, index) pair for a |
local. The assumption here is that no one uses addends on |
the reloc. */ |
rel = cookie->rels + cie->personality.reloc_index; |
memset (&cie->personality, 0, sizeof (cie->personality)); |
#ifdef BFD64 |
1068,14 → 1258,13 |
return cie_inf; |
|
cie->local_personality = 1; |
cie->personality.val = (sym->st_value |
+ sym_sec->output_offset |
+ sym_sec->output_section->vma); |
cie->personality.sym.bfd_id = abfd->id; |
cie->personality.sym.index = r_symndx; |
per_binds_local = TRUE; |
} |
|
if (per_binds_local |
&& info->shared |
&& bfd_link_pic (info) |
&& (cie->per_encoding & 0x70) == DW_EH_PE_absptr |
&& (get_elf_backend_data (abfd) |
->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) |
1086,15 → 1275,15 |
} |
|
/* See if we can merge this CIE with an earlier one. */ |
cie->output_sec = sec->output_section; |
cie_compute_hash (cie); |
if (hdr_info->cies == NULL) |
if (hdr_info->u.dwarf.cies == NULL) |
{ |
hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); |
if (hdr_info->cies == NULL) |
hdr_info->u.dwarf.cies = htab_try_create (1, cie_hash, cie_eq, free); |
if (hdr_info->u.dwarf.cies == NULL) |
return cie_inf; |
} |
loc = htab_find_slot_with_hash (hdr_info->cies, cie, cie->hash, INSERT); |
loc = htab_find_slot_with_hash (hdr_info->u.dwarf.cies, cie, |
cie->hash, INSERT); |
if (loc == NULL) |
return cie_inf; |
|
1153,7 → 1342,7 |
/* There should only be one zero terminator, on the last input |
file supplying .eh_frame (crtend.o). Remove any others. */ |
ent->removed = sec->map_head.s != NULL; |
else if (!ent->cie) |
else if (!ent->cie && ent->u.fde.cie_inf != NULL) |
{ |
bfd_boolean keep; |
if ((sec->flags & SEC_LINKER_CREATED) != 0 && cookie->rels == NULL) |
1175,7 → 1364,7 |
} |
if (keep) |
{ |
if (info->shared |
if (bfd_link_pic (info) |
&& (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr |
&& ent->make_relative == 0) |
|| (ent->fde_encoding & 0x70) == DW_EH_PE_aligned)) |
1184,13 → 1373,13 |
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; |
hdr_info->u.dwarf.table = FALSE; |
(*info->callbacks->einfo) |
(_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" |
(_("%P: FDE encoding in %B(%A) prevents .eh_frame_hdr" |
" table being created.\n"), abfd, sec); |
} |
ent->removed = 0; |
hdr_info->fde_count++; |
hdr_info->u.dwarf.fde_count++; |
ent->u.fde.cie_inf = find_merged_cie (abfd, info, sec, hdr_info, |
cookie, ent->u.fde.cie_inf); |
} |
1229,10 → 1418,10 |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
|
if (hdr_info->cies != NULL) |
if (!hdr_info->frame_hdr_is_compact && hdr_info->u.dwarf.cies != NULL) |
{ |
htab_delete (hdr_info->cies); |
hdr_info->cies = NULL; |
htab_delete (hdr_info->u.dwarf.cies); |
hdr_info->u.dwarf.cies = NULL; |
} |
|
sec = hdr_info->hdr_sec; |
1239,9 → 1428,18 |
if (sec == NULL) |
return FALSE; |
|
if (info->eh_frame_hdr_type == COMPACT_EH_HDR) |
{ |
/* For compact frames we only add the header. The actual table comes |
from the .eh_frame_entry sections. */ |
sec->size = 8; |
} |
else |
{ |
sec->size = EH_FRAME_HDR_SIZE; |
if (hdr_info->table) |
sec->size += 4 + hdr_info->fde_count * 8; |
if (hdr_info->u.dwarf.table) |
sec->size += 4 + hdr_info->u.dwarf.fde_count * 8; |
} |
|
elf_eh_frame_hdr (abfd) = sec; |
return TRUE; |
1250,6 → 1448,7 |
/* Return true if there is at least one non-empty .eh_frame section in |
input files. Can only be called after ld has mapped input to |
output sections, and before sections are stripped. */ |
|
bfd_boolean |
_bfd_elf_eh_frame_present (struct bfd_link_info *info) |
{ |
1267,6 → 1466,29 |
return FALSE; |
} |
|
/* Return true if there is at least one .eh_frame_entry section in |
input files. */ |
|
bfd_boolean |
_bfd_elf_eh_frame_entry_present (struct bfd_link_info *info) |
{ |
asection *o; |
bfd *abfd; |
|
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) |
{ |
for (o = abfd->sections; o; o = o->next) |
{ |
const char *name = bfd_get_section_name (abfd, o); |
|
if (strcmp (name, ".eh_frame_entry") |
&& !bfd_is_abs_section (o->output_section)) |
return TRUE; |
} |
} |
return FALSE; |
} |
|
/* This function is called from size_dynamic_sections. |
It needs to decide whether .eh_frame_hdr should be output or not, |
because when the dynamic symbol table has been sized it is too late |
1277,6 → 1499,8 |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
struct bfd_link_hash_entry *bh = NULL; |
struct elf_link_hash_entry *h; |
|
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
1284,8 → 1508,11 |
return TRUE; |
|
if (bfd_is_abs_section (hdr_info->hdr_sec->output_section) |
|| !info->eh_frame_hdr |
|| !_bfd_elf_eh_frame_present (info)) |
|| info->eh_frame_hdr_type == 0 |
|| (info->eh_frame_hdr_type == DWARF2_EH_HDR |
&& !_bfd_elf_eh_frame_present (info)) |
|| (info->eh_frame_hdr_type == COMPACT_EH_HDR |
&& !_bfd_elf_eh_frame_entry_present (info))) |
{ |
hdr_info->hdr_sec->flags |= SEC_EXCLUDE; |
hdr_info->hdr_sec = NULL; |
1292,7 → 1519,21 |
return TRUE; |
} |
|
hdr_info->table = TRUE; |
/* Add a hidden symbol so that systems without access to PHDRs can |
find the table. */ |
if (! (_bfd_generic_link_add_one_symbol |
(info, info->output_bfd, "__GNU_EH_FRAME_HDR", BSF_LOCAL, |
hdr_info->hdr_sec, 0, NULL, FALSE, FALSE, &bh))) |
return FALSE; |
|
h = (struct elf_link_hash_entry *) bh; |
h->def_regular = 1; |
h->other = STV_HIDDEN; |
get_elf_backend_data |
(info->output_bfd)->elf_backend_hide_symbol (info, h, TRUE); |
|
if (!hdr_info->frame_hdr_is_compact) |
hdr_info->u.dwarf.table = TRUE; |
return TRUE; |
} |
|
1383,6 → 1624,83 |
+ extra_augmentation_data_bytes (sec_info->entry + mid)); |
} |
|
/* Write out .eh_frame_entry section. Add CANTUNWIND terminator if needed. |
Also check that the contents look sane. */ |
|
bfd_boolean |
_bfd_elf_write_section_eh_frame_entry (bfd *abfd, struct bfd_link_info *info, |
asection *sec, bfd_byte *contents) |
{ |
const struct elf_backend_data *bed; |
bfd_byte cantunwind[8]; |
bfd_vma addr; |
bfd_vma last_addr; |
bfd_vma offset; |
asection *text_sec = (asection *) elf_section_data (sec)->sec_info; |
|
if (!sec->rawsize) |
sec->rawsize = sec->size; |
|
BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_EH_FRAME_ENTRY); |
|
/* Check to make sure that the text section corresponding to this eh_frame_entry |
section has not been excluded. In particular, mips16 stub entries will be |
excluded outside of the normal process. */ |
if (sec->flags & SEC_EXCLUDE |
|| text_sec->flags & SEC_EXCLUDE) |
return TRUE; |
|
if (!bfd_set_section_contents (abfd, sec->output_section, contents, |
sec->output_offset, sec->rawsize)) |
return FALSE; |
|
last_addr = bfd_get_signed_32 (abfd, contents); |
/* Check that all the entries are in order. */ |
for (offset = 8; offset < sec->rawsize; offset += 8) |
{ |
addr = bfd_get_signed_32 (abfd, contents + offset) + offset; |
if (addr <= last_addr) |
{ |
(*_bfd_error_handler) (_("%B: %s not in order"), sec->owner, sec->name); |
return FALSE; |
} |
|
last_addr = addr; |
} |
|
addr = text_sec->output_section->vma + text_sec->output_offset |
+ text_sec->size; |
addr &= ~1; |
addr -= (sec->output_section->vma + sec->output_offset + sec->rawsize); |
if (addr & 1) |
{ |
(*_bfd_error_handler) (_("%B: %s invalid input section size"), |
sec->owner, sec->name); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
if (last_addr >= addr + sec->rawsize) |
{ |
(*_bfd_error_handler) (_("%B: %s points past end of text section"), |
sec->owner, sec->name); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
|
if (sec->size == sec->rawsize) |
return TRUE; |
|
bed = get_elf_backend_data (abfd); |
BFD_ASSERT (sec->size == sec->rawsize + 8); |
BFD_ASSERT ((addr & 1) == 0); |
BFD_ASSERT (bed->cant_unwind_opcode); |
|
bfd_put_32 (abfd, addr, cantunwind); |
bfd_put_32 (abfd, (*bed->cant_unwind_opcode) (info), cantunwind + 4); |
return bfd_set_section_contents (abfd, sec->output_section, cantunwind, |
sec->output_offset + sec->rawsize, 8); |
} |
|
/* Write out .eh_frame section. This is called with the relocated |
contents. */ |
|
1397,6 → 1715,7 |
struct eh_frame_hdr_info *hdr_info; |
unsigned int ptr_size; |
struct eh_cie_fde *ent; |
bfd_size_type sec_size; |
|
if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) |
/* FIXME: octets_per_byte. */ |
1411,10 → 1730,14 |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
|
if (hdr_info->table && hdr_info->array == NULL) |
hdr_info->array = (struct eh_frame_array_ent *) |
bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); |
if (hdr_info->array == NULL) |
if (hdr_info->u.dwarf.table && hdr_info->u.dwarf.array == NULL) |
{ |
hdr_info->frame_hdr_is_compact = FALSE; |
hdr_info->u.dwarf.array = (struct eh_frame_array_ent *) |
bfd_malloc (hdr_info->u.dwarf.fde_count |
* sizeof (*hdr_info->u.dwarf.array)); |
} |
if (hdr_info->u.dwarf.array == NULL) |
hdr_info = NULL; |
|
/* The new offsets can be bigger or smaller than the original offsets. |
1583,6 → 1906,8 |
value = ((ent->new_offset + sec->output_offset + 4) |
- (cie->new_offset + cie->u.cie.u.sec->output_offset)); |
bfd_put_32 (abfd, value, buf); |
if (bfd_link_relocatable (info)) |
continue; |
buf += 4; |
width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); |
value = read_value (abfd, buf, width, |
1647,8 → 1972,11 |
dwarf_vma is 64-bit. */ |
if (sizeof (address) > 4 && ptr_size == 4) |
address &= 0xffffffff; |
hdr_info->array[hdr_info->array_count].initial_loc = address; |
hdr_info->array[hdr_info->array_count++].fde |
hdr_info->u.dwarf.array[hdr_info->array_count].initial_loc |
= address; |
hdr_info->u.dwarf.array[hdr_info->array_count].range |
= read_value (abfd, buf + width, width, FALSE); |
hdr_info->u.dwarf.array[hdr_info->array_count++].fde |
= (sec->output_section->vma |
+ sec->output_offset |
+ ent->new_offset); |
1718,7 → 2046,11 |
the pointer size. _bfd_elf_discard_section_eh_frame should |
have padded CIE/FDE records to multiple of pointer size with |
size_of_output_cie_fde. */ |
if ((sec->size % ptr_size) != 0) |
sec_size = sec->size; |
if (sec_info->count != 0 |
&& sec_info->entry[sec_info->count - 1].size == 4) |
sec_size -= 4; |
if ((sec_size % ptr_size) != 0) |
abort (); |
|
/* FIXME: octets_per_byte. */ |
1739,13 → 2071,118 |
return 1; |
if (p->initial_loc < q->initial_loc) |
return -1; |
if (p->range > q->range) |
return 1; |
if (p->range < q->range) |
return -1; |
return 0; |
} |
|
/* Write out .eh_frame_hdr section. This must be called after |
_bfd_elf_write_section_eh_frame has been called on all input |
.eh_frame sections. |
.eh_frame_hdr format: |
/* Reorder .eh_frame_entry sections to match the associated text sections. |
This routine is called during the final linking step, just before writing |
the contents. At this stage, sections in the eh_frame_hdr_info are already |
sorted in order of increasing text section address and so we simply need |
to make the .eh_frame_entrys follow that same order. Note that it is |
invalid for a linker script to try to force a particular order of |
.eh_frame_entry sections. */ |
|
bfd_boolean |
_bfd_elf_fixup_eh_frame_hdr (struct bfd_link_info *info) |
{ |
asection *sec = NULL; |
asection *osec; |
struct eh_frame_hdr_info *hdr_info; |
unsigned int i; |
bfd_vma offset; |
struct bfd_link_order *p; |
|
hdr_info = &elf_hash_table (info)->eh_info; |
|
if (hdr_info->hdr_sec == NULL |
|| info->eh_frame_hdr_type != COMPACT_EH_HDR |
|| hdr_info->array_count == 0) |
return TRUE; |
|
/* Change section output offsets to be in text section order. */ |
offset = 8; |
osec = hdr_info->u.compact.entries[0]->output_section; |
for (i = 0; i < hdr_info->array_count; i++) |
{ |
sec = hdr_info->u.compact.entries[i]; |
if (sec->output_section != osec) |
{ |
(*_bfd_error_handler) |
(_("Invalid output section for .eh_frame_entry: %s"), |
sec->output_section->name); |
return FALSE; |
} |
sec->output_offset = offset; |
offset += sec->size; |
} |
|
|
/* Fix the link_order to match. */ |
for (p = sec->output_section->map_head.link_order; p != NULL; p = p->next) |
{ |
if (p->type != bfd_indirect_link_order) |
abort(); |
|
p->offset = p->u.indirect.section->output_offset; |
if (p->next != NULL) |
i--; |
} |
|
if (i != 0) |
{ |
(*_bfd_error_handler) |
(_("Invalid contents in %s section"), osec->name); |
return FALSE; |
} |
|
return TRUE; |
} |
|
/* The .eh_frame_hdr format for Compact EH frames: |
ubyte version (2) |
ubyte eh_ref_enc (DW_EH_PE_* encoding of typinfo references) |
uint32_t count (Number of entries in table) |
[array from .eh_frame_entry sections] */ |
|
static bfd_boolean |
write_compact_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
asection *sec; |
const struct elf_backend_data *bed; |
bfd_vma count; |
bfd_byte contents[8]; |
unsigned int i; |
|
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
sec = hdr_info->hdr_sec; |
|
if (sec->size != 8) |
abort(); |
|
for (i = 0; i < sizeof (contents); i++) |
contents[i] = 0; |
|
contents[0] = COMPACT_EH_HDR; |
bed = get_elf_backend_data (abfd); |
|
BFD_ASSERT (bed->compact_eh_encoding); |
contents[1] = (*bed->compact_eh_encoding) (info); |
|
count = (sec->output_section->size - 8) / 8; |
bfd_put_32 (abfd, count, contents + 4); |
return bfd_set_section_contents (abfd, sec->output_section, contents, |
(file_ptr) sec->output_offset, sec->size); |
} |
|
/* The .eh_frame_hdr format for DWARF frames: |
|
ubyte version (currently 1) |
ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of |
.eh_frame section) |
1764,8 → 2201,8 |
FDE initial_location field and FDE address, |
sorted by increasing initial_loc). */ |
|
bfd_boolean |
_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
static bfd_boolean |
write_dwarf_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
1775,9 → 2212,6 |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
sec = hdr_info->hdr_sec; |
|
if (info->eh_frame_hdr && sec != NULL) |
{ |
bfd_byte *contents; |
asection *eh_frame_sec; |
bfd_size_type size; |
1784,8 → 2218,9 |
bfd_vma encoded_eh_frame; |
|
size = EH_FRAME_HDR_SIZE; |
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
size += 4 + hdr_info->fde_count * 8; |
if (hdr_info->u.dwarf.array |
&& hdr_info->array_count == hdr_info->u.dwarf.fde_count) |
size += 4 + hdr_info->u.dwarf.fde_count * 8; |
contents = (bfd_byte *) bfd_malloc (size); |
if (contents == NULL) |
return FALSE; |
1804,7 → 2239,8 |
contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address |
(abfd, info, eh_frame_sec, 0, sec, 4, &encoded_eh_frame); |
|
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
if (hdr_info->u.dwarf.array |
&& hdr_info->array_count == hdr_info->u.dwarf.fde_count) |
{ |
/* FDE count encoding. */ |
contents[2] = DW_EH_PE_udata4; |
1821,33 → 2257,87 |
if (contents[2] != DW_EH_PE_omit) |
{ |
unsigned int i; |
bfd_boolean overlap, overflow; |
|
bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE); |
qsort (hdr_info->array, hdr_info->fde_count, |
sizeof (*hdr_info->array), vma_compare); |
for (i = 0; i < hdr_info->fde_count; i++) |
bfd_put_32 (abfd, hdr_info->u.dwarf.fde_count, |
contents + EH_FRAME_HDR_SIZE); |
qsort (hdr_info->u.dwarf.array, hdr_info->u.dwarf.fde_count, |
sizeof (*hdr_info->u.dwarf.array), vma_compare); |
overlap = FALSE; |
overflow = FALSE; |
for (i = 0; i < hdr_info->u.dwarf.fde_count; i++) |
{ |
bfd_put_32 (abfd, |
hdr_info->array[i].initial_loc |
- sec->output_section->vma, |
contents + EH_FRAME_HDR_SIZE + i * 8 + 4); |
bfd_put_32 (abfd, |
hdr_info->array[i].fde - sec->output_section->vma, |
contents + EH_FRAME_HDR_SIZE + i * 8 + 8); |
bfd_vma val; |
|
val = hdr_info->u.dwarf.array[i].initial_loc |
- sec->output_section->vma; |
val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; |
if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 |
&& (hdr_info->u.dwarf.array[i].initial_loc |
!= sec->output_section->vma + val)) |
overflow = TRUE; |
bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 4); |
val = hdr_info->u.dwarf.array[i].fde - sec->output_section->vma; |
val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; |
if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 |
&& (hdr_info->u.dwarf.array[i].fde |
!= sec->output_section->vma + val)) |
overflow = TRUE; |
bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 8); |
if (i != 0 |
&& (hdr_info->u.dwarf.array[i].initial_loc |
< (hdr_info->u.dwarf.array[i - 1].initial_loc |
+ hdr_info->u.dwarf.array[i - 1].range))) |
overlap = TRUE; |
} |
if (overflow) |
(*info->callbacks->einfo) (_("%P: .eh_frame_hdr entry overflow.\n")); |
if (overlap) |
(*info->callbacks->einfo) |
(_("%P: .eh_frame_hdr refers to overlapping FDEs.\n")); |
if (overflow || overlap) |
{ |
bfd_set_error (bfd_error_bad_value); |
retval = FALSE; |
} |
} |
|
/* FIXME: octets_per_byte. */ |
retval = bfd_set_section_contents (abfd, sec->output_section, contents, |
if (!bfd_set_section_contents (abfd, sec->output_section, contents, |
(file_ptr) sec->output_offset, |
sec->size); |
sec->size)) |
retval = FALSE; |
free (contents); |
} |
if (hdr_info->array != NULL) |
free (hdr_info->array); |
|
if (hdr_info->u.dwarf.array != NULL) |
free (hdr_info->u.dwarf.array); |
return retval; |
} |
|
/* Write out .eh_frame_hdr section. This must be called after |
_bfd_elf_write_section_eh_frame has been called on all input |
.eh_frame sections. */ |
|
bfd_boolean |
_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
asection *sec; |
|
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
sec = hdr_info->hdr_sec; |
|
if (info->eh_frame_hdr_type == 0 || sec == NULL) |
return TRUE; |
|
if (info->eh_frame_hdr_type == COMPACT_EH_HDR) |
return write_compact_eh_frame_hdr (abfd, info); |
else |
return write_dwarf_eh_frame_hdr (abfd, info); |
} |
|
/* Return the width of FDE addresses. This is the default implementation. */ |
|
unsigned int |