daily update
[deliverable/binutils-gdb.git] / bfd / elf32-xtensa.c
index 472ec34f48d19cc883c782d12b746e07eced40ab..bb1983025f7172b05bd3f9a6884ff9171701d8d4 100644 (file)
@@ -1,5 +1,5 @@
 /* Xtensa-specific support for 32-bit ELF.
-   Copyright 2003, 2004 Free Software Foundation, Inc.
+   Copyright 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
 
-#ifdef ANSI_PROTOTYPES
 #include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
 #include <strings.h>
 
 #include "bfdlink.h"
@@ -40,7 +36,7 @@
 /* Local helper functions.  */
 
 static bfd_boolean add_extra_plt_sections (bfd *, int);
-static char *build_encoding_error_message (xtensa_opcode, bfd_vma);
+static char *vsprint_msg (const char *, const char *, int, ...) ATTRIBUTE_PRINTF(2,4);
 static bfd_reloc_status_type bfd_elf_xtensa_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_boolean do_fix_for_relocatable_link
@@ -110,7 +106,7 @@ static bfd_boolean xtensa_is_property_section (asection *);
 static bfd_boolean xtensa_is_littable_section (asection *);
 static int internal_reloc_compare (const void *, const void *);
 static int internal_reloc_matches (const void *, const void *);
-extern char *xtensa_get_property_section_name (asection *, const char *);
+extern asection *xtensa_get_property_section (asection *, const char *);
 static flagword xtensa_get_property_predef_flags (asection *);
 
 /* Other functions called directly by the linker.  */
