X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-xtensa.c;h=41506f431d8dfe4ac31df11bb0864c544a0d4d37;hb=f4e0d9f40b21fb42bbf7da07917683fb1cc16e8e;hp=21b287123243f80c5b2c68a32e23980ca5fc0f7a;hpb=071aa5c98a31c966f5fbfc573fcee61350fd1936;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c index 21b2871232..41506f431d 100644 --- a/bfd/elf32-xtensa.c +++ b/bfd/elf32-xtensa.c @@ -1,5 +1,5 @@ /* Xtensa-specific support for 32-bit ELF. - Copyright (C) 2003-2015 Free Software Foundation, Inc. + Copyright (C) 2003-2016 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -28,6 +28,7 @@ #include "libbfd.h" #include "elf-bfd.h" #include "elf/xtensa.h" +#include "splay-tree.h" #include "xtensa-isa.h" #include "xtensa-config.h" @@ -109,7 +110,6 @@ static bfd_boolean xtensa_is_proptable_section (asection *); static int internal_reloc_compare (const void *, const void *); static int internal_reloc_matches (const void *, const void *); static asection *xtensa_get_property_section (asection *, const char *); -extern asection *xtensa_make_property_section (asection *, const char *); static flagword xtensa_get_property_predef_flags (asection *); /* Other functions called directly by the linker. */ @@ -520,7 +520,9 @@ elf_xtensa_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, static const bfd_byte elf_xtensa_be_plt_entry[PLT_ENTRY_SIZE] = { +#if XSHAL_ABI == XTHAL_ABI_WINDOWED 0x6c, 0x10, 0x04, /* entry sp, 32 */ +#endif 0x18, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ 0x1a, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ 0x1b, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ @@ -530,7 +532,9 @@ static const bfd_byte elf_xtensa_be_plt_entry[PLT_ENTRY_SIZE] = static const bfd_byte elf_xtensa_le_plt_entry[PLT_ENTRY_SIZE] = { +#if XSHAL_ABI == XTHAL_ABI_WINDOWED 0x36, 0x41, 0x00, /* entry sp, 32 */ +#endif 0x81, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ 0xa1, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ 0xb1, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ @@ -970,7 +974,7 @@ elf_xtensa_check_relocs (bfd *abfd, const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; - if (info->relocatable || (sec->flags & SEC_ALLOC) == 0) + if (bfd_link_relocatable (info) || (sec->flags & SEC_ALLOC) == 0) return TRUE; BFD_ASSERT (is_xtensa_elf (abfd)); @@ -1020,7 +1024,7 @@ elf_xtensa_check_relocs (bfd *abfd, switch (r_type) { case R_XTENSA_TLSDESC_FN: - if (info->shared) + if (bfd_link_pic (info)) { tls_type = GOT_TLS_GD; is_got = TRUE; @@ -1031,7 +1035,7 @@ elf_xtensa_check_relocs (bfd *abfd, break; case R_XTENSA_TLSDESC_ARG: - if (info->shared) + if (bfd_link_pic (info)) { tls_type = GOT_TLS_GD; is_got = TRUE; @@ -1045,7 +1049,7 @@ elf_xtensa_check_relocs (bfd *abfd, break; case R_XTENSA_TLS_DTPOFF: - if (info->shared) + if (bfd_link_pic (info)) tls_type = GOT_TLS_GD; else tls_type = GOT_TLS_IE; @@ -1053,9 +1057,9 @@ elf_xtensa_check_relocs (bfd *abfd, case R_XTENSA_TLS_TPOFF: tls_type = GOT_TLS_IE; - if (info->shared) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; - if (info->shared || h) + if (bfd_link_pic (info) || h) is_got = TRUE; break; @@ -1200,7 +1204,7 @@ static void elf_xtensa_make_sym_local (struct bfd_link_info *info, struct elf_link_hash_entry *h) { - if (info->shared) + if (bfd_link_pic (info)) { if (h->plt.refcount > 0) { @@ -1287,7 +1291,7 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, if (htab == NULL) return FALSE; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; if ((sec->flags & SEC_ALLOC) == 0) @@ -1321,7 +1325,7 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, switch (r_type) { case R_XTENSA_TLSDESC_FN: - if (info->shared) + if (bfd_link_pic (info)) { is_got = TRUE; is_tlsfunc = TRUE; @@ -1329,7 +1333,7 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, break; case R_XTENSA_TLSDESC_ARG: - if (info->shared) + if (bfd_link_pic (info)) is_got = TRUE; else { @@ -1339,7 +1343,7 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, break; case R_XTENSA_TLS_TPOFF: - if (info->shared || h) + if (bfd_link_pic (info) || h) is_got = TRUE; break; @@ -1359,10 +1363,14 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, { if (is_plt) { + /* If the symbol has been localized its plt.refcount got moved + to got.refcount. Handle it as GOT. */ if (h->plt.refcount > 0) h->plt.refcount--; + else + is_got = TRUE; } - else if (is_got) + if (is_got) { if (h->got.refcount > 0) h->got.refcount--; @@ -1632,7 +1640,7 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, && htab->sgotloc != NULL); /* Set the contents of the .interp section to the interpreter. */ - if (info->executable) + if (bfd_link_executable (info) && !info->nointerp) { s = bfd_get_linker_section (dynobj, ".interp"); if (s == NULL) @@ -1654,7 +1662,7 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* If we are generating a shared object, we also need space in ".rela.got" for R_XTENSA_RELATIVE relocs for literals that reference local symbols. */ - if (info->shared) + if (bfd_link_pic (info)) elf_xtensa_allocate_local_got_size (info); /* Allocate space in ".plt" to match the size of ".rela.plt". For @@ -1810,7 +1818,7 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, #define add_dynamic_entry(TAG, VAL) \ _bfd_elf_add_dynamic_entry (info, TAG, VAL) - if (info->executable) + if (bfd_link_executable (info)) { if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; @@ -2312,7 +2320,7 @@ elf_xtensa_create_plt_entry (struct bfd_link_info *info, { asection *splt, *sgotplt; bfd_vma plt_base, got_base; - bfd_vma code_offset, lit_offset; + bfd_vma code_offset, lit_offset, abi_offset; int chunk; chunk = reloc_index / PLT_ENTRIES_PER_CHUNK; @@ -2337,15 +2345,16 @@ elf_xtensa_create_plt_entry (struct bfd_link_info *info, ? elf_xtensa_be_plt_entry : elf_xtensa_le_plt_entry), PLT_ENTRY_SIZE); + abi_offset = XSHAL_ABI == XTHAL_ABI_WINDOWED ? 3 : 0; bfd_put_16 (output_bfd, l32r_offset (got_base + 0, - plt_base + code_offset + 3), - splt->contents + code_offset + 4); + plt_base + code_offset + abi_offset), + splt->contents + code_offset + abi_offset + 1); bfd_put_16 (output_bfd, l32r_offset (got_base + 4, - plt_base + code_offset + 6), - splt->contents + code_offset + 7); + plt_base + code_offset + abi_offset + 3), + splt->contents + code_offset + abi_offset + 4); bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset, - plt_base + code_offset + 9), - splt->contents + code_offset + 10); + plt_base + code_offset + abi_offset + 6), + splt->contents + code_offset + abi_offset + 7); return plt_base + code_offset; } @@ -2622,7 +2631,7 @@ elf_xtensa_relocate_section (bfd *output_bfd, unresolved_reloc = FALSE; warned = FALSE; - if (howto->partial_inplace && !info->relocatable) + if (howto->partial_inplace && !bfd_link_relocatable (info)) { /* Because R_XTENSA_32 was made partial_inplace to fix some problems with DWARF info in partial links, there may be @@ -2660,7 +2669,7 @@ elf_xtensa_relocate_section (bfd *output_bfd, RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, rel, 1, relend, howto, 0, contents); - if (info->relocatable) + if (bfd_link_relocatable (info)) { bfd_vma dest_addr; asection * sym_sec = get_elf_r_symndx_section (input_bfd, r_symndx); @@ -2692,12 +2701,10 @@ elf_xtensa_relocate_section (bfd *output_bfd, r = contract_asm_expansion (contents, input_size, rel, &error_message); if (r != bfd_reloc_ok) - { - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; - } + (*info->callbacks->reloc_dangerous) + (info, error_message, + input_bfd, input_section, rel->r_offset); + r_type = ELF32_R_TYPE (rel->r_info); } @@ -2749,12 +2756,9 @@ elf_xtensa_relocate_section (bfd *output_bfd, } } if (r != bfd_reloc_ok) - { - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; - } + (*info->callbacks->reloc_dangerous) + (info, error_message, + input_bfd, input_section, rel->r_offset); /* Done with work for relocatable link; continue with next reloc. */ continue; @@ -2822,7 +2826,7 @@ elf_xtensa_relocate_section (bfd *output_bfd, case R_XTENSA_PLT: if (elf_hash_table (info)->dynamic_sections_created && (input_section->flags & SEC_ALLOC) != 0 - && (dynamic_symbol || info->shared)) + && (dynamic_symbol || bfd_link_pic (info))) { Elf_Internal_Rela outrel; bfd_byte *loc; @@ -2854,10 +2858,9 @@ elf_xtensa_relocate_section (bfd *output_bfd, { error_message = _("dynamic relocation in read-only section"); - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; + (*info->callbacks->reloc_dangerous) + (info, error_message, + input_bfd, input_section, rel->r_offset); } if (dynamic_symbol) @@ -2910,7 +2913,7 @@ elf_xtensa_relocate_section (bfd *output_bfd, case R_XTENSA_TLS_TPOFF: /* Switch to LE model for local symbols in an executable. */ - if (! info->shared && ! dynamic_symbol) + if (! bfd_link_pic (info) && ! dynamic_symbol) { relocation = tpoff (info, relocation); break; @@ -2922,12 +2925,12 @@ elf_xtensa_relocate_section (bfd *output_bfd, { if (r_type == R_XTENSA_TLSDESC_FN) { - if (! info->shared || (tls_type & GOT_TLS_IE) != 0) + if (! bfd_link_pic (info) || (tls_type & GOT_TLS_IE) != 0) r_type = R_XTENSA_NONE; } else if (r_type == R_XTENSA_TLSDESC_ARG) { - if (info->shared) + if (bfd_link_pic (info)) { if ((tls_type & GOT_TLS_IE) != 0) r_type = R_XTENSA_TLS_TPOFF; @@ -2951,10 +2954,9 @@ elf_xtensa_relocate_section (bfd *output_bfd, { error_message = _("TLS relocation invalid without dynamic sections"); - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; + (*info->callbacks->reloc_dangerous) + (info, error_message, + input_bfd, input_section, rel->r_offset); } else { @@ -2975,10 +2977,9 @@ elf_xtensa_relocate_section (bfd *output_bfd, { error_message = _("dynamic relocation in read-only section"); - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; + (*info->callbacks->reloc_dangerous) + (info, error_message, + input_bfd, input_section, rel->r_offset); } indx = h && h->dynindx != -1 ? h->dynindx : 0; @@ -3003,7 +3004,7 @@ elf_xtensa_relocate_section (bfd *output_bfd, break; case R_XTENSA_TLS_DTPOFF: - if (! info->shared) + if (! bfd_link_pic (info)) /* Switch from LD model to LE model. */ relocation = tpoff (info, relocation); else @@ -3020,12 +3021,9 @@ elf_xtensa_relocate_section (bfd *output_bfd, (h && elf_xtensa_hash_entry (h) == htab->tlsbase); if (! replace_tls_insn (rel, input_bfd, input_section, contents, is_ld_model, &error_message)) - { - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; - } + (*info->callbacks->reloc_dangerous) + (info, error_message, + input_bfd, input_section, rel->r_offset); if (r_type != R_XTENSA_TLS_ARG || is_ld_model) { @@ -3044,10 +3042,8 @@ elf_xtensa_relocate_section (bfd *output_bfd, error_message = vsprint_msg ("invalid relocation for dynamic symbol", ": %s", strlen (name) + 2, name); - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; + (*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, rel->r_offset); continue; } break; @@ -3095,10 +3091,8 @@ elf_xtensa_relocate_section (bfd *output_bfd, strlen (name) + 22, name, (int) rel->r_addend); - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; + (*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, rel->r_offset); } } @@ -3390,7 +3384,7 @@ elf_xtensa_finish_dynamic_sections (bfd *output_bfd, } /* Combine adjacent literal table entries. */ - BFD_ASSERT (! info->relocatable); + BFD_ASSERT (! bfd_link_relocatable (info)); sxtlit = bfd_get_section_by_name (output_bfd, ".xt.lit"); sgotloc = htab->sgotloc; BFD_ASSERT (sgotloc); @@ -3420,19 +3414,22 @@ elf_xtensa_finish_dynamic_sections (bfd *output_bfd, break; case DT_XTENSA_GOT_LOC_OFF: - dyn.d_un.d_ptr = htab->sgotloc->output_section->vma; + dyn.d_un.d_ptr = (htab->sgotloc->output_section->vma + + htab->sgotloc->output_offset); break; case DT_PLTGOT: - dyn.d_un.d_ptr = htab->sgot->output_section->vma; + dyn.d_un.d_ptr = (htab->sgot->output_section->vma + + htab->sgot->output_offset); break; case DT_JMPREL: - dyn.d_un.d_ptr = htab->srelplt->output_section->vma; + dyn.d_un.d_ptr = (htab->srelplt->output_section->vma + + htab->srelplt->output_offset); break; case DT_PLTRELSZ: - dyn.d_un.d_val = htab->srelplt->output_section->size; + dyn.d_un.d_val = htab->srelplt->size; break; case DT_RELASZ: @@ -3443,7 +3440,7 @@ elf_xtensa_finish_dynamic_sections (bfd *output_bfd, for .rela.plt to follow all other relocation sections, we don't have to worry about changing the DT_RELA entry. */ if (htab->srelplt) - dyn.d_un.d_val -= htab->srelplt->output_section->size; + dyn.d_un.d_val -= htab->srelplt->size; break; } @@ -5416,8 +5413,6 @@ struct text_action_struct bfd_vma virtual_offset; /* Zero except for adding literals. */ int removed_bytes; literal_value value; /* Only valid when adding literals. */ - - text_action *next; }; struct removal_by_action_entry_struct @@ -5440,7 +5435,8 @@ typedef struct removal_by_action_map_struct removal_by_action_map; /* List of all of the actions taken on a text section. */ struct text_action_list_struct { - text_action *head; + unsigned count; + splay_tree tree; removal_by_action_map map; }; @@ -5448,20 +5444,18 @@ struct text_action_list_struct static text_action * find_fill_action (text_action_list *l, asection *sec, bfd_vma offset) { - text_action **m_p; + text_action a; /* It is not necessary to fill at the end of a section. */ if (sec->size == offset) return NULL; - for (m_p = &l->head; *m_p && (*m_p)->offset <= offset; m_p = &(*m_p)->next) - { - text_action *t = *m_p; - /* When the action is another fill at the same address, - just increase the size. */ - if (t->offset == offset && t->action == ta_fill) - return t; - } + a.offset = offset; + a.action = ta_fill; + + splay_tree_node node = splay_tree_lookup (l->tree, (splay_tree_key)&a); + if (node) + return (text_action *)node->value; return NULL; } @@ -5509,6 +5503,49 @@ adjust_fill_action (text_action *ta, int fill_diff) } +static int +text_action_compare (splay_tree_key a, splay_tree_key b) +{ + text_action *pa = (text_action *)a; + text_action *pb = (text_action *)b; + static const int action_priority[] = + { + [ta_fill] = 0, + [ta_none] = 1, + [ta_convert_longcall] = 2, + [ta_narrow_insn] = 3, + [ta_remove_insn] = 4, + [ta_remove_longcall] = 5, + [ta_remove_literal] = 6, + [ta_widen_insn] = 7, + [ta_add_literal] = 8, + }; + + if (pa->offset == pb->offset) + { + if (pa->action == pb->action) + return 0; + return action_priority[pa->action] - action_priority[pb->action]; + } + else + return pa->offset < pb->offset ? -1 : 1; +} + +static text_action * +action_first (text_action_list *action_list) +{ + splay_tree_node node = splay_tree_min (action_list->tree); + return node ? (text_action *)node->value : NULL; +} + +static text_action * +action_next (text_action_list *action_list, text_action *action) +{ + splay_tree_node node = splay_tree_successor (action_list->tree, + (splay_tree_key)action); + return node ? (text_action *)node->value : NULL; +} + /* Add a modification action to the text. For the case of adding or removing space, modify any current fill and assume that "unreachable_space" bytes can be freely contracted. Note that a @@ -5521,8 +5558,8 @@ text_action_add (text_action_list *l, bfd_vma offset, int removed) { - text_action **m_p; text_action *ta; + text_action a; /* It is not necessary to fill at the end of a section. */ if (action == ta_fill && sec->size == offset) @@ -5532,34 +5569,30 @@ text_action_add (text_action_list *l, if (action == ta_fill && removed == 0) return; - for (m_p = &l->head; *m_p && (*m_p)->offset <= offset; m_p = &(*m_p)->next) + a.action = action; + a.offset = offset; + + if (action == ta_fill) { - text_action *t = *m_p; + splay_tree_node node = splay_tree_lookup (l->tree, (splay_tree_key)&a); - if (action == ta_fill) + if (node) { - /* When the action is another fill at the same address, - just increase the size. */ - if (t->offset == offset && t->action == ta_fill) - { - t->removed_bytes += removed; - return; - } - /* Fills need to happen before widens so that we don't - insert fill bytes into the instruction stream. */ - if (t->offset == offset && t->action == ta_widen_insn) - break; + ta = (text_action *)node->value; + ta->removed_bytes += removed; + return; } } + else + BFD_ASSERT (splay_tree_lookup (l->tree, (splay_tree_key)&a) == NULL); - /* Create a new record and fill it up. */ ta = (text_action *) bfd_zmalloc (sizeof (text_action)); ta->action = action; ta->sec = sec; ta->offset = offset; ta->removed_bytes = removed; - ta->next = (*m_p); - *m_p = ta; + splay_tree_insert (l->tree, (splay_tree_key)ta, (splay_tree_value)ta); + ++l->count; } @@ -5570,7 +5603,6 @@ text_action_add_literal (text_action_list *l, const literal_value *value, int removed) { - text_action **m_p; text_action *ta; asection *sec = r_reloc_get_section (loc); bfd_vma offset = loc->target_offset; @@ -5578,14 +5610,6 @@ text_action_add_literal (text_action_list *l, BFD_ASSERT (action == ta_add_literal); - for (m_p = &l->head; *m_p != NULL; m_p = &(*m_p)->next) - { - if ((*m_p)->offset > offset - && ((*m_p)->offset != offset - || (*m_p)->virtual_offset > virtual_offset)) - break; - } - /* Create a new record and fill it up. */ ta = (text_action *) bfd_zmalloc (sizeof (text_action)); ta->action = action; @@ -5594,8 +5618,10 @@ text_action_add_literal (text_action_list *l, ta->virtual_offset = virtual_offset; ta->value = *value; ta->removed_bytes = removed; - ta->next = (*m_p); - *m_p = ta; + + BFD_ASSERT (splay_tree_lookup (l->tree, (splay_tree_key)ta) == NULL); + splay_tree_insert (l->tree, (splay_tree_key)ta, (splay_tree_value)ta); + ++l->count; } @@ -5606,7 +5632,8 @@ text_action_add_literal (text_action_list *l, so that each search may begin where the previous one left off. */ static int -removed_by_actions (text_action **p_start_action, +removed_by_actions (text_action_list *action_list, + text_action **p_start_action, bfd_vma offset, bfd_boolean before_fill) { @@ -5614,6 +5641,13 @@ removed_by_actions (text_action **p_start_action, int removed = 0; r = *p_start_action; + if (r) + { + splay_tree_node node = splay_tree_lookup (action_list->tree, + (splay_tree_key)r); + BFD_ASSERT (node != NULL && r == (text_action *)node->value); + } + while (r) { if (r->offset > offset) @@ -5625,7 +5659,7 @@ removed_by_actions (text_action **p_start_action, removed += r->removed_bytes; - r = r->next; + r = action_next (action_list, r); } *p_start_action = r; @@ -5636,68 +5670,74 @@ removed_by_actions (text_action **p_start_action, static bfd_vma offset_with_removed_text (text_action_list *action_list, bfd_vma offset) { - text_action *r = action_list->head; - return offset - removed_by_actions (&r, offset, FALSE); + text_action *r = action_first (action_list); + + return offset - removed_by_actions (action_list, &r, offset, FALSE); } static unsigned action_list_count (text_action_list *action_list) { - text_action *r = action_list->head; - unsigned count = 0; - for (r = action_list->head; r != NULL; r = r->next) - { - count++; - } - return count; + return action_list->count; } -static void -map_removal_by_action (text_action_list *action_list) +typedef struct map_action_fn_context_struct map_action_fn_context; +struct map_action_fn_context_struct { - text_action *r; - int removed = 0; + int removed; removal_by_action_map map; bfd_boolean eq_complete; +}; - map.n_entries = 0; - map.entry = bfd_malloc (action_list_count (action_list) * - sizeof (removal_by_action_entry)); - eq_complete = FALSE; +static int +map_action_fn (splay_tree_node node, void *p) +{ + map_action_fn_context *ctx = p; + text_action *r = (text_action *)node->value; + removal_by_action_entry *ientry = ctx->map.entry + ctx->map.n_entries; - for (r = action_list->head; r;) + if (ctx->map.n_entries && (ientry - 1)->offset == r->offset) { - removal_by_action_entry *ientry = map.entry + map.n_entries; + --ientry; + } + else + { + ++ctx->map.n_entries; + ctx->eq_complete = FALSE; + ientry->offset = r->offset; + ientry->eq_removed_before_fill = ctx->removed; + } - if (map.n_entries && (ientry - 1)->offset == r->offset) + if (!ctx->eq_complete) + { + if (r->action != ta_fill || r->removed_bytes >= 0) { - --ientry; + ientry->eq_removed = ctx->removed; + ctx->eq_complete = TRUE; } else - { - ++map.n_entries; - eq_complete = FALSE; - ientry->offset = r->offset; - ientry->eq_removed_before_fill = removed; - } + ientry->eq_removed = ctx->removed + r->removed_bytes; + } - if (!eq_complete) - { - if (r->action != ta_fill || r->removed_bytes >= 0) - { - ientry->eq_removed = removed; - eq_complete = TRUE; - } - else - ientry->eq_removed = removed + r->removed_bytes; - } + ctx->removed += r->removed_bytes; + ientry->removed = ctx->removed; + return 0; +} - removed += r->removed_bytes; - ientry->removed = removed; - r = r->next; - } - action_list->map = map; +static void +map_removal_by_action (text_action_list *action_list) +{ + map_action_fn_context ctx; + + ctx.removed = 0; + ctx.map.n_entries = 0; + ctx.map.entry = bfd_malloc (action_list_count (action_list) * + sizeof (removal_by_action_entry)); + ctx.eq_complete = FALSE; + + splay_tree_foreach (action_list->tree, map_action_fn, &ctx); + action_list->map = ctx.map; } static int @@ -5754,28 +5794,26 @@ offset_with_removed_text_map (text_action_list *action_list, bfd_vma offset) static text_action * find_insn_action (text_action_list *action_list, bfd_vma offset) { - text_action *t; - for (t = action_list->head; t; t = t->next) + static const text_action_t action[] = { - if (t->offset == offset) - { - switch (t->action) - { - case ta_none: - case ta_fill: - break; - case ta_remove_insn: - case ta_remove_longcall: - case ta_convert_longcall: - case ta_narrow_insn: - case ta_widen_insn: - return t; - case ta_remove_literal: - case ta_add_literal: - BFD_ASSERT (0); - break; - } - } + ta_convert_longcall, + ta_remove_longcall, + ta_widen_insn, + ta_narrow_insn, + ta_remove_insn, + }; + text_action a; + unsigned i; + + a.offset = offset; + for (i = 0; i < sizeof (action) / sizeof (*action); ++i) + { + splay_tree_node node; + + a.action = action[i]; + node = splay_tree_lookup (action_list->tree, (splay_tree_key)&a); + if (node) + return (text_action *)node->value; } return NULL; } @@ -5784,40 +5822,50 @@ find_insn_action (text_action_list *action_list, bfd_vma offset) #if DEBUG static void -print_action_list (FILE *fp, text_action_list *action_list) +print_action (FILE *fp, text_action *r) +{ + const char *t = "unknown"; + switch (r->action) + { + case ta_remove_insn: + t = "remove_insn"; break; + case ta_remove_longcall: + t = "remove_longcall"; break; + case ta_convert_longcall: + t = "convert_longcall"; break; + case ta_narrow_insn: + t = "narrow_insn"; break; + case ta_widen_insn: + t = "widen_insn"; break; + case ta_fill: + t = "fill"; break; + case ta_none: + t = "none"; break; + case ta_remove_literal: + t = "remove_literal"; break; + case ta_add_literal: + t = "add_literal"; break; + } + + fprintf (fp, "%s: %s[0x%lx] \"%s\" %d\n", + r->sec->owner->filename, + r->sec->name, (unsigned long) r->offset, t, r->removed_bytes); +} + +static int +print_action_list_fn (splay_tree_node node, void *p) { - text_action *r; + text_action *r = (text_action *)node->value; - fprintf (fp, "Text Action\n"); - for (r = action_list->head; r != NULL; r = r->next) - { - const char *t = "unknown"; - switch (r->action) - { - case ta_remove_insn: - t = "remove_insn"; break; - case ta_remove_longcall: - t = "remove_longcall"; break; - case ta_convert_longcall: - t = "convert_longcall"; break; - case ta_narrow_insn: - t = "narrow_insn"; break; - case ta_widen_insn: - t = "widen_insn"; break; - case ta_fill: - t = "fill"; break; - case ta_none: - t = "none"; break; - case ta_remove_literal: - t = "remove_literal"; break; - case ta_add_literal: - t = "add_literal"; break; - } + print_action (p, r); + return 0; +} - fprintf (fp, "%s: %s[0x%lx] \"%s\" %d\n", - r->sec->owner->filename, - r->sec->name, (unsigned long) r->offset, t, r->removed_bytes); - } +static void +print_action_list (FILE *fp, text_action_list *action_list) +{ + fprintf (fp, "Text Action\n"); + splay_tree_foreach (action_list->tree, print_action_list_fn, fp); } #endif /* DEBUG */ @@ -5832,6 +5880,7 @@ print_action_list (FILE *fp, text_action_list *action_list) by the "from" offset field. */ typedef struct removed_literal_struct removed_literal; +typedef struct removed_literal_map_entry_struct removed_literal_map_entry; typedef struct removed_literal_list_struct removed_literal_list; struct removed_literal_struct @@ -5841,10 +5890,19 @@ struct removed_literal_struct removed_literal *next; }; +struct removed_literal_map_entry_struct +{ + bfd_vma addr; + removed_literal *literal; +}; + struct removed_literal_list_struct { removed_literal *head; removed_literal *tail; + + unsigned n_map; + removed_literal_map_entry *map; }; @@ -5893,6 +5951,39 @@ add_removed_literal (removed_literal_list *removed_list, } } +static void +map_removed_literal (removed_literal_list *removed_list) +{ + unsigned n_map = 0; + unsigned i; + removed_literal_map_entry *map = NULL; + removed_literal *r = removed_list->head; + + for (i = 0; r; ++i, r = r->next) + { + if (i == n_map) + { + n_map = (n_map * 2) + 2; + map = bfd_realloc (map, n_map * sizeof (*map)); + } + map[i].addr = r->from.target_offset; + map[i].literal = r; + } + removed_list->map = map; + removed_list->n_map = i; +} + +static int +removed_literal_compare (const void *a, const void *b) +{ + const removed_literal_map_entry *pa = a; + const removed_literal_map_entry *pb = b; + + if (pa->addr == pb->addr) + return 0; + else + return pa->addr < pb->addr ? -1 : 1; +} /* Check if the list of removed literals contains an entry for the given address. Return the entry if found. */ @@ -5900,12 +5991,21 @@ add_removed_literal (removed_literal_list *removed_list, static removed_literal * find_removed_literal (removed_literal_list *removed_list, bfd_vma addr) { - removed_literal *r = removed_list->head; - while (r && r->from.target_offset < addr) - r = r->next; - if (r && r->from.target_offset == addr) - return r; - return NULL; + removed_literal_map_entry *p; + removed_literal *r = NULL; + + if (removed_list->map == NULL) + map_removed_literal (removed_list); + + p = bsearch (&addr, removed_list->map, removed_list->n_map, + sizeof (*removed_list->map), removed_literal_compare); + if (p) + { + while (p != removed_list->map && (p - 1)->addr == addr) + --p; + r = p->literal; + } + return r; } @@ -6019,8 +6119,8 @@ init_xtensa_relax_info (asection *sec) relax_info->removed_list.head = NULL; relax_info->removed_list.tail = NULL; - relax_info->action_list.head = NULL; - + relax_info->action_list.tree = splay_tree_new (text_action_compare, + NULL, NULL); relax_info->action_list.map.n_entries = 0; relax_info->action_list.map.entry = NULL; @@ -7240,7 +7340,7 @@ is_resolvable_asm_expansion (bfd *abfd, /* For relocatable sections, we can only simplify when the output section of the target is the same as the output section of the source. */ - if (link_info->relocatable + if (bfd_link_relocatable (link_info) && (target_sec->output_section != sec->output_section || is_reloc_sym_weak (abfd, irel))) return FALSE; @@ -7710,7 +7810,7 @@ compute_text_actions (bfd *abfd, free_reloc_range_list (&relevant_relocs); #if DEBUG - if (relax_info->action_list.head) + if (action_list_count (&relax_info->action_list)) print_action_list (stderr, &relax_info->action_list); #endif @@ -8211,6 +8311,54 @@ xlate_offset_with_removed_text (const xlate_map_t *map, return e->new_address - e->orig_address + offset; } +typedef struct xlate_map_context_struct xlate_map_context; +struct xlate_map_context_struct +{ + xlate_map_t *map; + xlate_map_entry_t *current_entry; + int removed; +}; + +static int +xlate_map_fn (splay_tree_node node, void *p) +{ + text_action *r = (text_action *)node->value; + xlate_map_context *ctx = p; + unsigned orig_size = 0; + + switch (r->action) + { + case ta_none: + case ta_remove_insn: + case ta_convert_longcall: + case ta_remove_literal: + case ta_add_literal: + break; + case ta_remove_longcall: + orig_size = 6; + break; + case ta_narrow_insn: + orig_size = 3; + break; + case ta_widen_insn: + orig_size = 2; + break; + case ta_fill: + break; + } + ctx->current_entry->size = + r->offset + orig_size - ctx->current_entry->orig_address; + if (ctx->current_entry->size != 0) + { + ctx->current_entry++; + ctx->map->entry_count++; + } + ctx->current_entry->orig_address = r->offset + orig_size; + ctx->removed += r->removed_bytes; + ctx->current_entry->new_address = r->offset + orig_size - ctx->removed; + ctx->current_entry->size = 0; + return 0; +} /* Build a binary searchable offset translation map from a section's action list. */ @@ -8218,75 +8366,40 @@ xlate_offset_with_removed_text (const xlate_map_t *map, static xlate_map_t * build_xlate_map (asection *sec, xtensa_relax_info *relax_info) { - xlate_map_t *map = (xlate_map_t *) bfd_malloc (sizeof (xlate_map_t)); text_action_list *action_list = &relax_info->action_list; unsigned num_actions = 0; - text_action *r; - int removed; - xlate_map_entry_t *current_entry; + xlate_map_context ctx; - if (map == NULL) + ctx.map = (xlate_map_t *) bfd_malloc (sizeof (xlate_map_t)); + + if (ctx.map == NULL) return NULL; num_actions = action_list_count (action_list); - map->entry = (xlate_map_entry_t *) + ctx.map->entry = (xlate_map_entry_t *) bfd_malloc (sizeof (xlate_map_entry_t) * (num_actions + 1)); - if (map->entry == NULL) + if (ctx.map->entry == NULL) { - free (map); + free (ctx.map); return NULL; } - map->entry_count = 0; + ctx.map->entry_count = 0; - removed = 0; - current_entry = &map->entry[0]; + ctx.removed = 0; + ctx.current_entry = &ctx.map->entry[0]; - current_entry->orig_address = 0; - current_entry->new_address = 0; - current_entry->size = 0; + ctx.current_entry->orig_address = 0; + ctx.current_entry->new_address = 0; + ctx.current_entry->size = 0; - for (r = action_list->head; r != NULL; r = r->next) - { - unsigned orig_size = 0; - switch (r->action) - { - case ta_none: - case ta_remove_insn: - case ta_convert_longcall: - case ta_remove_literal: - case ta_add_literal: - break; - case ta_remove_longcall: - orig_size = 6; - break; - case ta_narrow_insn: - orig_size = 3; - break; - case ta_widen_insn: - orig_size = 2; - break; - case ta_fill: - break; - } - current_entry->size = - r->offset + orig_size - current_entry->orig_address; - if (current_entry->size != 0) - { - current_entry++; - map->entry_count++; - } - current_entry->orig_address = r->offset + orig_size; - removed += r->removed_bytes; - current_entry->new_address = r->offset + orig_size - removed; - current_entry->size = 0; - } + splay_tree_foreach (action_list->tree, xlate_map_fn, &ctx); - current_entry->size = (bfd_get_section_limit (sec->owner, sec) - - current_entry->orig_address); - if (current_entry->size != 0) - map->entry_count++; + ctx.current_entry->size = (bfd_get_section_limit (sec->owner, sec) + - ctx.current_entry->orig_address); + if (ctx.current_entry->size != 0) + ctx.map->entry_count++; - return map; + return ctx.map; } @@ -8883,7 +8996,7 @@ identify_literal_placement (bfd *abfd, sec_size = bfd_get_section_limit (abfd, sec); final_static_link = - (!link_info->relocatable + (!bfd_link_relocatable (link_info) && !elf_hash_table (link_info)->dynamic_sections_created); /* The placement algorithm first checks to see if the literal is @@ -8922,7 +9035,7 @@ identify_literal_placement (bfd *abfd, /* For relocatable links, do not try to move literals. To do it correctly might increase the number of relocations in an input section making the default relocatable linking fail. */ - if (!link_info->relocatable && !literal_placed + if (!bfd_link_relocatable (link_info) && !literal_placed && values->has_last_loc && !(*last_loc_is_prev_p)) { asection *target_sec = r_reloc_get_section (&values->last_loc); @@ -9250,6 +9363,16 @@ move_shared_literal (asection *sec, /* Second relaxation pass. */ +static int +action_remove_bytes_fn (splay_tree_node node, void *p) +{ + bfd_size_type *final_size = p; + text_action *action = (text_action *)node->value; + + *final_size -= action->removed_bytes; + return 0; +} + /* Modify all of the relocations to point to the right spot, and if this is a relaxable section, delete the unwanted literals and fix the section size. */ @@ -9282,7 +9405,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); - if (!internal_relocs && !relax_info->action_list.head) + if (!internal_relocs && !action_list_count (&relax_info->action_list)) return TRUE; contents = retrieve_contents (abfd, sec, link_info->keep_memory); @@ -9360,6 +9483,12 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) } /* Update the action so that the code that moves the contents will do the right thing. */ + /* ta_remove_longcall and ta_remove_insn actions are + grouped together in the tree as well as + ta_convert_longcall and ta_none, so that changes below + can be done w/o removing and reinserting action into + the tree. */ + if (action->action == ta_remove_longcall) action->action = ta_remove_insn; else @@ -9532,13 +9661,12 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) if ((relax_info->is_relaxable_literal_section || relax_info->is_relaxable_asm_section) - && relax_info->action_list.head) + && action_list_count (&relax_info->action_list)) { /* Walk through the planned actions and build up a table of move, copy and fill records. Use the move, copy and fill records to perform the actions once. */ - int removed = 0; bfd_size_type final_size, copy_size, orig_insn_size; bfd_byte *scratch = NULL; bfd_byte *dup_contents = NULL; @@ -9549,15 +9677,12 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) bfd_vma orig_dot_vo = 0; /* Virtual offset from orig_dot. */ bfd_vma dup_dot = 0; - text_action *action = relax_info->action_list.head; + text_action *action; final_size = sec->size; - for (action = relax_info->action_list.head; action; - action = action->next) - { - final_size -= action->removed_bytes; - } + splay_tree_foreach (relax_info->action_list.tree, + action_remove_bytes_fn, &final_size); scratch = (bfd_byte *) bfd_zmalloc (final_size); dup_contents = (bfd_byte *) bfd_zmalloc (final_size); @@ -9566,8 +9691,8 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) print_action_list (stderr, &relax_info->action_list); #endif - for (action = relax_info->action_list.head; action; - action = action->next) + for (action = action_first (&relax_info->action_list); action; + action = action_next (&relax_info->action_list, action)) { virtual_action = FALSE; if (action->offset > orig_dot) @@ -9696,7 +9821,6 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) break; } - removed += action->removed_bytes; BFD_ASSERT (dup_dot <= final_size); BFD_ASSERT (orig_dot <= orig_size); } @@ -9987,7 +10111,7 @@ shrink_dynamic_reloc_sections (struct bfd_link_info *info, if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT) && (input_section->flags & SEC_ALLOC) != 0 - && (dynamic_symbol || info->shared)) + && (dynamic_symbol || bfd_link_pic (info))) { asection *srel; bfd_boolean is_plt = FALSE; @@ -10093,7 +10217,7 @@ move_literal (bfd *abfd, bfd_put_32 (abfd, lit->value, contents + offset); /* Currently, we cannot move relocations during a relocatable link. */ - BFD_ASSERT (!link_info->relocatable); + BFD_ASSERT (!bfd_link_relocatable (link_info)); fix = reloc_bfd_fix_init (sec, offset, r_type, r_reloc_get_section (r_rel), r_rel->target_offset + r_rel->virtual_offset, @@ -10332,7 +10456,7 @@ relax_property_section (bfd *abfd, finish_dynamic_sections() but at that point it's too late to reclaim the space in the output section, so we do this twice. */ - if (internal_relocs && (!link_info->relocatable + if (internal_relocs && (!bfd_link_relocatable (link_info) || xtensa_is_littable_section (sec))) { Elf_Internal_Rela *last_irel = NULL;