]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-xtensa.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / tc-xtensa.c
index 9defd739b3b7b908cb94fc26f648483f59346969..cbda45e6f0c3271587439ea6c126e9263e7abb62 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-xtensa.c -- Assemble Xtensa instructions.
-   Copyright (C) 2003-2017 Free Software Foundation, Inc.
+   Copyright (C) 2003-2021 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 #include "xtensa-relax.h"
 #include "dwarf2dbg.h"
 #include "xtensa-istack.h"
-#include "struc-symbol.h"
 #include "xtensa-config.h"
 #include "elf/xtensa.h"
 
 /* Provide default values for new configuration settings.  */
-#ifndef XSHAL_ABI
-#define XSHAL_ABI 0
+#ifndef XTHAL_ABI_WINDOWED
+#define XTHAL_ABI_WINDOWED 0
+#endif
+
+#ifndef XTHAL_ABI_CALL0
+#define XTHAL_ABI_CALL0 1
+#endif
+
+#ifndef XTENSA_MARCH_EARLIEST
+#define XTENSA_MARCH_EARLIEST 0
 #endif
 
 #ifndef uint32
@@ -75,6 +82,8 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 bfd_boolean density_supported;
 bfd_boolean absolute_literals_supported;
 
+static unsigned microarch_earliest;
+
 static vliw_insn cur_vinsn;
 
 unsigned xtensa_num_pipe_stages;
@@ -438,6 +447,7 @@ struct litpool_frag
   addressT addr;
   short priority; /* 1, 2, or 3 -- 1 is highest  */
   short original_priority;
+  int literal_count;
 };
 
 /* Map a segment to its litpool_frag list.  */
@@ -451,6 +461,14 @@ struct litpool_seg
 
 static struct litpool_seg litpool_seg_list;
 
+/* Limit maximal size of auto litpool by half of the j range.  */
+#define MAX_AUTO_POOL_LITERALS 16384
+
+/* Limit maximal size of explicit literal pool by l32r range.  */
+#define MAX_EXPLICIT_POOL_LITERALS 65536
+
+#define MAX_POOL_LITERALS \
+  (auto_litpools ? MAX_AUTO_POOL_LITERALS : MAX_EXPLICIT_POOL_LITERALS)
 
 /* Directive functions.  */
 
@@ -488,7 +506,8 @@ static int init_trampoline_frag (fragS *);
 static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset);
 static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
 static bfd_boolean auto_litpools = FALSE;
-static int auto_litpool_limit = 10000;
+static int auto_litpool_limit = 0;
+static bfd_boolean xtensa_is_init_fini (segT seg);
 
 /* Alignment Functions.  */
 
@@ -619,6 +638,7 @@ static bfd_boolean maybe_has_short_loop = FALSE;
 static bfd_boolean workaround_close_loop_end = FALSE;
 static bfd_boolean maybe_has_close_loop_end = FALSE;
 static bfd_boolean enforce_three_byte_loop_align = FALSE;
+static bfd_boolean opt_linkrelax = TRUE;
 
 /* When workaround_short_loops is TRUE, all loops with early exits must
    have at least 3 instructions.  workaround_all_short_loops is a modifier
@@ -628,6 +648,13 @@ static bfd_boolean enforce_three_byte_loop_align = FALSE;
 
 static bfd_boolean workaround_all_short_loops = FALSE;
 
+/* Generate individual property section for every section.
+   This option is defined in BDF library.  */
+extern bfd_boolean elf32xtensa_separate_props;
+
+/* Xtensa ABI.
+   This option is defined in BDF library.  */
+extern int elf32xtensa_abi;
 
 static void
 xtensa_setup_hw_workarounds (int earliest, int latest)
@@ -713,6 +740,12 @@ enum
   option_auto_litpools,
   option_no_auto_litpools,
   option_auto_litpool_limit,
+
+  option_separate_props,
+  option_no_separate_props,
+
+  option_abi_windowed,
+  option_abi_call0,
 };
 
 const char *md_shortopts = "";
@@ -792,6 +825,11 @@ struct option md_longopts[] =
   { "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
   { "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
 
+  { "separate-prop-tables", no_argument, NULL, option_separate_props },
+
+  { "abi-windowed", no_argument, NULL, option_abi_windowed },
+  { "abi-call0", no_argument, NULL, option_abi_call0 },
+
   { NULL, no_argument, NULL, 0 }
 };
 
@@ -810,10 +848,10 @@ md_parse_option (int c, const char *arg)
       as_warn (_("--no-density option is ignored"));
       return 1;
     case option_link_relax:
-      linkrelax = 1;
+      opt_linkrelax = TRUE;
       return 1;
     case option_no_link_relax:
-      linkrelax = 0;
+      opt_linkrelax = FALSE;
       return 1;
     case option_flix:
       produce_flix = FLIX_ALL;
@@ -984,6 +1022,8 @@ md_parse_option (int c, const char *arg)
     case option_auto_litpools:
       auto_litpools = TRUE;
       use_literal_section = FALSE;
+      if (auto_litpool_limit <= 0)
+       auto_litpool_limit = MAX_AUTO_POOL_LITERALS / 2;
       return 1;
 
     case option_no_auto_litpools:
@@ -1010,6 +1050,22 @@ md_parse_option (int c, const char *arg)
        return 1;
       }
 