@@ -523,12 +519,6 @@ property_table_compare (const void *ap, const void *bp)
 
   if (a->address == b->address)
     {
-      /* The only circumstance where two entries may legitimately have the
-        same address is when one of them is a zero-size placeholder to
-        mark a place where fill can be inserted.  The zero-size entry should
-        come first.  */
-      BFD_ASSERT ((a->size == 0 || b->size == 0));
-
       if (a->size != b->size)
        return (a->size - b->size);
 
@@ -581,11 +571,10 @@ xtensa_read_table_entries (bfd *abfd,
                           bfd_boolean output_addr)
 {
   asection *table_section;
-  char *table_section_name;
   bfd_size_type table_size = 0;
   bfd_byte *table_data;
   property_table_entry *blocks;
-  int block_count;
+  int blk, block_count;
   bfd_size_type num_records;
   Elf_Internal_Rela *internal_relocs;
   bfd_vma section_addr;
@@ -600,9 +589,7 @@ xtensa_read_table_entries (bfd *abfd,
       return 0;
     }
 
-  table_section_name = xtensa_get_property_section_name (section, sec_name);
-  table_section = bfd_get_section_by_name (abfd, table_section_name);
-  free (table_section_name);
+  table_section = xtensa_get_property_section (section, sec_name);
   if (table_section)
     table_size = table_section->size;
 
@@ -650,7 +637,6 @@ xtensa_read_table_entries (bfd *abfd,
            {
              bfd_vma sym_off = get_elf_r_symndx_offset (abfd, r_symndx);
              BFD_ASSERT (sym_off == 0);
-             BFD_ASSERT (rel->r_addend == 0);
              blocks[block_count].address =
                (section_addr + sym_off + rel->r_addend
                 + bfd_get_32 (abfd, table_data + rel->r_offset));
@@ -700,6 +686,25 @@ xtensa_read_table_entries (bfd *abfd,
       /* Now sort them into address order for easy reference.  */
       qsort (blocks, block_count, sizeof (property_table_entry),
             property_table_compare);
+
+      /* Check that the table contents are valid.  Problems may occur,
+         for example, if an unrelocated object file is stripped.  */
+      for (blk = 1; blk < block_count; blk++)
+       {
+         /* The only circumstance where two entries may legitimately
+            have the same address is when one of them is a zero-size
+            placeholder to mark a place where fill can be inserted.
+            The zero-size entry should come first.  */
+         if (blocks[blk - 1].address == blocks[blk].address &&
+             blocks[blk - 1].size != 0)
+           {
+             (*_bfd_error_handler) (_("%B(%A): invalid property table"),
+                                    abfd, section);
+             bfd_set_error (bfd_error_bad_value);
+             free (blocks);
+             return -1;
+           }
+       }
     }
 
   *table_p = blocks;
@@ -961,38 +966,20 @@ elf_xtensa_hide_symbol (struct bfd_link_info *info,
 
 static asection *
 elf_xtensa_gc_mark_hook (asection *sec,
-                        struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                        struct bfd_link_info *info,
                         Elf_Internal_Rela *rel,
                         struct elf_link_hash_entry *h,
                         Elf_Internal_Sym *sym)
 {
-  if (h)
-    {
-      switch (ELF32_R_TYPE (rel->r_info))
-       {
-       case R_XTENSA_GNU_VTINHERIT:
-       case R_XTENSA_GNU_VTENTRY:
-         break;
-
-       default:
-         switch (h->root.type)
-           {
-           case bfd_link_hash_defined:
-           case bfd_link_hash_defweak:
-             return h->root.u.def.section;
-
-           case bfd_link_hash_common:
-             return h->root.u.c.p->section;
-
-           default:
-             break;
-           }
-       }
-    }
-  else
-    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+  if (h != NULL)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_XTENSA_GNU_VTINHERIT:
+      case R_XTENSA_GNU_VTENTRY:
+       return NULL;
+      }
 
-  return NULL;
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
 
 
@@ -1026,7 +1013,12 @@ elf_xtensa_gc_sweep_hook (bfd *abfd,
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+       }
 
       r_type = ELF32_R_TYPE (rel->r_info);
       switch (r_type)
@@ -1087,23 +1079,21 @@ elf_xtensa_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   /* Create ".rela.got".  */
-  s = bfd_make_section (dynobj, ".rela.got");
+  s = bfd_make_section_with_flags (dynobj, ".rela.got", flags);
   if (s == NULL
-      || ! bfd_set_section_flags (dynobj, s, flags)
       || ! bfd_set_section_alignment (dynobj, s, 2))
     return FALSE;
 
   /* Create ".got.loc" (literal tables for use by dynamic linker).  */
-  s = bfd_make_section (dynobj, ".got.loc");
+  s = bfd_make_section_with_flags (dynobj, ".got.loc", flags);
   if (s == NULL
-      || ! bfd_set_section_flags (dynobj, s, flags)
       || ! bfd_set_section_alignment (dynobj, s, 2))
     return FALSE;
 
   /* Create ".xt.lit.plt" (literal table for ".got.plt*").  */
-  s = bfd_make_section (dynobj, ".xt.lit.plt");
+  s = bfd_make_section_with_flags (dynobj, ".xt.lit.plt",
+                                  noalloc_flags);
   if (s == NULL
-      || ! bfd_set_section_flags (dynobj, s, noalloc_flags)
       || ! bfd_set_section_alignment (dynobj, s, 2))
     return FALSE;
 
@@ -1133,17 +1123,15 @@ add_extra_plt_sections (bfd *dynobj, int count)
 
       sname = (char *) bfd_malloc (10);
       sprintf (sname, ".plt.%u", chunk);
-      s = bfd_make_section (dynobj, sname);
+      s = bfd_make_section_with_flags (dynobj, sname, flags | SEC_CODE);
       if (s == NULL
-         || ! bfd_set_section_flags (dynobj, s, flags | SEC_CODE)
          || ! bfd_set_section_alignment (dynobj, s, 2))
        return FALSE;
 
       sname = (char *) bfd_malloc (14);
       sprintf (sname, ".got.plt.%u", chunk);
-      s = bfd_make_section (dynobj, sname);
+      s = bfd_make_section_with_flags (dynobj, sname, flags);
       if (s == NULL
-         || ! bfd_set_section_flags (dynobj, s, flags)
          || ! bfd_set_section_alignment (dynobj, s, 2))
        return FALSE;
     }
@@ -1394,7 +1382,6 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
-      bfd_boolean strip;
 
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
@@ -1403,37 +1390,23 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
         of the dynobj section names depend upon the input files.  */
       name = bfd_get_section_name (dynobj, s);
 
-      strip = FALSE;
-
-      if (strncmp (name, ".rela", 5) == 0)
-       {
-         if (strcmp (name, ".rela.plt") == 0)
-           relplt = TRUE;
-         else if (strcmp (name, ".rela.got") == 0)
-           relgot = TRUE;
-
-         /* We use the reloc_count field as a counter if we need
-            to copy relocs into the output file.  */
-         s->reloc_count = 0;
-       }
-      else if (strncmp (name, ".plt.", 5) == 0
-              || strncmp (name, ".got.plt.", 9) == 0)
+      if (CONST_STRNEQ (name, ".rela"))
        {
-         if (s->size == 0)
+         if (s->size != 0)
            {
-             /* If we don't need this section, strip it from the output
-                file.  We must create the ".plt*" and ".got.plt*"
-                sections in create_dynamic_sections and/or check_relocs
-                based on a conservative estimate of the PLT relocation
-                count, because the sections must be created before the
-                linker maps input sections to output sections.  The
-                linker does that before size_dynamic_sections, where we
-                compute the exact size of the PLT, so there may be more
-                of these sections than are actually needed.  */
-             strip = TRUE;
+             if (strcmp (name, ".rela.plt") == 0)
+               relplt = TRUE;
+             else if (strcmp (name, ".rela.got") == 0)
+               relgot = TRUE;
+
+             /* We use the reloc_count field as a counter if we need
+                to copy relocs into the output file.  */
+             s->reloc_count = 0;
            }
        }
-      else if (strcmp (name, ".got") != 0
+      else if (! CONST_STRNEQ (name, ".plt.")
+              && ! CONST_STRNEQ (name, ".got.plt.")
+              && strcmp (name, ".got") != 0
               && strcmp (name, ".plt") != 0
               && strcmp (name, ".got.plt") != 0
               && strcmp (name, ".xt.lit.plt") != 0
@@ -1443,13 +1416,24 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          continue;
        }
 
-      if (strip)
-       _bfd_strip_section_from_output (info, s);
-      else
+      if (s->size == 0)
+       {
+         /* If we don't need this section, strip it from the output
+            file.  We must create the ".plt*" and ".got.plt*"
+            sections in create_dynamic_sections and/or check_relocs
+            based on a conservative estimate of the PLT relocation
+            count, because the sections must be created before the
+            linker maps input sections to output sections.  The
+            linker does that before size_dynamic_sections, where we
+            compute the exact size of the PLT, so there may be more
+            of these sections than are actually needed.  */
+         s->flags |= SEC_EXCLUDE;
+       }
+      else if ((s->flags & SEC_HAS_CONTENTS) != 0)
        {
          /* Allocate memory for the section contents.  */
          s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
-         if (s->contents == NULL && s->size != 0)
+         if (s->contents == NULL)
            return FALSE;
        }
     }
@@ -1486,7 +1470,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->shared)
+      if (info->executable)
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -1518,31 +1502,6 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
-\f
-/* Remove any PT_LOAD segments with no allocated sections.  Prior to
-   binutils 2.13, this function used to remove the non-SEC_ALLOC
-   sections from PT_LOAD segments, but that task has now been moved
-   into elf.c.  We still need this function to remove any empty
-   segments that result, but there's nothing Xtensa-specific about
-   this and it probably ought to be moved into elf.c as well.  */
-
-static bfd_boolean
-elf_xtensa_modify_segment_map (bfd *abfd,
-                              struct bfd_link_info *info ATTRIBUTE_UNUSED)
-{
-  struct elf_segment_map **m_p;
-
-  m_p = &elf_tdata (abfd)->segment_map;
-  while (*m_p)
-    {
-      if ((*m_p)->p_type == PT_LOAD && (*m_p)->count == 0)
-       *m_p = (*m_p)->next;
-      else
-       m_p = &(*m_p)->next;
-    }
-  return TRUE;
-}
-
 \f
 /* Perform the specified relocation.  The instruction at (contents + address)
    is modified to set one operand to represent the value in "relocation".  The
@@ -1735,7 +1694,30 @@ elf_xtensa_do_reloc (reloc_howto_type *howto,
       || xtensa_operand_set_field (isa, opcode, opnd, fmt, slot,
                                   sbuff, newval))
     {
-      *error_message = build_encoding_error_message (opcode, relocation);
+      const char *opname = xtensa_opcode_name (isa, opcode);
+      const char *msg;
+
+      msg = "cannot encode";
+      if (is_direct_call_opcode (opcode))
+       {
+         if ((relocation & 0x3) != 0)
+           msg = "misaligned call target";
+         else
+           msg = "call target out of range";
+       }
+      else if (opcode == get_l32r_opcode ())
+       {
+         if ((relocation & 0x3) != 0)
+           msg = "misaligned literal target";
+         else if (is_alt_relocation (howto->type))
+           msg = "literal target out of range (too many literals)";
+         else if (self_address > relocation)
+           msg = "literal target out of range (try using text-section-literals)";
+         else
+           msg = "literal placed after use";
+       }
+
+      *error_message = vsprint_msg (opname, ": %s", strlen (msg) + 2, msg);
       return bfd_reloc_dangerous;
     }
 
@@ -1790,32 +1772,6 @@ vsprint_msg (const char *origmsg, const char *fmt, int arglen, ...)
 }
 
 
-static char *
-build_encoding_error_message (xtensa_opcode opcode, bfd_vma target_address)
-{
-  const char *opname = xtensa_opcode_name (xtensa_default_isa, opcode);
-  const char *msg;
-
-  msg = "cannot encode";
-  if (is_direct_call_opcode (opcode))
-    {
-      if ((target_address & 0x3) != 0)
-       msg = "misaligned call target";
-      else
-       msg = "call target out of range";
-    }
-  else if (opcode == get_l32r_opcode ())
-    {
-      if ((target_address & 0x3) != 0)
-       msg = "misaligned literal target";
-      else
-       msg = "literal target out of range";
-    }
-
-  return vsprint_msg (opname, ": %s", strlen (msg) + 2, msg);
-}
-
-
 /* This function is registered as the "special_function" in the
    Xtensa howto for handling simplify operations.
    bfd_perform_relocation / bfd_install_relocation use it to
@@ -1840,6 +1796,9 @@ bfd_elf_xtensa_reloc (bfd *abfd,
   asection *reloc_target_output_section;
   bfd_boolean is_weak_undef;
 
+  if (!xtensa_default_isa)
+    xtensa_default_isa = xtensa_isa_init (0, 0);
+
   /* ELF relocs are against symbols.  If we are producing relocatable
      output, and the reloc is against an external symbol, the resulting
      reloc will also be against the same symbol.  In such a case, we
@@ -1920,7 +1879,8 @@ bfd_elf_xtensa_reloc (bfd *abfd,
        *error_message = "";
       *error_message = vsprint_msg (*error_message, ": (%s + 0x%lx)",
                                    strlen (symbol->name) + 17,
-                                   symbol->name, reloc_entry->addend);
+                                   symbol->name,
+                                   (unsigned long) reloc_entry->addend);
     }
 
   return flag;
@@ -2299,12 +2259,26 @@ elf_xtensa_relocate_section (bfd *output_bfd,
       if (unresolved_reloc
          && !((input_section->flags & SEC_DEBUGGING) != 0
               && h->def_dynamic))
-       (*_bfd_error_handler)
-         (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
-          input_bfd,
-          input_section,
-          (long) rel->r_offset,
-          h->root.root.string);
+       {
+         (*_bfd_error_handler)
+           (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
+            input_bfd,
+            input_section,
+            (long) rel->r_offset,
+            howto->name,
+            h->root.root.string);
+         return FALSE;
+       }
+
+      if (r_symndx == 0)
+       {
+         /* r_symndx will be zero only for relocs against symbols from
+            removed linkonce sections, or sections discarded by a linker
+            script.  For these relocs, we just want the section contents
+            zeroed.  Avoid any special processing.  */
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         continue;
+       }
 
       /* There's no point in calling bfd_perform_relocation here.
         Just go directly to our "special function".  */
@@ -2337,7 +2311,7 @@ elf_xtensa_relocate_section (bfd *output_bfd,
              else
                error_message = vsprint_msg (error_message, ": (%s+0x%x)",
                                             strlen (name) + 22,
-                                            name, rel->r_addend);
+                                            name, (int)rel->r_addend);
            }
 
          if (!((*info->callbacks->reloc_dangerous)
@@ -2365,17 +2339,22 @@ elf_xtensa_finish_dynamic_symbol (bfd *output_bfd ATTRIBUTE_UNUSED,
                                  struct elf_link_hash_entry *h,
                                  Elf_Internal_Sym *sym)
 {
-  if (h->needs_plt
-      && !h->def_regular)
+  if (h->needs_plt && !h->def_regular)
     {
       /* Mark the symbol as undefined, rather than as defined in
         the .plt section.  Leave the value alone.  */
       sym->st_shndx = SHN_UNDEF;
+      /* If the symbol is weak, we do need to clear the value.
+        Otherwise, the PLT entry would provide a definition for
+        the symbol even if the symbol wasn't defined anywhere,
+        and so the symbol would never be NULL.  */
+      if (!h->ref_regular_nonweak)
+       sym->st_value = 0;
     }
 
   /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+      || h == elf_hash_table (info)->hgot)
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -3000,6 +2979,19 @@ elf_xtensa_ignore_discarded_relocs (asection *sec)
   return xtensa_is_property_section (sec);
 }
 
+
+static unsigned int
+elf_xtensa_action_discarded (asection *sec)
+{
+  if (strcmp (".xt_except_table", sec->name) == 0)
+    return 0;
+
+  if (strcmp (".xt_except_desc", sec->name) == 0)
+    return 0;
+
+  return _bfd_elf_default_action_discarded (sec);
+}
+
 \f
 /* Support for core dump NOTE sections.  */
 
@@ -3425,24 +3417,23 @@ check_loop_aligned (bfd_byte *contents,
                    bfd_vma address)
 {
   bfd_size_type loop_len, insn_len;
-  xtensa_opcode opcode =
-    insn_decode_opcode (contents, content_length, offset, 0);
-  BFD_ASSERT (opcode != XTENSA_UNDEFINED);
-  if (opcode != XTENSA_UNDEFINED)
-    return FALSE;
-  BFD_ASSERT (xtensa_opcode_is_loop (xtensa_default_isa, opcode));
-  if (!xtensa_opcode_is_loop (xtensa_default_isa, opcode))
-    return FALSE;
+  xtensa_opcode opcode;
 
+  opcode = insn_decode_opcode (contents, content_length, offset, 0);
+  if (opcode == XTENSA_UNDEFINED
+      || xtensa_opcode_is_loop (xtensa_default_isa, opcode) != 1)
+    {
+      BFD_ASSERT (FALSE);
+      return FALSE;
+    }
+  
   loop_len = insn_decode_len (contents, content_length, offset);
-  BFD_ASSERT (loop_len != 0);
-  if (loop_len == 0)
-    return FALSE;
-
   insn_len = insn_decode_len (contents, content_length, offset + loop_len);
-  BFD_ASSERT (insn_len != 0);
-  if (insn_len == 0)
-    return FALSE;
+  if (loop_len == 0 || insn_len == 0)
+    {
+      BFD_ASSERT (FALSE);
+      return FALSE;
+    }
 
   return check_branch_target_aligned_address (address + loop_len, insn_len);
 }
@@ -3554,60 +3545,31 @@ struct string_pair widenable[] =
 };
 
 
-/* Attempt to narrow an instruction.  Return true if the narrowing is
-   valid.  If the do_it parameter is non-zero, then perform the action
-   in-place directly into the contents.  Otherwise, do not modify the
-   contents.  The set of valid narrowing are specified by a string table
+/* Check if an instruction can be "narrowed", i.e., changed from a standard
+   3-byte instruction to a 2-byte "density" instruction.  If it is valid,
+   return the instruction buffer holding the narrow instruction.  Otherwise,
+   return 0.  The set of valid narrowing are specified by a string table
    but require some special case operand checks in some cases.  */
 
-static bfd_boolean
-narrow_instruction (bfd_byte *contents,
-                   bfd_size_type content_length,
-                   bfd_size_type offset,
-                   bfd_boolean do_it)
+static xtensa_insnbuf
+can_narrow_instruction (xtensa_insnbuf slotbuf,
+                       xtensa_format fmt,
+                       xtensa_opcode opcode)
 {
-  xtensa_opcode opcode;
-  bfd_size_type insn_len, opi;
   xtensa_isa isa = xtensa_default_isa;
-  xtensa_format fmt, o_fmt;
+  xtensa_format o_fmt;
+  unsigned opi;
 
-  static xtensa_insnbuf insnbuf = NULL;
-  static xtensa_insnbuf slotbuf = NULL;
   static xtensa_insnbuf o_insnbuf = NULL;
   static xtensa_insnbuf o_slotbuf = NULL;
 
-  if (insnbuf == NULL)
+  if (o_insnbuf == NULL)
     {
-      insnbuf = xtensa_insnbuf_alloc (isa);
-      slotbuf = xtensa_insnbuf_alloc (isa);
       o_insnbuf = xtensa_insnbuf_alloc (isa);
       o_slotbuf = xtensa_insnbuf_alloc (isa);
     }
 
-  BFD_ASSERT (offset < content_length);
-
-  if (content_length < 2)
-    return FALSE;
-
-  /* We will hand-code a few of these for a little while.
-     These have all been specified in the assembler aleady.  */
-  xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset],
-                            content_length - offset);
-  fmt = xtensa_format_decode (isa, insnbuf);
-  if (xtensa_format_num_slots (isa, fmt) != 1)
-    return FALSE;
-
-  if (xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf) != 0)
-    return FALSE;
-
-  opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf);
-  if (opcode == XTENSA_UNDEFINED)
-    return FALSE;
-  insn_len = xtensa_format_length (isa, fmt);
-  if (insn_len > content_length)
-    return FALSE;
-
-  for (opi = 0; opi < (sizeof (narrowable)/sizeof (struct string_pair)); ++opi)
+  for (opi = 0; opi < (sizeof (narrowable)/sizeof (struct string_pair)); opi++)
     {
       bfd_boolean is_or = (strcmp ("or", narrowable[opi].wide) == 0);
 
@@ -3623,47 +3585,41 @@ narrow_instruction (bfd_byte *contents,
 
          o_opcode = xtensa_opcode_lookup (isa, narrowable[opi].narrow);
          if (o_opcode == XTENSA_UNDEFINED)
-           return FALSE;
+           return 0;
          o_fmt = get_single_format (o_opcode);
          if (o_fmt == XTENSA_UNDEFINED)
-           return FALSE;
+           return 0;
 
          if (xtensa_format_length (isa, fmt) != 3
              || xtensa_format_length (isa, o_fmt) != 2)
-           return FALSE;
+           return 0;
 
          xtensa_format_encode (isa, o_fmt, o_insnbuf);
          operand_count = xtensa_opcode_num_operands (isa, opcode);
          o_operand_count = xtensa_opcode_num_operands (isa, o_opcode);
 
          if (xtensa_opcode_encode (isa, o_fmt, 0, o_slotbuf, o_opcode) != 0)
-           return FALSE;
+           return 0;
 
          if (!is_or)
            {
              if (xtensa_opcode_num_operands (isa, o_opcode) != operand_count)
-               return FALSE;
+               return 0;
            }
          else
            {
              uint32 rawval0, rawval1, rawval2;
 
-             if (o_operand_count + 1 != operand_count)
-               return FALSE;
-             if (xtensa_operand_get_field (isa, opcode, 0,
-                                           fmt, 0, slotbuf, &rawval0) != 0)
-               return FALSE;
-             if (xtensa_operand_get_field (isa, opcode, 1,
-                                           fmt, 0, slotbuf, &rawval1) != 0)
-               return FALSE;
-             if (xtensa_operand_get_field (isa, opcode, 2,
-                                           fmt, 0, slotbuf, &rawval2) != 0)
-               return FALSE;
-
-             if (rawval1 != rawval2)
-               return FALSE;
-             if (rawval0 == rawval1) /* it is a nop */
-               return FALSE;
+             if (o_operand_count + 1 != operand_count
+                 || xtensa_operand_get_field (isa, opcode, 0,
+                                              fmt, 0, slotbuf, &rawval0) != 0
+                 || xtensa_operand_get_field (isa, opcode, 1,
+                                              fmt, 0, slotbuf, &rawval1) != 0
+                 || xtensa_operand_get_field (isa, opcode, 2,
+                                              fmt, 0, slotbuf, &rawval2) != 0
+                 || rawval1 != rawval2
+                 || rawval0 == rawval1 /* it is a nop */)
+               return 0;
            }
 
          for (i = 0; i < o_operand_count; ++i)
@@ -3671,7 +3627,7 @@ narrow_instruction (bfd_byte *contents,
              if (xtensa_operand_get_field (isa, opcode, i, fmt, 0,
                                            slotbuf, &value)
                  || xtensa_operand_decode (isa, opcode, i, &value))
-               return FALSE;
+               return 0;
 
              /* PC-relative branches need adjustment, but
                 the PC-rel operand will always have a relocation.  */
@@ -3681,52 +3637,41 @@ narrow_instruction (bfd_byte *contents,
                  || xtensa_operand_encode (isa, o_opcode, i, &newval)
                  || xtensa_operand_set_field (isa, o_opcode, i, o_fmt, 0,
                                               o_slotbuf, newval))
-               return FALSE;
+               return 0;
            }
 
-         if (xtensa_format_set_slot (isa, o_fmt, 0,
-                                     o_insnbuf, o_slotbuf) != 0)
-           return FALSE;
+         if (xtensa_format_set_slot (isa, o_fmt, 0, o_insnbuf, o_slotbuf))
+           return 0;
 
-         if (do_it)
-           xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset,
-                                    content_length - offset);
-         return TRUE;
+         return o_insnbuf;
        }
     }
