]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-xtensa.c
gas: xtensa: reuse trampoline placement code
[thirdparty/binutils-gdb.git] / gas / config / tc-xtensa.c
index fdca2322b74966503d89ae7d1ecbba22243f4654..b507d4425a368049089f50b1924df4498a6907d0 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-xtensa.c -- Assemble Xtensa instructions.
-   Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2003-2017 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -18,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"
@@ -29,6 +29,7 @@
 #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
@@ -71,16 +72,13 @@ 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;
-
-/* Maximum width we would pad an unreachable frag to get alignment.  */
-#define UNREACHABLE_MAX_WIDTH  8
+bfd_boolean density_supported;
+bfd_boolean absolute_literals_supported;
 
 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;
 
@@ -216,8 +214,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))
@@ -238,8 +234,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))
@@ -364,10 +358,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 }
@@ -383,7 +377,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 }
 };
 
 
@@ -426,23 +419,38 @@ 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;
+};
+
+/* 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;
+
 
 /* Directive functions.  */
 
@@ -471,6 +479,16 @@ 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 = 10000;
 
 /* Alignment Functions.  */
 
@@ -500,10 +518,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);
@@ -523,6 +537,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.  */
 
@@ -587,6 +602,7 @@ static xtensa_opcode xtensa_retw_opcode;
 static xtensa_opcode xtensa_retw_n_opcode;
 static xtensa_opcode xtensa_rsr_lcount_opcode;
 static xtensa_opcode xtensa_waiti_opcode;
+static int config_max_slots = 0;
 
 \f
 /* Command-line Options.  */
@@ -689,7 +705,14 @@ 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,
 };
 
 const char *md_shortopts = "";
@@ -762,6 +785,13 @@ 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 },
+
   { NULL, no_argument, NULL, 0 }
 };
 
@@ -769,7 +799,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)
     {
@@ -907,20 +937,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);
@@ -942,6 +973,43 @@ 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;
+      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;
+      }
+
     default:
       return 0;
     }
@@ -965,7 +1033,14 @@ 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", stream);
 }
 
 \f
@@ -977,7 +1052,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;
@@ -1075,11 +1150,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;
@@ -1105,7 +1180,7 @@ directive_pop (directiveE *directive,
 
   if (!directive_state_stack)
     {
-      as_bad (_("unmatched end directive"));
+      as_bad (_("unmatched .end directive"));
       *directive = directive_none;
       return;
     }
@@ -1156,7 +1231,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;
@@ -1233,7 +1308,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;
@@ -1252,7 +1327,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;
@@ -1322,18 +1397,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"));
@@ -1453,15 +1528,18 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
   if (use_literal_section || directive_state[directive_absolute_literals])
     dest_seg = now_seg;
 
+  /* FIXME, despite the previous comments, dest_seg is unused...  */
+  (void) dest_seg;
+
   /* All literals are aligned to four-byte boundaries.  */
   frag_align (2, 0, 0);
   record_alignment (now_seg, 2);
 
-  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 != ':')
     {
@@ -1471,11 +1549,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);
@@ -1501,10 +1579,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;
@@ -1586,7 +1661,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
@@ -1634,7 +1711,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;
@@ -1651,10 +1728,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 == '+')
@@ -1675,7 +1752,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;
@@ -1683,21 +1760,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;
 }
 
@@ -1706,14 +1783,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;
        }
     }
@@ -1824,6 +1901,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)
        {
@@ -1932,7 +2010,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)
@@ -2145,8 +2223,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;
@@ -2177,11 +2254,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);
 }
 
 
@@ -2276,8 +2352,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;
 
@@ -2336,7 +2411,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);
@@ -2347,8 +2422,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)
@@ -2401,8 +2476,7 @@ 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;
@@ -2429,7 +2503,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
@@ -2442,12 +2516,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;
@@ -2719,7 +2790,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);
@@ -3233,15 +3304,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;
 
@@ -3277,15 +3349,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;
 