+    case option_separate_props:
+      elf32xtensa_separate_props = TRUE;
+      return 1;
+
+    case option_no_separate_props:
+      elf32xtensa_separate_props = FALSE;
+      return 1;
+
+    case option_abi_windowed:
+      elf32xtensa_abi = XTHAL_ABI_WINDOWED;
+      return 1;
+
+    case option_abi_call0:
+      elf32xtensa_abi = XTHAL_ABI_CALL0;
+      return 1;
+
     default:
       return 0;
     }
@@ -1040,7 +1096,11 @@ Xtensa options:\n\
   --auto-litpool-limit=<value>\n\
                           (range 100-10000) Maximum number of blocks of\n\
                           instructions to emit between literal pool\n\
-                          locations; implies --auto-litpools flag\n", stream);
+                          locations; implies --auto-litpools flag\n\
+  --[no-]separate-prop-tables\n\
+                          [Do not] place Xtensa property records into\n\
+                          individual property sections for each section.\n\
+                          Default is to generate single property section.\n", stream);
 }
 
 \f
@@ -1500,7 +1560,6 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
   emit_state state;
   char *p, *base_name;
   char c;
-  segT dest_seg;
 
   if (inside_directive (directive_literal))
     {
@@ -1516,21 +1575,10 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
   saved_insn_labels = insn_labels;
   insn_labels = NULL;
 
-  /* If we are using text-section literals, then this is the right value... */
-  dest_seg = now_seg;
-
   base_name = input_line_pointer;
 
   xtensa_switch_to_literal_fragment (&state);
 
-  /* ...but if we aren't using text-section-literals, then we
-     need to put them in the section we just switched to.  */
-  if (use_literal_section || directive_state[directive_absolute_literals])
-    dest_seg = now_seg;
-
-  /* FIXME, despite the previous comments, dest_seg is unused...  */
-  (void) dest_seg;
-
   /* All literals are aligned to four-byte boundaries.  */
   frag_align (2, 0, 0);
   record_alignment (now_seg, 2);
@@ -2027,13 +2075,13 @@ tokenize_arguments (char **args, char *str)
        }
     }
 
-fini:
+ fini:
   if (saw_comma || saw_colon)
     goto err;
   input_line_pointer = old_input_line_pointer;
   return num_args;
 
-err:
+ err:
   if (saw_comma)
     as_bad (_("extra comma"));
   else if (saw_colon)
@@ -2482,6 +2530,18 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
       return 0;
     }
 
+  /* Without an operand, this is given a default immediate operand of 0.  */
+  if ((strcmp (opname, "simcall") == 0 && microarch_earliest >= 280000))
+    {
+      if (*pnum_args == 0)
+       {
+         arg_strings[0] = (char *) xmalloc (2);
+         strcpy (arg_strings[0], "0");
+         *pnum_args = 1;
+       }
+      return 0;
+    }
+
   if (strcmp (opname, "bbsi.l") == 0)
     {
       if (xg_check_num_args (pnum_args, 3, opname, arg_strings))
@@ -4095,7 +4155,7 @@ get_is_linkonce_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec)
 {
   flagword flags, link_once_flags;
 
-  flags = bfd_get_section_flags (abfd, sec);
+  flags = bfd_section_flags (sec);
   link_once_flags = (flags & SEC_LINK_ONCE);
 
   /* Flags might not be set yet.  */
@@ -4133,12 +4193,12 @@ xtensa_create_literal_symbol (segT sec, fragS *frag)
      symbol will be in the output file.  */
   if (get_is_linkonce_section (stdoutput, sec))
     {
-      symbolP = symbol_new (name, sec, 0, frag);
+      symbolP = symbol_new (name, sec, frag, 0);
       S_CLEAR_EXTERNAL (symbolP);
       /* symbolP->local = 1; */
     }
   else
-    symbolP = symbol_new (name, sec, 0, frag);
+    symbolP = symbol_new (name, sec, frag, 0);
 
   xtensa_add_literal_sym (symbolP);
 
@@ -4767,7 +4827,6 @@ xtensa_mark_literal_pool_location (void)
 {
   /* Any labels pointing to the current location need
      to be adjusted to after the literal pool.  */
-  emit_state s;
   fragS *pool_location;
 
   if (use_literal_section)
@@ -4788,19 +4847,7 @@ xtensa_mark_literal_pool_location (void)
                RELAX_LITERAL_POOL_END, NULL, 0, NULL);
   xtensa_set_frag_assembly_state (frag_now);
 
-  /* Now put a frag into the literal pool that points to this location.  */
   set_literal_pool_location (now_seg, pool_location);
-  xtensa_switch_to_non_abs_literal_fragment (&s);
-  frag_align (2, 0, 0);
-  record_alignment (now_seg, 2);
-
-  /* Close whatever frag is there.  */
-  frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
-  xtensa_set_frag_assembly_state (frag_now);
-  frag_now->tc_frag_data.literal_frag = pool_location;
-  frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
-  xtensa_restore_emit_state (&s);
-  xtensa_set_frag_assembly_state (frag_now);
 }
 
 