-  return FALSE;
+  return 0;
 }
 
 
-/* Attempt to widen an instruction.  Return true if the widening is
-   valid.  If the do_it parameter is non-zero, then the action should
-   be performed inplace into the contents.  Otherwise, do not modify
-   the contents.  The set of valid widenings are specified by a string
-   table but require some special case operand checks in some
-   cases.  */
+/* Attempt to narrow an instruction.  If the narrowing is valid, perform
+   the action in-place directly into the contents and return TRUE.  Otherwise,
+   the return value is FALSE and the contents are not modified.  */
 
 static bfd_boolean
-widen_instruction (bfd_byte *contents,
-                  bfd_size_type content_length,
-                  bfd_size_type offset,
-                  bfd_boolean do_it)
+narrow_instruction (bfd_byte *contents,
+                   bfd_size_type content_length,
+                   bfd_size_type offset)
 {
   xtensa_opcode opcode;
-  bfd_size_type insn_len, opi;
+  bfd_size_type insn_len;
   xtensa_isa isa = xtensa_default_isa;
-  xtensa_format fmt, o_fmt;
+  xtensa_format fmt;
+  xtensa_insnbuf o_insnbuf;
 
   static xtensa_insnbuf insnbuf = NULL;
   static xtensa_insnbuf slotbuf = NULL;
-  static xtensa_insnbuf o_insnbuf = NULL;
-  static xtensa_insnbuf o_slotbuf = NULL;
 
   if (insnbuf == NULL)
     {
       insnbuf = xtensa_insnbuf_alloc (isa);
       slotbuf = xtensa_insnbuf_alloc (isa);
-      o_insnbuf = xtensa_insnbuf_alloc (isa);
-      o_slotbuf = xtensa_insnbuf_alloc (isa);
     }
 
   BFD_ASSERT (offset < content_length);
@@ -3734,7 +3679,7 @@ widen_instruction (bfd_byte *contents,
   if (content_length < 2)
     return FALSE;
 
-  /* We will hand code a few of these for a little while.
+  /* We will hand-code a few of these for a little while.
      These have all been specified in the assembler aleady.  */
   xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset],
                             content_length - offset);
