]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-rx.c
Support ELF SHF_GNU_MBIND and PT_GNU_MBIND_XXX
[thirdparty/binutils-gdb.git] / gas / config / tc-rx.c
index d1980509823da223f0adb11912d2760a9625cdc6..ba826c7b298c4804f03e832d346f8358b0deb4ce 100644 (file)
@@ -1,6 +1,5 @@
 /* tc-rx.c -- Assembler for the Renesas RX
-   Copyright 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2008-2017 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 
 #include "as.h"
 #include "struc-symbol.h"
-#include "obstack.h"
 #include "safe-ctype.h"
 #include "dwarf2dbg.h"
-#include "libbfd.h"
 #include "elf/common.h"
 #include "elf/rx.h"
 #include "rx-defs.h"
@@ -46,11 +43,20 @@ const char EXP_CHARS[]            = "eE";
 const char FLT_CHARS[]            = "dD";
 \f
 /* ELF flags to set in the output file header.  */
-static int elf_flags = 0;
+static int elf_flags = E_FLAG_RX_ABI;
 
 bfd_boolean rx_use_conventional_section_names = FALSE;
 static bfd_boolean rx_use_small_data_limit = FALSE;
 
+static bfd_boolean rx_pid_mode = FALSE;
+static int rx_num_int_regs = 0;
+int rx_pid_register;
+int rx_gp_register;
+
+enum rx_cpu_types rx_cpu = RX600;
+
+static void rx_fetchalign (int ignore ATTRIBUTE_UNUSED);
+
 enum options
 {
   OPTION_BIG = OPTION_MD_BASE,
@@ -60,7 +66,13 @@ enum options
   OPTION_CONVENTIONAL_SECTION_NAMES,
   OPTION_RENESAS_SECTION_NAMES,
   OPTION_SMALL_DATA_LIMIT,
-  OPTION_RELAX
+  OPTION_RELAX,
+  OPTION_PID,
+  OPTION_INT_REGS,
+  OPTION_USES_GCC_ABI,
+  OPTION_USES_RX_ABI,
+  OPTION_CPU,
+  OPTION_DISALLOW_STRING_INSNS,
 };
 
 #define RX_SHORTOPTS ""
@@ -83,12 +95,33 @@ struct option md_longopts[] =
   {"muse-renesas-section-names", no_argument, NULL, OPTION_RENESAS_SECTION_NAMES},
   {"msmall-data-limit", no_argument, NULL, OPTION_SMALL_DATA_LIMIT},
   {"relax", no_argument, NULL, OPTION_RELAX},
+  {"mpid", no_argument, NULL, OPTION_PID},
+  {"mint-register", required_argument, NULL, OPTION_INT_REGS},
+  {"mgcc-abi", no_argument, NULL, OPTION_USES_GCC_ABI},
+  {"mrx-abi", no_argument, NULL, OPTION_USES_RX_ABI},
+  {"mcpu", required_argument, NULL, OPTION_CPU},
+  {"mno-allow-string-insns", no_argument, NULL, OPTION_DISALLOW_STRING_INSNS},
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
 
+struct cpu_type
+{
+  const char *cpu_name;
+  enum rx_cpu_types type;
+};
+
+struct cpu_type  cpu_type_list[] =
+{
+  {"rx100",RX100},
+  {"rx200",RX200},
+  {"rx600",RX600},
+  {"rx610",RX610},
+  {"rxv2",RXV2}
+};
+
 int
-md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
+md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
@@ -123,7 +156,46 @@ md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
     case OPTION_RELAX:
       linkrelax = 1;
       return 1;
+
+    case OPTION_PID:
+      rx_pid_mode = TRUE;
+      elf_flags |= E_FLAG_RX_PID;
+      return 1;
+
+    case OPTION_INT_REGS:
+      rx_num_int_regs = atoi (optarg);
+      return 1;
+
+    case OPTION_USES_GCC_ABI:
+      elf_flags &= ~ E_FLAG_RX_ABI;
+      return 1;
+
+    case OPTION_USES_RX_ABI:
+      elf_flags |= E_FLAG_RX_ABI;
+      return 1;
+
+    case OPTION_CPU:
+      {
+       unsigned int i;
+       for (i = 0; i < ARRAY_SIZE (cpu_type_list); i++)
+         {
+           if (strcasecmp (arg, cpu_type_list[i].cpu_name) == 0)
+             {
+               rx_cpu = cpu_type_list[i].type;
+               if (rx_cpu == RXV2)
+                 elf_flags |= E_FLAG_RX_V2;
+               return 1;
+             }
+         }
+       as_warn (_("unrecognised RX CPU type %s"), arg);
+       break;
+      }
+
+    case OPTION_DISALLOW_STRING_INSNS:
+      elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_NO;
+      return 1;
     }