@@ -4884,29 +4931,32 @@ get_expanded_loop_offset (xtensa_opcode opcode)
 static fragS *
 get_literal_pool_location (segT seg)
 {
-  struct litpool_seg *lps = litpool_seg_list.next;
-  struct litpool_frag *lpf;
-  for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
-    ;
-  if (lps)
+  if (auto_litpools)
     {
-      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
-       { /* Skip "candidates" for now.  */
-         if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
-             lpf->priority == 1)
-           return lpf->fragP;
-       }
-      /* Must convert a lower-priority pool.  */
-      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
-       {
-         if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
-           return lpf->fragP;
-       }
-      /* Still no match -- try for a low priority pool.  */
-      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+      struct litpool_seg *lps = litpool_seg_list.next;
+      struct litpool_frag *lpf;
+      for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
+       ;
+      if (lps)
        {
-         if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
-           return lpf->fragP;
+         for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+           { /* Skip "candidates" for now.  */
+             if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
+                 lpf->priority == 1)
+               return lpf->fragP;
+           }
+         /* Must convert a lower-priority pool.  */
+         for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+           {
+             if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
+               return lpf->fragP;
+           }
+         /* Still no match -- try for a low priority pool.  */
+         for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+           {
+             if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+               return lpf->fragP;
+           }
        }
     }
   return seg_info (seg)->tc_segment_info_data.literal_pool_loc;
@@ -4970,7 +5020,7 @@ xtensa_mark_frags_for_org (void)
       segment_info_type *seginfo;
       fragS *fragP;
       flagword flags;
-      flags = bfd_get_section_flags (stdoutput, sec);
+      flags = bfd_section_flags (sec);
       if (flags & SEC_DEBUGGING)
        continue;
       if (!(flags & SEC_ALLOC))
@@ -5015,7 +5065,7 @@ xtensa_find_unmarked_state_frags (void)
       segment_info_type *seginfo;
       fragS *fragP;
       flagword flags;
-      flags = bfd_get_section_flags (stdoutput, sec);
+      flags = bfd_section_flags (sec);
       if (flags & SEC_DEBUGGING)
        continue;
       if (!(flags & SEC_ALLOC))
@@ -5063,7 +5113,7 @@ xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED,
                                      asection *sec,
                                      void *unused ATTRIBUTE_UNUSED)
 {
-  flagword flags = bfd_get_section_flags (abfd, sec);
+  flagword flags = bfd_section_flags (sec);
   segment_info_type *seginfo = seg_info (sec);
   fragS *frag = seginfo->frchainP->frch_root;
 
@@ -5102,7 +5152,7 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
                             asection *sec,
                             void *unused ATTRIBUTE_UNUSED)
 {
-  flagword flags = bfd_get_section_flags (abfd, sec);
+  flagword flags = bfd_section_flags (sec);
   segment_info_type *seginfo = seg_info (sec);
   fragS *frag = seginfo->frchainP->frch_root;
   xtensa_isa isa = xtensa_default_isa;
@@ -5226,6 +5276,8 @@ xg_init_global_config (void)
 
   directive_state[directive_density] = XCHAL_HAVE_DENSITY;
   directive_state[directive_absolute_literals] = XSHAL_USE_ABSOLUTE_LITERALS;
+
+  microarch_earliest = XTENSA_MARCH_EARLIEST;
 }
 
 void
@@ -5249,7 +5301,7 @@ md_begin (void)
   xtensa_default_isa = xtensa_isa_init (0, 0);
   isa = xtensa_default_isa;
 
-  linkrelax = 1;
+  linkrelax = opt_linkrelax;
 
   /* Set up the literal sections.  */
   memset (&default_lit_sections, 0, sizeof (default_lit_sections));
@@ -5304,6 +5356,9 @@ md_begin (void)
   /* Set up the assembly state.  */
   if (!frag_now->tc_frag_data.is_assembly_state_set)
     xtensa_set_frag_assembly_state (frag_now);
+
+  if (!use_literal_section)
+    xtensa_mark_literal_pool_location ();
 }
 
 
@@ -5903,6 +5958,11 @@ xtensa_elf_section_change_hook (void)
   /* Set up the assembly state.  */
   if (!frag_now->tc_frag_data.is_assembly_state_set)
     xtensa_set_frag_assembly_state (frag_now);
+
+  if (!use_literal_section
+      && seg_info (now_seg)->tc_segment_info_data.literal_pool_loc == NULL
+      && !xtensa_is_init_fini (now_seg))
+    xtensa_mark_literal_pool_location ();
 }
 
 