@@ -3752,7 +3697,43 @@ widen_instruction (bfd_byte *contents,
   if (insn_len > content_length)
     return FALSE;
 
-  for (opi = 0; opi < (sizeof (widenable)/sizeof (struct string_pair)); ++opi)
+  o_insnbuf = can_narrow_instruction (slotbuf, fmt, opcode);
+  if (o_insnbuf)
+    {
+      xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset,
+                              content_length - offset);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+/* Check if an instruction can be "widened", i.e., changed from a 2-byte
+   "density" instruction to a standard 3-byte instruction.  If it is valid,
+   return the instruction buffer holding the wide instruction.  Otherwise,
+   return 0.  The set of valid widenings are specified by a string table
+   but require some special case operand checks in some cases.  */
+
+static xtensa_insnbuf
+can_widen_instruction (xtensa_insnbuf slotbuf,
+                      xtensa_format fmt,
+                      xtensa_opcode opcode)
+{
+  xtensa_isa isa = xtensa_default_isa;
+  xtensa_format o_fmt;
+  unsigned opi;
+
+  static xtensa_insnbuf o_insnbuf = NULL;
+  static xtensa_insnbuf o_slotbuf = NULL;
+
+  if (o_insnbuf == NULL)
+    {
+      o_insnbuf = xtensa_insnbuf_alloc (isa);
+      o_slotbuf = xtensa_insnbuf_alloc (isa);
+    }
+
+  for (opi = 0; opi < (sizeof (widenable)/sizeof (struct string_pair)); opi++)
     {
       bfd_boolean is_or = (strcmp ("or", widenable[opi].wide) == 0);
       bfd_boolean is_branch = (strcmp ("beqz", widenable[opi].wide) == 0
@@ -3770,14 +3751,14 @@ widen_instruction (bfd_byte *contents,
 
          o_opcode = xtensa_opcode_lookup (isa, widenable[opi].wide);
          if (o_opcode == XTENSA_UNDEFINED)
-           return FALSE;
+           return 0;
          o_fmt = get_single_format (o_opcode);
          if (o_fmt == XTENSA_UNDEFINED)
-           return FALSE;
+           return 0;
 
          if (xtensa_format_length (isa, fmt) != 2
              || xtensa_format_length (isa, o_fmt) != 3)
-           return FALSE;
+           return 0;
 
          xtensa_format_encode (isa, o_fmt, o_insnbuf);
          operand_count = xtensa_opcode_num_operands (isa, opcode);
@@ -3785,32 +3766,29 @@ widen_instruction (bfd_byte *contents,
          check_operand_count = o_operand_count;
 
          if (xtensa_opcode_encode (isa, o_fmt, 0, o_slotbuf, o_opcode) != 0)
-           return FALSE;
+           return 0;
 
          if (!is_or)
            {
              if (xtensa_opcode_num_operands (isa, o_opcode) != operand_count)
-               return FALSE;
+               return 0;
            }
          else
            {
              uint32 rawval0, rawval1;
 
-             if (o_operand_count != operand_count + 1)
-               return FALSE;
-             if (xtensa_operand_get_field (isa, opcode, 0,
-                                           fmt, 0, slotbuf, &rawval0) != 0)
-               return FALSE;
-             if (xtensa_operand_get_field (isa, opcode, 1,
-                                           fmt, 0, slotbuf, &rawval1) != 0)
-               return FALSE;
-             if (rawval0 == rawval1) /* it is a nop */
-               return FALSE;
+             if (o_operand_count != operand_count + 1
+                 || xtensa_operand_get_field (isa, opcode, 0,
+                                              fmt, 0, slotbuf, &rawval0) != 0
+                 || xtensa_operand_get_field (isa, opcode, 1,
+                                              fmt, 0, slotbuf, &rawval1) != 0
+                 || rawval0 == rawval1 /* it is a nop */)
+               return 0;
            }
          if (is_branch)
            check_operand_count--;
 
-         for (i = 0; i < check_operand_count; ++i)
+         for (i = 0; i < check_operand_count; i++)
            {
              int new_i = i;
              if (is_or && i == o_operand_count - 1)
@@ -3818,7 +3796,7 @@ widen_instruction (bfd_byte *contents,
              if (xtensa_operand_get_field (isa, opcode, new_i, fmt, 0,
                                            slotbuf, &value)
                  || xtensa_operand_decode (isa, opcode, new_i, &value))
-               return FALSE;
+               return 0;
 
              /* PC-relative branches need adjustment, but
                 the PC-rel operand will always have a relocation.  */
@@ -3828,18 +3806,73 @@ widen_instruction (bfd_byte *contents,
                  || xtensa_operand_encode (isa, o_opcode, i, &newval)
                  || xtensa_operand_set_field (isa, o_opcode, i, o_fmt, 0,
                                               o_slotbuf, newval))
-               return FALSE;
+               return 0;
            }
 
          if (xtensa_format_set_slot (isa, o_fmt, 0, o_insnbuf, o_slotbuf))
-           return FALSE;
+           return 0;
 
-         if (do_it)
-           xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset,
-                                    content_length - offset);
-         return TRUE;
+         return o_insnbuf;
        }
     }
+  return 0;
+}
+
+                      
+/* Attempt to widen an instruction.  If the widening is valid, perform
+   the action in-place directly into the contents and return TRUE.  Otherwise,
+   the return value is FALSE and the contents are not modified.  */
+
+static bfd_boolean
+widen_instruction (bfd_byte *contents,
+                  bfd_size_type content_length,
+                  bfd_size_type offset)
+{
+  xtensa_opcode opcode;
+  bfd_size_type insn_len;
+  xtensa_isa isa = xtensa_default_isa;
+  xtensa_format fmt;
+  xtensa_insnbuf o_insnbuf;
+
+  static xtensa_insnbuf insnbuf = NULL;
+  static xtensa_insnbuf slotbuf = NULL;
+
+  if (insnbuf == NULL)
+    {
+      insnbuf = xtensa_insnbuf_alloc (isa);
+      slotbuf = xtensa_insnbuf_alloc (isa);
+    }
+
+  BFD_ASSERT (offset < content_length);
+
+  if (content_length < 2)
+    return FALSE;
+
+  /* We will hand-code a few of these for a little while.
+     These have all been specified in the assembler aleady.  */
+  xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset],
+                            content_length - offset);
+  fmt = xtensa_format_decode (isa, insnbuf);
+  if (xtensa_format_num_slots (isa, fmt) != 1)
+    return FALSE;
+
+  if (xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf) != 0)
+    return FALSE;
+
+  opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf);
+  if (opcode == XTENSA_UNDEFINED)
+    return FALSE;
+  insn_len = xtensa_format_length (isa, fmt);
+  if (insn_len > content_length)
+    return FALSE;
+
+  o_insnbuf = can_widen_instruction (slotbuf, fmt, opcode);
+  if (o_insnbuf)
+    {
+      xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset,
+                              content_length - offset);
+      return TRUE;
+    }
   return FALSE;
 }
 
