]> 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 932b2d6aaa052b1c66d4965a02152930933328a8..cbda45e6f0c3271587439ea6c126e9263e7abb62 100644 (file)
@@ -1,6 +1,5 @@
 /* tc-xtensa.c -- Assemble Xtensa instructions.
-   Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 2003-2021 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -19,8 +18,8 @@
    the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
    MA 02110-1301, USA.  */
 
-#include <limits.h>
 #include "as.h"
+#include <limits.h>
 #include "sb.h"
 #include "safe-ctype.h"
 #include "tc-xtensa.h"
 #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
@@ -72,16 +79,15 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 /* Flags to indicate whether the hardware supports the density and
    absolute literals options.  */
 
-bfd_boolean density_supported = XCHAL_HAVE_DENSITY;
-bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
+bfd_boolean density_supported;
+bfd_boolean absolute_literals_supported;
 
-/* Maximum width we would pad an unreachable frag to get alignment.  */
-#define UNREACHABLE_MAX_WIDTH  8
+static unsigned microarch_earliest;
 
 static vliw_insn cur_vinsn;
 
 unsigned xtensa_num_pipe_stages;
-unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+unsigned xtensa_fetch_width;
 
 static enum debug_info_type xt_saved_debug_type = DEBUG_NONE;
 
@@ -217,8 +223,6 @@ int generating_literals = 0;
 /* Required branch target alignment.  */
 #define XTENSA_PROP_BT_ALIGN_REQUIRE    0x3
 
-#define GET_XTENSA_PROP_BT_ALIGN(flag) \
-  (((unsigned) ((flag) & (XTENSA_PROP_BT_ALIGN_MASK))) >> 9)
 #define SET_XTENSA_PROP_BT_ALIGN(flag, align) \
   (((flag) & (~XTENSA_PROP_BT_ALIGN_MASK)) | \
     (((align) << 9) & XTENSA_PROP_BT_ALIGN_MASK))
@@ -239,8 +243,6 @@ int generating_literals = 0;
 
 #define XTENSA_PROP_ALIGNMENT_MASK      0x0001f000
 
-#define GET_XTENSA_PROP_ALIGNMENT(flag) \
-  (((unsigned) ((flag) & (XTENSA_PROP_ALIGNMENT_MASK))) >> 12)
 #define SET_XTENSA_PROP_ALIGNMENT(flag, align) \
   (((flag) & (~XTENSA_PROP_ALIGNMENT_MASK)) | \
     (((align) << 12) & XTENSA_PROP_ALIGNMENT_MASK))
@@ -365,10 +367,10 @@ op_placement_info_table op_placement_table;
 
 struct suffix_reloc_map
 {
-  char *suffix;
+  const char *suffix;
   int length;
   bfd_reloc_code_real_type reloc;
-  unsigned char operator;
+  operatorT operator;
 };
 
 #define SUFFIX_MAP(str, reloc, op) { str, sizeof (str) - 1, reloc, op }
@@ -384,7 +386,6 @@ static struct suffix_reloc_map suffix_relocs[] =
   SUFFIX_MAP ("tlscall", BFD_RELOC_XTENSA_TLS_CALL,    O_tlscall),
   SUFFIX_MAP ("tpoff", BFD_RELOC_XTENSA_TLS_TPOFF,     O_tpoff),
   SUFFIX_MAP ("dtpoff",        BFD_RELOC_XTENSA_TLS_DTPOFF,    O_dtpoff),
-  { (char *) 0, 0,     BFD_RELOC_UNUSED,               0 }
 };
 
 
@@ -427,23 +428,47 @@ bfd_boolean directive_state[] =
 {
   FALSE,                       /* none */
   FALSE,                       /* literal */
-#if !XCHAL_HAVE_DENSITY
   FALSE,                       /* density */
-#else
-  TRUE,                                /* density */
-#endif
   TRUE,                                /* transform */
   FALSE,                       /* freeregs */
   FALSE,                       /* longcalls */
   FALSE,                       /* literal_prefix */
   FALSE,                       /* schedule */
-#if XSHAL_USE_ABSOLUTE_LITERALS
-  TRUE                         /* absolute_literals */
-#else
   FALSE                                /* absolute_literals */
-#endif
 };
 
+/* A circular list of all potential and actual literal pool locations
+   in a segment.  */
+struct litpool_frag
+{
+  struct litpool_frag *next;
+  struct litpool_frag *prev;
+  fragS *fragP;
+  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.  */
+struct litpool_seg
+{
+  struct litpool_seg *next;
+  asection *seg;
+  struct litpool_frag frag_list;
+  int frag_count; /* since last litpool location  */
+};
+
+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.  */
 
@@ -472,6 +497,17 @@ static void xtensa_set_frag_assembly_state (fragS *);
 static void finish_vinsn (vliw_insn *);
 static bfd_boolean emit_single_op (TInsn *);
 static int total_frag_text_expansion (fragS *);
+static bfd_boolean use_trampolines = TRUE;
+static void xtensa_check_frag_count (void);
+static void xtensa_create_trampoline_frag (bfd_boolean);
+static void xtensa_maybe_create_trampoline_frag (void);
+struct trampoline_frag;
+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 = 0;
+static bfd_boolean xtensa_is_init_fini (segT seg);
 
 /* Alignment Functions.  */
 
@@ -501,10 +537,6 @@ static void xtensa_switch_section_emit_state (emit_state *, segT, subsegT);
 static void xtensa_restore_emit_state (emit_state *);
 static segT cache_literal_section (bfd_boolean);
 
-/* Import from elf32-xtensa.c in BFD library.  */
-
-extern asection *xtensa_make_property_section (asection *, const char *);
-
 /* op_placement_info functions.  */
 
 static void init_op_placement_info_table (void);
@@ -524,6 +556,7 @@ static void tinsn_from_chars (TInsn *, char *, int);
 static void tinsn_immed_from_frag (TInsn *, fragS *, int);
 static int get_num_stack_text_bytes (IStack *);
 static int get_num_stack_literal_bytes (IStack *);
+static bfd_boolean tinsn_to_slotbuf (xtensa_format, int, TInsn *, xtensa_insnbuf);
 
 /* vliw_insn functions.  */
 
@@ -605,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
@@ -614,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)
@@ -691,7 +732,20 @@ enum
   option_prefer_l32r,
   option_prefer_const16,
 
-  option_target_hardware
+  option_target_hardware,
+
+  option_trampolines,
+  option_no_trampolines,
+
+  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 = "";
@@ -764,6 +818,18 @@ struct option md_longopts[] =
 
   { "target-hardware", required_argument, NULL, option_target_hardware },
 
+  { "trampolines", no_argument, NULL, option_trampolines },
+  { "no-trampolines", no_argument, NULL, option_no_trampolines },
+
+  { "auto-litpools", no_argument, NULL, option_auto_litpools },
+  { "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 }
 };
 