@@ -5956,18 +6016,24 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
     case BFD_RELOC_8:
       if (fixP->fx_subsy)
        {
+         bfd_boolean neg = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+           < S_GET_VALUE (fixP->fx_subsy);
+
          switch (fixP->fx_r_type)
            {
            case BFD_RELOC_8:
-             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
+             fixP->fx_r_type = neg
+               ? BFD_RELOC_XTENSA_NDIFF8 : BFD_RELOC_XTENSA_PDIFF8;
              fixP->fx_signed = 0;
              break;
            case BFD_RELOC_16:
-             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
+             fixP->fx_r_type = neg
+               ? BFD_RELOC_XTENSA_NDIFF16 : BFD_RELOC_XTENSA_PDIFF16;
              fixP->fx_signed = 0;
              break;
            case BFD_RELOC_32:
-             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
+             fixP->fx_r_type = neg
+               ? BFD_RELOC_XTENSA_NDIFF32 : BFD_RELOC_XTENSA_PDIFF32;
              fixP->fx_signed = 0;
              break;
            default:
@@ -5989,6 +6055,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
          val = *valP;
          fixP->fx_done = 1;
        }
+      else if (S_GET_SEGMENT (fixP->fx_addsy) == absolute_section)
+       {
+         val = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset;
+         *valP = val;
+         fixP->fx_done = 1;
+       }
       /* fall through */
 
     case BFD_RELOC_XTENSA_PLT:
@@ -7184,10 +7256,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
       frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
       if (tinsn->opcode == xtensa_l32r_opcode)
-       {
-         frag_now->tc_frag_data.literal_frags[slot] =
-                 tinsn->tok[1].X_add_symbol->sy_frag;
-       }
+       frag_now->tc_frag_data.literal_frags[slot]
+         = symbol_get_frag (tinsn->tok[1].X_add_symbol);
       if (tinsn->literal_space != 0)
        xg_assemble_literal_space (tinsn->literal_space, slot);
       frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
@@ -7453,11 +7523,18 @@ static struct trampoline_seg *
 find_trampoline_seg (asection *seg)
 {
   struct trampoline_seg *ts = trampoline_seg_list.next;
+  static struct trampoline_seg *mr;
+
+  if (mr && mr->seg == seg)
+    return mr;
 
   for ( ; ts; ts = ts->next)
     {
       if (ts->seg == seg)
-       return ts;
+       {
+         mr = ts;
+         return ts;
+       }
     }
 
   return NULL;
@@ -7555,14 +7632,17 @@ static int xg_order_trampoline_chain_entry (const void *a, const void *b)
   const struct trampoline_chain_entry *pa = a;
   const struct trampoline_chain_entry *pb = b;
 
-  if (pa->sym == pb->sym ||
-      S_GET_VALUE (pa->sym) == S_GET_VALUE (pb->sym))
-    if (pa->offset == pb->offset)
-      return 0;
-    else
-      return pa->offset < pb->offset ? -1 : 1;
-  else
-    return S_GET_VALUE (pa->sym) < S_GET_VALUE (pb->sym) ? -1 : 1;
+  if (pa->sym != pb->sym)
+    {
+      valueT aval = S_GET_VALUE (pa->sym);
+      valueT bval = S_GET_VALUE (pb->sym);
+
+      if (aval != bval)
+       return aval < bval ? -1 : 1;
+    }
+  if (pa->offset != pb->offset)
+    return pa->offset < pb->offset ? -1 : 1;
+  return 0;
 }
 
 static void xg_sort_trampoline_chain (struct trampoline_chain *tc)
@@ -7639,10 +7719,30 @@ xg_get_best_chain_entry (struct trampoline_chain *tc, addressT source)
 
 static int xg_order_trampoline_chain (const void *a, const void *b)
 {
-  const struct trampoline_chain *pa = a;
-  const struct trampoline_chain *pb = b;
+  const struct trampoline_chain *_pa = a;
+  const struct trampoline_chain *_pb = b;
+  const struct trampoline_chain_entry *pa = &_pa->target;
+  const struct trampoline_chain_entry *pb = &_pb->target;
+  symbolS *s1 = pa->sym;
+  symbolS *s2 = pb->sym;
+
+  if (s1 != s2)
+    {
+      symbolS *tmp = symbol_symbolS (s1);
+      if (tmp)
+       s1 = tmp;
+
+      tmp = symbol_symbolS (s2);
+      if (tmp)
+       s2 = tmp;
 
-  return xg_order_trampoline_chain_entry (&pa->target, &pb->target);
+      if (s1 != s2)
+       return s1 < s2 ? -1 : 1;
+    }
+
+  if (pa->offset != pb->offset)
+    return pa->offset < pb->offset ? -1 : 1;
+  return 0;
 }
 
 static struct trampoline_chain *
@@ -7653,6 +7753,9 @@ xg_get_trampoline_chain (struct trampoline_seg *ts,
   struct trampoline_chain_index *idx = &ts->chain_index;
   struct trampoline_chain c;
 
+  if (idx->n_entries == 0)
+    return NULL;
+
   if (idx->needs_sorting)
     {
       qsort (idx->entry, idx->n_entries, sizeof (*idx->entry),
@@ -7782,7 +7885,7 @@ dump_litpools (void)
          printf("   %ld <%d:%d> (%d) [%d]: ",
                 lpf->addr, lpf->priority, lpf->original_priority,
                 lpf->fragP->fr_line, count);
-         //dump_frag(lpf->fragP);
+         /* dump_frag(lpf->fragP);  */
        }
     }
 }
@@ -7887,6 +7990,7 @@ xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
   lpf->fragP = fragP;
   lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
   lpf->original_priority = lpf->priority;
+  lpf->literal_count = 0;
 
   lps->frag_count = 0;
 }
