* elf32-xtensa.c (elf_xtensa_relocate_section): Remove updates of
[binutils-gdb.git] / bfd / elf32-xtensa.c
index 945123df206a9e27ce96d24ea95ec965126f93fc..dac6896a015293e4a8862ccc2c17817a0944a6c7 100644 (file)
@@ -5,7 +5,7 @@
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of the
+   published by the Free Software Foundation; either version 3 of the
    License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful, but
@@ -18,8 +18,8 @@
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 
 #include <stdarg.h>
 #include <strings.h>
@@ -612,10 +612,10 @@ xtensa_read_table_entries (bfd *abfd,
   property_table_entry *blocks;
   int blk, block_count;
   bfd_size_type num_records;
-  Elf_Internal_Rela *internal_relocs;
-  bfd_vma section_addr;
+  Elf_Internal_Rela *internal_relocs, *irel, *rel_end;
+  bfd_vma section_addr, off;
   flagword predef_flags;
-  bfd_size_type table_entry_size;
+  bfd_size_type table_entry_size, section_limit;
 
   if (!section
       || !(section->flags & SEC_ALLOC)
@@ -651,67 +651,63 @@ xtensa_read_table_entries (bfd *abfd,
   else
     section_addr = section->vma;
 
-  /* If the file has not yet been relocated, process the relocations
-     and sort out the table entries that apply to the specified section.  */
   internal_relocs = retrieve_internal_relocs (abfd, table_section, TRUE);
   if (internal_relocs && !table_section->reloc_done)
     {
-      unsigned i;
+      qsort (internal_relocs, table_section->reloc_count,
+            sizeof (Elf_Internal_Rela), internal_reloc_compare);
+      irel = internal_relocs;
+    }
+  else
+    irel = NULL;
 
-      for (i = 0; i < table_section->reloc_count; i++)
-       {
-         Elf_Internal_Rela *rel = &internal_relocs[i];
-         unsigned long r_symndx;
+  section_limit = bfd_get_section_limit (abfd, section);
+  rel_end = internal_relocs + table_section->reloc_count;
 
-         if (ELF32_R_TYPE (rel->r_info) == R_XTENSA_NONE)
-           continue;
-
-         BFD_ASSERT (ELF32_R_TYPE (rel->r_info) == R_XTENSA_32);
-         r_symndx = ELF32_R_SYM (rel->r_info);
+  for (off = 0; off < table_size; off += table_entry_size) 
+    {
+      bfd_vma address = bfd_get_32 (abfd, table_data + off);
 
-         if (get_elf_r_symndx_section (abfd, r_symndx) == section)
-           {
-             bfd_vma sym_off = get_elf_r_symndx_offset (abfd, r_symndx);
-             BFD_ASSERT (sym_off == 0);
-             blocks[block_count].address =
-               (section_addr + sym_off + rel->r_addend
-                + bfd_get_32 (abfd, table_data + rel->r_offset));
-             blocks[block_count].size =
-               bfd_get_32 (abfd, table_data + rel->r_offset + 4);
-             if (predef_flags)
-               blocks[block_count].flags = predef_flags;
-             else
-               blocks[block_count].flags =
-                 bfd_get_32 (abfd, table_data + rel->r_offset + 8);
-             block_count++;
-           }
+      /* Skip any relocations before the current offset.  This should help
+        avoid confusion caused by unexpected relocations for the preceding
+        table entry.  */
+      while (irel &&
+            (irel->r_offset < off
+             || (irel->r_offset == off
+                 && ELF32_R_TYPE (irel->r_info) == R_XTENSA_NONE)))
+       {
+         irel += 1;
+         if (irel >= rel_end)
+           irel = 0;
        }
-    }
-  else
-    {
-      /* The file has already been relocated and the addresses are
-        already in the table.  */
-      bfd_vma off;
-      bfd_size_type section_limit = bfd_get_section_limit (abfd, section);
 
-      for (off = 0; off < table_size; off += table_entry_size) 
+      if (irel && irel->r_offset == off)
        {
-         bfd_vma address = bfd_get_32 (abfd, table_data + off);
+         bfd_vma sym_off;
+         unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
+         BFD_ASSERT (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32);
 
-         if (address >= section_addr
-             && address < section_addr + section_limit)
-           {
-             blocks[block_count].address = address;
-             blocks[block_count].size =
-               bfd_get_32 (abfd, table_data + off + 4);
-             if (predef_flags)
-               blocks[block_count].flags = predef_flags;
-             else
-               blocks[block_count].flags =
-                 bfd_get_32 (abfd, table_data + off + 8);
-             block_count++;
-           }
+         if (get_elf_r_symndx_section (abfd, r_symndx) != section)
+           continue;
+
+         sym_off = get_elf_r_symndx_offset (abfd, r_symndx);
+         BFD_ASSERT (sym_off == 0);
+         address += (section_addr + sym_off + irel->r_addend);
        }
+      else
+       {
+         if (address < section_addr
+             || address >= section_addr + section_limit)
+           continue;
+       }
+
+      blocks[block_count].address = address;
+      blocks[block_count].size = bfd_get_32 (abfd, table_data + off + 4);
+      if (predef_flags)
+       blocks[block_count].flags = predef_flags;
+      else
+       blocks[block_count].flags = bfd_get_32 (abfd, table_data + off + 8);
+      block_count++;
     }
 
   release_contents (table_section, table_data);
@@ -948,7 +944,9 @@ elf_xtensa_check_relocs (bfd *abfd,
        case R_XTENSA_GNU_VTENTRY:
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
-         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+         BFD_ASSERT (h != NULL);
+         if (h != NULL
+             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
          break;
 
@@ -961,6 +959,44 @@ elf_xtensa_check_relocs (bfd *abfd,
 }
 
 
+static void
+elf_xtensa_make_sym_local (struct bfd_link_info *info,
+                           struct elf_link_hash_entry *h)
+{
+  if (info->shared)
+    {
+      if (h->plt.refcount > 0)
+        {
+         /* For shared objects, there's no need for PLT entries for local
+            symbols (use RELATIVE relocs instead of JMP_SLOT relocs).  */
+          if (h->got.refcount < 0)
+            h->got.refcount = 0;
+          h->got.refcount += h->plt.refcount;
+          h->plt.refcount = 0;
+        }
+    }
+  else
+    {
+      /* Don't need any dynamic relocations at all.  */
+      h->plt.refcount = 0;
+      h->got.refcount = 0;
+    }
+}
+
+
+static void
+elf_xtensa_hide_symbol (struct bfd_link_info *info,
+                        struct elf_link_hash_entry *h,
+                        bfd_boolean force_local)
+{
+  /* For a shared link, move the plt refcount to the got refcount to leave
+     space for RELATIVE relocs.  */
+  elf_xtensa_make_sym_local (info, h);
+
+  _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+}
+
+
 /* Return the section that should be marked against GC for a given
    relocation.  */
 
@@ -1208,26 +1244,7 @@ elf_xtensa_allocate_dynrelocs (struct elf_link_hash_entry *h, void *arg)
   is_dynamic = elf_xtensa_dynamic_symbol_p (h, info);
 
   if (! is_dynamic)
-    {
-      if (info->shared)
-       {
-         /* For shared objects, there's no need for PLT entries for local
-            symbols (use RELATIVE relocs instead of JMP_SLOT relocs).  */
-         if (h->plt.refcount > 0)
-           {
-             if (h->got.refcount < 0)
-               h->got.refcount = 0;
-             h->got.refcount += h->plt.refcount;
-             h->plt.refcount = 0;
-           }
-       }
-      else
-       {
-         /* Don't need any dynamic relocations at all.  */
-         h->plt.refcount = 0;
-         h->got.refcount = 0;
-       }
-    }
+    elf_xtensa_make_sym_local (info, h);
 
   if (h->plt.refcount > 0)
     htab->srelplt->size += (h->plt.refcount * sizeof (Elf32_External_Rela));
@@ -2078,7 +2095,6 @@ elf_xtensa_relocate_section (bfd *output_bfd,
              if (!do_fix_for_relocatable_link (rel, input_bfd, input_section,
                                                contents))
                return FALSE;
-             r_type = ELF32_R_TYPE (rel->r_info);
            }
 
          if (r_type == R_XTENSA_ASM_SIMPLIFY)
@@ -2148,10 +2164,6 @@ elf_xtensa_relocate_section (bfd *output_bfd,
          /* Check if this references a section in another input file.  */
          do_fix_for_final_link (rel, input_bfd, input_section, contents,
                                 &relocation);
-
-         /* Update some already cached values.  */
-         r_type = ELF32_R_TYPE (rel->r_info);
-         howto = &elf_howto_table[r_type];
        }
 
       /* Sanity check the address.  */
@@ -2634,19 +2646,19 @@ elf_xtensa_finish_dynamic_sections (bfd *output_bfd,
          break;
 
        case DT_XTENSA_GOT_LOC_OFF:
-         dyn.d_un.d_ptr = htab->sgotloc->vma;
+         dyn.d_un.d_ptr = htab->sgotloc->output_section->vma;
          break;
 
        case DT_PLTGOT:
-         dyn.d_un.d_ptr = htab->sgot->vma;
+         dyn.d_un.d_ptr = htab->sgot->output_section->vma;
          break;
 
        case DT_JMPREL:
-         dyn.d_un.d_ptr = htab->srelplt->vma;
+         dyn.d_un.d_ptr = htab->srelplt->output_section->vma;
          break;
 
        case DT_PLTRELSZ:
-         dyn.d_un.d_val = htab->srelplt->size;
+         dyn.d_un.d_val = htab->srelplt->output_section->size;
          break;
 
        case DT_RELASZ:
@@ -2657,7 +2669,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->size;
+           dyn.d_un.d_val -= htab->srelplt->output_section->size;
          break;
        }
 
@@ -4763,20 +4775,45 @@ text_action_add_literal (text_action_list *l,
 }
 
 
-static bfd_vma 
-offset_with_removed_text (text_action_list *action_list, bfd_vma offset)
+/* Find the total offset adjustment for the relaxations specified by
+   text_actions, beginning from a particular starting action.  This is
+   typically used from offset_with_removed_text to search an entire list of
+   actions, but it may also be called directly when adjusting adjacent offsets
+   so that each search may begin where the previous one left off.  */
+
+static int
+removed_by_actions (text_action **p_start_action,
+                   bfd_vma offset,
+                   bfd_boolean before_fill)
 {
   text_action *r;
   int removed = 0;
 
-  for (r = action_list->head; r && r->offset <= offset; r = r->next)
+  r = *p_start_action;
+  while (r)
     {
-      if (r->offset < offset
-         || (r->action == ta_fill && r->removed_bytes < 0))
-       removed += r->removed_bytes;
+      if (r->offset > offset)
+       break;
+
+      if (r->offset == offset
+         && (before_fill || r->action != ta_fill || r->removed_bytes >= 0))
+       break;
+
+      removed += r->removed_bytes;
+
+      r = r->next;
     }
 
-  return (offset - removed);
+  *p_start_action = r;
+  return removed;
+}
+
+
+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);
 }
 
 
@@ -4793,20 +4830,6 @@ action_list_count (text_action_list *action_list)
 }
 
 
-static bfd_vma
-offset_with_removed_text_before_fill (text_action_list *action_list,
-                                     bfd_vma offset)
-{
-  text_action *r;
-  int removed = 0;
-
-  for (r = action_list->head; r && r->offset < offset; r = r->next)
-    removed += r->removed_bytes;
-
-  return (offset - removed);
-}
-
-
 /* The find_insn_action routine will only find non-fill actions.  */
 
 static text_action *
@@ -5104,7 +5127,6 @@ struct reloc_bfd_fix_struct
   bfd_vma src_offset;
   unsigned src_type;                   /* Relocation type.  */
   
-  bfd *target_abfd;
   asection *target_sec;
   bfd_vma target_offset;
   bfd_boolean translated;
@@ -5117,7 +5139,6 @@ static reloc_bfd_fix *
 reloc_bfd_fix_init (asection *src_sec,
                    bfd_vma src_offset,
                    unsigned src_type,
-                   bfd *target_abfd,
                    asection *target_sec,
                    bfd_vma target_offset,
                    bfd_boolean translated)
@@ -5128,7 +5149,6 @@ reloc_bfd_fix_init (asection *src_sec,
   fix->src_sec = src_sec;
   fix->src_offset = src_offset;
   fix->src_type = src_type;
-  fix->target_abfd = target_abfd;
   fix->target_sec = target_sec;
   fix->target_offset = target_offset;
   fix->translated = translated;
@@ -5526,7 +5546,7 @@ extend_ebb_bounds_forward (ebb_t *ebb)
 
       new_entry = &ebb->ptbl[ebb->end_ptbl_idx + 1];
       if (((new_entry->flags & XTENSA_PROP_INSN) == 0)
-         || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0)
+         || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0)
          || ((the_entry->flags & XTENSA_PROP_ALIGN) != 0))
        break;
 
@@ -5599,7 +5619,7 @@ extend_ebb_bounds_backward (ebb_t *ebb)
 
       new_entry = &ebb->ptbl[ebb->start_ptbl_idx - 1];
       if ((new_entry->flags & XTENSA_PROP_INSN) == 0
-         || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0)
+         || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0)
          || ((new_entry->flags & XTENSA_PROP_ALIGN) != 0))
        return TRUE;
       if (new_entry->address + new_entry->size != the_entry->address)