@@ -4453,7 +4486,7 @@ literal_value_hash (const literal_value *src)
        sec_or_hash = r_reloc_get_section (&src->r_rel);
       else
        sec_or_hash = r_reloc_get_hash_entry (&src->r_rel);
-      hash_val += hash_bfd_vma ((bfd_vma) (unsigned) sec_or_hash);
+      hash_val += hash_bfd_vma ((bfd_vma) (size_t) sec_or_hash);
     }
   return hash_val;
 }
@@ -4747,6 +4780,19 @@ offset_with_removed_text (text_action_list *action_list, bfd_vma offset)
 }
 
 
+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;
+}
+
+
 static bfd_vma
 offset_with_removed_text_before_fill (text_action_list *action_list,
                                      bfd_vma offset)
@@ -4986,13 +5032,16 @@ struct elf_xtensa_section_data
 static bfd_boolean
 elf_xtensa_new_section_hook (bfd *abfd, asection *sec)
 {
-  struct elf_xtensa_section_data *sdata;
-  bfd_size_type amt = sizeof (*sdata);
+  if (!sec->used_by_bfd)
+    {
+      struct elf_xtensa_section_data *sdata;
+      bfd_size_type amt = sizeof (*sdata);
 
-  sdata = (struct elf_xtensa_section_data *) bfd_zalloc (abfd, amt);
-  if (sdata == NULL)
-    return FALSE;
-  sec->used_by_bfd = (void *) sdata;
+      sdata = bfd_zalloc (abfd, amt);
+      if (sdata == NULL)
+       return FALSE;
+      sec->used_by_bfd = sdata;
+    }
 
   return _bfd_elf_new_section_hook (abfd, sec);
 }