@@ -8247,7 +8351,7 @@ next_instrs_are_b_retw (fragS *fragP)
   static xtensa_insnbuf insnbuf = NULL;
   static xtensa_insnbuf slotbuf = NULL;
   xtensa_isa isa = xtensa_default_isa;
-  int offset = 0;
+  unsigned int offset = 0;
   int slot;
   bfd_boolean branch_seen = FALSE;
 
@@ -8640,7 +8744,7 @@ unrelaxed_frag_min_insn_count (fragS *fragP)
   xtensa_isa isa = xtensa_default_isa;
   static xtensa_insnbuf insnbuf = NULL;
   int insn_count = 0;
-  int offset = 0;
+  unsigned int offset = 0;
 
   if (!fragP->tc_frag_data.is_insn)
     return insn_count;
@@ -8693,7 +8797,7 @@ unrelaxed_frag_has_b_j (fragS *fragP)
 {
   static xtensa_insnbuf insnbuf = NULL;
   xtensa_isa isa = xtensa_default_isa;
-  int offset = 0;
+  unsigned int offset = 0;
 
   if (!fragP->tc_frag_data.is_insn)
     return FALSE;
@@ -8879,7 +8983,6 @@ is_local_forward_loop (const TInsn *insn, fragS *fragP)
   return FALSE;
 }
 
-
 #define XTINFO_NAME "Xtensa_Info"
 #define XTINFO_NAMESZ 12
 #define XTINFO_TYPE 1
@@ -8892,11 +8995,11 @@ xtensa_add_config_info (void)
   int sz;
 
   info_sec = subseg_new (".xtensa.info", 0);
-  bfd_set_section_flags (stdoutput, info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
+  bfd_set_section_flags (info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
 
   data = XNEWVEC (char, 100);
   sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
-          XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
+          XSHAL_USE_ABSOLUTE_LITERALS, xtensa_abi_choice ());
   sz = strlen (data) + 1;
 
   /* Add enough null terminators to pad to a word boundary.  */
@@ -9314,6 +9417,12 @@ static size_t xg_find_best_trampoline (struct trampoline_index *idx,
                 trampoline_frag->fr_address > target))
              continue;
 
+           /* Don't choose trampoline that contains the source.  */
+           if (source >= trampoline_frag->fr_address
+               && source <= trampoline_frag->fr_address +
+               trampoline_frag->fr_fix)
+             continue;
+
            off = trampoline_frag->fr_address - fulcrum;
            /* Stop if some trampoline is found and the search is more than
               J_RANGE / 4 from the projected fulcrum.  A trampoline w/o jump
@@ -10104,7 +10213,7 @@ init_trampoline_frag (fragS *fp)
       char label[10 + 2 * sizeof(fp)];
 
       sprintf (label, ".L0_TR_%p", fp);
-      lsym = (symbolS *)local_symbol_make (label, now_seg, 0, fp);
+      lsym = (symbolS *) local_symbol_make (label, now_seg, fp, 0);
       fp->fr_symbol = lsym;
       if (fp->tc_frag_data.needs_jump_around)
         {
@@ -10601,7 +10710,6 @@ convert_frag_fill_nop (fragS *fragP)
 static fixS *fix_new_exp_in_seg
   (segT, subsegT, fragS *, int, int, expressionS *, int,
    bfd_reloc_code_real_type);
-static void convert_frag_immed_finish_loop (segT, fragS *, TInsn *);
 
 static void
 convert_frag_immed (segT segP,
@@ -10727,9 +10835,9 @@ convert_frag_immed (segT segP,
                  target_offset += unreach->tc_frag_data.text_expansion[0];
                }
              gas_assert (gen_label == NULL);
-             gen_label = symbol_new (FAKE_LABEL_NAME, now_seg,
+             gen_label = symbol_new (FAKE_LABEL_NAME, now_seg, fragP,
                                      fr_opcode - fragP->fr_literal
-                                     + target_offset, fragP);
+                                     + target_offset);
              break;
 
            case ITYPE_INSN:
@@ -10843,9 +10951,6 @@ convert_frag_immed (segT segP,
        }
     }
 
-  if (expanded && xtensa_opcode_is_loop (isa, orig_tinsn.opcode) == 1)
-    convert_frag_immed_finish_loop (segP, fragP, &orig_tinsn);
-
   if (expanded && is_direct_call_opcode (orig_tinsn.opcode))
     {
       /* Add an expansion note on the expanded instruction.  */