@@ -3305,8 +3378,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
@@ -3316,16 +3389,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
@@ -3566,11 +3639,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;
@@ -3944,14 +4017,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);
@@ -4035,7 +4112,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;
@@ -4190,7 +4267,7 @@ xg_add_opcode_fix (TInsn *tinsn,
                   int opnum,
                   xtensa_format fmt,
                   int slot,
-                  expressionS *expr,
+                  expressionS *exp,
                   fragS *fragP,
                   offsetT offset)
 {
@@ -4210,15 +4287,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;
        }
     }
 
@@ -4232,7 +4309,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));
@@ -4257,11 +4334,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;
@@ -4519,12 +4596,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)
@@ -4641,6 +4724,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)
 {
@@ -4663,7 +4752,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;
 }
@@ -4689,6 +4778,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);
@@ -4793,6 +4884,31 @@ get_expanded_loop_offset (xtensa_opcode opcode)
 static fragS *
 get_literal_pool_location (segT seg)
 {
+  struct litpool_seg *lps = litpool_seg_list.next;
+  struct litpool_frag *lpf;
+  for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
+    ;
+  if (lps)
+    {
+      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;
 }
 
@@ -5002,16 +5118,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;
        }
@@ -5093,6 +5215,24 @@ 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;
+}
+
+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
@@ -5104,6 +5244,7 @@ md_begin (void)
   segT current_section = now_seg;
   int current_subsec = now_subseg;
   xtensa_isa isa;
+  int i;
 
   xtensa_default_isa = xtensa_isa_init (0, 0);
   isa = xtensa_default_isa;
@@ -5115,8 +5256,6 @@ md_begin (void)
 
   subseg_set (current_section, current_subsec);
 
-  xg_init_vinsn (&cur_vinsn);
-
   xtensa_addi_opcode = xtensa_opcode_lookup (isa, "addi");
   xtensa_addmi_opcode = xtensa_opcode_lookup (isa, "addmi");
   xtensa_call0_opcode = xtensa_opcode_lookup (isa, "call0");
@@ -5149,6 +5288,15 @@ 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++)
+    {
+      int format_slots = xtensa_format_num_slots (isa, i);
+      if (format_slots > config_max_slots)
+       config_max_slots = format_slots;
+    }
+
+  xg_init_vinsn (&cur_vinsn);
+
   xtensa_num_pipe_stages = xtensa_isa_num_pipe_stages (isa);
 
   init_op_placement_info_table ();
@@ -5352,9 +5500,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)
@@ -5378,7 +5524,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)
@@ -5409,12 +5555,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))
@@ -5428,7 +5573,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)
     {
@@ -5539,6 +5684,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 ();
 }
 
 
@@ -5555,7 +5702,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)
     {
@@ -5765,14 +5911,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)
@@ -5786,7 +5924,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)
@@ -5822,26 +5960,20 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
            {
            case BFD_RELOC_8:
              fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
+             fixP->fx_signed = 0;
              break;
            case BFD_RELOC_16:
              fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
+             fixP->fx_signed = 0;
              break;
            case BFD_RELOC_32:
              fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
+             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));
 
@@ -5946,7 +6078,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);
@@ -5968,8 +6100,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;
 
@@ -6014,7 +6146,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;
@@ -6024,9 +6156,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;
 }
@@ -6056,13 +6188,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);
 }
 
 
@@ -6194,8 +6324,7 @@ finish_vinsn (vliw_insn *vinsn)
 {
   IStack slotstack;
   int i;
-  char *file_name;
-  unsigned line;
+  int slots;
 
   if (find_vinsn_conflicts (vinsn))
     {
@@ -6207,7 +6336,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."));
@@ -6217,9 +6347,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;"),
@@ -6230,21 +6358,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;",
@@ -6341,8 +6466,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;",
@@ -6360,6 +6484,8 @@ finish_vinsn (vliw_insn *vinsn)
   xg_assemble_vliw_tokens (vinsn);
 
   xg_clear_vinsn (vinsn);
+
+  xtensa_check_frag_count ();
 }
 
 
@@ -6844,7 +6970,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);
@@ -6881,7 +7007,7 @@ total_frag_text_expansion (fragS *fragP)
   int slot;
   int total_expansion = 0;
 
-  for (slot = 0; slot < MAX_SLOTS; slot++)
+  for (slot = 0; slot < config_max_slots; slot++)
     total_expansion += fragP->tc_frag_data.text_expansion[slot];
 
   return total_expansion;