@@ -5586,8 +5635,8 @@ insn_block_decodable_len (bfd_byte *contents,
 
 static void
 ebb_propose_action (ebb_constraint *c,
-                   bfd_vma alignment_pow,
                    enum ebb_target_enum align_type,
+                   bfd_vma alignment_pow,
                    text_action_t action,
                    bfd_vma offset,
                    int removed_bytes,
@@ -5745,7 +5794,8 @@ static bfd_boolean compute_text_actions
 static bfd_boolean compute_ebb_proposed_actions (ebb_constraint *);
 static bfd_boolean compute_ebb_actions (ebb_constraint *);
 static bfd_boolean check_section_ebb_pcrels_fit
-  (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, const ebb_constraint *);
+  (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, const ebb_constraint *,
+   const xtensa_opcode *);
 static bfd_boolean check_section_ebb_reduces (const ebb_constraint *);
 static void text_action_add_proposed
   (text_action_list *, const ebb_constraint *, asection *);
@@ -6281,6 +6331,24 @@ find_associated_l32r_irel (bfd *abfd,
 }
 
 
+static xtensa_opcode *
+build_reloc_opcodes (bfd *abfd,
+                    asection *sec,
+                    bfd_byte *contents,
+                    Elf_Internal_Rela *internal_relocs)
+{
+  unsigned i;
+  xtensa_opcode *reloc_opcodes =
+    (xtensa_opcode *) bfd_malloc (sizeof (xtensa_opcode) * sec->reloc_count);
+  for (i = 0; i < sec->reloc_count; i++)
+    {
+      Elf_Internal_Rela *irel = &internal_relocs[i];
+      reloc_opcodes[i] = get_relocation_opcode (abfd, sec, contents, irel);
+    }
+  return reloc_opcodes;
+}
+
+
 /* The compute_text_actions function will build a list of potential
    transformation actions for code in the extended basic block of each
    longcall that is optimized to a direct call.  From this list we
@@ -6297,6 +6365,7 @@ compute_text_actions (bfd *abfd,
                      asection *sec,
                      struct bfd_link_info *link_info)
 {
+  xtensa_opcode *reloc_opcodes = NULL;
   xtensa_relax_info *relax_info;
   bfd_byte *contents;
   Elf_Internal_Rela *internal_relocs;
@@ -6402,11 +6471,17 @@ compute_text_actions (bfd *abfd,
       ebb->start_reloc_idx = i;
       ebb->end_reloc_idx = i;
 
+      /* Precompute the opcode for each relocation.  */
+      if (reloc_opcodes == NULL)
+       reloc_opcodes = build_reloc_opcodes (abfd, sec, contents,
+                                            internal_relocs);
+
       if (!extend_ebb_bounds (ebb)
          || !compute_ebb_proposed_actions (&ebb_table)
          || !compute_ebb_actions (&ebb_table)
          || !check_section_ebb_pcrels_fit (abfd, sec, contents,
-                                           internal_relocs, &ebb_table)
+                                           internal_relocs, &ebb_table,
+                                           reloc_opcodes)
          || !check_section_ebb_reduces (&ebb_table))
        {
          /* If anything goes wrong or we get unlucky and something does
@@ -6438,11 +6513,30 @@ error_return:
   release_internal_relocs (sec, internal_relocs);
   if (prop_table)
     free (prop_table);
+  if (reloc_opcodes)
+    free (reloc_opcodes);
 
   return ok;
 }
 
 
+/* Do not widen an instruction if it is preceeded by a
+   loop opcode.  It might cause misalignment.  */
+
+static bfd_boolean
+prev_instr_is_a_loop (bfd_byte *contents,
+                     bfd_size_type content_length,
+                     bfd_size_type offset)
+{
+  xtensa_opcode prev_opcode;
+
+  if (offset < 3)
+    return FALSE;
+  prev_opcode = insn_decode_opcode (contents, content_length, offset-3, 0);
+  return (xtensa_opcode_is_loop (xtensa_default_isa, prev_opcode) == 1);
+} 
+
+
 /* Find all of the possible actions for an extended basic block.  */
 
 bfd_boolean
@@ -6451,13 +6545,24 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table)
   const ebb_t *ebb = &ebb_table->ebb;
   unsigned rel_idx = ebb->start_reloc_idx;
   property_table_entry *entry, *start_entry, *end_entry;
+  bfd_vma offset = 0;
+  xtensa_isa isa = xtensa_default_isa;
+  xtensa_format fmt;
+  static xtensa_insnbuf insnbuf = NULL;
+  static xtensa_insnbuf slotbuf = NULL;
+
+  if (insnbuf == NULL)
+    {
+      insnbuf = xtensa_insnbuf_alloc (isa);
+      slotbuf = xtensa_insnbuf_alloc (isa);
+    }
 
   start_entry = &ebb->ptbl[ebb->start_ptbl_idx];
   end_entry = &ebb->ptbl[ebb->end_ptbl_idx];
 
   for (entry = start_entry; entry <= end_entry; entry++)
     {
-      bfd_vma offset, start_offset, end_offset;
+      bfd_vma start_offset, end_offset;
       bfd_size_type insn_len;
 
       start_offset = entry->address - ebb->sec->vma;
@@ -6479,15 +6584,9 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table)
 
          insn_len = insn_decode_len (ebb->contents, ebb->content_length,
                                      offset);
-
-         /* Propose no actions for a section with an undecodable offset.  */
          if (insn_len == 0) 
-           {
-             (*_bfd_error_handler)
-               (_("%B(%A+0x%lx): could not decode instruction; possible configuration mismatch"),
-                ebb->sec->owner, ebb->sec, offset);
-             return FALSE;
-           }
+           goto decode_error;
+
          if (check_branch_target_aligned_address (offset, insn_len))
            align_type = EBB_REQUIRE_TGT_ALIGN;
 
@@ -6518,12 +6617,7 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table)
                                                     ebb->content_length,
                                                     irel->r_offset);
              if (simplify_size == 0)
-               {
-                 (*_bfd_error_handler)
-                   (_("%B(%A+0x%lx): could not decode instruction for XTENSA_ASM_SIMPLIFY relocation; possible configuration mismatch"),
-                    ebb->sec->owner, ebb->sec, offset);
-                 return FALSE;
-               }
+               goto decode_error;
 
              ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0,
                                  ta_convert_longcall, offset, 0, TRUE);
@@ -6532,47 +6626,50 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table)
              continue;
            }
 
-         insn_len = insn_decode_len (ebb->contents, ebb->content_length,
-                                     offset);
-         /* If the instruction is undecodable, then report an error.  */
-         if (insn_len == 0)
+         if (offset + MIN_INSN_LENGTH > ebb->content_length)
+           goto decode_error;
+         xtensa_insnbuf_from_chars (isa, insnbuf, &ebb->contents[offset],
+                                    ebb->content_length - offset);
+         fmt = xtensa_format_decode (isa, insnbuf);
+         if (fmt == XTENSA_UNDEFINED)
+           goto decode_error;
+         insn_len = xtensa_format_length (isa, fmt);
+         if (insn_len == (bfd_size_type) XTENSA_UNDEFINED)
+           goto decode_error;
+
+         if (xtensa_format_num_slots (isa, fmt) != 1)
            {
-             (*_bfd_error_handler)
-               (_("%B(%A+0x%lx): could not decode instruction; possible configuration mismatch"),
-                ebb->sec->owner, ebb->sec, offset);
-             return FALSE;
+             offset += insn_len;
+             continue;
            }
-           
+
+         xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf);
+         opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf);
+         if (opcode == XTENSA_UNDEFINED)
+           goto decode_error;
+
          if ((entry->flags & XTENSA_PROP_INSN_NO_DENSITY) == 0
              && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
-             && narrow_instruction (ebb->contents, ebb->content_length,
-                                    offset, FALSE))
+             && 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);
-             offset += insn_len;
-             continue;
            }
-         if ((entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
-             && widen_instruction (ebb->contents, ebb->content_length,
-                                   offset, FALSE))
+         else if ((entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
+                  && can_widen_instruction (slotbuf, fmt, opcode) != 0
+                  && ! prev_instr_is_a_loop (ebb->contents,
+                                             ebb->content_length, offset))
            {
              /* Add an instruction widen action.  */
              ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0,
                                  ta_widen_insn, offset, 0, FALSE);
-             offset += insn_len;
-             continue;
            }
-         opcode = insn_decode_opcode (ebb->contents, ebb->content_length,
-                                      offset, 0);
-         if (xtensa_opcode_is_loop (xtensa_default_isa, opcode))
+         else if (xtensa_opcode_is_loop (xtensa_default_isa, opcode) == 1)
            {
              /* Check for branch targets.  */
              ebb_propose_action (ebb_table, EBB_REQUIRE_LOOP_ALIGN, 0,
                                  ta_none, offset, 0, TRUE);
-             offset += insn_len;
-             continue;
            }
 
          offset += insn_len;
@@ -6586,6 +6683,12 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table)
     }
 
   return TRUE;
+
+ decode_error:
+  (*_bfd_error_handler)
+    (_("%B(%A+0x%lx): could not decode instruction; possible configuration mismatch"),
+     ebb->sec->owner, ebb->sec, offset);
+  return FALSE;
 }
 
 
@@ -6842,6 +6945,160 @@ compute_ebb_actions (ebb_constraint *ebb_table)
 }
 
 