@@ -10882,122 +10987,6 @@ fix_new_exp_in_seg (segT new_seg,
 }
 
 
-/* Relax a loop instruction so that it can span loop >256 bytes.
-
-                  loop    as, .L1
-          .L0:
-                  rsr     as, LEND
-                  wsr     as, LBEG
-                  addi    as, as, lo8 (label-.L1)
-                  addmi   as, as, mid8 (label-.L1)
-                  wsr     as, LEND
-                  isync
-                  rsr     as, LCOUNT
-                  addi    as, as, 1
-          .L1:
-                  <<body>>
-          label:
-*/
-
-static void
-convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
-{
-  TInsn loop_insn;
-  TInsn addi_insn;
-  TInsn addmi_insn;
-  unsigned long target;
-  static xtensa_insnbuf insnbuf = NULL;
-  unsigned int loop_length, loop_length_hi, loop_length_lo;
-  xtensa_isa isa = xtensa_default_isa;
-  addressT loop_offset;
-  addressT addi_offset = 9;
-  addressT addmi_offset = 12;
-  fragS *next_fragP;
-  int target_count;
-
-  if (!insnbuf)
-    insnbuf = xtensa_insnbuf_alloc (isa);
-
-  /* Get the loop offset.  */
-  loop_offset = get_expanded_loop_offset (tinsn->opcode);
-
-  /* Validate that there really is a LOOP at the loop_offset.  Because
-     loops are not bundleable, we can assume that the instruction will be
-     in slot 0.  */
-  tinsn_from_chars (&loop_insn, fragP->fr_opcode + loop_offset, 0);
-  tinsn_immed_from_frag (&loop_insn, fragP, 0);
-
-  gas_assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1);
-  addi_offset += loop_offset;
-  addmi_offset += loop_offset;
-
-  gas_assert (tinsn->ntok == 2);
-  if (tinsn->tok[1].X_op == O_constant)
-    target = tinsn->tok[1].X_add_number;
-  else if (tinsn->tok[1].X_op == O_symbol)
-    {
-      /* Find the fragment.  */
-      symbolS *sym = tinsn->tok[1].X_add_symbol;
-      gas_assert (S_GET_SEGMENT (sym) == segP
-             || S_GET_SEGMENT (sym) == absolute_section);
-      target = (S_GET_VALUE (sym) + tinsn->tok[1].X_add_number);
-    }
-  else
-    {
-      as_bad (_("invalid expression evaluation type %d"), tinsn->tok[1].X_op);
-      target = 0;
-    }
-
-  loop_length = target - (fragP->fr_address + fragP->fr_fix);
-  loop_length_hi = loop_length & ~0x0ff;
-  loop_length_lo = loop_length & 0x0ff;
-  if (loop_length_lo >= 128)
-    {
-      loop_length_lo -= 256;
-      loop_length_hi += 256;
-    }
-
-  /* Because addmi sign-extends the immediate, 'loop_length_hi' can be at most
-     32512.  If the loop is larger than that, then we just fail.  */
-  if (loop_length_hi > 32512)
-    as_bad_where (fragP->fr_file, fragP->fr_line,
-                 _("loop too long for LOOP instruction"));
-
-  tinsn_from_chars (&addi_insn, fragP->fr_opcode + addi_offset, 0);
-  gas_assert (addi_insn.opcode == xtensa_addi_opcode);
-
-  tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0);
-  gas_assert (addmi_insn.opcode == xtensa_addmi_opcode);
-
-  set_expr_const (&addi_insn.tok[2], loop_length_lo);
-  tinsn_to_insnbuf (&addi_insn, insnbuf);
-
-  fragP->tc_frag_data.is_insn = TRUE;
-  xtensa_insnbuf_to_chars
-    (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addi_offset, 0);
-
-  set_expr_const (&addmi_insn.tok[2], loop_length_hi);
-  tinsn_to_insnbuf (&addmi_insn, insnbuf);
-  xtensa_insnbuf_to_chars
-    (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addmi_offset, 0);
-
-  /* Walk through all of the frags from here to the loop end
-     and mark them as no_transform to keep them from being modified
-     by the linker.  If we ever have a relocation for the
-     addi/addmi of the difference of two symbols we can remove this.  */
-
-  target_count = 0;
-  for (next_fragP = fragP; next_fragP != NULL;
-       next_fragP = next_fragP->fr_next)
-    {
-      next_fragP->tc_frag_data.is_no_transform = TRUE;
-      if (next_fragP->tc_frag_data.is_loop_target)
-       target_count++;
-      if (target_count == 2)
-       break;
-    }
-}
-
 \f
 /* A map that keeps information on a per-subsegment basis.  This is
    maintained during initial assembly, but is invalid once the
@@ -11151,36 +11140,83 @@ xg_promote_candidate_litpool (struct litpool_seg *lps,
   /* Create a local symbol pointing to the
      end of the pool.  */
   sprintf (label, ".L0_LT_%p", poolbeg);
