daily update
[deliverable/binutils-gdb.git] / bfd / elf32-xtensa.c
index fc235deeb53bd5457d575fc421b4ec1ac04e0265..bb1983025f7172b05bd3f9a6884ff9171701d8d4 100644 (file)
@@ -1,5 +1,5 @@
 /* Xtensa-specific support for 32-bit ELF.
-   Copyright 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -106,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.  */
@@ -571,7 +571,6 @@ 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;
@@ -590,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;
 
@@ -640,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));
@@ -970,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);
 }
 
 
@@ -1145,8 +1123,7 @@ add_extra_plt_sections (bfd *dynobj, int count)
 
       sname = (char *) bfd_malloc (10);
       sprintf (sname, ".plt.%u", chunk);
-      s = bfd_make_section_with_flags (dynobj, sname,
-                                      flags | SEC_CODE);
+      s = bfd_make_section_with_flags (dynobj, sname, flags | SEC_CODE);
       if (s == NULL
          || ! bfd_set_section_alignment (dynobj, s, 2))
        return FALSE;
@@ -1413,7 +1390,7 @@ 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);
 
-      if (strncmp (name, ".rela", 5) == 0)
+      if (CONST_STRNEQ (name, ".rela"))
        {
          if (s->size != 0)
            {
@@ -1427,8 +1404,8 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              s->reloc_count = 0;
            }
        }
-      else if (strncmp (name, ".plt.", 5) != 0
-              && strncmp (name, ".got.plt.", 9) != 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
@@ -1493,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;
@@ -1525,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
@@ -2307,13 +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 %s relocation against symbol `%s'"),
-          input_bfd,
-          input_section,
-          (long) rel->r_offset,
-          howto->name,
-          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".  */
@@ -2374,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;
@@ -3009,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.  */
 
@@ -3434,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);
 }
@@ -3563,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);
 
@@ -3632,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)
@@ -3680,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.  */
@@ -3690,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);
@@ -3743,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);
@@ -3761,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
@@ -3779,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);
@@ -3794,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)
@@ -3827,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.  */
@@ -3837,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;
 }
 
@@ -4756,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)
@@ -4995,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);
 }
@@ -5754,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 *);
@@ -6290,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
@@ -6306,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;
@@ -6411,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
@@ -6447,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
@@ -6460,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;
@@ -6488,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;
 
@@ -6527,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);
@@ -6541,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;
@@ -6595,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;
 }
 
 
@@ -6851,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.  */
@@ -6860,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;
@@ -6903,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;
@@ -6940,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;
 }
 
 
@@ -7462,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)
        {
@@ -7620,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;
@@ -8021,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;
@@ -8054,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;
@@ -8586,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)
     {
@@ -9249,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;
@@ -9275,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
@@ -9322,13 +9597,42 @@ 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)
 {
-  if (strncmp (sec->name, ".gnu.linkonce.", linkonce_len) == 0)
+  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)
+{
+  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) 
@@ -9348,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);
@@ -9398,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;
 
@@ -9475,10 +9798,11 @@ xtensa_callback_required_dependence (bfd *abfd,
    module loader so that the literals are not placed after the text.  */
 static const struct bfd_elf_special_section elf_xtensa_special_sections[] =
 {
-  { ".fini.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".init.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".literal",       8, 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
@@ -9527,11 +9851,13 @@ static const struct bfd_elf_special_section 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.041928 seconds and 4 git commands to generate.