+/* The xlate_map is a sorted array of address mappings designed to
+   answer the offset_with_removed_text() query with a binary search instead
+   of a linear search through the section's action_list.  */
+
+typedef struct xlate_map_entry xlate_map_entry_t;
+typedef struct xlate_map xlate_map_t;
+
+struct xlate_map_entry
+{
+  unsigned orig_address;
+  unsigned new_address;
+  unsigned size;
+};
+
+struct xlate_map
+{
+  unsigned entry_count;
+  xlate_map_entry_t *entry;
+};
+
+
+static int 
+xlate_compare (const void *a_v, const void *b_v)
+{
+  const xlate_map_entry_t *a = (const xlate_map_entry_t *) a_v;
+  const xlate_map_entry_t *b = (const xlate_map_entry_t *) b_v;
+  if (a->orig_address < b->orig_address)
+    return -1;
+  if (a->orig_address > (b->orig_address + b->size - 1))
+    return 1;
+  return 0;
+}
+
+
+static bfd_vma
+xlate_offset_with_removed_text (const xlate_map_t *map,
+                               text_action_list *action_list,
+                               bfd_vma offset)
+{
+  xlate_map_entry_t tmp;
+  void *r;
+  xlate_map_entry_t *e;
+
+  if (map == NULL)
+    return offset_with_removed_text (action_list, offset);
+
+  if (map->entry_count == 0)
+    return offset;
+
+  tmp.orig_address = offset;
+  tmp.new_address = offset;
+  tmp.size = 1;
+
+  r = bsearch (&offset, map->entry, map->entry_count,
+              sizeof (xlate_map_entry_t), &xlate_compare);
+  e = (xlate_map_entry_t *) r;
+  
+  BFD_ASSERT (e != NULL);
+  if (e == NULL)
+    return offset;
+  return e->new_address - e->orig_address + offset;
+}
+
+
+/* Build a binary searchable offset translation map from a section's
+   action list.  */
+
+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;
+
+  if (map == NULL)
+    return NULL;
+
+  num_actions = action_list_count (action_list);
+  map->entry = (xlate_map_entry_t *) 
+    bfd_malloc (sizeof (xlate_map_entry_t) * (num_actions + 1));
+  if (map->entry == NULL)
+    {
+      free (map);
+      return NULL;
+    }
+  map->entry_count = 0;
+  
+  removed = 0;
+  current_entry = &map->entry[0];
+
+  current_entry->orig_address = 0;
+  current_entry->new_address = 0;
+  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;
+    }
+
+  current_entry->size = (bfd_get_section_limit (sec->owner, sec)
+                        - current_entry->orig_address);
+  if (current_entry->size != 0)
+    map->entry_count++;
+
+  return map;
+}
+
+
+/* Free an offset translation map.  */
+
+static void 
+free_xlate_map (xlate_map_t *map)
+{
+  if (map && map->entry)
+    free (map->entry);
+  if (map)
+    free (map);
+}
+
+
 /* Use check_section_ebb_pcrels_fit to make sure that all of the
    relocations in a section will fit if a proposed set of actions
    are performed.  */
@@ -6851,14 +7108,24 @@ check_section_ebb_pcrels_fit (bfd *abfd,
                              asection *sec,
                              bfd_byte *contents,
                              Elf_Internal_Rela *internal_relocs,
-                             const ebb_constraint *constraint)
+                             const ebb_constraint *constraint,
+                             const xtensa_opcode *reloc_opcodes)
 {
   unsigned i, j;
   Elf_Internal_Rela *irel;
+  xlate_map_t *xmap = NULL;
+  bfd_boolean ok = TRUE;
   xtensa_relax_info *relax_info;
 
   relax_info = get_xtensa_relax_info (sec);
 
+  if (relax_info && sec->reloc_count > 100)
+    {
+      xmap = build_xlate_map (sec, relax_info);
+      /* NULL indicates out of memory, but the slow version
+        can still be used.  */
+    }
+
   for (i = 0; i < sec->reloc_count; i++)
     {
       r_reloc r_rel;
@@ -6894,10 +7161,12 @@ check_section_ebb_pcrels_fit (bfd *abfd,
 
       if (relax_info)
        {
-         self_offset = offset_with_removed_text (&relax_info->action_list,
-                                                 orig_self_offset);
-         target_offset = offset_with_removed_text (&relax_info->action_list,
-                                                   orig_target_offset);
+         self_offset =
+           xlate_offset_with_removed_text (xmap, &relax_info->action_list,
+                                           orig_self_offset);
+         target_offset =
+           xlate_offset_with_removed_text (xmap, &relax_info->action_list,
+                                           orig_target_offset);
        }
 
       self_removed_bytes = 0;
@@ -6931,20 +7200,35 @@ check_section_ebb_pcrels_fit (bfd *abfd,
          xtensa_opcode opcode;
          int opnum;
 
-         opcode = get_relocation_opcode (abfd, sec, contents, irel);
+         if (reloc_opcodes)
+           opcode = reloc_opcodes[i];
+         else
+           opcode = get_relocation_opcode (abfd, sec, contents, irel);
          if (opcode == XTENSA_UNDEFINED)
-           return FALSE;
+           {
+             ok = FALSE;
+             break;
+           }
 
          opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info));
          if (opnum == XTENSA_UNDEFINED)
-           return FALSE;
+           {
+             ok = FALSE;
+             break;
+           }
 
          if (!pcrel_reloc_fits (opcode, opnum, self_offset, target_offset))
-           return FALSE;
+           {
+             ok = FALSE;
+             break;
+           }
        }
     }
 
-  return TRUE;
+  if (xmap)
+    free_xlate_map (xmap);
+
+  return ok;
 }
 
 
@@ -7453,6 +7737,11 @@ relocations_reach (source_reloc *reloc,
          != sec->output_section)
        return FALSE;
 
+      /* Absolute literals in the same output section can always be
+        combined.  */
+      if (reloc[i].is_abs_literal)
+       continue;
+
       /* A literal with no PC-relative relocations can be moved anywhere.  */
       if (reloc[i].opnd != -1)
        {
@@ -7611,7 +7900,7 @@ move_shared_literal (asection *sec,
   relocs_fit = check_section_ebb_pcrels_fit (target_sec->owner, target_sec, 
                                             target_sec_cache->contents,
                                             target_sec_cache->relocs,
-                                            &ebb_table);
+                                            &ebb_table, NULL);
 
   if (!relocs_fit) 
     return FALSE;
@@ -8012,7 +8301,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
              copy_size = 2;
              memmove (scratch, &contents[orig_dot], orig_insn_size);
              BFD_ASSERT (action->removed_bytes == 1);
-             rv = narrow_instruction (scratch, final_size, 0, TRUE);
+             rv = narrow_instruction (scratch, final_size, 0);
              BFD_ASSERT (rv);
              memmove (&dup_contents[dup_dot], scratch, copy_size);
              orig_dot += orig_insn_size;
@@ -8045,7 +8334,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
              copy_size = 3;
              memmove (scratch, &contents[orig_dot], orig_insn_size);
              BFD_ASSERT (action->removed_bytes == -1);
-             rv = widen_instruction (scratch, final_size, 0, TRUE);
+             rv = widen_instruction (scratch, final_size, 0);
              BFD_ASSERT (rv);
              memmove (&dup_contents[dup_dot], scratch, copy_size);
              orig_dot += orig_insn_size;
@@ -8577,9 +8866,8 @@ relax_property_section (bfd *abfd,
     }
 
   is_full_prop_section =
-    ((strcmp (sec->name, XTENSA_PROP_SEC_NAME) == 0)
-     || (strncmp (sec->name, ".gnu.linkonce.prop.",
-                 sizeof ".gnu.linkonce.prop." - 1) == 0));
+    (   CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME)
+     || CONST_STRNEQ (sec->name, ".gnu.linkonce.prop."));
 
   if (internal_relocs)
     {
@@ -9240,23 +9528,19 @@ pcrel_reloc_fits (xtensa_opcode opc,
 
 
 static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
-static int insn_sec_len = sizeof (XTENSA_INSN_SEC_NAME) - 1;
-static int lit_sec_len = sizeof (XTENSA_LIT_SEC_NAME) - 1;
-static int prop_sec_len = sizeof (XTENSA_PROP_SEC_NAME) - 1;
-
 
 static bfd_boolean 
 xtensa_is_property_section (asection *sec)
 {
-  if (strncmp (XTENSA_INSN_SEC_NAME, sec->name, insn_sec_len) == 0
-      || strncmp (XTENSA_LIT_SEC_NAME, sec->name, lit_sec_len) == 0
-      || strncmp (XTENSA_PROP_SEC_NAME, sec->name, prop_sec_len) == 0)
+  if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME)
+      || CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME)
+      || CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME))
     return TRUE;
 
   if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0