+
   return 0;
 }
 
@@ -138,6 +210,11 @@ md_show_usage (FILE * stream)
   fprintf (stream, _("  --muse-conventional-section-names\n"));
   fprintf (stream, _("  --muse-renesas-section-names [default]\n"));
   fprintf (stream, _("  --msmall-data-limit\n"));
+  fprintf (stream, _("  --mrelax\n"));
+  fprintf (stream, _("  --mpid\n"));
+  fprintf (stream, _("  --mint-register=<value>\n"));
+  fprintf (stream, _("  --mcpu=<rx100|rx200|rx600|rx610|rxv2>\n"));
+  fprintf (stream, _("  --mno-allow-string-insns"));
 }
 
 static void
@@ -188,10 +265,10 @@ rx_include (int ignore)
   FILE * try;
   char * path;
   char * filename;
-  char * current_filename;
-  char * eof;
-  char * p;
-  char * d;
+  const char * current_filename;
+  char * last_char;
+  const char * p;
+  const char * d;
   char * f;
   char   end_char;
   size_t len;
@@ -208,29 +285,29 @@ rx_include (int ignore)
 
   /* Get the filename.  Spaces are allowed, NUL characters are not.  */
   filename = input_line_pointer;
-  eof = find_end_of_line (filename, FALSE);
-  input_line_pointer = eof;
-
-  while (eof >= filename && (* eof == ' ' || * eof == '\n'))
-    -- eof;
-  end_char = *(++ eof);
-  * eof = 0;
-  if (eof == filename)
+  last_char = find_end_of_line (filename, FALSE);
+  input_line_pointer = last_char;
+
+  while (last_char >= filename && (* last_char == ' ' || * last_char == '\n'))
+    -- last_char;
+  end_char = *(++ last_char);
+  * last_char = 0;
+  if (last_char == filename)
     {
       as_bad (_("no filename following .INCLUDE pseudo-op"));
-      * eof = end_char;
+      * last_char = end_char;
       return;
     }
 
-  as_where (& current_filename, NULL);
-  f = (char *) xmalloc (strlen (current_filename) + strlen (filename) + 1);
+   current_filename = as_where (NULL);
+  f = XNEWVEC (char, strlen (current_filename) + strlen (filename) + 1);
 
   /* Check the filename.  If [@]..FILE[@] is found then replace
      this with the current assembler source filename, stripped
      of any directory prefixes or extensions.  */
   if ((p = rx_strcasestr (filename, "..file")) != NULL)
     {
-      char * c;
+      const char * c;
 
       len = 6; /* strlen ("..file"); */
 
@@ -265,7 +342,7 @@ rx_include (int ignore)
      3. Try any directories specified by the -I command line
         option(s).
 
-     4 .Try a directory specifed by the INC100 environment variable.  */
+     4 .Try a directory specified by the INC100 environment variable.  */
 
   if (IS_ABSOLUTE_PATH (f))
     try = fopen (path = f, FOPEN_RT);
@@ -281,7 +358,7 @@ rx_include (int ignore)
       if (env && strlen (env) > len)
        len = strlen (env);
 
-      path = (char *) xmalloc (strlen (f) + len + 5);
+      path = XNEWVEC (char, strlen (f) + len + 5);
 
       if (current_filename != NULL)
        {
@@ -330,7 +407,7 @@ rx_include (int ignore)
       input_scrub_insert_file (path);
     }
 
-  * eof = end_char;
+  * last_char = end_char;
 }
 
 static void
@@ -339,7 +416,7 @@ parse_rx_section (char * name)
   asection * sec;
   int   type;
   int   attr = SHF_ALLOC | SHF_EXECINSTR;
-  int   align = 2;
+  int   align = 1;
   char  end_char;
 
   do