@@ -771,7 +837,7 @@ size_t md_longopts_size = sizeof md_longopts;
 
 
 int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
 {
   switch (c)
     {
@@ -782,10 +848,10 @@ md_parse_option (int c, 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;
@@ -909,20 +975,21 @@ md_parse_option (int c, char *arg)
     case option_target_hardware:
       {
        int earliest, latest = 0;
+       char *end;
        if (*arg == 0 || *arg == '-')
          as_fatal (_("invalid target hardware version"));
 
-       earliest = strtol (arg, &arg, 0);
+       earliest = strtol (arg, &end, 0);
 
-       if (*arg == 0)
+       if (*end == 0)
          latest = earliest;
-       else if (*arg == '-')
+       else if (*end == '-')
          {
-           if (*++arg == 0)
+           if (*++end == 0)
              as_fatal (_("invalid target hardware version"));
-           latest = strtol (arg, &arg, 0);
+           latest = strtol (end, &end, 0);
          }
-       if (*arg != 0)
+       if (*end != 0)
          as_fatal (_("invalid target hardware version"));
 
        xtensa_setup_hw_workarounds (earliest, latest);
@@ -944,6 +1011,61 @@ md_parse_option (int c, char *arg)
       directive_state[directive_transform] = FALSE;
       return 1;
 
+    case option_trampolines:
+      use_trampolines = TRUE;
+      return 1;
+
+    case option_no_trampolines:
+      use_trampolines = FALSE;
+      return 1;
+
+    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:
+      auto_litpools = FALSE;
+      auto_litpool_limit = -1;
+      return 1;
+
+    case option_auto_litpool_limit:
+      {
+       int value = 0;
+       char *end;
+       if (auto_litpool_limit < 0)
+         as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
+       if (*arg == 0 || *arg == '-')
+         as_fatal (_("invalid auto-litpool-limit argument"));
+       value = strtol (arg, &end, 10);
+       if (*end != 0)
+         as_fatal (_("invalid auto-litpool-limit argument"));
+       if (value < 100 || value > 10000)
+         as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
+       auto_litpool_limit = value;
+       auto_litpools = TRUE;
+       use_literal_section = FALSE;
+       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;
     }
@@ -967,7 +1089,18 @@ Xtensa options:\n\
                           flix bundles\n\
   --no-allow-flix         neither allow hand-written nor generate\n\
                           flix bundles\n\
-  --rename-section old=new Rename section 'old' to 'new'\n", stream);
+  --rename-section old=new Rename section 'old' to 'new'\n\
+  --[no-]trampolines      [Do not] generate trampolines (jumps to jumps)\n\
+                          when jumps do not reach their targets\n\
+  --[no-]auto-litpools    [Do not] automatically create literal pools\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\
+  --[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
@@ -979,7 +1112,7 @@ xtensa_add_insn_label (symbolS *sym)
   sym_list *l;
 
   if (!free_insn_labels)
-    l = (sym_list *) xmalloc (sizeof (sym_list));
+    l = XNEW (sym_list);
   else
     {
       l = free_insn_labels;
@@ -1077,11 +1210,11 @@ do_align_targets (void)
 static void
 directive_push (directiveE directive, bfd_boolean negated, const void *datum)
 {
-  char *file;
+  const char *file;
   unsigned int line;
-  state_stackS *stack = (state_stackS *) xmalloc (sizeof (state_stackS));
+  state_stackS *stack = XNEW (state_stackS);
 
-  as_where (&file, &line);
+  file = as_where (&line);
 
   stack->directive = directive;
   stack->negated = negated;
@@ -1107,7 +1240,7 @@ directive_pop (directiveE *directive,
 
   if (!directive_state_stack)
     {
-      as_bad (_("unmatched end directive"));
+      as_bad (_("unmatched .end directive"));
       *directive = directive_none;
       return;
     }
@@ -1158,7 +1291,7 @@ get_directive (directiveE *directive, bfd_boolean *negated)
 {
   int len;
   unsigned i;
-  char *directive_string;
+  const char *directive_string;
 
   if (strncmp (input_line_pointer, "no-", 3) != 0)
     *negated = FALSE;
@@ -1235,7 +1368,7 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
          insn_labels = NULL;
        }
       as_warn (_(".begin literal is deprecated; use .literal instead"));
-      state = (emit_state *) xmalloc (sizeof (emit_state));
+      state = XNEW (emit_state);
       xtensa_switch_to_literal_fragment (state);
       directive_push (directive_literal, negated, state);
       break;
@@ -1254,7 +1387,7 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
 
       /* Allocate the literal state for this section and push
         onto the directive stack.  */
-      ls = xmalloc (sizeof (lit_state));
+      ls = XNEW (lit_state);
       gas_assert (ls);
 
       *ls = default_lit_sections;
@@ -1324,18 +1457,18 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
 
   md_flush_pending_output ();
 
-  switch (end_directive)
+  switch ((int) end_directive)
     {
-    case (directiveE) XTENSA_UNDEFINED:
+    case XTENSA_UNDEFINED:
       discard_rest_of_line ();
       return;
 
-    case directive_density:
+    case (int) directive_density:
       as_warn (_(".end [no-]density is ignored"));
       demand_empty_rest_of_line ();
       break;
 
-    case directive_absolute_literals:
+    case (int) directive_absolute_literals:
       if (!absolute_literals_supported && !end_negated)
        {
          as_warn (_("Xtensa absolute literals option not supported; ignored"));
@@ -1427,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))
     {
@@ -1443,27 +1575,19 @@ 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;
-
   /* All literals are aligned to four-byte boundaries.  */
   frag_align (2, 0, 0);
   record_alignment (now_seg, 2);
 
-  c = get_symbol_end ();
+  c = get_symbol_name (&base_name);
   /* Just after name is now '\0'.  */
   p = input_line_pointer;
   *p = c;
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
 
   if (*input_line_pointer != ',' && *input_line_pointer != ':')
     {
@@ -1473,11 +1597,11 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
       xtensa_restore_emit_state (&state);
       return;
     }
-  *p = 0;
 
+  *p = 0;
   colon (base_name);
-
   *p = c;
+
   input_line_pointer++;                /* skip ',' or ':' */
 
   xtensa_elf_cons (4);
@@ -1503,10 +1627,7 @@ xtensa_literal_prefix (void)
                "abcdefghijklmnopqrstuvwxyz_/0123456789.$");
 
   /* Get a null-terminated copy of the name.  */
-  name = xmalloc (len + 1);
-  gas_assert (name);
-  strncpy (name, input_line_pointer, len);
-  name[len] = 0;
+  name = xmemdup0 (input_line_pointer, len);
 
   /* Skip the name in the input line.  */
   input_line_pointer += len;
@@ -1588,7 +1709,9 @@ xtensa_elf_cons (int nbytes)
            as_bad (_("opcode-specific %s relocation used outside "
                      "an instruction"), reloc_howto->name);
          else if (nbytes != (int) bfd_get_reloc_size (reloc_howto))
-           as_bad (_("%s relocations do not fit in %d bytes"),
+           as_bad (ngettext ("%s relocations do not fit in %d byte",
+                             "%s relocations do not fit in %d bytes",
+                             nbytes),
                    reloc_howto->name, nbytes);
          else if (reloc == BFD_RELOC_XTENSA_TLS_FUNC
                   || reloc == BFD_RELOC_XTENSA_TLS_ARG
@@ -1636,7 +1759,7 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p)
   char *str2;
   int ch;
   int len;
-  struct suffix_reloc_map *ptr;
+  unsigned int i;
 
   if (*str++ != '@')
     return BFD_RELOC_NONE;
@@ -1653,10 +1776,10 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p)
   len = str2 - ident;
 
   ch = ident[0];
-  for (ptr = &suffix_relocs[0]; ptr->length > 0; ptr++)
-    if (ch == ptr->suffix[0]
-       && len == ptr->length
-       && memcmp (ident, ptr->suffix, ptr->length) == 0)
+  for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
+    if (ch == suffix_relocs[i].suffix[0]
+       && len == suffix_relocs[i].length
+       && memcmp (ident, suffix_relocs[i].suffix, suffix_relocs[i].length) == 0)
       {
        /* Now check for "identifier@suffix+constant".  */
        if (*str == '-' || *str == '+')
@@ -1677,7 +1800,7 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p)
          }
 
        *str_p = str;
-       return ptr->reloc;
+       return suffix_relocs[i].reloc;
       }
 
   return BFD_RELOC_UNUSED;
@@ -1685,21 +1808,21 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p)
 
 
 /* Find the matching operator type.  */
-static unsigned char
+static operatorT
 map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
 {
-  struct suffix_reloc_map *sfx;
-  unsigned char operator = (unsigned char) -1;
-  
-  for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+  operatorT operator = O_illegal;
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
     {
-      if (sfx->reloc == reloc)
+      if (suffix_relocs[i].reloc == reloc)
        {
-         operator = sfx->operator;
+         operator = suffix_relocs[i].operator;
          break;
        }
     }
-  gas_assert (operator != (unsigned char) -1);
+  gas_assert (operator != O_illegal);
   return operator;
 }
 
@@ -1708,14 +1831,14 @@ map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
 static bfd_reloc_code_real_type
 map_operator_to_reloc (unsigned char operator, bfd_boolean is_literal)
 {
-  struct suffix_reloc_map *sfx;
+  unsigned int i;
   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
 
-  for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+  for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
     {
-      if (sfx->operator == operator)
+      if (suffix_relocs[i].operator == operator)
        {
-         reloc = sfx->reloc;
+         reloc = suffix_relocs[i].reloc;
          break;
        }
     }
@@ -1826,6 +1949,7 @@ expression_maybe_register (xtensa_opcode opc, int opnd, expressionS *tok)
     {
       bfd_reloc_code_real_type reloc;
       segT t = expression (tok);
+
       if (t == absolute_section
          && xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
        {
@@ -1934,7 +2058,7 @@ tokenize_arguments (char **args, char *str)
            arg_end += 1;
 
          arg_len = arg_end - input_line_pointer;
-         arg = (char *) xmalloc ((saw_colon ? 1 : 0) + arg_len + 1);
+         arg = XNEWVEC (char, (saw_colon ? 1 : 0) + arg_len + 1);
          args[num_args] = arg;
 
          if (saw_colon)
@@ -1951,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)
@@ -2147,8 +2271,7 @@ xg_reverse_shift_count (char **cnt_argp)
   cnt_arg = *cnt_argp;
 
   /* replace the argument with "31-(argument)" */
-  new_arg = (char *) xmalloc (strlen (cnt_arg) + 6);
-  sprintf (new_arg, "31-(%s)", cnt_arg);
+  new_arg = concat ("31-(", cnt_arg, ")", (char *) NULL);
 
   free (cnt_arg);
   *cnt_argp = new_arg;
@@ -2179,11 +2302,10 @@ xg_arg_is_constant (char *arg, offsetT *valp)
 
 
 static void
-xg_replace_opname (char **popname, char *newop)
+xg_replace_opname (char **popname, const char *newop)
 {
   free (*popname);
-  *popname = (char *) xmalloc (strlen (newop) + 1);
-  strcpy (*popname, newop);
+  *popname = xstrdup (newop);
 }
 
 
@@ -2278,8 +2400,7 @@ xg_translate_sysreg_op (char **popname, int *pnum_args, char **arg_strings)
   /* Another special case for "WSR.INTSET"....  */
   if (is_write && !is_user && !strcasecmp ("interrupt", sr_name))
     sr_name = "intset";
-  new_opname = (char *) xmalloc (strlen (sr_name) + 6);
-  sprintf (new_opname, "%s.%s", *popname, sr_name);
+  new_opname = concat (*popname, ".", sr_name, (char *) NULL);
   free (*popname);
   *popname = new_opname;
 
@@ -2338,7 +2459,7 @@ xtensa_translate_old_userreg_ops (char **popname)
 
   /* Translate the opcode.  */
   sr_name = xtensa_sysreg_name (isa, sr);
-  new_opname = (char *) xmalloc (strlen (sr_name) + 6);
+  new_opname = XNEWVEC (char, strlen (sr_name) + 6);
   sprintf (new_opname, "%s%cur.%s", (has_underbar ? "_" : ""),
           opname[0], sr_name);
   free (*popname);
@@ -2349,8 +2470,8 @@ xtensa_translate_old_userreg_ops (char **popname)
 
 
 static int
-xtensa_translate_zero_immed (char *old_op,
-                            char *new_op,
+xtensa_translate_zero_immed (const char *old_op,
+                            const char *new_op,
                             char **popname,
                             int *pnum_args,
                             char **arg_strings)
@@ -2403,13 +2524,24 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
          if (xg_check_num_args (pnum_args, 2, opname, arg_strings))
            return -1;
          xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
-         arg_strings[2] = (char *) xmalloc (strlen (arg_strings[1]) + 1);
-         strcpy (arg_strings[2], arg_strings[1]);
+         arg_strings[2] = xstrdup (arg_strings[1]);
          *pnum_args = 3;
        }
       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))
@@ -2431,7 +2563,7 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
     }
 
   /* Don't do anything special with NOPs inside FLIX instructions.  They
-     are handled elsewhere.  Real NOP instructions are always available 
+     are handled elsewhere.  Real NOP instructions are always available
      in configurations with FLIX, so this should never be an issue but
      check for it anyway.  */
   if (!cur_vinsn.inside_bundle && xtensa_nop_opcode == XTENSA_UNDEFINED
@@ -2444,12 +2576,9 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
          if (xg_check_num_args (pnum_args, 0, opname, arg_strings))
            return -1;
          xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
-         arg_strings[0] = (char *) xmalloc (3);
-         arg_strings[1] = (char *) xmalloc (3);
-         arg_strings[2] = (char *) xmalloc (3);
-         strcpy (arg_strings[0], "a1");
-         strcpy (arg_strings[1], "a1");
-         strcpy (arg_strings[2], "a1");
+         arg_strings[0] = xstrdup ("a1");
+         arg_strings[1] = xstrdup ("a1");
+         arg_strings[2] = xstrdup ("a1");
          *pnum_args = 3;
        }
       return 0;
@@ -2721,7 +2850,7 @@ xtensa_insnbuf_set_operand (xtensa_insnbuf slotbuf,
       if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, operand)
          == 1)
        as_bad_where ((char *) file, line,
-                     _("operand %d of '%s' has out of range value '%u'"), 
+                     _("operand %d of '%s' has out of range value '%u'"),
                      operand + 1,
                      xtensa_opcode_name (xtensa_default_isa, opcode),
                      value);
@@ -3235,15 +3364,16 @@ xg_immeds_fit (const TInsn *insn)
   gas_assert (insn->insn_type == ITYPE_INSN);
   for (i = 0; i < n; ++i)
     {
-      const expressionS *expr = &insn->tok[i];
+      const expressionS *exp = &insn->tok[i];
+
       if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
        continue;
 
-      switch (expr->X_op)
+      switch (exp->X_op)
        {
        case O_register:
        case O_constant:
-         if (xg_check_operand (expr->X_add_number, insn->opcode, i))
+         if (xg_check_operand (exp->X_add_number, insn->opcode, i))
            return FALSE;
          break;
 
@@ -3279,15 +3409,16 @@ xg_symbolic_immeds_fit (const TInsn *insn,
 
   for (i = 0; i < n; ++i)
     {
-      const expressionS *expr = &insn->tok[i];
+      const expressionS *exp = &insn->tok[i];
+
       if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
        continue;
 
-      switch (expr->X_op)
+      switch (exp->X_op)
        {
        case O_register:
        case O_constant:
-         if (xg_check_operand (expr->X_add_number, insn->opcode, i))
+         if (xg_check_operand (exp->X_add_number, insn->opcode, i))
            return FALSE;
          break;
 
@@ -3307,8 +3438,8 @@ xg_symbolic_immeds_fit (const TInsn *insn,
 
          /* If it is a weak symbol or a symbol in a different section,
             it cannot be known to fit at assembly time.  */
-         if (S_IS_WEAK (expr->X_add_symbol)
-             || S_GET_SEGMENT (expr->X_add_symbol) != pc_seg)
+         if (S_IS_WEAK (exp->X_add_symbol)
+             || S_GET_SEGMENT (exp->X_add_symbol) != pc_seg)
            {
              /* For a direct call with --no-longcalls, be optimistic and
                 assume it will be in range.  If the symbol is weak and
@@ -3318,16 +3449,16 @@ xg_symbolic_immeds_fit (const TInsn *insn,
                 symbols even if longcalls is not enabled.  */
              if (is_direct_call_opcode (insn->opcode)
                  && ! pc_frag->tc_frag_data.use_longcalls
-                 && (! S_IS_WEAK (expr->X_add_symbol)
-                     || S_IS_DEFINED (expr->X_add_symbol)))
+                 && (! S_IS_WEAK (exp->X_add_symbol)
+                     || S_IS_DEFINED (exp->X_add_symbol)))
                return TRUE;
 
              return FALSE;
            }
 
-         symbolP = expr->X_add_symbol;
+         symbolP = exp->X_add_symbol;
          sym_frag = symbol_get_frag (symbolP);
-         target = S_GET_VALUE (symbolP) + expr->X_add_number;
+         target = S_GET_VALUE (symbolP) + exp->X_add_number;
          pc = pc_frag->fr_address + pc_offset;
 
          /* If frag has yet to be reached on this pass, assume it
@@ -3568,11 +3699,11 @@ xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps)
              /* Check to see if it fits.  */
              for (i = stack_size; i < istack->ninsn; i++)
                {
-                 TInsn *insn = &istack->insn[i];
+                 TInsn *tinsn = &istack->insn[i];
 
-                 if (insn->insn_type == ITYPE_INSN
-                     && !tinsn_has_symbolic_operands (insn)
-                     && !xg_immeds_fit (insn))
+                 if (tinsn->insn_type == ITYPE_INSN
+                     && !tinsn_has_symbolic_operands (tinsn)
+                     && !xg_immeds_fit (tinsn))
                    {
                      istack->ninsn = stack_size;
                      return FALSE;
@@ -3946,14 +4077,18 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn)
                                          orig_insn->opcode);
   if (orig_insn->ntok < noperands)
     {
-      as_bad (_("found %d operands for '%s':  Expected %d"),
+      as_bad (ngettext ("found %d operand for '%s':  Expected %d",
+                       "found %d operands for '%s':  Expected %d",
+                       orig_insn->ntok),
              orig_insn->ntok,
              xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode),
              noperands);
       return TRUE;
     }
   if (orig_insn->ntok > noperands)
-    as_warn (_("found too many (%d) operands for '%s':  Expected %d"),
+    as_warn (ngettext ("found %d operand for '%s':  Expected %d",
+                      "found %d operands for '%s':  Expected %d",
+                      orig_insn->ntok),
             orig_insn->ntok,
             xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode),
             noperands);
@@ -4020,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.  */
@@ -4037,7 +4172,7 @@ xtensa_add_literal_sym (symbolS *sym)
 {
   sym_list *l;
 
-  l = (sym_list *) xmalloc (sizeof (sym_list));
+  l = XNEW (sym_list);
   l->sym = sym;
   l->next = literal_syms;
   literal_syms = l;
@@ -4058,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);
 
@@ -4192,7 +4327,7 @@ xg_add_opcode_fix (TInsn *tinsn,
                   int opnum,
                   xtensa_format fmt,
                   int slot,
-                  expressionS *expr,
+                  expressionS *exp,
                   fragS *fragP,
                   offsetT offset)
 {
@@ -4212,15 +4347,15 @@ xg_add_opcode_fix (TInsn *tinsn,
     }
   else if (opcode == xtensa_const16_opcode)
     {
-      if (expr->X_op == O_lo16)
+      if (exp->X_op == O_lo16)
        {
          reloc = encode_reloc (slot);
-         expr->X_op = O_symbol;
+         exp->X_op = O_symbol;
        }
-      else if (expr->X_op == O_hi16)
+      else if (exp->X_op == O_hi16)
        {
          reloc = encode_alt_reloc (slot);
-         expr->X_op = O_symbol;
+         exp->X_op = O_symbol;
        }
     }
 
@@ -4234,7 +4369,7 @@ xg_add_opcode_fix (TInsn *tinsn,
   /* Handle erroneous "@h" and "@l" expressions here before they propagate
      into the symbol table where the generic portions of the assembler
      won't know what to do with them.  */
-  if (expr->X_op == O_lo16 || expr->X_op == O_hi16)
+  if (exp->X_op == O_lo16 || exp->X_op == O_hi16)
     {
       as_bad (_("invalid expression for operand %i of '%s'"),
              opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
@@ -4259,11 +4394,11 @@ xg_add_opcode_fix (TInsn *tinsn,
     }
 
   fmt_length = xtensa_format_length (xtensa_default_isa, fmt);
-  the_fix = fix_new_exp (fragP, offset, fmt_length, expr,
+  the_fix = fix_new_exp (fragP, offset, fmt_length, exp,
                         howto->pc_relative, reloc);
   the_fix->fx_no_overflow = 1;
-  the_fix->tc_fix_data.X_add_symbol = expr->X_add_symbol;
-  the_fix->tc_fix_data.X_add_number = expr->X_add_number;
+  the_fix->tc_fix_data.X_add_symbol = exp->X_add_symbol;
+  the_fix->tc_fix_data.X_add_number = exp->X_add_number;
   the_fix->tc_fix_data.slot = slot;
 
   return TRUE;
@@ -4521,12 +4656,18 @@ frag_format_size (const fragS *fragP)
         be accompanied by major changes to make use of that data.
 
         In any event, we can tell that we are expanding from a single-slot
-        three-byte format to a wider one with the logic below.  */
+        format to a wider one with the logic below.  */
 
-      if (fmt_size <= 3 && fragP->tc_frag_data.text_expansion[0] != 3)
-       return 3 + fragP->tc_frag_data.text_expansion[0];
-      else
-       return 3;
+      int i;
+      int relaxed_size = fmt_size + fragP->tc_frag_data.text_expansion[0];
+
+      for (i = 0; i < xtensa_isa_num_formats (isa); i++)
+       {
+         if (relaxed_size == xtensa_format_length (isa, i))
+           return relaxed_size;
+       }
+
+      return 3;
     }
 
   if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
@@ -4643,6 +4784,12 @@ next_frag_is_loop_target (const fragS *fragP)
 }
 
 
+/* As specified in the relaxation table, when a loop instruction is
+   relaxed, there are 24 bytes between the loop instruction itself and
+   the first instruction in the loop.  */
+
+#define RELAXED_LOOP_INSN_BYTES 24
+
 static addressT
 next_frag_pre_opcode_bytes (const fragS *fragp)
 {
@@ -4665,7 +4812,7 @@ next_frag_pre_opcode_bytes (const fragS *fragp)
      been relaxed.  Note that we can assume that the LOOP
      instruction is in slot 0 because loops aren't bundleable.  */
   if (next_fragp->tc_frag_data.slot_subtypes[0] > RELAX_IMMED)
-      return get_expanded_loop_offset (next_opcode);
+      return get_expanded_loop_offset (next_opcode) + RELAXED_LOOP_INSN_BYTES;
 
   return 0;
 }
@@ -4680,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)
@@ -4691,6 +4837,8 @@ xtensa_mark_literal_pool_location (void)
   pool_location = frag_now;
   frag_now->tc_frag_data.lit_frchain = frchain_now;
   frag_now->tc_frag_data.literal_frag = frag_now;
+  /* Just record this frag.  */
+  xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
   frag_variant (rs_machine_dependent, 0, 0,
                RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
   xtensa_set_frag_assembly_state (frag_now);
@@ -4699,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);
 }
 
 
@@ -4795,6 +4931,34 @@ get_expanded_loop_offset (xtensa_opcode opcode)
 static fragS *
 get_literal_pool_location (segT seg)
 {
+  if (auto_litpools)
+    {
+      struct litpool_seg *lps = litpool_seg_list.next;
+      struct litpool_frag *lpf;
+      for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
+       ;
+      if (lps)
+       {
+         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;
 }
 
@@ -4856,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))
@@ -4901,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))
@@ -4949,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;
 
@@ -4988,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;
@@ -5004,16 +5168,22 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
              addressT frag_addr;
              xtensa_format fmt;
 
-             xtensa_insnbuf_from_chars
-               (isa, insnbuf, (unsigned char *) frag->fr_literal, 0);
-             fmt = xtensa_format_decode (isa, insnbuf);
-             op_size = xtensa_format_length (isa, fmt);
-             frag_addr = frag->fr_address % xtensa_fetch_width;
+             if (frag->fr_fix == 0)
+               frag = next_non_empty_frag (frag);
 
-             if (frag_addr + op_size > xtensa_fetch_width)
-               as_warn_where (frag->fr_file, frag->fr_line,
-                              _("unaligned loop: %d bytes at 0x%lx"),
-                              op_size, (long) frag->fr_address);
+             if (frag)
+               {
+                 xtensa_insnbuf_from_chars
+                   (isa, insnbuf, (unsigned char *) frag->fr_literal, 0);
+                 fmt = xtensa_format_decode (isa, insnbuf);
+                 op_size = xtensa_format_length (isa, fmt);
+                 frag_addr = frag->fr_address % xtensa_fetch_width;
+
+                 if (frag_addr + op_size > xtensa_fetch_width)
+                   as_warn_where (frag->fr_file, frag->fr_line,
+                                  _("unaligned loop: %d bytes at 0x%lx"),
+                                  op_size, (long) frag->fr_address);
+               }
            }
          frag = frag->fr_next;
        }
@@ -5095,6 +5265,26 @@ md_number_to_chars (char *buf, valueT val, int n)
     number_to_chars_littleendian (buf, val, n);
 }
 
+static void
+xg_init_global_config (void)
+{
+  target_big_endian = XCHAL_HAVE_BE;
+
+  density_supported = XCHAL_HAVE_DENSITY;
+  absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
+  xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+
+  directive_state[directive_density] = XCHAL_HAVE_DENSITY;
+  directive_state[directive_absolute_literals] = XSHAL_USE_ABSOLUTE_LITERALS;
+
+  microarch_earliest = XTENSA_MARCH_EARLIEST;
+}
+
+void
+xtensa_init (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+  xg_init_global_config ();
+}
 
 /* This function is called once, at assembler startup time.  It should
    set up all the tables, etc. that the MD part of the assembler will
@@ -5111,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));
@@ -5150,7 +5340,7 @@ md_begin (void)
   xtensa_rsr_lcount_opcode = xtensa_opcode_lookup (isa, "rsr.lcount");
   xtensa_waiti_opcode = xtensa_opcode_lookup (isa, "waiti");
 
-  for (i = 0; i < xtensa_isa_num_formats (isa); i++) 
+  for (i = 0; i < xtensa_isa_num_formats (isa); i++)
     {
       int format_slots = xtensa_format_num_slots (isa, i);
       if (format_slots > config_max_slots)
@@ -5166,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 ();
 }
 
 
@@ -5362,9 +5555,7 @@ md_assemble (char *str)
 
   /* Split off the opcode.  */
   opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/0123456789.");
-  opname = xmalloc (opnamelen + 1);
-  memcpy (opname, str, opnamelen);
-  opname[opnamelen] = '\0';
+  opname = xstrndup (str, opnamelen);
 
   num_args = tokenize_arguments (arg_strings, str + opnamelen);
   if (num_args == -1)
@@ -5388,7 +5579,7 @@ md_assemble (char *str)
   orig_insn.is_specific_opcode = (has_underbar || !use_transform ());
   orig_insn.opcode = xtensa_opcode_lookup (isa, opname);
 
-  /* Special case: Check for "CALLXn.TLS" psuedo op.  If found, grab its
+  /* Special case: Check for "CALLXn.TLS" pseudo op.  If found, grab its
      extra argument and set the opcode to "CALLXn".  */
   if (orig_insn.opcode == XTENSA_UNDEFINED
       && strncasecmp (opname, "callx", 5) == 0)
@@ -5419,12 +5610,11 @@ md_assemble (char *str)
              bfd_reloc_code_real_type reloc;
              char *old_input_line_pointer;
              expressionS *tok = &orig_insn.extra_arg;
-             segT t;
 
              old_input_line_pointer = input_line_pointer;
              input_line_pointer = arg_strings[num_args - 1];
 
-             t = expression (tok);
+             expression (tok);
              if (tok->X_op == O_symbol
                  && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok))
                      == BFD_RELOC_XTENSA_TLS_CALL))
@@ -5438,7 +5628,7 @@ md_assemble (char *str)
        }
     }
 