@@ -6922,7 +7048,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]
@@ -7057,6 +7183,11 @@ 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] =
+                 tinsn->tok[1].X_add_symbol->sy_frag;
+       }
       if (tinsn->literal_space != 0)
        xg_assemble_literal_space (tinsn->literal_space, slot);
       frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
@@ -7124,16 +7255,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);
@@ -7210,8 +7344,341 @@ xtensa_end (void)
   xtensa_sanity_check ();
 
   xtensa_add_config_info ();
+
+  xtensa_check_frag_count ();
+}
+
+struct trampoline_index
+{
+  fragS **entry;
+  size_t n_entries;
+  size_t n_max;
+};
+
+struct trampoline_seg
+{
+  struct trampoline_seg *next;
+  asection *seg;
+  struct trampoline_index index;
+};
+
+static struct trampoline_seg trampoline_seg_list;
+#define J_RANGE (128 * 1024)
+#define J_MARGIN 4096
+
+static int unreachable_count = 0;
+
+
+static void
+xtensa_maybe_create_trampoline_frag (void)
+{
+  if (!use_trampolines)
+    return;
+
+  /* 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.  */
+
+  if (++unreachable_count > 10)
+    {
+      xtensa_create_trampoline_frag (FALSE);
+      clear_frag_count ();
+      unreachable_count = 0;
+    }
+}
+
+static void
+xtensa_check_frag_count (void)
+{
+  if (!use_trampolines || frag_now->tc_frag_data.is_no_transform)
+    return;
+
+  /* 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.  */
+
+  if (get_frag_count () > 8000)
+    {
+      xtensa_create_trampoline_frag (TRUE);
+      clear_frag_count ();
+      unreachable_count = 0;
+    }
+
+  /* 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;
+
+static xtensa_insnbuf litpool_buf = NULL;
+static xtensa_insnbuf litpool_slotbuf = NULL;
+
+#define TRAMPOLINE_FRAG_SIZE 3000
+
+static struct trampoline_seg *
+find_trampoline_seg (asection *seg)
+{
+  struct trampoline_seg *ts = trampoline_seg_list.next;
+
+  for ( ; ts; ts = ts->next)
+    {
+      if (ts->seg == seg)
+       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;
+}
+
+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;
+
+  lps->frag_count = 0;
+}
 
 static void
 xtensa_cleanup_align_frags (void)
@@ -7356,12 +7823,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);
@@ -7402,9 +7869,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.  */
@@ -7439,22 +7933,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))
@@ -7463,7 +7957,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);
@@ -7479,7 +7973,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;
@@ -7855,7 +8349,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.  */
@@ -7868,7 +8361,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);
@@ -8032,12 +8524,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)
       {
@@ -8047,7 +8539,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;
@@ -8090,7 +8582,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;
 
@@ -8103,12 +8595,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;
 
@@ -8137,7 +8629,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;
 
@@ -8150,12 +8642,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;
 
@@ -8191,7 +8683,7 @@ xtensa_add_config_info (void)
   info_sec = subseg_new (".xtensa.info", 0);
   bfd_set_section_flags (stdoutput, 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);
   sz = strlen (data) + 1;
@@ -8233,8 +8725,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;
 }
 
 
@@ -8307,19 +8824,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;
 }
@@ -8540,6 +9055,171 @@ 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;
+
+           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;
+
+      while (xg_is_relaxable_fixup (fixP))
+       fixP = xg_relax_fixup (idx, fixP);
+    }
+}
+
+/* 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".  */
@@ -8550,14 +9230,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;
@@ -8636,7 +9316,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.  */
@@ -8648,6 +9362,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"));
     }
@@ -8817,7 +9536,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:
@@ -8945,7 +9664,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;
@@ -8983,39 +9702,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
@@ -9025,9 +9716,13 @@ 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;
 