@@ -367,9 +444,9 @@ parse_rx_section (char * name)
                p++;
              switch (*p)
                {
-               case '2': align = 2; break;
-               case '4': align = 4; break;
-               case '8': align = 8; break;
+               case '2': align = 1; break;
+               case '4': align = 2; break;
+               case '8': align = 3; break;
                default:
                  as_bad (_("unrecognised alignment value in .SECTION directive: %s"), p);
                  ignore_rest_of_line ();
@@ -409,7 +486,7 @@ parse_rx_section (char * name)
       else
        type = SHT_NOBITS;
 
-      obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+      obj_elf_change_section (name, type, 0, attr, 0, NULL, FALSE, FALSE);
     }
   else /* Try not to redefine a section, especially B_1.  */
     {
@@ -424,7 +501,7 @@ parse_rx_section (char * name)
        | ((flags & SEC_STRINGS) ? SHF_STRINGS : 0)
        | ((flags & SEC_THREAD_LOCAL) ? SHF_TLS : 0);
 
-      obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+      obj_elf_change_section (name, type, 0, attr, 0, NULL, FALSE, FALSE);
     }
 
   bfd_set_section_alignment (stdoutput, now_seg, align);
@@ -453,10 +530,7 @@ rx_section (int ignore)
 
       if (*p != '"' && *p != '#')
        {
-         char * name = (char *) xmalloc (len + 1);
-
-         strncpy (name, input_line_pointer, len);
-         name[len] = 0;
+         char *name = xmemdup0 (input_line_pointer, len);
 
          input_line_pointer = p;
          parse_rx_section (name);
@@ -548,7 +622,7 @@ const pseudo_typeS md_pseudo_table[] =
   /* The manual documents ".stk" but the compiler emits ".stack".  */
   { "stack",    rx_nop,         0 },
 
-  /* Theae are Renesas as100 assembler pseudo-ops that we do support.  */
+  /* These are Renesas as100 assembler pseudo-ops that we do support.  */
   { "addr",     rx_cons,        3 },
   { "align",    s_align_bytes,  2 },
   { "byte",     rx_cons,        1 },
@@ -579,29 +653,64 @@ const pseudo_typeS md_pseudo_table[] =
   { "int",     cons,           4 },
   { "word",    cons,           4 },
 
+  { "fetchalign", rx_fetchalign, 0 },
+
   /* End of list marker.  */
   { NULL,      NULL,           0 }
 };
 
 static asymbol * gp_symbol;
+static asymbol * rx_pid_symbol;
+
+static symbolS * rx_pidreg_symbol;
+static symbolS * rx_gpreg_symbol;
 
 void
 md_begin (void)
 {
+  /* Make the __gp and __pid_base symbols now rather
+     than after the symbol table is frozen.  We only do this
+     when supporting small data limits because otherwise we
+     pollute the symbol table.  */
+
+  /* The meta-registers %pidreg and %gpreg depend on what other
+     options are specified.  The __rx_*_defined symbols exist so we
+     can .ifdef asm code based on what options were passed to gas,
+     without needing a preprocessor  */
+
+  if (rx_pid_mode)
+    {
+      rx_pid_register = 13 - rx_num_int_regs;
+      rx_pid_symbol = symbol_get_bfdsym (symbol_find_or_make ("__pid_base"));
+      rx_pidreg_symbol = symbol_find_or_make ("__rx_pidreg_defined");
+      S_SET_VALUE (rx_pidreg_symbol, rx_pid_register);
+      S_SET_SEGMENT (rx_pidreg_symbol, absolute_section);
+    }
+
   if (rx_use_small_data_limit)
-    /* Make the __gp symbol now rather
-       than after the symbol table is frozen.  We only do this
-       when supporting small data limits because otherwise we
-       pollute the symbol table.  */
-    gp_symbol = symbol_get_bfdsym (symbol_find_or_make ("__gp"));
+    {
+      if (rx_pid_mode)
+       rx_gp_register = rx_pid_register - 1;
+      else
+       rx_gp_register = 13 - rx_num_int_regs;
+      gp_symbol = symbol_get_bfdsym (symbol_find_or_make ("__gp"));
+      rx_gpreg_symbol = symbol_find_or_make ("__rx_gpreg_defined");
+      S_SET_VALUE (rx_gpreg_symbol, rx_gp_register);
+      S_SET_SEGMENT (rx_gpreg_symbol, absolute_section);
+    }
 }
 
 char * rx_lex_start;
 char * rx_lex_end;
 
+/* These negative numbers are found in rx_bytesT.n_base for non-opcode
+   md_frags */
+#define RX_NBASE_FETCHALIGN    -1
+
 typedef struct rx_bytesT
 {
   char base[4];
+  /* If this is negative, it's a special-purpose frag as per the defines above. */
   int n_base;
   char ops[8];
   int n_ops;
@@ -629,6 +738,31 @@ typedef struct rx_bytesT
 } rx_bytesT;
 
 static rx_bytesT rx_bytes;