-  /* Special case: Check for "j.l" psuedo op.  */
+  /* Special case: Check for "j.l" pseudo op.  */
   if (orig_insn.opcode == XTENSA_UNDEFINED
       && strncasecmp (opname, "j.l", 3) == 0)
     {
@@ -5549,6 +5739,8 @@ md_assemble (char *str)
 
   /* We've just emitted a new instruction so clear the list of labels.  */
   xtensa_clear_insn_labels ();
+
+  xtensa_check_frag_count ();
 }
 
 
@@ -5565,7 +5757,6 @@ xtensa_handle_align (fragS *fragP)
       && ! fragP->tc_frag_data.is_literal
       && (fragP->fr_type == rs_align
          || fragP->fr_type == rs_align_code)
-      && fragP->fr_address + fragP->fr_fix > 0
       && fragP->fr_offset > 0
       && now_seg != bss_section)
     {
@@ -5767,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 ();
 }
 
 
@@ -5775,14 +5971,6 @@ xtensa_elf_section_change_hook (void)
 bfd_boolean
 xtensa_fix_adjustable (fixS *fixP)
 {
-  /* An offset is not allowed in combination with the difference of two
-     symbols, but that cannot be easily detected after a local symbol
-     has been adjusted to a (section+offset) form.  Return 0 so that such
-     an fix will not be adjusted.  */
-  if (fixP->fx_subsy && fixP->fx_addsy && fixP->fx_offset
-      && relaxable_section (S_GET_SEGMENT (fixP->fx_subsy)))
-    return 0;
-
   /* We need the symbol name for the VTABLE entries.  */
   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
@@ -5796,7 +5984,7 @@ xtensa_fix_adjustable (fixS *fixP)
 
 symbolS *expr_symbols = NULL;
 
-void 
+void
 xtensa_symbol_new_hook (symbolS *sym)
 {
   if (is_leb128_expr && S_GET_SEGMENT (sym) == expr_section)
@@ -5828,30 +6016,30 @@ 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:
              break;
            }
 
-         /* An offset is only allowed when it results from adjusting a
-            local symbol into a section-relative offset.  If the offset
-            came from the original expression, tc_fix_adjustable will have
-            prevented the fix from being converted to a section-relative
-            form so that we can flag the error here.  */
-         if (fixP->fx_offset != 0 && !symbol_section_p (fixP->fx_addsy))
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("cannot represent subtraction with an offset"));
-
          val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
                 - S_GET_VALUE (fixP->fx_subsy));
 