@@ -9054,104 +9749,184 @@ bytes_to_stretch (fragS *this_frag,
   /* 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)
+  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)
     {
-      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);
-       }
+      if (this_frag->fr_subtype == RELAX_FILL_NOP)
+       return 3;
+      else if (num_widens == extra_bytes)
+       return 1;
+      return 0;
     }
-  else
+
+  /* Add a narrow nop.  */
+  nops_needed++;
+  nop_bytes += 2;
+  extra_bytes -= 2;
+  if (narrow_nops == 0 || nops_needed > wide_nops)
+    return 0;
+
+  if (nop_bytes + num_widens >= desired_diff && extra_bytes >= 0)
     {
-      /* We will need a NOP no matter what, but should we widen
-        this instruction to help?
+      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;
+    }
 
-        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;
-       }
+  /* 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)
+    {
+      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;
     }
-  gas_assert (0);
+
+  /* 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))
+    {
+      frag_wane (fragP);
+      fragP->fr_subtype = 0;
+    }
+
+  return fixP;
+}
+
+
+static int
+init_trampoline_frag (fragS *fp)
+{
+  int growth = 0;
+
+  if (fp->fr_fix == 0)
+    {
+      symbolS *lsym;
+      char label[10 + 2 * sizeof(fp)];
+
+      sprintf (label, ".L0_TR_%p", fp);
+      lsym = (symbolS *)local_symbol_make (label, now_seg, 0, fp);
+      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;
+        }
+    }
+  return growth;
+}
+
+
+static int
+add_jump_to_trampoline (fragS *tramp, fragS *origfrag)
+{
+  int i, slot = -1;
+
+  for (i = 0; i < MAX_SLOTS; ++i)
+    if (origfrag->tc_frag_data.slot_symbols[i])
+      {
+       gas_assert (slot == -1);
+       slot = i;
+      }
+
+  gas_assert (slot >= 0 && slot < MAX_SLOTS);
+
+  /* Assemble a jump to the target label in the trampoline frag.  */
+  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 3;
+}
+
+
 static long
 relax_frag_immed (segT segP,
                  fragS *fragP,
@@ -9235,20 +10010,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;
        }
     }
@@ -9290,6 +10065,37 @@ 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];
+
+      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)
+           {
+             this_text_diff += init_trampoline_frag (tf);
+             this_text_diff += add_jump_to_trampoline (tf, fragP);
+           }
+         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;
 }
 
@@ -9309,10 +10115,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)
@@ -9410,6 +10216,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;
@@ -9603,7 +10412,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.  */
@@ -9678,7 +10486,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];
@@ -9969,7 +10776,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;
@@ -10064,28 +10871,153 @@ 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,
+                                      0, poolend);
+  poolbeg->fr_symbol = lsym;
+  /* Rest is done in xtensa_relax_frag.  */
+}
+
 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;
+  struct litpool_seg *lps;
+  const char *init_name = INIT_SECTION_NAME;
+  const char *fini_name = FINI_SECTION_NAME;
+  int init_name_len = strlen(init_name);
+  int fini_name_len = strlen(fini_name);
 
   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.  */
+
+  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;
+
+      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++)
+                   {
+                     if (fragP->tc_frag_data.literal_frags[slot])
+                       {
+                         /* L32R; point its literal to the nearest litpool
+                            preferring non-"candidate" positions to avoid
+                            the jump-around.  */
+                         fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
+                         struct litpool_frag *lp = lpf->prev;
+                         if (!lp->fragP)
+                           {
+                             break;
+                           }
+                         while (lp->fragP->fr_subtype ==
+                                RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+                           {
+                             lp = lp->prev;
+                             if (lp->fragP == NULL)
+                               {
+                                 /* End of list; have to bite the bullet.
+                                    Take the nearest.  */
+                                 lp = lpf->prev;
+                                 break;
+                               }
+                             /* Does it (conservatively) reach?  */
+                             if (addr - lp->addr <= 128 * 1024)
+                               {
+                                 if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
+                                   {
+                                     /* Found a good one.  */
+                                     break;
+                                   }
+                                 else if (lp->prev->fragP &&
+                                          addr - lp->prev->addr > 128 * 1024)
+                                   {
+                                     /* This is still a "candidate" but the next one
+                                        will be too far away, so revert to the nearest
+                                        one, convert it and add the jump around.  */
+                                     lp = lpf->prev;
+                                     break;
+                                   }
+                               }
+                           }
+
+                         /* Convert candidate and add the jump around.  */
+                         if (lp->fragP->fr_subtype ==
+                             RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+                           xg_promote_candidate_litpool (lps, lp);
+
+                         if (! litfrag->tc_frag_data.literal_frag)
+                           {
+                             /* Take earliest use of this literal to avoid
+                                forward refs.  */
+                             litfrag->tc_frag_data.literal_frag = lp->fragP;
+                           }
+                       }
+                   }
+               }
+             addr += fragP->fr_fix;
+             if (fragP->fr_type == rs_fill)
+               addr += fragP->fr_offset;
+           }
+       }
+    }
+
   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;