+/* We set n_ops to be "size of next opcode" if the next opcode doesn't relax.  */
+static rx_bytesT *fetchalign_bytes = NULL;
+
+static void
+rx_fetchalign (int ignore ATTRIBUTE_UNUSED)
+{
+  char * bytes;
+  fragS * frag_then;
+
+  memset (& rx_bytes, 0, sizeof (rx_bytes));
+  rx_bytes.n_base = RX_NBASE_FETCHALIGN;
+
+  bytes = frag_more (8);
+  frag_then = frag_now;
+  frag_variant (rs_machine_dependent,
+               0 /* max_chars */,
+               0 /* var */,
+               0 /* subtype */,
+               0 /* symbol */,
+               0 /* offset */,
+               0 /* opcode */);
+  frag_then->fr_opcode = bytes;
+  frag_then->fr_subtype = 0;
+  fetchalign_bytes = frag_then->tc_frag_data;
+}
 
 void
 rx_relax (int type, int pos)
@@ -821,43 +955,50 @@ rx_field5s2 (expressionS exp)
 void
 rx_op (expressionS exp, int nbytes, int type)
 {
-  int v = 0;
+  offsetT v = 0;
 
   if ((exp.X_op == O_constant || exp.X_op == O_big)
       && type != RXREL_PCREL)
     {
-      if (exp.X_op == O_big && exp.X_add_number <= 0)
+      if (exp.X_op == O_big)
        {
-         LITTLENUM_TYPE w[2];
-         char * ip = rx_bytes.ops + rx_bytes.n_ops;
+         if (exp.X_add_number == -1)
+           {
+             LITTLENUM_TYPE w[2];
+             char * ip = rx_bytes.ops + rx_bytes.n_ops;
 
-         gen_to_words (w, F_PRECISION, 8);
+             gen_to_words (w, F_PRECISION, 8);
 #if RX_OPCODE_BIG_ENDIAN
-         ip[0] = w[0] >> 8;
-         ip[1] = w[0];
-         ip[2] = w[1] >> 8;
-         ip[3] = w[1];
+             ip[0] = w[0] >> 8;
+             ip[1] = w[0];
+             ip[2] = w[1] >> 8;
+             ip[3] = w[1];
 #else
-         ip[3] = w[0] >> 8;
-         ip[2] = w[0];
-         ip[1] = w[1] >> 8;
-         ip[0] = w[1];
+             ip[3] = w[0] >> 8;
+             ip[2] = w[0];
+             ip[1] = w[1] >> 8;
+             ip[0] = w[1];
 #endif
-         rx_bytes.n_ops += 4;
+             rx_bytes.n_ops += 4;
+             return;
+           }
+
+         v = ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
+           |  (generic_bignum[0] & LITTLENUM_MASK);
+
        }
       else
+       v = exp.X_add_number;
+
+      while (nbytes)
        {
-         v = exp.X_add_number;
-         while (nbytes)
-           {
 #if RX_OPCODE_BIG_ENDIAN
-             OP ((v >> (8 * (nbytes - 1))) & 0xff);
+         OP ((v >> (8 * (nbytes - 1))) & 0xff);
 #else
-             OP (v & 0xff);
-             v >>= 8;
+         OP (v & 0xff);
+         v >>= 8;
 #endif
-             nbytes --;
-           }
+         nbytes --;
        }
     }
   else
@@ -884,9 +1025,9 @@ rx_wrap (void)
 void
 rx_frag_init (fragS * fragP)
 {
-  if (rx_bytes.n_relax || rx_bytes.link_relax)
+  if (rx_bytes.n_relax || rx_bytes.link_relax || rx_bytes.n_base < 0)
     {
-      fragP->tc_frag_data = malloc (sizeof (rx_bytesT));
+      fragP->tc_frag_data = XNEW (rx_bytesT);
       memcpy (fragP->tc_frag_data, & rx_bytes, sizeof (rx_bytesT));
     }
   else
@@ -936,7 +1077,7 @@ scan_for_infix_rx_pseudo_ops (char * str)
   if (dot == NULL || dot == str)
     return FALSE;
 
-  /* A real pseudo-op must be preceeded by whitespace.  */
+  /* A real pseudo-op must be preceded by whitespace.  */
   if (dot[-1] != ' ' && dot[-1] != '\t')
     return FALSE;
 
@@ -1000,8 +1141,12 @@ md_assemble (char * str)
     {
       bytes = frag_more (rx_bytes.n_base + rx_bytes.n_ops);
       frag_then = frag_now;
+      if (fetchalign_bytes)
+       fetchalign_bytes->n_ops = rx_bytes.n_base + rx_bytes.n_ops;
     }
 
+  fetchalign_bytes = NULL;
+
   APPEND (base, n_base);
   APPEND (ops, n_ops);
 
@@ -1074,7 +1219,7 @@ md_number_to_chars (char * buf, valueT val, int n)
 
 static struct
 {
-  char * fname;
+  const char * fname;
   int    reloc;
 }
 reloc_functions[] =
@@ -1116,7 +1261,7 @@ valueT
 md_section_align (segT segment, valueT size)
 {
   int align = bfd_get_section_alignment (stdoutput, segment);
-  return ((size + (1 << align) - 1) & (-1 << align));
+  return ((size + (1 << align) - 1) & -(1 << align));
 }
 
                                /* NOP - 1 cycle */
@@ -1131,8 +1276,8 @@ static unsigned char nop_4[] = { 0x76, 0x10, 0x01, 0x00 };
 static unsigned char nop_5[] = { 0x77, 0x10, 0x01, 0x00, 0x00 };
                                /* MUL #1,R0 - 1 cycle */
 static unsigned char nop_6[] = { 0x74, 0x10, 0x01, 0x00, 0x00, 0x00 };
-                               /* BRA.S .+7 - 1 cycle */
-static unsigned char nop_7[] = { 0x0F, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
+                               /* MAX 0x80000000,R0 - 1 cycle */
+static unsigned char nop_7[] = { 0xFD, 0x70, 0x40, 0x00, 0x00, 0x00, 0x80 };
 
 static unsigned char *nops[] = { NULL, nop_1, nop_2, nop_3, nop_4, nop_5, nop_6, nop_7 };
 #define BIGGEST_NOP 7
@@ -1142,25 +1287,31 @@ static unsigned char *nops[] = { NULL, nop_1, nop_2, nop_3, nop_4, nop_5, nop_6,
 void
 rx_handle_align (fragS * frag)
 {
+  /* If handling an alignment frag, use an optimal NOP pattern.
+     Only do this if a fill value has not already been provided.
+     FIXME: This test fails if the provided fill value is zero.  */
   if ((frag->fr_type == rs_align
        || frag->fr_type == rs_align_code)
       && subseg_text_p (now_seg))
     {
       int count = (frag->fr_next->fr_address
-                  - frag->fr_address   
+                  - frag->fr_address
                   - frag->fr_fix);
       unsigned char *base = (unsigned char *)frag->fr_literal + frag->fr_fix;
 
-      if (count > BIGGEST_NOP)
+      if (* base == 0)
        {
-         base[0] = 0x2e;
-         base[1] = count;
-         frag->fr_var = 2;
-       }
-      else if (count > 0)
-       {
-         memcpy (base, nops[count], count);
-         frag->fr_var = count;
+         if (count > BIGGEST_NOP)
+           {
+             base[0] = 0x2e;
+             base[1] = count;
+             frag->fr_var = 2;
+           }
+         else if (count > 0)
+           {
+             memcpy (base, nops[count], count);
+             frag->fr_var = count;
+           }
        }
     }
 
@@ -1183,7 +1334,7 @@ rx_handle_align (fragS * frag)
     }
 }
 
-char *
+const char *
 md_atof (int type, char * litP, int * sizeP)
 {
   return ieee_md_atof (type, litP, sizeP, target_big_endian);
@@ -1335,7 +1486,7 @@ rx_frag_fix_value (fragS *    fragP,
 /* Estimate how big the opcode is after this relax pass.  The return
    value is the difference between fr_fix and the actual size.  We
    compute the total size in rx_relax_frag and store it in fr_subtype,
-   sowe only need to subtract fx_fix and return it.  */
+   so we only need to subtract fx_fix and return it.  */
 
 int
 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED)
@@ -1358,6 +1509,18 @@ md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTR
   return delta;
 }
 
+/* Given a frag FRAGP, return the "next" frag that contains an
+   opcode.  Assumes the next opcode is relaxable, and thus rs_machine_dependent.  */
+
+static fragS *
+rx_next_opcode (fragS *fragP)
+{
+  do {
+    fragP = fragP->fr_next;
+  } while (fragP && fragP->fr_type != rs_machine_dependent);
+  return fragP;
+}
+
 /* Given the new addresses for this relax pass, figure out how big
    each opcode must be.  We store the total number of bytes needed in
    fr_subtype.  The return value is the difference between the size
@@ -1382,6 +1545,34 @@ rx_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch)
           (long) fragP->fr_fix, (long) fragP->fr_var, (long) fragP->fr_offset,
           fragP->fr_literal, fragP->fr_opcode, fragP->fr_type, fragP->fr_subtype, stretch);
 
+  mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
+
+  if (fragP->tc_frag_data->n_base == RX_NBASE_FETCHALIGN)
+    {
+      unsigned int next_size;
+      if (fragP->fr_next == NULL)
+       return 0;
+
+      next_size = fragP->tc_frag_data->n_ops;
+      if (next_size == 0)
+       {
+         fragS *n = rx_next_opcode (fragP);
+         next_size = n->fr_subtype;
+       }
+
+      fragP->fr_subtype = (8-(mypc & 7)) & 7;
+      tprintf("subtype %u\n", fragP->fr_subtype);
+      if (fragP->fr_subtype >= next_size)
+       fragP->fr_subtype = 0;
+      tprintf ("\033[34m -> mypc %lu next_size %u new %d old %d delta %d (fetchalign)\033[0m\n",
+              (unsigned long) (mypc & 7),
+              next_size, fragP->fr_subtype, oldsize, fragP->fr_subtype-oldsize);
+
+      newsize = fragP->fr_subtype;
+
+      return newsize - oldsize;
+    }
+
   optype = rx_opcode_type (fragP->fr_opcode);
 
   /* In the one case where we have both a disp and imm relaxation, we want
@@ -1430,7 +1621,6 @@ rx_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch)
       return newsize - oldsize;
     }
 
-  mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
   if (sym_addr > mypc)
     addr0 += stretch;
 
@@ -1571,7 +1761,8 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
   rx_bytesT * rxb = fragP->tc_frag_data;
   addressT addr0, mypc;
   int disp;
-  int reloc_type, reloc_adjust;
+  int reloc_adjust;
+  bfd_reloc_code_real_type reloc_type;
   char * op = fragP->fr_opcode;
   int keep_reloc = 0;
   int ri;
@@ -1589,13 +1780,29 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
   {
     int i;
 
-    printf ("lit %08x opc %08x", (int) fragP->fr_literal, (int) fragP->fr_opcode);
+    printf ("lit 0x%p opc 0x%p", fragP->fr_literal, fragP->fr_opcode);
     for (i = 0; i < 10; i++)
       printf (" %02x", (unsigned char) (fragP->fr_opcode[i]));
     printf ("\n");
   }
 #endif
 
+  if (fragP->tc_frag_data->n_base == RX_NBASE_FETCHALIGN)
+    {
+      int count = fragP->fr_subtype;
+      if (count == 0)
+       ;
+      else if (count > BIGGEST_NOP)
+       {
+         op[0] = 0x2e;
+         op[1] = count;
+       }
+      else if (count > 0)
+       {
+         memcpy (op, nops[count], count);
+       }
+    }
+
   /* In the one case where we have both a disp and imm relaxation, we want
      the imm relaxation here.  */
   ri = 0;
@@ -1603,20 +1810,29 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       && fragP->tc_frag_data->relax[0].type == RX_RELAX_DISP)
     ri = 1;
 
+  /* We used a new frag for this opcode, so the opcode address should
+     be the frag address.  */
+  mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
+
   /* Try to get the target address.  If we fail here, we just use the
      largest format.  */
   if (rx_frag_fix_value (fragP, segment, 0, & addr0,
                         fragP->tc_frag_data->relax[ri].type != RX_RELAX_BRANCH, 0))
-    keep_reloc = 1;
+    {
+      /* We don't know the target address.  */
+      keep_reloc = 1;
+      addr0 = 0;
+      disp = 0;
+    }
+  else
+    {
+      /* We know the target address, and it's in addr0.  */
+      disp = (int) addr0 - (int) mypc;
+    }
 
   if (linkrelax)
     keep_reloc = 1;
 
-  /* We used a new frag for this opcode, so the opcode address should
-     be the frag address.  */
-  mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
-  disp = (int) addr0 - (int) mypc;
-
   reloc_type = BFD_RELOC_NONE;
   reloc_adjust = 0;
 
@@ -1686,7 +1902,7 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
          reloc_adjust = 1;
          break;
        case OPCODE (OT_beq, 5): /* BEQ.A - synthetic.  */
-         op[0] = 0x1e; /* bne.s .+4.  */
+         op[0] = 0x1d; /* bne.s .+5.  */
          op[1] = 0x04; /* bra.a dsp:24.  */
          disp -= 1;
 #if RX_OPCODE_BIG_ENDIAN
@@ -1724,7 +1940,7 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
          reloc_adjust = 1;
          break;
        case OPCODE (OT_bne, 5): /* BNE.A - synthetic.  */
-         op[0] = 0x15; /* beq.s .+4.  */
+         op[0] = 0x15; /* beq.s .+5.  */
          op[1] = 0x04; /* bra.a dsp:24.  */
          disp -= 1;
 #if RX_OPCODE_BIG_ENDIAN
@@ -1922,6 +2138,8 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
        case BFD_RELOC_RX_32_OP:
          fix->fx_size = 4;
          break;
+       default:
+         break;
        }
     }
 