-  lsym = (symbolS *)local_symbol_make (label, lps->seg,
-                                      0, poolend);
+  lsym = (symbolS *) local_symbol_make (label, lps->seg, poolend, 0);
   poolbeg->fr_symbol = lsym;
   /* Rest is done in xtensa_relax_frag.  */
 }
 
-static void
-xtensa_move_literals (void)
+static struct litpool_frag *xg_find_litpool (struct litpool_seg *lps,
+                                            struct litpool_frag *lpf,
+                                            addressT addr)
 {
-  seg_list *segment;
-  frchainS *frchain_from, *frchain_to;
-  fragS *search_frag, *next_frag, *literal_pool, *insert_after;
-  fragS **frag_splice;
-  emit_state state;
-  segT dest_seg;
-  fixS *fix, *next_fix, **fix_splice;
-  sym_list *lit;
-  struct litpool_seg *lps;
-  const char *init_name = INIT_SECTION_NAME;
-  const char *fini_name = FINI_SECTION_NAME;
-  int init_name_len = strlen(init_name);
-  int fini_name_len = strlen(fini_name);
+  struct litpool_frag *lp = lpf->prev;
 
-  mark_literal_frags (literal_head->next);
+  gas_assert (lp->fragP);
 
-  if (use_literal_section)
-    return;
+  while (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+    {
+      lp = lp->prev;
+      if (lp->fragP == NULL)
+       {
+         /* End of list; have to bite the bullet.
+            Take the nearest.  */
+         lp = lpf->prev;
+         break;
+       }
+      /* Does it (conservatively) reach?  */
+      if (addr - lp->addr <= 128 * 1024)
+       {
+         if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
+             lp->literal_count < MAX_POOL_LITERALS)
+           {
+             /* Found a good one.  */
+             break;
+           }
+         else if (lp->prev->fragP &&
+                  addr - lp->prev->addr > 128 * 1024 &&
+                  lp->prev->literal_count < MAX_POOL_LITERALS)
+           {
+             /* This is still a "candidate" but the next one
+                will be too far away, so revert to the nearest
+                one, convert it and add the jump around.  */
+             lp = lpf->prev;
+             break;
+           }
+       }
+    }
 
-  /* Assign addresses (rough estimates) to the potential literal pool locations
-     and create new ones if the gaps are too large.  */
+  if (lp->literal_count >= MAX_POOL_LITERALS)
+    {
+      lp = lpf->prev;
+      while (lp && lp->fragP && lp->literal_count >= MAX_POOL_LITERALS)
+       {
+         lp = lp->prev;
+       }
+      gas_assert (lp);
+    }
+
+  gas_assert (lp && lp->fragP && lp->literal_count < MAX_POOL_LITERALS);
+  ++lp->literal_count;
+
+  /* Convert candidate and add the jump around.  */
+  if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+    xg_promote_candidate_litpool (lps, lp);
+
+  return lp;
+}
+
+static bfd_boolean xtensa_is_init_fini (segT seg)
+{
+  if (!seg)
+    return 0;
+  return strcmp (segment_name (seg), INIT_SECTION_NAME) == 0
+    || strcmp (segment_name (seg), FINI_SECTION_NAME) == 0;
+}
+
+static void
+xtensa_assign_litpool_addresses (void)
+{
+  struct litpool_seg *lps;
 
   for (lps = litpool_seg_list.next; lps; lps = lps->next)
     {
@@ -11188,6 +11224,9 @@ xtensa_move_literals (void)
       struct litpool_frag *lpf = lps->frag_list.next;
       addressT addr = 0;
 
+      if (xtensa_is_init_fini (lps->seg))
+       continue;
+
       for ( ; frchP; frchP = frchP->frch_next)
        {
          fragS *fragP;
@@ -11208,59 +11247,23 @@ xtensa_move_literals (void)
                  int slot;
                  for (slot = 0; slot < MAX_SLOTS; slot++)
                    {
-                     if (fragP->tc_frag_data.literal_frags[slot])
+                     fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
+
+                     if (litfrag
+                         && litfrag->tc_frag_data.is_literal
+                         && !litfrag->tc_frag_data.literal_frag)
                        {
-                         /* L32R; point its literal to the nearest litpool
-                            preferring non-"candidate" positions to avoid
-                            the jump-around.  */
-                         fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
-                         struct litpool_frag *lp = lpf->prev;
-                         if (!lp->fragP)
-                           {
-                             break;
-                           }
-                         while (lp->fragP->fr_subtype ==
-                                RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
-                           {
-                             lp = lp->prev;
-                             if (lp->fragP == NULL)
-                               {
-                                 /* End of list; have to bite the bullet.
-                                    Take the nearest.  */
-                                 lp = lpf->prev;
-                                 break;
-                               }
-                             /* Does it (conservatively) reach?  */
-                             if (addr - lp->addr <= 128 * 1024)
-                               {
-                                 if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
-                                   {
-                                     /* Found a good one.  */
-                                     break;
-                                   }
-                                 else if (lp->prev->fragP &&
-                                          addr - lp->prev->addr > 128 * 1024)
-                                   {
-                                     /* This is still a "candidate" but the next one
-                                        will be too far away, so revert to the nearest
-                                        one, convert it and add the jump around.  */
-                                     lp = lpf->prev;
-                                     break;
-                                   }
-                               }
-                           }
-
-                         /* Convert candidate and add the jump around.  */
-                         if (lp->fragP->fr_subtype ==
-                             RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
-                           xg_promote_candidate_litpool (lps, lp);
-
-                         if (! litfrag->tc_frag_data.literal_frag)
-                           {
-                             /* Take earliest use of this literal to avoid
-                                forward refs.  */
-                             litfrag->tc_frag_data.literal_frag = lp->fragP;
-                           }
+                         /* L32R referring .literal or generated as a result
+                            of relaxation.  Point its literal to the nearest
+                            litpool preferring non-"candidate" positions to
+                            avoid the jump-around.  */
+
+                         struct litpool_frag *lp;
+
+                         lp = xg_find_litpool (lps, lpf, addr);
+                         /* Take earliest use of this literal to avoid
+                            forward refs.  */
+                         litfrag->tc_frag_data.literal_frag = lp->fragP;
                        }
                    }
                }
@@ -11270,7 +11273,35 @@ xtensa_move_literals (void)
            }
        }
     }
+}
+
+static void
+xtensa_move_literals (void)
+{
+  seg_list *segment;
+  frchainS *frchain_from, *frchain_to;
+  fragS *search_frag, *next_frag, *literal_pool, *insert_after;
+  fragS **frag_splice;
+  emit_state state;
+  segT dest_seg;
+  fixS *fix, *next_fix, **fix_splice;
+  sym_list *lit;
+  const char *init_name = INIT_SECTION_NAME;
+  const char *fini_name = FINI_SECTION_NAME;
+  int init_name_len = strlen(init_name);
+  int fini_name_len = strlen(fini_name);
 
+  mark_literal_frags (literal_head->next);
+
+  if (use_literal_section)
+    return;
+
+  /* Assign addresses (rough estimates) to the potential literal pool locations
+     and create new ones if the gaps are too large.  */
+
+  xtensa_assign_litpool_addresses ();
+
+  /* Walk through the literal segments.  */
   for (segment = literal_head->next; segment; segment = segment->next)
     {
       const char *seg_name = segment_name (segment->seg);
@@ -11296,12 +11327,7 @@ xtensa_move_literals (void)
        }
 
       if (!search_frag)
-       {
-         search_frag = frchain_from->frch_root;
-         as_bad_where (search_frag->fr_file, search_frag->fr_line,
-                       _("literal pool location required for text-section-literals; specify with .literal_position"));
-         continue;
-       }
+       continue;
 
       gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
              == RELAX_LITERAL_POOL_BEGIN);