-      && (strncmp (&sec->name[linkonce_len], "x.", 2) == 0
-         || strncmp (&sec->name[linkonce_len], "p.", 2) == 0
-         || strncmp (&sec->name[linkonce_len], "prop.", 5) == 0))
+      && (CONST_STRNEQ (&sec->name[linkonce_len], "x.")
+         || CONST_STRNEQ (&sec->name[linkonce_len], "p.")
+         || CONST_STRNEQ (&sec->name[linkonce_len], "prop.")))
     return TRUE;
 
   return FALSE;
@@ -9266,7 +9550,7 @@ xtensa_is_property_section (asection *sec)
 static bfd_boolean 
 xtensa_is_littable_section (asection *sec)
 {
-  if (strncmp (XTENSA_LIT_SEC_NAME, sec->name, lit_sec_len) == 0)
+  if (CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME))
     return TRUE;
 
   if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0
@@ -9313,19 +9597,48 @@ internal_reloc_matches (const void *ap, const void *bp)
 }
 
 
-char *
-xtensa_get_property_section_name (asection *sec, const char *base_name)
+/* Predicate function used to look up a section in a particular group.  */
+
+static bfd_boolean
+match_section_group (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
+{
+  const char *gname = inf;
+  const char *group_name = elf_group_name (sec);
+  
+  return (group_name == gname
+         || (group_name != NULL
+             && gname != NULL
+             && strcmp (group_name, gname) == 0));
+}
+
+
+asection *
+xtensa_get_property_section (asection *sec, const char *base_name)
 {
-  if (strncmp (sec->name, ".gnu.linkonce.", linkonce_len) == 0)
+  const char *suffix, *group_name;
+  char *prop_sec_name;
+  asection *prop_sec;
+
+  group_name = elf_group_name (sec);
+  if (group_name)
+    {
+      suffix = strrchr (sec->name, '.');
+      if (suffix == sec->name)
+       suffix = 0;
+      prop_sec_name = (char *) bfd_malloc (strlen (base_name) + 1
+                                          + (suffix ? strlen (suffix) : 0));
+      strcpy (prop_sec_name, base_name);
+      if (suffix)
+       strcat (prop_sec_name, suffix);
+    }
+  else if (strncmp (sec->name, ".gnu.linkonce.", linkonce_len) == 0)
     {
-      char *prop_sec_name;
-      const char *suffix;
       char *linkonce_kind = 0;
 
       if (strcmp (base_name, XTENSA_INSN_SEC_NAME) == 0) 
-       linkonce_kind = "x";
+       linkonce_kind = "x.";
       else if (strcmp (base_name, XTENSA_LIT_SEC_NAME) == 0) 
-       linkonce_kind = "p";
+       linkonce_kind = "p.";
       else if (strcmp (base_name, XTENSA_PROP_SEC_NAME) == 0)
        linkonce_kind = "prop.";
       else
@@ -9339,23 +9652,42 @@ xtensa_get_property_section_name (asection *sec, const char *base_name)
       suffix = sec->name + linkonce_len;
       /* For backward compatibility, replace "t." instead of inserting
          the new linkonce_kind (but not for "prop" sections).  */
-      if (strncmp (suffix, "t.", 2) == 0 && linkonce_kind[1] == '.')
+      if (CONST_STRNEQ (suffix, "t.") && linkonce_kind[1] == '.')
         suffix += 2;
       strcat (prop_sec_name + linkonce_len, suffix);
+    }
+  else
+    prop_sec_name = strdup (base_name);
+
+  /* Check if the section already exists.  */
+  prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name,
+                                        match_section_group,
+                                        (void *) group_name);
+  /* If not, create it.  */
+  if (! prop_sec)
+    {
+      flagword flags = (SEC_RELOC | SEC_HAS_CONTENTS | SEC_READONLY);
+      flags |= (bfd_get_section_flags (sec->owner, sec)
+               & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES));
+
+      prop_sec = bfd_make_section_anyway_with_flags
+       (sec->owner, strdup (prop_sec_name), flags);
+      if (! prop_sec)
+       return 0;
 
-      return prop_sec_name;
+      elf_group_name (prop_sec) = group_name;
     }
 
-  return strdup (base_name);
+  free (prop_sec_name);
+  return prop_sec;
 }
 
 
 flagword
 xtensa_get_property_predef_flags (asection *sec)
 {
-  if (strcmp (sec->name, XTENSA_INSN_SEC_NAME) == 0
-      || strncmp (sec->name, ".gnu.linkonce.x.",
-                 sizeof ".gnu.linkonce.x." - 1) == 0)
+  if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME)
+      || CONST_STRNEQ (sec->name, ".gnu.linkonce.x."))
     return (XTENSA_PROP_INSN
            | XTENSA_PROP_INSN_NO_TRANSFORM
            | XTENSA_PROP_INSN_NO_REORDER);
@@ -9389,7 +9721,7 @@ xtensa_callback_required_dependence (bfd *abfd,
   /* ".plt*" sections have no explicit relocations but they contain L32R
      instructions that reference the corresponding ".got.plt*" sections.  */
   if ((sec->flags & SEC_LINKER_CREATED) != 0
-      && strncmp (sec->name, ".plt", 4) == 0)
+      && CONST_STRNEQ (sec->name, ".plt"))
     {
       asection *sgotplt;
 
@@ -9464,14 +9796,14 @@ xtensa_callback_required_dependence (bfd *abfd,
 /* The default literal sections should always be marked as "code" (i.e.,
    SHF_EXECINSTR).  This is particularly important for the Linux kernel
    module loader so that the literals are not placed after the text.  */
-static struct bfd_elf_special_section const elf_xtensa_special_sections[]=
+static const struct bfd_elf_special_section elf_xtensa_special_sections[] =
 {
-  { ".literal",       8, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".init.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".fini.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { NULL,             0, 0, 0,            0 }
+  { STRING_COMMA_LEN (".fini.literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".init.literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".literal"),      0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".xtensa.info"),  0, SHT_NOTE,     0 },
+  { NULL,                       0,      0, 0,            0 }
 };
-
 \f
 #ifndef ELF_ARCH
 #define TARGET_LITTLE_SYM              bfd_elf32_xtensa_le_vec
@@ -9480,14 +9812,8 @@ static struct bfd_elf_special_section const elf_xtensa_special_sections[]=
 #define TARGET_BIG_NAME                        "elf32-xtensa-be"
 #define ELF_ARCH                       bfd_arch_xtensa
 
-/* The new EM_XTENSA value will be recognized beginning in the Xtensa T1040
-   release. However, we still have to generate files with the EM_XTENSA_OLD
-   value so that pre-T1040 tools can read the files.  As soon as we stop
-   caring about pre-T1040 tools, the following two values should be
-   swapped. At the same time, any other code that uses EM_XTENSA_OLD
-   should be changed to use EM_XTENSA.  */
-#define ELF_MACHINE_CODE               EM_XTENSA_OLD
-#define ELF_MACHINE_ALT1               EM_XTENSA
+#define ELF_MACHINE_CODE               EM_XTENSA
+#define ELF_MACHINE_ALT1               EM_XTENSA_OLD
 
 #if XCHAL_HAVE_MMU
 #define ELF_MAXPAGESIZE                        (1 << XCHAL_MMU_MIN_PTE_PAGE_SIZE)
@@ -9525,11 +9851,13 @@ static struct bfd_elf_special_section const elf_xtensa_special_sections[]=
 #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_modify_segment_map      elf_xtensa_modify_segment_map
 #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
 #define elf_backend_size_dynamic_sections    elf_xtensa_size_dynamic_sections
+#define elf_backend_omit_section_dynsym \
+  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
 #define elf_backend_special_sections        elf_xtensa_special_sections
+#define elf_backend_action_discarded        elf_xtensa_action_discarded
 
 #include "elf32-target.h"
This page took 0.046267 seconds and 4 git commands to generate.