@@ -5807,7 +5827,8 @@ static bfd_boolean compute_removed_literals
 static Elf_Internal_Rela *get_irel_at_offset
   (asection *, Elf_Internal_Rela *, bfd_vma);
 static bfd_boolean is_removable_literal 
-  (const source_reloc *, int, const source_reloc *, int);
+  (const source_reloc *, int, const source_reloc *, int, asection *,
+   property_table_entry *, int);
 static bfd_boolean remove_dead_literal
   (bfd *, asection *, struct bfd_link_info *, Elf_Internal_Rela *,
    Elf_Internal_Rela *, source_reloc *, property_table_entry *, int); 
@@ -6465,7 +6486,7 @@ compute_text_actions (bfd *abfd,
          the_entry++;
        }
 
-      if (the_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM)
+      if (the_entry->flags & XTENSA_PROP_NO_TRANSFORM)
          /* NO_REORDER is OK */
        continue;
 
@@ -6658,14 +6679,14 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table)
            goto decode_error;
 
          if ((entry->flags & XTENSA_PROP_INSN_NO_DENSITY) == 0
-             && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
+             && (entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0
              && can_narrow_instruction (slotbuf, fmt, opcode) != 0)
            {
              /* Add an instruction narrow action.  */
              ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0,
                                  ta_narrow_insn, offset, 0, FALSE);
            }
