Fix PR ld/20254
[deliverable/binutils-gdb.git] / bfd / elf32-xtensa.c
index 51733ad09cbfd00fba24dd3eb9770042016f03f9..af9618dbfc23f91b881920d12f775f515b3e6d13 100644 (file)
@@ -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"
 
@@ -520,7 +521,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 +533,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 +975,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 +1025,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 +1036,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 +1050,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 +1058,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 +1205,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 +1292,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 +1326,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 +1334,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 +1344,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 +1364,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 +1641,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 +1663,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 +1819,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 +2321,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 +2346,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 +2632,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 +2670,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 +2702,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 +2757,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 +2827,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 +2859,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 +2914,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 +2926,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 +2955,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 +2978,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 +3005,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 +3022,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 +3043,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 +3092,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 +3385,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 +3415,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 +3441,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 +5414,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 +5436,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 +5445,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 +5504,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 +5559,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 +5570,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 +5604,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 +5611,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 +5619,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 +5633,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 +5642,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 +5660,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 +5671,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 +5795,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 +5823,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 */
@@ -6071,8 +6120,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;
 
@@ -7292,7 +7341,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;
@@ -7762,7 +7811,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
 
@@ -8263,6 +8312,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.  */
@@ -8270,75 +8367,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;
 }
 
 
@@ -8935,7 +8997,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
@@ -8974,7 +9036,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);
@@ -9302,6 +9364,16 @@ move_shared_literal (asection *sec,
 \f
 /* 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.  */
@@ -9334,7 +9406,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);
@@ -9412,6 +9484,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
@@ -9584,13 +9662,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;
@@ -9601,15 +9678,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);
 
@@ -9618,8 +9692,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)
@@ -9748,7 +9822,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);
        }
@@ -10039,7 +10112,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;
@@ -10145,7 +10218,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,
@@ -10384,7 +10457,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;
This page took 0.049632 seconds and 4 git commands to generate.