@@ -1981,10 +2199,9 @@ void
 rx_cons_fix_new (fragS *       frag,
                 int            where,
                 int            size,
-                expressionS *  exp)
+                expressionS *  exp,
+                bfd_reloc_code_real_type type)
 {
-  bfd_reloc_code_real_type type;
-
   switch (size)
     {
     case 1:
@@ -2184,8 +2401,10 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
 
     case BFD_RELOC_RX_GPRELL:
       val >>= 1;
+      /* Fall through.  */
     case BFD_RELOC_RX_GPRELW:
       val >>= 1;
+      /* Fall through.  */
     case BFD_RELOC_RX_GPRELB:
 #if RX_OPCODE_BIG_ENDIAN
       op[1] = val & 0xff;
@@ -2207,10 +2426,10 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
 }
 
 arelent **
-tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
+tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp)
 {
   static arelent * reloc[5];
-  int is_opcode = 0;
+  bfd_boolean is_opcode = FALSE;
 
   if (fixp->fx_r_type == BFD_RELOC_NONE)
     {
@@ -2225,8 +2444,8 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
       fixp->fx_subsy = NULL;
     }
 
-  reloc[0]               = (arelent *) xmalloc (sizeof (arelent));
-  reloc[0]->sym_ptr_ptr   = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc[0]               = XNEW (arelent);
+  reloc[0]->sym_ptr_ptr   = XNEW (asymbol *);
   * reloc[0]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc[0]->address       = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc[0]->addend        = fixp->fx_offset;
@@ -2235,8 +2454,10 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
       && fixp->fx_subsy)
     {
       fixp->fx_r_type = BFD_RELOC_RX_DIFF;
-      is_opcode = 1;
+      is_opcode = TRUE;
     }