-         else if ((entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
+         else if ((entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0
                   && can_widen_instruction (slotbuf, fmt, opcode) != 0
                   && ! prev_instr_is_a_loop (ebb->contents,
                                              ebb->content_length, offset))
@@ -6910,6 +6931,8 @@ compute_ebb_actions (ebb_constraint *ebb_table)
                      bad_alignment = FALSE;
                      break;
                    }
+                 if (new_action->do_action)
+                   removed_bytes += new_action->removed_bytes;
                }
              if (!bad_alignment)
                {
@@ -7415,7 +7438,8 @@ compute_removed_literals (bfd *abfd,
       /* Check if the relocation was from an L32R that is being removed
         because a CALLX was converted to a direct CALL, and check if
         there are no other relocations to the literal.  */
-      if (is_removable_literal (rel, i, src_relocs, relax_info->src_count))
+      if (is_removable_literal (rel, i, src_relocs, relax_info->src_count, 
+                               sec, prop_table, ptblsize))
        {
          if (!remove_dead_literal (abfd, sec, link_info, internal_relocs,
                                    irel, rel, prop_table, ptblsize))
@@ -7499,12 +7523,22 @@ bfd_boolean
 is_removable_literal (const source_reloc *rel,
                      int i,
                      const source_reloc *src_relocs,
-                     int src_count)
+                     int src_count,
+                     asection *sec,
+                     property_table_entry *prop_table,
+                     int ptblsize)
 {
   const source_reloc *curr_rel;
+  property_table_entry *entry;
+
   if (!rel->is_null)
     return FALSE;
   
+  entry = elf_xtensa_find_property_entry (prop_table, ptblsize, 
+                                         sec->vma + rel->r_rel.target_offset);
+  if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM))
+    return FALSE;
+
   for (++i; i < src_count; ++i)
     {
       curr_rel = &src_relocs[i];
@@ -7794,7 +7828,7 @@ coalesce_shared_literal (asection *sec,
 
   entry = elf_xtensa_find_property_entry
     (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset);
-  if (entry && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM))
+  if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM))
     return TRUE;
 
   /* Mark that the literal will be coalesced.  */
@@ -8200,7 +8234,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
              addend_displacement =
                new_reloc.target_offset + new_reloc.virtual_offset;
 
-             fix = reloc_bfd_fix_init (sec, source_offset, r_type, 0,
+             fix = reloc_bfd_fix_init (sec, source_offset, r_type,
                                        r_reloc_get_section (&new_reloc),
                                        addend_displacement, TRUE);
              add_fix (sec, fix);
@@ -8753,7 +8787,7 @@ move_literal (bfd *abfd,
 
       /* Currently, we cannot move relocations during a relocatable link.  */
       BFD_ASSERT (!link_info->relocatable);
-      fix = reloc_bfd_fix_init (sec, offset, r_type, r_rel->abfd,
+      fix = reloc_bfd_fix_init (sec, offset, r_type,
                                r_reloc_get_section (r_rel),
                                r_rel->target_offset + r_rel->virtual_offset,
                                FALSE);
@@ -8915,14 +8949,16 @@ relax_property_section (bfd *abfd,
                  || target_relax_info->is_relaxable_asm_section ))
            {
              /* Translate the relocation's destination.  */
-             bfd_vma new_offset, new_end_offset;
+             bfd_vma old_offset = val.r_rel.target_offset;
+             bfd_vma new_offset;
              long old_size, new_size;
-
-             new_offset = offset_with_removed_text
-               (&target_relax_info->action_list, val.r_rel.target_offset);
+             text_action *act = target_relax_info->action_list.head;
+             new_offset = old_offset -
+               removed_by_actions (&act, old_offset, FALSE);
 
              /* Assert that we are not out of bounds.  */
              old_size = bfd_get_32 (abfd, size_p);
+             new_size = old_size;
 
              if (old_size == 0)
                {
@@ -8934,39 +8970,34 @@ relax_property_section (bfd *abfd,
                     offset before or after the fill address depending
                     on whether the expanding unreachable entry
                     preceeds it.  */
-                 if (last_zfill_target_sec
-                     && last_zfill_target_sec == target_sec
-                     && last_zfill_target_offset == val.r_rel.target_offset)
-                   new_end_offset = new_offset;
-                 else
+                 if (last_zfill_target_sec == 0
+                     || last_zfill_target_sec != target_sec
+                     || last_zfill_target_offset != old_offset)
                    {
-                     new_end_offset = new_offset;
-                     new_offset = offset_with_removed_text_before_fill
-                       (&target_relax_info->action_list,
-                        val.r_rel.target_offset);
+                     bfd_vma new_end_offset = new_offset;
+
+                     /* Recompute the new_offset, but this time don't
+                        include any fill inserted by relaxation.  */
+                     act = target_relax_info->action_list.head;
+                     new_offset = old_offset -
+                       removed_by_actions (&act, old_offset, TRUE);
 
                      /* If it is not unreachable and we have not yet
                         seen an unreachable at this address, place it
                         before the fill address.  */
-                     if (!flags_p
-                         || (bfd_get_32 (abfd, flags_p)
-                             & XTENSA_PROP_UNREACHABLE) == 0)
-                       new_end_offset = new_offset;
-                     else
+                     if (flags_p && (bfd_get_32 (abfd, flags_p)
+                                     & XTENSA_PROP_UNREACHABLE) != 0)
                        {
+                         new_size = new_end_offset - new_offset;
+
                          last_zfill_target_sec = target_sec;
-                         last_zfill_target_offset = val.r_rel.target_offset;
+                         last_zfill_target_offset = old_offset;
                        }
                    }
                }
              else
-               {
-                 new_end_offset = offset_with_removed_text_before_fill
-                   (&target_relax_info->action_list,
-                    val.r_rel.target_offset + old_size);
-               }
-
-             new_size = new_end_offset - new_offset;
+               new_size -=
+                   removed_by_actions (&act, old_offset + old_size, TRUE);
 
              if (new_size != old_size)
                {
@@ -8974,9 +9005,9 @@ relax_property_section (bfd *abfd,
                  pin_contents (sec, contents);
                }
 
-             if (new_offset != val.r_rel.target_offset)
+             if (new_offset != old_offset)
                {
-                 bfd_vma diff = new_offset - val.r_rel.target_offset;
+                 bfd_vma diff = new_offset - old_offset;
                  irel->r_addend += diff;
                  pin_internal_relocs (sec, internal_relocs);
                }
@@ -9037,7 +9068,6 @@ relax_property_section (bfd *abfd,
                      break;
                    }
                  irel->r_offset -= removed_bytes;
-                 irel++;
                }
            }
 
@@ -9230,19 +9260,14 @@ relax_section_symbols (bfd *abfd, asection *sec)
 
       if (isym->st_shndx == sec_shndx)
        {
-         bfd_vma new_address = offset_with_removed_text
-           (&relax_info->action_list, isym->st_value);
-         bfd_vma new_size = isym->st_size;
+         text_action *act = relax_info->action_list.head;
+         bfd_vma orig_addr = isym->st_value;
 
-         if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC)
-           {
-             bfd_vma new_end = offset_with_removed_text
-               (&relax_info->action_list, isym->st_value + isym->st_size);
-             new_size = new_end - new_address;
-           }
+         isym->st_value -= removed_by_actions (&act, orig_addr, FALSE);
 
-         isym->st_value = new_address;
-         isym->st_size = new_size;
+         if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC)
+           isym->st_size -=
+             removed_by_actions (&act, orig_addr + isym->st_size, FALSE);
        }
     }
 
@@ -9260,20 +9285,15 @@ relax_section_symbols (bfd *abfd, asection *sec)
           || sym_hash->root.type == bfd_link_hash_defweak)
          && sym_hash->root.u.def.section == sec)
        {
-         bfd_vma new_address = offset_with_removed_text
-           (&relax_info->action_list, sym_hash->root.u.def.value);
-         bfd_vma new_size = sym_hash->size;
+         text_action *act = relax_info->action_list.head;
+         bfd_vma orig_addr = sym_hash->root.u.def.value;
 
-         if (sym_hash->type == STT_FUNC)
-           {
-             bfd_vma new_end = offset_with_removed_text
-               (&relax_info->action_list,
-                sym_hash->root.u.def.value + sym_hash->size);
-             new_size = new_end - new_address;
-           }
+         sym_hash->root.u.def.value -=
+           removed_by_actions (&act, orig_addr, FALSE);
 
-         sym_hash->root.u.def.value = new_address;
-         sym_hash->size = new_size;
+         if (sym_hash->type == STT_FUNC)
+           sym_hash->size -=
+             removed_by_actions (&act, orig_addr + sym_hash->size, FALSE);
        }
     }
 