@@ -11528,14 +11554,11 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
 {
   fragS *pool_location = get_literal_pool_location (now_seg);
   segT lit_seg;
-  bfd_boolean is_init =
-    (now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME));
-  bfd_boolean is_fini =
-    (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME));
+  bfd_boolean is_init_fini = xtensa_is_init_fini (now_seg);
 
   if (pool_location == NULL
       && !use_literal_section
-      && !is_init && ! is_fini)
+      && !is_init_fini)
     {
       if (!auto_litpools)
        {
@@ -11549,7 +11572,7 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
   xtensa_switch_section_emit_state (result, lit_seg, 0);
 
   if (!use_literal_section
-      && !is_init && !is_fini
+      && !is_init_fini
       && get_literal_pool_location (now_seg) != pool_location)
     {
       /* Close whatever frag is there.  */
@@ -11712,8 +11735,8 @@ cache_literal_section (bfd_boolean use_abs_literals)
 
       elf_group_name (seg) = group_name;
 
-      bfd_set_section_flags (stdoutput, seg, flags);
-      bfd_set_section_alignment (stdoutput, seg, 2);
+      bfd_set_section_flags (seg, flags);
+      bfd_set_section_alignment (seg, 2);
     }
 
   *pcached = seg;
@@ -11844,7 +11867,7 @@ xtensa_create_property_segments (frag_predicate property_function,
            num_recs++;
 
          rec_size = num_recs * 8;
-         bfd_set_section_size (stdoutput, sec, rec_size);
+         bfd_set_section_size (sec, rec_size);
 
          if (num_recs)
            {
@@ -11941,7 +11964,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
            num_recs++;
 
          rec_size = num_recs * (8 + 4);
-         bfd_set_section_size (stdoutput, sec, rec_size);
+         bfd_set_section_size (sec, rec_size);
          /* elf_section_data (sec)->this_hdr.sh_entsize = 12; */
 
          if (num_recs)
@@ -11985,7 +12008,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
 static bfd_boolean
 exclude_section_from_property_tables (segT sec)
 {
-  flagword flags = bfd_get_section_flags (stdoutput, sec);
+  flagword flags = bfd_section_flags (sec);
 
   /* Sections that don't contribute to the memory footprint are excluded.  */
   if ((flags & SEC_DEBUGGING)