@@ -10094,13 +11026,21 @@ 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)
+       {
+         search_frag = frchain_from->frch_root;
+         as_bad_where (search_frag->fr_file, search_frag->fr_line,
+                       _("literal pool location required for text-section-literals; specify with .literal_position"));
+         continue;
+       }
+
       gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
              == RELAX_LITERAL_POOL_BEGIN);
       xtensa_switch_section_emit_state (&state, segment->seg, 0);
@@ -10111,16 +11051,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;
@@ -10128,8 +11064,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;
@@ -10174,9 +11158,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);
     }
 }
 
@@ -10280,7 +11264,6 @@ 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 =
@@ -10290,20 +11273,14 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
 
   if (pool_location == NULL
       && !use_literal_section
-      && !recursive
       && !is_init && ! is_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);
@@ -10358,7 +11335,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
@@ -10373,7 +11350,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;
@@ -10399,7 +11377,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)
     {
@@ -10411,32 +11389,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.
@@ -10455,7 +11438,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;
@@ -10832,8 +11815,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;
@@ -11090,8 +12072,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;
                }
@@ -11116,8 +12097,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++)
@@ -11198,7 +12178,6 @@ xg_get_single_slot (xtensa_opcode opcode)
 void
 istack_init (IStack *stack)
 {
-  memset (stack, 0, sizeof (IStack));
   stack->ninsn = 0;
 }
 
@@ -11408,20 +12387,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);
@@ -11432,11 +12411,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:
@@ -11675,7 +12654,7 @@ xg_init_vinsn (vliw_insn *v)
   if (v->insnbuf == NULL)
     as_fatal (_("out of memory"));
 
-  for (i = 0; i < MAX_SLOTS; i++)
+  for (i = 0; i < config_max_slots; i++)
     {
       v->slotbuf[i] = xtensa_insnbuf_alloc (isa);
       if (v->slotbuf[i] == NULL)
@@ -11689,7 +12668,8 @@ xg_clear_vinsn (vliw_insn *v)
 {
   int i;
 
-  memset (v, 0, offsetof (vliw_insn, insnbuf));
+  memset (v, 0, offsetof (vliw_insn, slots)
+                + sizeof(TInsn) * config_max_slots);
 
   v->format = XTENSA_UNDEFINED;
   v->num_slots = 0;
@@ -11698,7 +12678,7 @@ xg_clear_vinsn (vliw_insn *v)
   if (xt_saved_debug_type != DEBUG_NONE)
     debug_type = xt_saved_debug_type;
 
-  for (i = 0; i < MAX_SLOTS; i++)
+  for (i = 0; i < config_max_slots; i++)
     v->slots[i].opcode = XTENSA_UNDEFINED;
 }
 
@@ -11706,7 +12686,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));
@@ -11732,7 +12712,7 @@ xg_free_vinsn (vliw_insn *v)
 {
   int i;
   xtensa_insnbuf_free (xtensa_default_isa, v->insnbuf);
-  for (i = 0; i < MAX_SLOTS; i++)
+  for (i = 0; i < config_max_slots; i++)
     xtensa_insnbuf_free (xtensa_default_isa, v->slotbuf[i]);
 }
 
@@ -11789,8 +12769,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:
@@ -11805,15 +12785,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
@@ -11959,7 +12939,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;
 };
@@ -12021,8 +13001,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;
@@ -12032,7 +13011,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;
 
@@ -12042,5 +13021,5 @@ xtensa_section_rename (char *name)
        return r->new_name;
     }
 
-  return name;
+  return (char *) name;
 }