@@ -9721,12 +9741,12 @@ xtensa_get_property_predef_flags (asection *sec)
 {
   if (xtensa_is_insntable_section (sec))
     return (XTENSA_PROP_INSN
-           | XTENSA_PROP_INSN_NO_TRANSFORM
+           | XTENSA_PROP_NO_TRANSFORM
            | XTENSA_PROP_INSN_NO_REORDER);
 
   if (xtensa_is_littable_section (sec))
     return (XTENSA_PROP_LITERAL
-           | XTENSA_PROP_INSN_NO_TRANSFORM
+           | XTENSA_PROP_NO_TRANSFORM
            | XTENSA_PROP_INSN_NO_REORDER);
 
   return 0;
@@ -9779,6 +9799,11 @@ xtensa_callback_required_dependence (bfd *abfd,
       (*callback) (sec, sec_size, sgotplt, 0, closure);
     }
 
+  /* Only ELF files are supported for Xtensa.  Check here to avoid a segfault
+     when building uclibc, which runs "ld -b binary /dev/null".  */
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return ok;
+
   internal_relocs = retrieve_internal_relocs (abfd, sec, 
                                              link_info->keep_memory);
   if (internal_relocs == NULL
@@ -9885,6 +9910,7 @@ static const struct bfd_elf_special_section elf_xtensa_special_sections[] =
 #define elf_backend_gc_sweep_hook           elf_xtensa_gc_sweep_hook
 #define elf_backend_grok_prstatus           elf_xtensa_grok_prstatus
 #define elf_backend_grok_psinfo                     elf_xtensa_grok_psinfo
+#define elf_backend_hide_symbol                     elf_xtensa_hide_symbol
 #define elf_backend_object_p                elf_xtensa_object_p
 #define elf_backend_reloc_type_class        elf_xtensa_reloc_type_class
 #define elf_backend_relocate_section        elf_xtensa_relocate_section