@@ -5867,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:
@@ -5956,7 +6150,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 }
 
 
-char *
+const char *
 md_atof (int type, char *litP, int *sizeP)
 {
   return ieee_md_atof (type, litP, sizeP, target_big_endian);
@@ -5978,8 +6172,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *reloc;
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc = XNEW (arelent);
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
@@ -6024,7 +6218,7 @@ new_resource_table (void *data,
                    opcode_funcUnit_use_stage_func ousf)
 {
   int i;
-  resource_table *rt = (resource_table *) xmalloc (sizeof (resource_table));
+  resource_table *rt = XNEW (resource_table);
   rt->data = data;
   rt->cycles = cycles;
   rt->allocated_cycles = cycles;
@@ -6034,9 +6228,9 @@ new_resource_table (void *data,
   rt->opcode_unit_use = ouuf;
   rt->opcode_unit_stage = ousf;
 
-  rt->units = (unsigned char **) xcalloc (cycles, sizeof (unsigned char *));
+  rt->units = XCNEWVEC (unsigned char *, cycles);
   for (i = 0; i < cycles; i++)
-    rt->units[i] = (unsigned char *) xcalloc (nu, sizeof (unsigned char));
+    rt->units[i] = XCNEWVEC (unsigned char, nu);
 
   return rt;
 }
@@ -6066,13 +6260,11 @@ resize_resource_table (resource_table *rt, int cycles)
   old_cycles = rt->allocated_cycles;
   rt->allocated_cycles = cycles;
 
-  rt->units = xrealloc (rt->units,
-                       rt->allocated_cycles * sizeof (unsigned char *));
+  rt->units = XRESIZEVEC (unsigned char *, rt->units, rt->allocated_cycles);
   for (i = 0; i < old_cycles; i++)
-    rt->units[i] = xrealloc (rt->units[i],
-                            rt->num_units * sizeof (unsigned char));
+    rt->units[i] = XRESIZEVEC (unsigned char, rt->units[i], rt->num_units);
   for (i = old_cycles; i < cycles; i++)
-    rt->units[i] = xcalloc (rt->num_units, sizeof (unsigned char));
+    rt->units[i] = XCNEWVEC (unsigned char, rt->num_units);
 }
 
 
@@ -6204,8 +6396,7 @@ finish_vinsn (vliw_insn *vinsn)
 {
   IStack slotstack;
   int i;
-  char *file_name;
-  unsigned line;
+  int slots;
 
   if (find_vinsn_conflicts (vinsn))
     {
@@ -6217,7 +6408,8 @@ finish_vinsn (vliw_insn *vinsn)
   if (vinsn->format == XTENSA_UNDEFINED)
     vinsn->format = xg_find_narrowest_format (vinsn);
 
-  if (xtensa_format_num_slots (xtensa_default_isa, vinsn->format) > 1
+  slots = xtensa_format_num_slots (xtensa_default_isa, vinsn->format);
+  if (slots > 1
       && produce_flix == FLIX_NONE)
     {
       as_bad (_("The option \"--no-allow-flix\" prohibits multi-slot flix."));
@@ -6227,9 +6419,7 @@ finish_vinsn (vliw_insn *vinsn)
 
   if (vinsn->format == XTENSA_UNDEFINED)
     {
-      as_where (&file_name, &line);
-      as_bad_where (file_name, line,
-                   _("couldn't find a valid instruction format"));
+      as_bad (_("couldn't find a valid instruction format"));
       fprintf (stderr, _("    ops were: "));
       for (i = 0; i < vinsn->num_slots; i++)
        fprintf (stderr, _(" %s;"),
@@ -6240,21 +6430,18 @@ finish_vinsn (vliw_insn *vinsn)
       return;
     }
 
-  if (vinsn->num_slots
-      != xtensa_format_num_slots (xtensa_default_isa, vinsn->format))
+  if (vinsn->num_slots != slots)
     {
-      as_bad (_("format '%s' allows %d slots, but there are %d opcodes"),
+      as_bad (_("mismatch for format '%s': #slots = %d, #opcodes = %d"),
              xtensa_format_name (xtensa_default_isa, vinsn->format),
-             xtensa_format_num_slots (xtensa_default_isa, vinsn->format),
-             vinsn->num_slots);
+             slots, vinsn->num_slots);
       xg_clear_vinsn (vinsn);
       return;
     }
 
   if (resources_conflict (vinsn))
     {
-      as_where (&file_name, &line);
-      as_bad_where (file_name, line, _("illegal resource usage in bundle"));
+      as_bad (_("illegal resource usage in bundle"));
       fprintf (stderr, "    ops were: ");
       for (i = 0; i < vinsn->num_slots; i++)
        fprintf (stderr, " %s;",
@@ -6351,8 +6538,7 @@ finish_vinsn (vliw_insn *vinsn)
   /* Now check resource conflicts on the modified bundle.  */
   if (resources_conflict (vinsn))
     {
-      as_where (&file_name, &line);
-      as_bad_where (file_name, line, _("illegal resource usage in bundle"));
+      as_bad (_("illegal resource usage in bundle"));
       fprintf (stderr, "    ops were: ");
       for (i = 0; i < vinsn->num_slots; i++)
        fprintf (stderr, " %s;",
@@ -6370,6 +6556,8 @@ finish_vinsn (vliw_insn *vinsn)
   xg_assemble_vliw_tokens (vinsn);
 
   xg_clear_vinsn (vinsn);
+
+  xtensa_check_frag_count ();
 }
 
 
@@ -6854,7 +7042,7 @@ emit_single_op (TInsn *orig_insn)
        case ITYPE_LABEL:
          {
            static int relaxed_sym_idx = 0;
-           char *label = xmalloc (strlen (FAKE_LABEL_NAME) + 12);
+           char *label = XNEWVEC (char, strlen (FAKE_LABEL_NAME) + 12);
            sprintf (label, "%s_rl_%x", FAKE_LABEL_NAME, relaxed_sym_idx++);
            colon (label);
            gas_assert (label_sym == NULL);
@@ -6932,7 +7120,7 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
   if (frag_now_fix () != 0
       && (! frag_now->tc_frag_data.is_insn
          || (vinsn_has_specific_opcodes (vinsn) && use_transform ())
-         || !use_transform () != frag_now->tc_frag_data.is_no_transform
+         || (!use_transform ()) != frag_now->tc_frag_data.is_no_transform
          || (directive_state[directive_longcalls]
              != frag_now->tc_frag_data.use_longcalls)
          || (directive_state[directive_absolute_literals]
@@ -7067,6 +7255,9 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
       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]
+         = 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;
@@ -7134,16 +7325,19 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
        {
          gas_assert (finish_frag);
          frag_var (rs_machine_dependent,
-                   UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH,
+                   xtensa_fetch_width, xtensa_fetch_width,
                    RELAX_UNREACHABLE,
                    frag_now->fr_symbol, frag_now->fr_offset, NULL);
          xtensa_set_frag_assembly_state (frag_now);
+         xtensa_maybe_create_trampoline_frag ();
+         /* Always create one here.  */
+         xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
        }
       else if (is_branch && do_align_targets ())
        {
          gas_assert (finish_frag);
          frag_var (rs_machine_dependent,
-                   UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH,
+                   xtensa_fetch_width, xtensa_fetch_width,
                    RELAX_MAYBE_UNREACHABLE,
                    frag_now->fr_symbol, frag_now->fr_offset, NULL);
          xtensa_set_frag_assembly_state (frag_now);
@@ -7220,137 +7414,715 @@ xtensa_end (void)
   xtensa_sanity_check ();
 
   xtensa_add_config_info ();
+
+  xtensa_check_frag_count ();
 }
 
+struct trampoline_chain_entry
+{
+  symbolS *sym;
+  addressT offset;
+};
 
-static void
-xtensa_cleanup_align_frags (void)
+/* Trampoline chain for a given (sym, offset) pair is a sorted array
+   of locations of trampoline jumps leading there.  Jumps are represented
+   as pairs (sym, offset): trampoline frag symbol and offset of the jump
+   inside the frag.  */
+struct trampoline_chain
+{
+  struct trampoline_chain_entry target;
+  struct trampoline_chain_entry *entry;
+  size_t n_entries;
+  size_t n_max;
+  bfd_boolean needs_sorting;
+};
+
+struct trampoline_chain_index
 {
-  frchainS *frchP;
-  asection *s;
+  struct trampoline_chain *entry;
+  size_t n_entries;
+  size_t n_max;
+  bfd_boolean needs_sorting;
+};
 
-  for (s = stdoutput->sections; s; s = s->next)
-    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
-      {
-       fragS *fragP;
-       /* Walk over all of the fragments in a subsection.  */
-       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-         {
-           if ((fragP->fr_type == rs_align
-                || fragP->fr_type == rs_align_code
-                || (fragP->fr_type == rs_machine_dependent
-                    && (fragP->fr_subtype == RELAX_DESIRE_ALIGN
-                        || fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)))
-               && fragP->fr_fix == 0)
-             {
-               fragS *next = fragP->fr_next;
+struct trampoline_index
+{
+  fragS **entry;
+  size_t n_entries;
+  size_t n_max;
+};
 
-               while (next
-                      && next->fr_fix == 0
-                      && next->fr_type == rs_machine_dependent
-                      && next->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
-                 {
-                   frag_wane (next);
-                   next = next->fr_next;
-                 }
-             }
-           /* If we don't widen branch targets, then they
-              will be easier to align.  */
-           if (fragP->tc_frag_data.is_branch_target
-               && fragP->fr_opcode == fragP->fr_literal
-               && fragP->fr_type == rs_machine_dependent
-               && fragP->fr_subtype == RELAX_SLOTS
-               && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
-             frag_wane (fragP);
-           if (fragP->fr_type == rs_machine_dependent
-               && fragP->fr_subtype == RELAX_UNREACHABLE)
-             fragP->tc_frag_data.is_unreachable = TRUE;
-         }
-      }
-}
+struct trampoline_seg
+{
+  struct trampoline_seg *next;
+  asection *seg;
+  /* Trampolines ordered by their frag fr_address */
+  struct trampoline_index index;
+  /* Known trampoline chains ordered by (sym, offset) pair */
+  struct trampoline_chain_index chain_index;
+};
 
+static struct trampoline_seg trampoline_seg_list;
+#define J_RANGE (128 * 1024)
+#define J_MARGIN 4096
+
+static int unreachable_count = 0;
 
-/* Re-process all of the fragments looking to convert all of the
-   RELAX_DESIRE_ALIGN_IF_TARGET fragments.  If there is a branch
-   target in the next fragment, convert this to RELAX_DESIRE_ALIGN.
-   Otherwise, convert to a .fill 0.  */
 
 static void
-xtensa_fix_target_frags (void)
+xtensa_maybe_create_trampoline_frag (void)
 {
-  frchainS *frchP;
-  asection *s;
+  if (!use_trampolines)
+    return;
 
-  /* When this routine is called, all of the subsections are still intact
-     so we walk over subsections instead of sections.  */
-  for (s = stdoutput->sections; s; s = s->next)
-    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
-      {
-       fragS *fragP;
+  /* We create an area for possible trampolines every 10 unreachable frags.
+     These are preferred over the ones not preceded by an unreachable frag,
+     because we don't have to jump around them. This function is called after
+     each RELAX_UNREACHABLE frag is created.  */
 
-       /* Walk over all of the fragments in a subsection.  */
-       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-         {
-           if (fragP->fr_type == rs_machine_dependent
-               && fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
-             {
-               if (next_frag_is_branch_target (fragP))
-                 fragP->fr_subtype = RELAX_DESIRE_ALIGN;
-               else
-                 frag_wane (fragP);
-             }
-         }
-      }
+  if (++unreachable_count > 10)
+    {
+      xtensa_create_trampoline_frag (FALSE);
+      clear_frag_count ();
+      unreachable_count = 0;
+    }
 }
 
-
-static bfd_boolean is_narrow_branch_guaranteed_in_range (fragS *, TInsn *);
-
 static void
-xtensa_mark_narrow_branches (void)
+xtensa_check_frag_count (void)
 {
-  frchainS *frchP;
-  asection *s;
+  if (!use_trampolines || frag_now->tc_frag_data.is_no_transform)
+    return;
 
-  for (s = stdoutput->sections; s; s = s->next)
-    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
-      {
-       fragS *fragP;
-       /* Walk over all of the fragments in a subsection.  */
-       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-         {
-           if (fragP->fr_type == rs_machine_dependent
-               && fragP->fr_subtype == RELAX_SLOTS
-               && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
-             {
-               vliw_insn vinsn;
+  /* We create an area for possible trampolines every 8000 frags or so. This
+     is an estimate based on the max range of a "j" insn (+/-128K) divided
+     by a typical frag byte count (16), minus a few for safety. This function
+     is called after each source line is processed.  */
 
-               vinsn_from_chars (&vinsn, fragP->fr_opcode);
-               tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0);
+  if (get_frag_count () > 8000)
+    {
+      xtensa_create_trampoline_frag (TRUE);
+      clear_frag_count ();
+      unreachable_count = 0;
+    }
 
-               if (vinsn.num_slots == 1
-                   && xtensa_opcode_is_branch (xtensa_default_isa,
-                                               vinsn.slots[0].opcode) == 1
-                   && xg_get_single_size (vinsn.slots[0].opcode) == 2
-                   && is_narrow_branch_guaranteed_in_range (fragP,
-                                                            &vinsn.slots[0]))
-                 {
-                   fragP->fr_subtype = RELAX_SLOTS;
-                   fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW;
-                   fragP->tc_frag_data.is_aligning_branch = 1;
-                 }
-             }
-         }
-      }
+  /* We create an area for a possible literal pool every N (default 5000)
+     frags or so.  */
+  xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
 }
 
+static xtensa_insnbuf trampoline_buf = NULL;
+static xtensa_insnbuf trampoline_slotbuf = NULL;
 
-/* A branch is typically widened only when its target is out of
-   range.  However, we would like to widen them to align a subsequent
-   branch target when possible.
+static xtensa_insnbuf litpool_buf = NULL;
+static xtensa_insnbuf litpool_slotbuf = NULL;
 
-   Because the branch relaxation code is so convoluted, the optimal solution
-   (combining the two cases) is difficult to get right in all circumstances.
+#define TRAMPOLINE_FRAG_SIZE 3000
+
+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)
+       {
+         mr = ts;
+         return ts;
+       }
+    }
+
+  return NULL;
+}
+
+static size_t xg_find_trampoline (const struct trampoline_index *idx,
+                                 addressT addr)
+{
+  size_t a = 0;
+  size_t b = idx->n_entries;
+
+  while (b - a > 1)
+    {
+      size_t c = (a + b) / 2;
+
+      if (idx->entry[c]->fr_address <= addr)
+       a = c;
+      else
+       b = c;
+    }
+  return a;
+}
+
+static void xg_add_trampoline_to_index (struct trampoline_index *idx,
+                                       fragS *fragP)
+{
+  if (idx->n_entries == idx->n_max)
+    {
+      idx->n_max = (idx->n_entries + 1) * 2;
+      idx->entry = xrealloc (idx->entry,
+                            sizeof (*idx->entry) * idx->n_max);
+    }
+  idx->entry[idx->n_entries] = fragP;
+  ++idx->n_entries;
+}
+
+static void xg_remove_trampoline_from_index (struct trampoline_index *idx,
+                                            size_t i)
+{
+  gas_assert (i < idx->n_entries);
+  memmove (idx->entry + i, idx->entry + i + 1,
+          (idx->n_entries - i - 1) * sizeof (*idx->entry));
+  --idx->n_entries;
+}
+
+static void xg_add_trampoline_to_seg (struct trampoline_seg *ts,
+                                     fragS *fragP)
+{
+  xg_add_trampoline_to_index (&ts->index, fragP);
+}
+
+static void
+xtensa_create_trampoline_frag (bfd_boolean needs_jump_around)
+{
+  /* Emit a frag where we can place intermediate jump instructions,
+     in case we need to jump farther than 128K bytes.
+     Each jump instruction takes three bytes.
+     We allocate enough for 1000 trampolines in each frag.
+     If that's not enough, oh well.  */
+
+  struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+  char *varP;
+  fragS *fragP;
+  int size = TRAMPOLINE_FRAG_SIZE;
+
+  if (ts == NULL)
+    {
+      ts = XCNEW(struct trampoline_seg);
+      ts->next = trampoline_seg_list.next;
+      trampoline_seg_list.next = ts;
+      ts->seg = now_seg;
+    }
+
+  frag_wane (frag_now);
+  frag_new (0);
+  xtensa_set_frag_assembly_state (frag_now);
+  varP = frag_var (rs_machine_dependent, size, size, RELAX_TRAMPOLINE, NULL, 0, NULL);
+  fragP = (fragS *)(varP - SIZEOF_STRUCT_FRAG);
+  if (trampoline_buf == NULL)
+    {
+      trampoline_buf = xtensa_insnbuf_alloc (xtensa_default_isa);
+      trampoline_slotbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
+    }
+  fragP->tc_frag_data.needs_jump_around = needs_jump_around;
+  xg_add_trampoline_to_seg (ts, fragP);
+}
+
+static bfd_boolean xg_is_trampoline_frag_full (const fragS *fragP)
+{
+  return fragP->fr_var < 3;
+}
+
+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)
+    {
+      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)
+{
+  qsort (tc->entry, tc->n_entries, sizeof (*tc->entry),
+        xg_order_trampoline_chain_entry);
+  tc->needs_sorting = FALSE;
+}
+
+/* Find entry index in the given chain with maximal address <= source.  */
+static size_t xg_find_chain_entry (struct trampoline_chain *tc,
+                                  addressT source)
+{
+  size_t a = 0;
+  size_t b = tc->n_entries;
+
+  if (tc->needs_sorting)
+    xg_sort_trampoline_chain (tc);
+
+  while (b - a > 1)
+    {
+      size_t c = (a + b) / 2;
+      struct trampoline_chain_entry *e = tc->entry + c;
+
+      if (S_GET_VALUE(e->sym) + e->offset <= source)
+       a = c;
+      else
+       b = c;
+    }
+  return a;
+}
+
+/* Find the best jump target for the source in the given trampoline chain.
+   The best jump target is the one that results in the shortest path to the
+   final target, it's the location of the jump closest to the final target,
+   but within the J_RANGE - J_MARGIN from the source.  */
+static struct trampoline_chain_entry *
+xg_get_best_chain_entry (struct trampoline_chain *tc, addressT source)
+{
+  addressT target = S_GET_VALUE(tc->target.sym) + tc->target.offset;
+  size_t i = xg_find_chain_entry (tc, source);
+  struct trampoline_chain_entry *e = tc->entry + i;
+  int step = target < source ? -1 : 1;
+  addressT chained_target;
+  offsetT off;
+
+  if (target > source &&
+      S_GET_VALUE(e->sym) + e->offset <= source &&
+      i + 1 < tc->n_entries)
+    ++i;
+
+  while (i + step < tc->n_entries)
+    {
+      struct trampoline_chain_entry *next = tc->entry + i + step;
+
+      chained_target = S_GET_VALUE(next->sym) + next->offset;
+      off = source - chained_target;
+
+      if (labs (off) >= J_RANGE - J_MARGIN)
+       break;
+
+      i += step;
+    }
+
+  e = tc->entry + i;
+  chained_target = S_GET_VALUE(e->sym) + e->offset;
+  off = source - chained_target;
+
+  if (labs (off) < J_MARGIN ||
+      labs (off) >= J_RANGE - J_MARGIN)
+    return &tc->target;
+  return tc->entry + i;
+}
+
+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_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;
+
+      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 *
+xg_get_trampoline_chain (struct trampoline_seg *ts,
+                        symbolS *sym,
+                        addressT offset)
+{
+  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),
+            xg_order_trampoline_chain);
+      idx->needs_sorting = FALSE;
+    }
+  c.target.sym = sym;
+  c.target.offset = offset;
+  return bsearch (&c, idx->entry, idx->n_entries,
+                 sizeof (struct trampoline_chain),
+                 xg_order_trampoline_chain);
+}
+
+/* Find trampoline chain in the given trampoline segment that is going
+   to the *sym + *offset.  If found, replace *sym and *offset with the
+   best jump target in that chain.  */
+static struct trampoline_chain *
+xg_find_best_eq_target (struct trampoline_seg *ts,
+                       addressT source, symbolS **sym,
+                       addressT *offset)
+{
+  struct trampoline_chain *tc = xg_get_trampoline_chain (ts, *sym, *offset);
+
+  if (tc)
+    {
+      struct trampoline_chain_entry *e = xg_get_best_chain_entry (tc, source);
+
+      *sym = e->sym;
+      *offset = e->offset;
+    }
+  return tc;
+}
+
+static void xg_add_location_to_chain (struct trampoline_chain *tc,
+                                     symbolS *sym, addressT offset)
+{
+  struct trampoline_chain_entry *e;
+
+  if (tc->n_entries == tc->n_max)
+    {
+      tc->n_max = (tc->n_max + 1) * 2;
+      tc->entry = xrealloc (tc->entry, sizeof (*tc->entry) * tc->n_max);
+    }
+  e = tc->entry + tc->n_entries;
+  e->sym = sym;
+  e->offset = offset;
+  ++tc->n_entries;
+  tc->needs_sorting = TRUE;
+}
+
+static struct trampoline_chain *
+xg_create_trampoline_chain (struct trampoline_seg *ts,
+                           symbolS *sym, addressT offset)
+{
+  struct trampoline_chain_index *idx = &ts->chain_index;
+  struct trampoline_chain *tc;
+
+  if (idx->n_entries == idx->n_max)
+    {
+      idx->n_max = (idx->n_max + 1) * 2;
+      idx->entry = xrealloc (idx->entry,
+                            sizeof (*idx->entry) * idx->n_max);
+    }
+
+  tc = idx->entry + idx->n_entries;
+  tc->target.sym = sym;
+  tc->target.offset = offset;
+  tc->entry = NULL;
+  tc->n_entries = 0;
+  tc->n_max = 0;
+  xg_add_location_to_chain (tc, sym, offset);
+
+  ++idx->n_entries;
+  idx->needs_sorting = TRUE;
+
+  return tc;
+}
+
+void dump_trampolines (void);
+
+void
+dump_trampolines (void)
+{
+  struct trampoline_seg *ts = trampoline_seg_list.next;
+
+  for ( ; ts; ts = ts->next)
+    {
+      size_t i;
+      asection *seg = ts->seg;
+
+      if (seg == NULL)
+       continue;
+      fprintf(stderr, "SECTION %s\n", seg->name);
+
+      for (i = 0; i < ts->index.n_entries; ++i)
+       {
+         fragS *tf = ts->index.entry[i];
+
+         fprintf(stderr, "   0x%08x: fix=%d, jump_around=%s\n",
+                 (int)tf->fr_address, (int)tf->fr_fix,
+                 tf->tc_frag_data.needs_jump_around ? "T" : "F");
+       }
+    }
+}
+
+static void dump_litpools (void) __attribute__ ((unused));
+
+static void
+dump_litpools (void)
+{
+  struct litpool_seg *lps = litpool_seg_list.next;
+  struct litpool_frag *lpf;
+
+  for ( ; lps ; lps = lps->next )
+    {
+      printf("litpool seg %s\n", lps->seg->name);
+      for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
+       {
+         fragS *litfrag = lpf->fragP->fr_next;
+         int count = 0;
+         while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
+           {
+             if (litfrag->fr_fix == 4)
+               count++;
+             litfrag = litfrag->fr_next;
+           }
+         printf("   %ld <%d:%d> (%d) [%d]: ",
+                lpf->addr, lpf->priority, lpf->original_priority,
+                lpf->fragP->fr_line, count);
+         /* dump_frag(lpf->fragP);  */
+       }
+    }
+}
+
+static void
+xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
+                                      bfd_boolean only_if_needed)
+{
+  struct litpool_seg *lps = litpool_seg_list.next;
+  fragS *fragP;
+  struct litpool_frag *lpf;
+  bfd_boolean needed = FALSE;
+
+  if (use_literal_section || !auto_litpools)
+    return;
+
+  for ( ; lps ; lps = lps->next )
+    {
+      if (lps->seg == now_seg)
+       break;
+    }
+
+  if (lps == NULL)
+    {
+      lps = XCNEW (struct litpool_seg);
+      lps->next = litpool_seg_list.next;
+      litpool_seg_list.next = lps;
+      lps->seg = now_seg;
+      lps->frag_list.next = &lps->frag_list;
+      lps->frag_list.prev = &lps->frag_list;
+      /* Put candidate literal pool at the beginning of every section,
+         so that even when section starts with literal load there's a
+        literal pool available.  */
+      lps->frag_count = auto_litpool_limit;
+    }
+
+  lps->frag_count++;
+
+  if (create)
+    {
+      if (only_if_needed)
+       {
+         if (past_xtensa_end || !use_transform() ||
+             frag_now->tc_frag_data.is_no_transform)
+           {
+             return;
+           }
+         if (auto_litpool_limit <= 0)
+           {
+             /* Don't create a litpool based only on frag count.  */
+             return;
+           }
+         else if (lps->frag_count > auto_litpool_limit)
+           {
+             needed = TRUE;
+           }
+         else
+           {
+             return;
+           }
+       }
+      else
+       {
+         needed = TRUE;
+       }
+    }
+
+  if (needed)
+    {
+      int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn.  */
+      /* Create a potential site for a literal pool.  */
+      frag_wane (frag_now);
+      frag_new (0);
+      xtensa_set_frag_assembly_state (frag_now);
+      fragP = frag_now;
+      fragP->tc_frag_data.lit_frchain = frchain_now;
+      fragP->tc_frag_data.literal_frag = fragP;
+      frag_var (rs_machine_dependent, size, size,
+                   (only_if_needed) ?
+                       RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
+                       RELAX_LITERAL_POOL_BEGIN,
+                   NULL, 0, NULL);
+      frag_now->tc_frag_data.lit_seg = now_seg;
+      frag_variant (rs_machine_dependent, 0, 0,
+                   RELAX_LITERAL_POOL_END, NULL, 0, NULL);
+      xtensa_set_frag_assembly_state (frag_now);
+    }
+  else
+    {
+      /* RELAX_LITERAL_POOL_BEGIN frag is being created;
+        just record it here.  */
+      fragP = frag_now;
+    }
+
+  lpf = XNEW (struct litpool_frag);
+  /* Insert at tail of circular list.  */
+  lpf->addr = 0;
+  lps->frag_list.prev->next = lpf;
+  lpf->next = &lps->frag_list;
+  lpf->prev = lps->frag_list.prev;
+  lps->frag_list.prev = lpf;
+  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;
+}
+
+static void
+xtensa_cleanup_align_frags (void)
+{
+  frchainS *frchP;
+  asection *s;
+
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if ((fragP->fr_type == rs_align
+                || fragP->fr_type == rs_align_code
+                || (fragP->fr_type == rs_machine_dependent
+                    && (fragP->fr_subtype == RELAX_DESIRE_ALIGN
+                        || fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)))
+               && fragP->fr_fix == 0)
+             {
+               fragS *next = fragP->fr_next;
+
+               while (next
+                      && next->fr_fix == 0
+                      && next->fr_type == rs_machine_dependent
+                      && next->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
+                 {
+                   frag_wane (next);
+                   next = next->fr_next;
+                 }
+             }
+           /* If we don't widen branch targets, then they
+              will be easier to align.  */
+           if (fragP->tc_frag_data.is_branch_target
+               && fragP->fr_opcode == fragP->fr_literal
+               && fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_SLOTS
+               && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
+             frag_wane (fragP);
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_UNREACHABLE)
+             fragP->tc_frag_data.is_unreachable = TRUE;
+         }
+      }
+}
+
+
+/* Re-process all of the fragments looking to convert all of the
+   RELAX_DESIRE_ALIGN_IF_TARGET fragments.  If there is a branch
+   target in the next fragment, convert this to RELAX_DESIRE_ALIGN.
+   Otherwise, convert to a .fill 0.  */
+
+static void
+xtensa_fix_target_frags (void)
+{
+  frchainS *frchP;
+  asection *s;
+
+  /* When this routine is called, all of the subsections are still intact
+     so we walk over subsections instead of sections.  */
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
+             {
+               if (next_frag_is_branch_target (fragP))
+                 fragP->fr_subtype = RELAX_DESIRE_ALIGN;
+               else
+                 frag_wane (fragP);
+             }
+         }
+      }
+}
+
+
+static bfd_boolean is_narrow_branch_guaranteed_in_range (fragS *, TInsn *);
+
+static void
+xtensa_mark_narrow_branches (void)
+{
+  frchainS *frchP;
+  asection *s;
+
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_SLOTS
+               && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
+             {
+               vliw_insn vinsn;
+
+               vinsn_from_chars (&vinsn, fragP->fr_opcode);
+               tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0);
+
+               if (vinsn.num_slots == 1
+                   && xtensa_opcode_is_branch (xtensa_default_isa,
+                                               vinsn.slots[0].opcode) == 1
+                   && xg_get_single_size (vinsn.slots[0].opcode) == 2
+                   && is_narrow_branch_guaranteed_in_range (fragP,
+                                                            &vinsn.slots[0]))
+                 {
+                   fragP->fr_subtype = RELAX_SLOTS;
+                   fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW;
+                   fragP->tc_frag_data.is_aligning_branch = 1;
+                 }
+             }
+         }
+      }
+}
+
+
+/* A branch is typically widened only when its target is out of
+   range.  However, we would like to widen them to align a subsequent
+   branch target when possible.
+
+   Because the branch relaxation code is so convoluted, the optimal solution
+   (combining the two cases) is difficult to get right in all circumstances.
    We therefore go with an "almost as good" solution, where we only
    use for alignment narrow branches that definitely will not expand to a
    jump and a branch.  These functions find and mark these cases.  */
@@ -7366,12 +8138,12 @@ static offsetT unrelaxed_frag_max_size (fragS *);
 static bfd_boolean
 is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn)
 {
-  const expressionS *expr = &tinsn->tok[1];
-  symbolS *symbolP = expr->X_add_symbol;
-  offsetT max_distance = expr->X_add_number;
+  const expressionS *exp = &tinsn->tok[1];
+  symbolS *symbolP = exp->X_add_symbol;
+  offsetT max_distance = exp->X_add_number;
   fragS *target_frag;
 
-  if (expr->X_op != O_symbol)
+  if (exp->X_op != O_symbol)
     return FALSE;
 
   target_frag = symbol_get_frag (symbolP);
@@ -7412,9 +8184,36 @@ xtensa_mark_zcl_first_insns (void)
                    || fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE))
              {
                /* Find the loop frag.  */
-               fragS *targ_frag = next_non_empty_frag (fragP);
+               fragS *loop_frag = next_non_empty_frag (fragP);
                /* Find the first insn frag.  */
-               targ_frag = next_non_empty_frag (targ_frag);
+               fragS *targ_frag = next_non_empty_frag (loop_frag);
+
+             /* Handle a corner case that comes up in hardware
+                diagnostics.  The original assembly looks like this:
+
+                loop aX, LabelA
+                <empty_frag>--not found by next_non_empty_frag
+                loop aY, LabelB
+
+                Depending on the start address, the assembler may or
+                may not change it to look something like this:
+
+                loop aX, LabelA
+                nop--frag isn't empty anymore
+                loop aY, LabelB
+
+                So set up to check the alignment of the nop if it
+                exists  */
+               while (loop_frag != targ_frag)
+                 {
+                   if (loop_frag->fr_type == rs_machine_dependent
+                       && (loop_frag->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
+                           || loop_frag->fr_subtype
+                           == RELAX_CHECK_ALIGN_NEXT_OPCODE))
+                     targ_frag = loop_frag;
+                   else
+                     loop_frag = loop_frag->fr_next;
+                 }
 
                /* Of course, sometimes (mostly for toy test cases) a
                   zero-cost loop instruction is the last in a section.  */
@@ -7449,22 +8248,22 @@ xtensa_mark_zcl_first_insns (void)
    sleb128 value, the linker is unable to adjust that value to account for
    link-time relaxation.  Mark all the code between such symbols so that
    its size cannot be changed by linker relaxation.  */
-  
+
 static void
 xtensa_mark_difference_of_two_symbols (void)
 {
   symbolS *expr_sym;
 
-  for (expr_sym = expr_symbols; expr_sym; 
+  for (expr_sym = expr_symbols; expr_sym;
        expr_sym = symbol_get_tc (expr_sym)->next_expr_symbol)
     {
-      expressionS *expr = symbol_get_value_expression (expr_sym);
+      expressionS *exp = symbol_get_value_expression (expr_sym);
 
-      if (expr->X_op == O_subtract)
+      if (exp->X_op == O_subtract)
        {
-         symbolS *left = expr->X_add_symbol;
-         symbolS *right = expr->X_op_symbol;
-         
+         symbolS *left = exp->X_add_symbol;
+         symbolS *right = exp->X_op_symbol;
+
          /* Difference of two symbols not in the same section
             are handled with relocations in the linker.  */
          if (S_GET_SEGMENT (left) == S_GET_SEGMENT (right))
@@ -7473,7 +8272,7 @@ xtensa_mark_difference_of_two_symbols (void)
              fragS *end;
              fragS *walk;
 
-             if (symbol_get_frag (left)->fr_address 
+             if (symbol_get_frag (left)->fr_address
                  <= symbol_get_frag (right)->fr_address)
                {
                  start = symbol_get_frag (left);
@@ -7489,7 +8288,7 @@ xtensa_mark_difference_of_two_symbols (void)
                walk = start->tc_frag_data.no_transform_end;
              else
                walk = start;
-             do 
+             do
                {
                  walk->tc_frag_data.is_no_transform = 1;
                  walk = walk->fr_next;
@@ -7552,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;
 
@@ -7865,7 +8664,6 @@ xtensa_fix_short_loop_frags (void)
     for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
       {
        fragS *fragP;
-       fragS *current_target = NULL;
        xtensa_opcode current_opcode = XTENSA_UNDEFINED;
 
        /* Walk over all of the fragments in a subsection.  */
@@ -7878,7 +8676,6 @@ xtensa_fix_short_loop_frags (void)
                TInsn t_insn;
                fragS *loop_frag = next_non_empty_frag (fragP);
                tinsn_from_chars (&t_insn, loop_frag->fr_opcode, 0);
-               current_target = symbol_get_frag (fragP->fr_symbol);
                current_opcode = t_insn.opcode;
                gas_assert (xtensa_opcode_is_loop (xtensa_default_isa,
                                               current_opcode) == 1);
@@ -7947,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;
@@ -8000,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;
@@ -8042,12 +8839,12 @@ static bfd_boolean is_local_forward_loop (const TInsn *, fragS *);
 static void
 xtensa_sanity_check (void)
 {
-  char *file_name;
+  const char *file_name;
   unsigned line;
   frchainS *frchP;
   asection *s;
 
-  as_where (&file_name, &line);
+  file_name = as_where (&line);
   for (s = stdoutput->sections; s; s = s->next)
     for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
       {
@@ -8057,7 +8854,7 @@ xtensa_sanity_check (void)
        for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
          {
            if (fragP->fr_type == rs_machine_dependent
-               && fragP->fr_subtype == RELAX_SLOTS 
+               && fragP->fr_subtype == RELAX_SLOTS
                && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
              {
                static xtensa_insnbuf insnbuf = NULL;
@@ -8100,7 +8897,7 @@ xtensa_sanity_check (void)
 static bfd_boolean
 is_empty_loop (const TInsn *insn, fragS *fragP)
 {
-  const expressionS *expr;
+  const expressionS *exp;
   symbolS *symbolP;
   fragS *next_fragP;
 
@@ -8113,12 +8910,12 @@ is_empty_loop (const TInsn *insn, fragS *fragP)
   if (insn->ntok <= LOOP_IMMED_OPN)
     return FALSE;
 
-  expr = &insn->tok[LOOP_IMMED_OPN];
+  exp = &insn->tok[LOOP_IMMED_OPN];
 
-  if (expr->X_op != O_symbol)
+  if (exp->X_op != O_symbol)
     return FALSE;
 
-  symbolP = expr->X_add_symbol;
+  symbolP = exp->X_add_symbol;
   if (!symbolP)
     return FALSE;
 
@@ -8147,7 +8944,7 @@ is_empty_loop (const TInsn *insn, fragS *fragP)
 static bfd_boolean
 is_local_forward_loop (const TInsn *insn, fragS *fragP)
 {
-  const expressionS *expr;
+  const expressionS *exp;
   symbolS *symbolP;
   fragS *next_fragP;
 
@@ -8160,12 +8957,12 @@ is_local_forward_loop (const TInsn *insn, fragS *fragP)
   if (insn->ntok <= LOOP_IMMED_OPN)
     return FALSE;
 
-  expr = &insn->tok[LOOP_IMMED_OPN];
+  exp = &insn->tok[LOOP_IMMED_OPN];
 
-  if (expr->X_op != O_symbol)
+  if (exp->X_op != O_symbol)
     return FALSE;
 
-  symbolP = expr->X_add_symbol;
+  symbolP = exp->X_add_symbol;
   if (!symbolP)
     return FALSE;
 
@@ -8186,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
@@ -8199,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 = xmalloc (100);
+  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.  */
@@ -8243,8 +9039,33 @@ get_text_align_power (unsigned target_size)
 {
   if (target_size <= 4)
     return 2;
-  gas_assert (target_size == 8);
-  return 3;
+
+  if (target_size <= 8)
+    return 3;
+
+  if (target_size <= 16)
+    return 4;
+
+  if (target_size <= 32)
+    return 5;
+
+  if (target_size <= 64)
+    return 6;
+
+  if (target_size <= 128)
+    return 7;
+
+  if (target_size <= 256)
+    return 8;
+
+  if (target_size <= 512)
+    return 9;
+
+  if (target_size <= 1024)
+    return 10;
+
+  gas_assert (0);
+  return 0;
 }
 
 
@@ -8317,19 +9138,17 @@ get_text_align_fill_size (addressT address,
 static int
 branch_align_power (segT sec)
 {
-  /* If the Xtensa processor has a fetch width of 8 bytes, and the section
-     is aligned to at least an 8-byte boundary, then a branch target need
-     only fit within an 8-byte aligned block of memory to avoid a stall.
-     Otherwise, try to fit branch targets within 4-byte aligned blocks
-     (which may be insufficient, e.g., if the section has no alignment, but
-     it's good enough).  */
-  if (xtensa_fetch_width == 8)
-    {
-      if (get_recorded_alignment (sec) >= 3)
-       return 3;
-    }
-  else
-    gas_assert (xtensa_fetch_width == 4);
+  /* If the Xtensa processor has a fetch width of X, and
+     the section is aligned to at least that boundary, then a branch
+     target need only fit within that aligned block of memory to avoid
+     a stall.  Otherwise, try to fit branch targets within 4-byte
+     aligned blocks (which may be insufficient, e.g., if the section
+     has no alignment, but it's good enough).  */
+  int fetch_align = get_text_align_power(xtensa_fetch_width);
+  int sec_align = get_recorded_alignment (sec);
+
+  if (sec_align >= fetch_align)
+    return fetch_align;
 
   return 2;
 }
@@ -8550,6 +9369,192 @@ static long relax_frag_for_align (fragS *, long);
 static long relax_frag_immed
   (segT, fragS *, long, int, xtensa_format, int, int *, bfd_boolean);
 
+/* Get projected address for the first fulcrum on a path from source to
+   target.  */
+static addressT xg_get_fulcrum (addressT source, addressT target)
+{
+  offsetT delta = target - source;
+  int n;
+
+  n = (labs (delta) + J_RANGE - J_MARGIN - 1) / (J_RANGE - J_MARGIN);
+  return source + delta / n;
+}
+
+/* Given trampoline index, source and target of a jump find the best
+   candidate trampoline for the first fulcrum.  The best trampoline is
+   the one in the reach of "j' instruction from the source, closest to
+   the projected fulcrum address, and preferrably w/o a jump around or
+   with already initialized jump around.  */
+static size_t xg_find_best_trampoline (struct trampoline_index *idx,
+                                      addressT source, addressT target)
+{
+  addressT fulcrum = xg_get_fulcrum (source, target);
+  size_t dist = 0;
+  size_t best = -1;
+  size_t base_tr = xg_find_trampoline (idx, fulcrum);
+  int checked = 1;
+
+  /* Check trampoline frags around the base_tr to find the best.  */
+  for (dist = 0; checked; ++dist)
+    {
+      int i;
+      size_t tr = base_tr - dist;
+
+      checked = 0;
+
+      /* Trampolines are checked in the following order:
+         base_tr, base_tr + 1, base_tr - 1, base_tr + 2, base_tr - 2  */
+      for (i = 0; i < 2; ++i, tr = base_tr + dist + 1)
+       if (tr < idx->n_entries)
+         {
+           fragS *trampoline_frag = idx->entry[tr];
+           offsetT off;
+
+           /* Don't check trampolines outside source - target interval.  */
+           if ((trampoline_frag->fr_address < source &&
+                trampoline_frag->fr_address < target) ||
+               (trampoline_frag->fr_address > source &&
+                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
+              around is nice, but it shouldn't have much overhead.  */
+           if (best < idx->n_entries && labs (off) > J_RANGE / 4)
+             return best;
+
+           off = trampoline_frag->fr_address - source;
+           if (labs (off) < J_RANGE - J_MARGIN)
+             {
+               ++checked;
+               /* Stop if a trampoline w/o jump around is found or initialized
+                  trampoline with jump around is found.  */
+               if (!trampoline_frag->tc_frag_data.needs_jump_around ||
+                   trampoline_frag->fr_fix)
+                 return tr;
+               else if (best >= idx->n_entries)
+                 best = tr;
+             }
+         }
+    }
+
+  if (best < idx->n_entries)
+    return best;
+  else
+    as_fatal (_("cannot find suitable trampoline"));
+}
+
+static fixS *xg_relax_fixup (struct trampoline_index *idx, fixS *fixP)
+{
+  symbolS *s = fixP->fx_addsy;
+  addressT source = fixP->fx_frag->fr_address;
+  addressT target = S_GET_VALUE (s) + fixP->fx_offset;
+  size_t tr = xg_find_best_trampoline (idx, source, target);
+  fragS *trampoline_frag = idx->entry[tr];
+  fixS *newfixP;
+
+  init_trampoline_frag (trampoline_frag);
+  newfixP = xg_append_jump (trampoline_frag,
+                           fixP->fx_addsy, fixP->fx_offset);
+
+  /* Adjust the fixup for the original "j" instruction to
+     point to the newly added jump.  */
+  fixP->fx_addsy = trampoline_frag->fr_symbol;
+  fixP->fx_offset = trampoline_frag->fr_fix - 3;
+  fixP->tc_fix_data.X_add_symbol = trampoline_frag->fr_symbol;
+  fixP->tc_fix_data.X_add_number = trampoline_frag->fr_fix - 3;
+
+  trampoline_frag->tc_frag_data.relax_seen = FALSE;
+
+  if (xg_is_trampoline_frag_full (trampoline_frag))
+    xg_remove_trampoline_from_index (idx, tr);
+
+  return newfixP;
+}
+
+static bfd_boolean xg_is_relaxable_fixup (fixS *fixP)
+{
+  xtensa_isa isa = xtensa_default_isa;
+  addressT addr = fixP->fx_frag->fr_address;
+  addressT target;
+  offsetT delta;
+  symbolS *s = fixP->fx_addsy;
+  int slot;
+  xtensa_format fmt;
+  xtensa_opcode opcode;
+
+  if (fixP->fx_r_type < BFD_RELOC_XTENSA_SLOT0_OP ||
+      fixP->fx_r_type > BFD_RELOC_XTENSA_SLOT14_OP)
+    return FALSE;
+
+  target = S_GET_VALUE (s) + fixP->fx_offset;
+  delta = target - addr;
+
+  if (labs (delta) < J_RANGE - J_MARGIN)
+    return FALSE;
+
+  xtensa_insnbuf_from_chars (isa, trampoline_buf,
+                            (unsigned char *) fixP->fx_frag->fr_literal +
+                            fixP->fx_where, 0);
+  fmt = xtensa_format_decode (isa, trampoline_buf);
+  gas_assert (fmt != XTENSA_UNDEFINED);
+  slot = fixP->tc_fix_data.slot;
+  xtensa_format_get_slot (isa, fmt, slot, trampoline_buf, trampoline_slotbuf);
+  opcode = xtensa_opcode_decode (isa, fmt, slot, trampoline_slotbuf);
+  return opcode == xtensa_j_opcode;
+}
+
+static void xg_relax_fixups (struct trampoline_seg *ts)
+{
+  struct trampoline_index *idx = &ts->index;
+  segment_info_type *seginfo = seg_info (now_seg);
+  fixS *fx;
+
+  for (fx = seginfo->fix_root; fx; fx = fx->fx_next)
+    {
+      fixS *fixP = fx;
+      struct trampoline_chain *tc = NULL;
+
+      if (xg_is_relaxable_fixup (fixP))
+       {
+         tc = xg_find_best_eq_target (ts, fixP->fx_frag->fr_address,
+                                      &fixP->fx_addsy, &fixP->fx_offset);
+         if (!tc)
+           tc = xg_create_trampoline_chain (ts, fixP->fx_addsy,
+                                            fixP->fx_offset);
+         gas_assert (tc);
+       }
+
+      while (xg_is_relaxable_fixup (fixP))
+       {
+         fixP = xg_relax_fixup (idx, fixP);
+         xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol,
+                                   fixP->fx_where);
+       }
+    }
+}
+
+/* Given a trampoline frag relax all jumps that might want to use this
+   trampoline.  Only do real work once per relaxation cycle, when
+   xg_relax_trampoline is called for the first trampoline in the now_seg.
+   Don't use stretch, don't update new_stretch: place fulcrums with a
+   slack to tolerate code movement.  In the worst case if a jump between
+   two trampolines wouldn't reach the next relaxation pass will fix it.  */
+static void xg_relax_trampoline (fragS *fragP, long stretch ATTRIBUTE_UNUSED,
+                                long *new_stretch ATTRIBUTE_UNUSED)
+{
+  struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+
+  if (ts->index.n_entries && ts->index.entry[0] == fragP)
+    xg_relax_fixups (ts);
+}
 
 /* Return the number of bytes added to this fragment, given that the
    input has been stretched already by "stretch".  */
@@ -8560,14 +9565,14 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
   xtensa_isa isa = xtensa_default_isa;
   int unreported = fragP->tc_frag_data.unreported_expansion;
   long new_stretch = 0;
-  char *file_name;
+  const char *file_name;
   unsigned line;
   int lit_size;
   static xtensa_insnbuf vbuf = NULL;
   int slot, num_slots;
   xtensa_format fmt;
 
-  as_where (&file_name, &line);
+  file_name = as_where (&line);
   new_logical_line (fragP->fr_file, fragP->fr_line);
 
   fragP->tc_frag_data.unreported_expansion = 0;
@@ -8646,7 +9651,41 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
       break;
 
     case RELAX_LITERAL_POOL_BEGIN:
+      if (fragP->fr_var != 0)
+       {
+         /* We have a converted "candidate" literal pool;
+            assemble a jump around it.  */
+         TInsn insn;
+         if (!litpool_slotbuf)
+           {
+             litpool_buf = xtensa_insnbuf_alloc (isa);
+             litpool_slotbuf = xtensa_insnbuf_alloc (isa);
+           }
+         new_stretch += 3;
+         fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass.  */
+         fragP->tc_frag_data.is_insn = TRUE;
+         tinsn_init (&insn);
+         insn.insn_type = ITYPE_INSN;
+         insn.opcode = xtensa_j_opcode;
+         insn.ntok = 1;
+         set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
+                                 fragP->fr_fix);
+         fmt = xg_get_single_format (xtensa_j_opcode);
+         tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
+         xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
+         xtensa_insnbuf_to_chars (isa, litpool_buf,
+                                  (unsigned char *)fragP->fr_literal +
+                                  fragP->fr_fix, 3);
+         fragP->fr_fix += 3;
+         fragP->fr_var -= 3;
+         /* Add a fix-up.  */
+         fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
+                  BFD_RELOC_XTENSA_SLOT0_OP);
+       }
+      break;
+
     case RELAX_LITERAL_POOL_END:
+    case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
     case RELAX_MAYBE_UNREACHABLE:
     case RELAX_MAYBE_DESIRE_ALIGN:
       /* No relaxation required.  */
@@ -8658,6 +9697,11 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
        new_stretch += relax_frag_for_align (fragP, stretch);
       break;
 
+    case RELAX_TRAMPOLINE:
+      if (fragP->tc_frag_data.relax_seen)
+       xg_relax_trampoline (fragP, stretch, &new_stretch);
+      break;
+
     default:
       as_bad (_("bad relaxation state"));
     }
@@ -8827,7 +9871,7 @@ find_address_of_next_align_frag (fragS **fragPP,
                  (*widens)++;
                  break;
                }
-             address += total_frag_text_expansion (fragP);;
+             address += total_frag_text_expansion (fragP);
              break;
 
            case RELAX_IMMED:
@@ -8955,7 +9999,7 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
        {
          if (this_frag->fr_subtype == RELAX_UNREACHABLE)
            {
-             gas_assert (opt_diff <= UNREACHABLE_MAX_WIDTH);
+             gas_assert (opt_diff <= (signed) xtensa_fetch_width);
              return opt_diff;
            }
          return 0;
@@ -8993,39 +10037,11 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
 /* The idea: widen everything you can to get a target or loop aligned,
    then start using NOPs.
 
-   When we must have a NOP, here is a table of how we decide
-   (so you don't have to fight through the control flow below):
-
    wide_nops   = the number of wide NOPs available for aligning
    narrow_nops = the number of narrow NOPs available for aligning
                 (a subset of wide_nops)
    widens      = the number of narrow instructions that should be widened
 
-   Desired   wide   narrow
-   Diff      nop    nop      widens
-   1           0      0         1
-   2           0      1         0
-   3a          1      0         0
-    b          0      1         1 (case 3a makes this case unnecessary)
-   4a          1      0         1
-    b          0      2         0
-    c          0      1         2 (case 4a makes this case unnecessary)
-   5a          1      0         2
-    b          1      1         0
-    c          0      2         1 (case 5b makes this case unnecessary)
-   6a          2      0         0
-    b          1      0         3
-    c          0      1         4 (case 6b makes this case unnecessary)
-    d          1      1         1 (case 6a makes this case unnecessary)
-    e          0      2         2 (case 6a makes this case unnecessary)
-    f          0      3         0 (case 6a makes this case unnecessary)
-   7a          1      0         4
-    b          2      0         1
-    c          1      1         2 (case 7b makes this case unnecessary)
-    d          0      1         5 (case 7a makes this case unnecessary)
-    e          0      2         3 (case 7b makes this case unnecessary)
-    f          0      3         1 (case 7b makes this case unnecessary)
-    g          1      2         1 (case 7b makes this case unnecessary)
 */
 
 static long
@@ -9035,130 +10051,223 @@ bytes_to_stretch (fragS *this_frag,
                  int num_widens,
                  int desired_diff)
 {
+  int nops_needed;
+  int nop_bytes;
+  int extra_bytes;
   int bytes_short = desired_diff - num_widens;
 
-  gas_assert (desired_diff >= 0 && desired_diff < 8);
+  gas_assert (desired_diff >= 0
+             && desired_diff < (signed) xtensa_fetch_width);
   if (desired_diff == 0)
     return 0;
 
-  gas_assert (wide_nops > 0 || num_widens > 0);
+  gas_assert (wide_nops > 0 || num_widens > 0);
+
+  /* Always prefer widening to NOP-filling.  */
+  if (bytes_short < 0)
+    {
+      /* There are enough RELAX_NARROW frags after this one
+        to align the target without widening this frag in any way.  */
+      return 0;
+    }
+
+  if (bytes_short == 0)
+    {
+      /* Widen every narrow between here and the align target
+        and the align target will be properly aligned.  */
+      if (this_frag->fr_subtype == RELAX_FILL_NOP)
+       return 0;
+      else
+       return 1;
+    }
+
+  /* From here we will need at least one NOP to get an alignment.
+     However, we may not be able to align at all, in which case,
+     don't widen.  */
+  nops_needed = desired_diff / 3;
+
+  /* If there aren't enough nops, don't widen.  */
+  if (nops_needed > wide_nops)
+    return 0;
+
+  /* First try it with all wide nops.  */
+  nop_bytes = nops_needed * 3;
+  extra_bytes = desired_diff - nop_bytes;
+
+  if (nop_bytes + num_widens >= desired_diff)
+    {
+      if (this_frag->fr_subtype == RELAX_FILL_NOP)
+       return 3;
+      else if (num_widens == extra_bytes)
+       return 1;
+      return 0;
+    }
+
+  /* Add a narrow nop.  */
+  nops_needed++;
+  nop_bytes += 2;
+  extra_bytes -= 2;
+  if (narrow_nops == 0 || nops_needed > wide_nops)
+    return 0;
 
-  /* Always prefer widening to NOP-filling.  */
-  if (bytes_short < 0)
+  if (nop_bytes + num_widens >= desired_diff && extra_bytes >= 0)
     {
-      /* There are enough RELAX_NARROW frags after this one
-        to align the target without widening this frag in any way.  */
+      if (this_frag->fr_subtype == RELAX_FILL_NOP)
+       return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
+      else if (num_widens == extra_bytes)
+       return 1;
       return 0;
     }
 
-  if (bytes_short == 0)
+  /* Replace a wide nop with a narrow nop--we can get here if
+     extra_bytes was negative in the previous conditional.  */
+  if (narrow_nops == 1)
+    return 0;
+  nop_bytes--;
+  extra_bytes++;
+  if (nop_bytes + num_widens >= desired_diff)
     {
-      /* Widen every narrow between here and the align target
-        and the align target will be properly aligned.  */
       if (this_frag->fr_subtype == RELAX_FILL_NOP)
-       return 0;
-      else
+       return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
+      else if (num_widens == extra_bytes)
        return 1;
+      return 0;
     }
 
-  /* From here we will need at least one NOP to get an alignment.
-     However, we may not be able to align at all, in which case,
-     don't widen.  */
-  if (this_frag->fr_subtype == RELAX_FILL_NOP)
+  /* If we can't satisfy any of the above cases, then we can't align
+     using padding or fill nops.  */
+  return 0;
+}
+
+
+static fragS *
+xg_find_best_trampoline_for_tinsn (TInsn *tinsn, fragS *fragP)
+{
+  symbolS *sym = tinsn->tok[0].X_add_symbol;
+  addressT source = fragP->fr_address;
+  addressT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number;
+  struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+  size_t i;
+
+  if (!ts || !ts->index.n_entries)
+    return NULL;
+
+  i = xg_find_best_trampoline (&ts->index, source, target);
+
+  return ts->index.entry[i];
+}
+
+
+/* Append jump to sym + offset to the end of the trampoline frag fragP.
+   Adjust fragP's jump around if it's present.  Adjust fragP's fr_fix/fr_var
+   and finish the frag if it's full (but don't remove it from the trampoline
+   frag index).  Return fixup for the newly created jump.  */
+static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset)
+{
+  fixS *fixP;
+  TInsn insn;
+  xtensa_format fmt;
+  xtensa_isa isa = xtensa_default_isa;
+
+  gas_assert (fragP->fr_var >= 3);
+  tinsn_init (&insn);
+  insn.insn_type = ITYPE_INSN;
+  insn.opcode = xtensa_j_opcode;
+  insn.ntok = 1;
+  set_expr_symbol_offset (&insn.tok[0], sym, offset);
+  fmt = xg_get_single_format (xtensa_j_opcode);
+  tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
+  xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
+  xtensa_insnbuf_to_chars (isa, trampoline_buf,
+                          (unsigned char *)fragP->fr_literal + fragP->fr_fix, 3);
+  fixP = fix_new (fragP, fragP->fr_fix, 3, sym, offset, TRUE,
+                 BFD_RELOC_XTENSA_SLOT0_OP);
+  fixP->tc_fix_data.slot = 0;
+
+  fragP->fr_fix += 3;
+  fragP->fr_var -= 3;
+
+  /* Adjust the jump around this trampoline (if present).  */
+  if (fragP->tc_frag_data.jump_around_fix)
+    fragP->tc_frag_data.jump_around_fix->fx_offset += 3;
+
+  /* Do we have room for more? */
+  if (xg_is_trampoline_frag_full (fragP))
     {
-      switch (desired_diff)
-       {
-       case 1:
-         return 0;
-       case 2:
-         if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 1)
-           return 2; /* case 2 */
-         return 0;
-       case 3:
-         if (wide_nops > 1)
-           return 0;
-         else
-           return 3; /* case 3a */
-       case 4:
-         if (num_widens >= 1 && wide_nops == 1)
-           return 3; /* case 4a */
-         if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 2)
-           return 2; /* case 4b */
-         return 0;
-       case 5:
-         if (num_widens >= 2 && wide_nops == 1)
-           return 3; /* case 5a */
-         /* We will need two nops.  Are there enough nops
-            between here and the align target?  */
-         if (wide_nops < 2 || narrow_nops == 0)
-           return 0;
-         /* Are there other nops closer that can serve instead?  */
-         if (wide_nops > 2 && narrow_nops > 1)
-           return 0;
-         /* Take the density one first, because there might not be
-            another density one available.  */
-         if (!this_frag->tc_frag_data.is_no_density)
-           return 2; /* case 5b narrow */
-         else
-           return 3; /* case 5b wide */
-         return 0;
-       case 6:
-         if (wide_nops == 2)
-           return 3; /* case 6a */
-         else if (num_widens >= 3 && wide_nops == 1)
-           return 3; /* case 6b */
-         return 0;
-       case 7:
-         if (wide_nops == 1 && num_widens >= 4)
-           return 3; /* case 7a */
-         else if (wide_nops == 2 && num_widens >= 1)
-           return 3; /* case 7b */
-         return 0;
-       default:
-         gas_assert (0);
-       }
+      frag_wane (fragP);
+      fragP->fr_subtype = 0;
     }
-  else
+
+  return fixP;
+}
+
+
+static int
+init_trampoline_frag (fragS *fp)
+{
+  int growth = 0;
+
+  if (fp->fr_fix == 0)
     {
-      /* We will need a NOP no matter what, but should we widen
-        this instruction to help?
+      symbolS *lsym;
+      char label[10 + 2 * sizeof(fp)];
 
-        This is a RELAX_NARROW frag.  */
-      switch (desired_diff)
-       {
-       case 1:
-         gas_assert (0);
-         return 0;
-       case 2:
-       case 3:
-         return 0;
-       case 4:
-         if (wide_nops >= 1 && num_widens == 1)
-           return 1; /* case 4a */
-         return 0;
-       case 5:
-         if (wide_nops >= 1 && num_widens == 2)
-           return 1; /* case 5a */
-         return 0;
-       case 6:
-         if (wide_nops >= 2)
-           return 0; /* case 6a */
-         else if (wide_nops >= 1 && num_widens == 3)
-           return 1; /* case 6b */
-         return 0;
-       case 7:
-         if (wide_nops >= 1 && num_widens == 4)
-           return 1; /* case 7a */
-         else if (wide_nops >= 2 && num_widens == 1)
-           return 1; /* case 7b */
-         return 0;
-       default:
-         gas_assert (0);
-         return 0;
-       }
+      sprintf (label, ".L0_TR_%p", fp);
+      lsym = (symbolS *) local_symbol_make (label, now_seg, fp, 0);
+      fp->fr_symbol = lsym;
+      if (fp->tc_frag_data.needs_jump_around)
+        {
+         fp->tc_frag_data.jump_around_fix = xg_append_jump (fp, lsym, 3);
+         growth = 3;
+        }
     }
-  gas_assert (0);
-  return 0;
+  return growth;
+}
+
+static int
+xg_get_single_symbol_slot (fragS *fragP)
+{
+  int i;
+  int slot = -1;
+
+  for (i = 0; i < MAX_SLOTS; ++i)
+    if (fragP->tc_frag_data.slot_symbols[i])
+      {
+       gas_assert (slot == -1);
+       slot = i;
+      }
+
+  gas_assert (slot >= 0 && slot < MAX_SLOTS);
+
+  return slot;
+}
+
+static fixS *
+add_jump_to_trampoline (fragS *tramp, fragS *origfrag)
+{
+  int slot = xg_get_single_symbol_slot (origfrag);
+  fixS *fixP;
+
+  /* Assemble a jump to the target label in the trampoline frag.  */
+  fixP = xg_append_jump (tramp,
+                        origfrag->tc_frag_data.slot_symbols[slot],
+                        origfrag->tc_frag_data.slot_offsets[slot]);
+
+  /* Modify the original j to point here.  */
+  origfrag->tc_frag_data.slot_symbols[slot] = tramp->fr_symbol;
+  origfrag->tc_frag_data.slot_offsets[slot] = tramp->fr_fix - 3;
+
+  /* If trampoline is full, remove it from the list.  */
+  if (xg_is_trampoline_frag_full (tramp))
+    {
+      struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+      size_t tr = xg_find_trampoline (&ts->index, tramp->fr_address);
+
+      gas_assert (ts->index.entry[tr] == tramp);
+      xg_remove_trampoline_from_index (&ts->index, tr);
+    }
+
+  return fixP;
 }
 
 
@@ -9245,20 +10354,20 @@ relax_frag_immed (segT segP,
          /* The first instruction in the relaxed sequence will go after
             the current wide instruction, and thus its symbolic immediates
             might not fit.  */
-         
+
          istack_init (&istack);
-         num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP, 
+         num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP,
                                         frag_offset + old_size,
                                         min_steps, stretch + old_size);
          gas_assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
 
-         fragP->tc_frag_data.slot_subtypes[slot] 
+         fragP->tc_frag_data.slot_subtypes[slot]
            = (int) RELAX_IMMED + num_steps;
 
          num_literal_bytes = get_num_stack_literal_bytes (&istack);
-         literal_diff 
+         literal_diff
            = num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
-         
+
          num_text_bytes = get_num_stack_text_bytes (&istack) + old_size;
        }
     }
@@ -9300,6 +10409,64 @@ relax_frag_immed (segT segP,
   if (negatable_branch && istack.ninsn > 1)
     update_next_frag_state (fragP);
 
+  /* If last insn is a jump, and it cannot reach its target, try to find a trampoline.  */
+  if (istack.ninsn > 2 &&
+      istack.insn[istack.ninsn - 1].insn_type == ITYPE_LABEL &&
+      istack.insn[istack.ninsn - 2].insn_type == ITYPE_INSN &&
+      istack.insn[istack.ninsn - 2].opcode == xtensa_j_opcode)
+    {
+      TInsn *jinsn = &istack.insn[istack.ninsn - 2];
+      struct trampoline_seg *ts = find_trampoline_seg (segP);
+      struct trampoline_chain *tc = NULL;
+
+      if (ts &&
+         !xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset,
+                                  total_text_diff))
+       {
+         int s = xg_get_single_symbol_slot (fragP);
+         addressT offset = fragP->tc_frag_data.slot_offsets[s];
+
+         tc = xg_find_best_eq_target (ts, fragP->fr_address,
+                                      &fragP->tc_frag_data.slot_symbols[s],
+                                      &offset);
+
+         if (!tc)
+           tc = xg_create_trampoline_chain (ts,
+                                            fragP->tc_frag_data.slot_symbols[s],
+                                            offset);
+         fragP->tc_frag_data.slot_offsets[s] = offset;
+         tinsn_immed_from_frag (jinsn, fragP, s);
+       }
+
+      if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset,
+                                  total_text_diff))
+       {
+         fragS *tf = xg_find_best_trampoline_for_tinsn (jinsn, fragP);
+
+         if (tf)
+           {
+             fixS *fixP;
+
+             this_text_diff += init_trampoline_frag (tf) + 3;
+             fixP = add_jump_to_trampoline (tf, fragP);
+             xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol,
+                                       fixP->fx_where);
+             fragP->tc_frag_data.relax_seen = FALSE;
+           }
+         else
+           {
+             /* If target symbol is undefined, assume it will reach once linked.  */
+             expressionS *exp = &istack.insn[istack.ninsn - 2].tok[0];
+
+             if (exp->X_op == O_symbol && S_IS_DEFINED (exp->X_add_symbol))
+               {
+                 as_bad_where (fragP->fr_file, fragP->fr_line,
+                   _("jump target out of range; no usable trampoline found"));
+               }
+           }
+       }
+    }
+
   return this_text_diff;
 }
 
@@ -9319,10 +10486,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
   int slot;
   int num_slots;
   xtensa_format fmt;
-  char *file_name;
+  const char *file_name;
   unsigned line;
 
-  as_where (&file_name, &line);
+  file_name = as_where (&line);
   new_logical_line (fragp->fr_file, fragp->fr_line);
 
   switch (fragp->fr_subtype)
@@ -9420,6 +10587,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
       else
        as_bad (_("invalid relaxation fragment result"));
       break;
+
+    case RELAX_TRAMPOLINE:
+      break;
     }
 
   fragp->fr_var = 0;
@@ -9540,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,
@@ -9613,7 +10782,6 @@ convert_frag_immed (segT segP,
       symbolS *gen_label = NULL;
       offsetT frag_offset;
       bfd_boolean first = TRUE;
-      bfd_boolean last_is_jump;
 
       /* It does not fit.  Find something that does and
          convert immediately.  */
@@ -9667,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:
@@ -9688,7 +10856,6 @@ convert_frag_immed (segT segP,
 
       total_size = 0;
       first = TRUE;
-      last_is_jump = FALSE;
       for (i = 0; i < istack.ninsn; i++)
        {
          TInsn *tinsn = &istack.insn[i];
@@ -9784,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.  */
@@ -9823,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
@@ -9979,7 +11027,7 @@ get_subseg_info (segT seg, subsegT subseg)
 static subseg_map *
 add_subseg_info (segT seg, subsegT subseg)
 {
-  subseg_map *subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map));
+  subseg_map *subseg_e = XNEW (subseg_map);
   memset (subseg_e, 0, sizeof (subseg_map));
   subseg_e->seg = seg;
   subseg_e->subseg = subseg;
@@ -10074,28 +11122,195 @@ xtensa_move_seg_list_to_beginning (seg_list *head)
 
 static void mark_literal_frags (seg_list *);
 
+static void
+xg_promote_candidate_litpool (struct litpool_seg *lps,
+                             struct litpool_frag *lp)
+{
+  fragS *poolbeg;
+  fragS *poolend;
+  symbolS *lsym;
+  char label[10 + 2 * sizeof (fragS *)];
+
+  poolbeg = lp->fragP;
+  lp->priority = 1;
+  poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
+  poolend = poolbeg->fr_next;
+  gas_assert (poolend->fr_type == rs_machine_dependent &&
+             poolend->fr_subtype == RELAX_LITERAL_POOL_END);
+  /* 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, poolend, 0);
+  poolbeg->fr_symbol = lsym;
+  /* Rest is done in xtensa_relax_frag.  */
+}
+
+static struct litpool_frag *xg_find_litpool (struct litpool_seg *lps,
+                                            struct litpool_frag *lpf,
+                                            addressT addr)
+{
+  struct litpool_frag *lp = lpf->prev;
+
+  gas_assert (lp->fragP);
+
+  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;
+           }
+       }
+    }
+
+  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)
+    {
+      frchainS *frchP = seg_info (lps->seg)->frchainP;
+      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;
+         for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+           {
+             if (lpf && fragP == lpf->fragP)
+               {
+                 gas_assert(fragP->fr_type == rs_machine_dependent &&
+                            (fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
+                             fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
+                 /* Found a litpool location.  */
+                 lpf->addr = addr;
+                 lpf = lpf->next;
+               }
+             if (fragP->fr_type == rs_machine_dependent &&
+                 fragP->fr_subtype == RELAX_SLOTS)
+               {
+                 int slot;
+                 for (slot = 0; slot < MAX_SLOTS; 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 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;
+                       }
+                   }
+               }
+             addr += fragP->fr_fix;
+             if (fragP->fr_type == rs_fill)
+               addr += fragP->fr_offset;
+           }
+       }
+    }
+}
+
 static void
 xtensa_move_literals (void)
 {
   seg_list *segment;
   frchainS *frchain_from, *frchain_to;
-  fragS *search_frag, *next_frag, *last_frag, *literal_pool, *insert_after;
+  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);
+
       /* Keep the literals for .init and .fini in separate sections.  */
-      if (!strcmp (segment_name (segment->seg), INIT_SECTION_NAME)
-         || !strcmp (segment_name (segment->seg), FINI_SECTION_NAME))
+      if ((!memcmp (seg_name, init_name, init_name_len) &&
+          !strcmp (seg_name + init_name_len, ".literal")) ||
+         (!memcmp (seg_name, fini_name, fini_name_len) &&
+          !strcmp (seg_name + fini_name_len, ".literal")))
        continue;
 
       frchain_from = seg_info (segment->seg)->frchainP;
@@ -10104,13 +11319,16 @@ xtensa_move_literals (void)
       frchain_to = NULL;
       frag_splice = &(frchain_from->frch_root);
 
-      while (!search_frag->tc_frag_data.literal_frag)
+      while (search_frag && !search_frag->tc_frag_data.literal_frag)
        {
          gas_assert (search_frag->fr_fix == 0
                  || search_frag->fr_type == rs_align);
          search_frag = search_frag->fr_next;
        }
 
+      if (!search_frag)
+       continue;
+
       gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
              == RELAX_LITERAL_POOL_BEGIN);
       xtensa_switch_section_emit_state (&state, segment->seg, 0);
@@ -10121,16 +11339,12 @@ xtensa_move_literals (void)
         frags in it.  */
       frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
       xtensa_set_frag_assembly_state (frag_now);
-      last_frag = frag_now;
       frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
       xtensa_set_frag_assembly_state (frag_now);
 
       while (search_frag != frag_now)
        {
          next_frag = search_frag->fr_next;
-
-         /* First, move the frag out of the literal section and
-            to the appropriate place.  */
          if (search_frag->tc_frag_data.literal_frag)
            {
              literal_pool = search_frag->tc_frag_data.literal_frag;
@@ -10138,8 +11352,56 @@ xtensa_move_literals (void)
              frchain_to = literal_pool->tc_frag_data.lit_frchain;
              gas_assert (frchain_to);
            }
+
+         if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
+           {
+             /* Skip empty fill frags.  */
+             *frag_splice = next_frag;
+             search_frag = next_frag;
+             continue;
+           }
+
+         if (search_frag->fr_type == rs_align)
+           {
+             /* Skip alignment frags, because the pool as a whole will be
+                aligned if used, and we don't want to force alignment if the
+                pool is unused.  */
+             *frag_splice = next_frag;
+             search_frag = next_frag;
+             continue;
+           }
+
+         /* First, move the frag out of the literal section and
+            to the appropriate place.  */
+
+         /* Insert an alignment frag at start of pool.  */
+         if (literal_pool->fr_next->fr_type == rs_machine_dependent &&
+             literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END)
+           {
+             segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
+             emit_state prev_state;
+             fragS *prev_frag;
+             fragS *align_frag;
+             xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
+             prev_frag = frag_now;
+             frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
+             align_frag = frag_now;
+             frag_align (2, 0, 0);
+             /* Splice it into the right place.  */
+             prev_frag->fr_next = align_frag->fr_next;
+             align_frag->fr_next = literal_pool->fr_next;
+             literal_pool->fr_next = align_frag;
+             /* Insert after this one.  */
+             literal_pool->tc_frag_data.literal_frag = align_frag;
+             xtensa_restore_emit_state (&prev_state);
+           }
          insert_after = literal_pool->tc_frag_data.literal_frag;
          dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
+         /* Skip align frag.  */
+         if (insert_after->fr_next->fr_type == rs_align)
+           {
+             insert_after = insert_after->fr_next;
+           }
 
          *frag_splice = next_frag;
          search_frag->fr_next = insert_after->fr_next;
@@ -10184,9 +11446,9 @@ xtensa_move_literals (void)
   for (lit = literal_syms; lit; lit = lit->next)
     {
       symbolS *lit_sym = lit->sym;
-      segT dest_seg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg;
-      if (dest_seg)
-       S_SET_SEGMENT (lit_sym, dest_seg);
+      segT dseg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg;
+      if (dseg)
+       S_SET_SEGMENT (lit_sym, dseg);
     }
 }
 
@@ -10290,37 +11552,27 @@ xtensa_switch_to_literal_fragment (emit_state *result)
 static void
 xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
 {
-  static bfd_boolean recursive = FALSE;
   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
-      && !recursive
-      && !is_init && ! is_fini)
+      && !is_init_fini)
     {
-      as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
-
-      /* When we mark a literal pool location, we want to put a frag in
-        the literal pool that points to it.  But to do that, we want to
-        switch_to_literal_fragment.  But literal sections don't have
-        literal pools, so their location is always null, so we would
-        recurse forever.  This is kind of hacky, but it works.  */
-
-      recursive = TRUE;
-      xtensa_mark_literal_pool_location ();
-      recursive = FALSE;
+      if (!auto_litpools)
+       {
+         as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
+       }
+      xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
+      pool_location = get_literal_pool_location (now_seg);
     }
 
   lit_seg = cache_literal_section (FALSE);
   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.  */
@@ -10368,7 +11620,7 @@ 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
@@ -10383,7 +11635,8 @@ static segT
 cache_literal_section (bfd_boolean use_abs_literals)
 {
   const char *text_name, *group_name = 0;
-  char *base_name, *name, *suffix;
+  const char *base_name, *suffix;
+  char *name;
   segT *pcached;
   segT seg, current_section;
   int current_subsec;
@@ -10409,7 +11662,7 @@ cache_literal_section (bfd_boolean use_abs_literals)
 
   if (*pcached)
     return *pcached;
-  
+
   text_name = default_lit_sections.lit_prefix;
   if (! text_name || ! *text_name)
     {
@@ -10421,32 +11674,37 @@ cache_literal_section (bfd_boolean use_abs_literals)
   base_name = use_abs_literals ? ".lit4" : ".literal";
   if (group_name)
     {
-      name = xmalloc (strlen (base_name) + strlen (group_name) + 2);
-      sprintf (name, "%s.%s", base_name, group_name);
+      name = concat (base_name, ".", group_name, (char *) NULL);
     }
   else if (strncmp (text_name, ".gnu.linkonce.", linkonce_len) == 0)
     {
       suffix = strchr (text_name + linkonce_len, '.');
 
-      name = xmalloc (linkonce_len + strlen (base_name) + 1
-                     + (suffix ? strlen (suffix) : 0));
-      strcpy (name, ".gnu.linkonce");
-      strcat (name, base_name);
-      if (suffix)
-       strcat (name, suffix);
+      name = concat (".gnu.linkonce", base_name, suffix ? suffix : "",
+                    (char *) NULL);
       linkonce = TRUE;
     }
   else
     {
-      /* If the section name ends with ".text", then replace that suffix
-        instead of appending an additional suffix.  */
+      /* If the section name begins or ends with ".text", then replace
+        that portion instead of appending an additional suffix.  */
       size_t len = strlen (text_name);
-      if (len >= 5 && strcmp (text_name + len - 5, ".text") == 0)
+      if (len >= 5
+         && (strcmp (text_name + len - 5, ".text") == 0
+             || strncmp (text_name, ".text", 5) == 0))
        len -= 5;
 
-      name = xmalloc (len + strlen (base_name) + 1);
-      strcpy (name, text_name);
-      strcpy (name + len, base_name);
+      name = XNEWVEC (char, len + strlen (base_name) + 1);
+      if (strncmp (text_name, ".text", 5) == 0)
+       {
+         strcpy (name, base_name);
+         strcat (name, text_name + 5);
+       }
+      else
+       {
+         strcpy (name, text_name);
+         strcpy (name + len, base_name);
+       }
     }
 
   /* Canonicalize section names to allow renaming literal sections.
@@ -10465,7 +11723,7 @@ cache_literal_section (bfd_boolean use_abs_literals)
       if (! use_abs_literals)
        {
          /* Add the newly created literal segment to the list.  */
-         seg_list *n = (seg_list *) xmalloc (sizeof (seg_list));
+         seg_list *n = XNEW (seg_list);
          n->seg = seg;
          n->next = literal_head->next;
          literal_head->next = n;
@@ -10477,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;
@@ -10609,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)
            {
@@ -10706,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)
@@ -10750,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)
@@ -10842,8 +12100,7 @@ add_xt_block_frags (segT sec,
                }
              if (*xt_block == NULL)
                {
-                 xtensa_block_info *new_block = (xtensa_block_info *)
-                   xmalloc (sizeof (xtensa_block_info));
+                 xtensa_block_info *new_block = XNEW (xtensa_block_info);
                  new_block->sec = sec;
                  new_block->offset = fragP->fr_address;
                  new_block->size = fragP->fr_fix;
@@ -11100,8 +12357,7 @@ add_xt_prop_frags (segT sec,
                  xtensa_block_info *new_block;
                  if ((*xt_block) != NULL)
                    xt_block = &(*xt_block)->next;
-                 new_block = (xtensa_block_info *)
-                   xmalloc (sizeof (xtensa_block_info));
+                 new_block = XNEW (xtensa_block_info);
                  *new_block = tmp_block;
                  *xt_block = new_block;
                }
@@ -11126,8 +12382,7 @@ init_op_placement_info_table (void)
   int slot;
   int num_opcodes = xtensa_isa_num_opcodes (isa);
 
-  op_placement_table = (op_placement_info_table)
-    xmalloc (sizeof (op_placement_info) * num_opcodes);
+  op_placement_table = XNEWVEC (op_placement_info, num_opcodes);
   gas_assert (xtensa_isa_num_formats (isa) < MAX_FORMATS);
 
   for (opcode = 0; opcode < num_opcodes; opcode++)
@@ -11208,7 +12463,6 @@ xg_get_single_slot (xtensa_opcode opcode)
 void
 istack_init (IStack *stack)
 {
-  memset (stack, 0, sizeof (IStack));
   stack->ninsn = 0;
 }
 
@@ -11418,20 +12672,20 @@ tinsn_to_slotbuf (xtensa_format fmt,
 
   for (i = 0; i < noperands; i++)
     {
-      expressionS *expr = &tinsn->tok[i];
+      expressionS *exp = &tinsn->tok[i];
       int rc;
       unsigned line;
-      char *file_name;
+      const char *file_name;
       uint32 opnd_value;
 
-      switch (expr->X_op)
+      switch (exp->X_op)
        {
        case O_register:
          if (xtensa_operand_is_visible (isa, opcode, i) == 0)
            break;
          /* The register number has already been checked in
             expression_maybe_register, so we don't need to check here.  */
-         opnd_value = expr->X_add_number;
+         opnd_value = exp->X_add_number;
          (void) xtensa_operand_encode (isa, opcode, i, &opnd_value);
          rc = xtensa_operand_set_field (isa, opcode, i, fmt, slot, slotbuf,
                                         opnd_value);
@@ -11442,11 +12696,11 @@ tinsn_to_slotbuf (xtensa_format fmt,
        case O_constant:
          if (xtensa_operand_is_visible (isa, opcode, i) == 0)
            break;
-         as_where (&file_name, &line);
+         file_name = as_where (&line);
          /* It is a constant and we called this function
             then we have to try to fit it.  */
          xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, i,
-                                     expr->X_add_number, file_name, line);
+                                     exp->X_add_number, file_name, line);
          break;
 
        default:
@@ -11699,7 +12953,7 @@ xg_clear_vinsn (vliw_insn *v)
 {
   int i;
 
-  memset (v, 0, offsetof (vliw_insn, slots) 
+  memset (v, 0, offsetof (vliw_insn, slots)
                 + sizeof(TInsn) * config_max_slots);
 
   v->format = XTENSA_UNDEFINED;
@@ -11717,7 +12971,7 @@ xg_clear_vinsn (vliw_insn *v)
 static void
 xg_copy_vinsn (vliw_insn *dst, vliw_insn *src)
 {
-  memcpy (dst, src, 
+  memcpy (dst, src,
          offsetof(vliw_insn, slots) + src->num_slots * sizeof(TInsn));
   dst->insnbuf = src->insnbuf;
   memcpy (dst->slotbuf, src->slotbuf, src->num_slots * sizeof(xtensa_insnbuf));
@@ -11800,8 +13054,8 @@ vinsn_to_insnbuf (vliw_insn *vinsn,
 
          for (i = 0; i < noperands; i++)
            {
-             expressionS* expr = &tinsn->tok[i];
-             switch (expr->X_op)
+             expressionS* exp = &tinsn->tok[i];
+             switch (exp->X_op)
                {
                case O_symbol:
                case O_lo16:
@@ -11816,15 +13070,15 @@ vinsn_to_insnbuf (vliw_insn *vinsn,
                          || tinsn->is_specific_opcode
                          || !xg_is_relaxable_insn (tinsn, 0))
                        {
-                         xg_add_opcode_fix (tinsn, i, fmt, slot, expr, fragP,
+                         xg_add_opcode_fix (tinsn, i, fmt, slot, exp, fragP,
                                             frag_offset - fragP->fr_literal);
                        }
                      else
                        {
-                         if (expr->X_op != O_symbol)
+                         if (exp->X_op != O_symbol)
                            as_bad (_("invalid operand"));
-                         tinsn->symbol = expr->X_add_symbol;
-                         tinsn->offset = expr->X_add_number;
+                         tinsn->symbol = exp->X_add_symbol;
+                         tinsn->offset = exp->X_add_number;
                        }
                    }
                  else
@@ -11970,7 +13224,7 @@ copy_expr (expressionS *dst, const expressionS *src)
 
 struct rename_section_struct
 {
-  char *old_name;
+  const char *old_name;
   char *new_name;
   struct rename_section_struct *next;
 };
@@ -12032,8 +13286,7 @@ build_section_rename (const char *arg)
        }
 
       /* Now add it.  */
-      r = (struct rename_section_struct *)
-       xmalloc (sizeof (struct rename_section_struct));
+      r = XNEW (struct rename_section_struct);
       r->old_name = xstrdup (old_name);
       r->new_name = xstrdup (new_name);
       r->next = section_rename;
@@ -12043,7 +13296,7 @@ build_section_rename (const char *arg)
 
 
 char *
-xtensa_section_rename (char *name)
+xtensa_section_rename (const char *name)
 {
   struct rename_section_struct *r = section_rename;
 
@@ -12053,5 +13306,5 @@ xtensa_section_rename (char *name)
        return r->new_name;
     }
 
-  return name;
+  return (char *) name;
 }