+  else if (sec)
+    is_opcode = sec->flags & SEC_CODE;
 
   /* Certain BFD relocations cannot be translated directly into
      a single (non-Red Hat) RX relocation, but instead need
@@ -2246,20 +2467,20 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
     case BFD_RELOC_RX_DIFF:
       reloc[0]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[1]               = (arelent *) xmalloc (sizeof (arelent));
-      reloc[1]->sym_ptr_ptr   = (asymbol **) xmalloc (sizeof (asymbol *));
+      reloc[1]               = XNEW (arelent);
+      reloc[1]->sym_ptr_ptr   = XNEW (asymbol *);
       * reloc[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
       reloc[1]->address       = fixp->fx_frag->fr_address + fixp->fx_where;
       reloc[1]->addend        = 0;
       reloc[1]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[2]               = (arelent *) xmalloc (sizeof (arelent));
+      reloc[2]               = XNEW (arelent);
       reloc[2]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
       reloc[2]->addend        = 0;
       reloc[2]->sym_ptr_ptr   = reloc[1]->sym_ptr_ptr;
       reloc[2]->address       = fixp->fx_frag->fr_address + fixp->fx_where;
 
-      reloc[3]               = (arelent *) xmalloc (sizeof (arelent));
+      reloc[3]               = XNEW (arelent);
       switch (fixp->fx_size)
        {
        case 1:
@@ -2268,6 +2489,8 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
        case 2:
          if (!is_opcode && target_big_endian)
            reloc[3]->howto   = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16_REV);
+         else if (is_opcode)
+           reloc[3]->howto   = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16UL);
          else
            reloc[3]->howto   = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16);
          break;
@@ -2288,8 +2511,8 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
     case BFD_RELOC_RX_GPRELL:
       reloc[0]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[1]               = (arelent *) xmalloc (sizeof (arelent));
-      reloc[1]->sym_ptr_ptr   = (asymbol **) xmalloc (sizeof (asymbol *));
+      reloc[1]               = XNEW (arelent);
+      reloc[1]->sym_ptr_ptr   = XNEW (asymbol *);
       if (gp_symbol == NULL)
        {
          if (symbol_table_frozen)
@@ -2310,13 +2533,13 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
       reloc[1]->addend        = 0;
       reloc[1]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[2]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[2]             = XNEW (arelent);
       reloc[2]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
       reloc[2]->addend      = 0;
       reloc[2]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
       reloc[2]->address     = fixp->fx_frag->fr_address + fixp->fx_where;
 
-      reloc[3]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[3]             = XNEW (arelent);
       reloc[3]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16UL);
       reloc[3]->addend      = 0;
       reloc[3]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
@@ -2328,8 +2551,8 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
     case BFD_RELOC_RX_GPRELW:
       reloc[0]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[1]               = (arelent *) xmalloc (sizeof (arelent));
-      reloc[1]->sym_ptr_ptr   = (asymbol **) xmalloc (sizeof (asymbol *));
+      reloc[1]               = XNEW (arelent);
+      reloc[1]->sym_ptr_ptr   = XNEW (asymbol *);
       if (gp_symbol == NULL)
        {
          if (symbol_table_frozen)
@@ -2350,13 +2573,13 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
       reloc[1]->addend        = 0;
       reloc[1]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[2]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[2]             = XNEW (arelent);
       reloc[2]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
       reloc[2]->addend      = 0;
       reloc[2]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
       reloc[2]->address     = fixp->fx_frag->fr_address + fixp->fx_where;
 
-      reloc[3]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[3]             = XNEW (arelent);
       reloc[3]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16UW);
       reloc[3]->addend      = 0;
       reloc[3]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
@@ -2368,8 +2591,8 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
     case BFD_RELOC_RX_GPRELB:
       reloc[0]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[1]               = (arelent *) xmalloc (sizeof (arelent));
-      reloc[1]->sym_ptr_ptr   = (asymbol **) xmalloc (sizeof (asymbol *));
+      reloc[1]               = XNEW (arelent);
+      reloc[1]->sym_ptr_ptr   = XNEW (asymbol *);
       if (gp_symbol == NULL)
        {
          if (symbol_table_frozen)
@@ -2390,13 +2613,13 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
       reloc[1]->addend        = 0;
       reloc[1]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[2]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[2]             = XNEW (arelent);
       reloc[2]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
       reloc[2]->addend      = 0;
       reloc[2]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
       reloc[2]->address     = fixp->fx_frag->fr_address + fixp->fx_where;
 
-      reloc[3]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[3]             = XNEW (arelent);
       reloc[3]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16U);
       reloc[3]->addend      = 0;
       reloc[3]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
@@ -2408,13 +2631,13 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
     case BFD_RELOC_RX_NEG32:
       reloc[0]->howto         = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
 
-      reloc[1]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[1]             = XNEW (arelent);
       reloc[1]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_NEG);
       reloc[1]->addend      = 0;
       reloc[1]->sym_ptr_ptr = reloc[0]->sym_ptr_ptr;
       reloc[1]->address     = fixp->fx_frag->fr_address + fixp->fx_where;
 
-      reloc[2]             = (arelent *) xmalloc (sizeof (arelent));
+      reloc[2]             = XNEW (arelent);
       reloc[2]->howto       = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS32);
       reloc[2]->addend      = 0;
       reloc[2]->sym_ptr_ptr = reloc[0]->sym_ptr_ptr;
@@ -2432,6 +2655,14 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
   return reloc;
 }
 
+void
+rx_note_string_insn_use (void)
+{
+  if ((elf_flags & E_FLAG_RX_SINSNS_MASK) == (E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_NO))
+    as_bad (_("Use of an RX string instruction detected in a file being assembled without string instruction support"));
+  elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_YES;
+}
+
 /* Set the ELF specific flags.  */
 
 void
@@ -2440,7 +2671,7 @@ rx_elf_final_processing (void)
   elf_elfheader (stdoutput)->e_flags |= elf_flags;
 }
 
-/* Scan the current input line for occurances of Renesas
+/* Scan the current input line for occurrences of Renesas
    local labels and replace them with the GAS version.  */
 
 void