* config/tc-alpha.c: More use of symbol accessor functions.
[binutils-gdb.git] / gas / config / tc-v850.c
index 48ee16e9ec0d4a7d0a57628ac2eaa6a7c32a39bf..7d4a91f122704415c1d1ac0424be36bb787a88de 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-v850.c -- Assembler code for the NEC V850
-   Copyright (C) 1996, 1997 Free Software Foundation.
+   Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
 #include "subsegs.h"     
 #include "opcode/v850.h"
 
+#define AREA_ZDA 0
+#define AREA_SDA 1
+#define AREA_TDA 2
+
 /* sign-extend a 16-bit number */
 #define SEXT16(x)      ((((x) & 0xffff) ^ (~ 0x7fff)) + 0x8000)
 
@@ -35,10 +39,10 @@ static boolean warn_signed_overflows   = FALSE;
 static boolean warn_unsigned_overflows = FALSE;
 
 /* Indicates the target BFD machine number.  */
-static int     machine                 = TARGET_MACHINE;
+static int     machine = -1;
 
 /* Indicates the target processor(s) for the assemble.  */
-static unsigned int    processor_mask = TARGET_PROCESSOR;
+static unsigned int    processor_mask = -1;
 
 \f
 /* Structure to hold information about predefined registers.  */
@@ -69,9 +73,14 @@ const char EXP_CHARS[] = "eE";
 const char FLT_CHARS[] = "dD";
 \f
 
-const relax_typeS md_relax_table[] = {
-  {0xff, -0x100, 2, 1},
+const relax_typeS md_relax_table[] =
+{
+  /* Conditional branches.  */
+  {0xff,     -0x100,    2, 1},
   {0x1fffff, -0x200000, 6, 0},
+  /* Unconditional branches.  */
+  {0xff,     -0x100,    2, 3},
+  {0x1fffff, -0x200000, 4, 0},
 };
 
 
@@ -83,17 +92,11 @@ static segT tbss_section = NULL;
 static segT zbss_section = NULL;
 static segT rosdata_section = NULL;
 static segT rozdata_section = NULL;
-/* start-sanitize-v850e */
+static segT scommon_section = NULL;
+static segT tcommon_section = NULL;
+static segT zcommon_section = NULL;
 static segT call_table_data_section = NULL;
 static segT call_table_text_section = NULL;
-/* end-sanitize-v850e */
-
-
-/* local functions */
-static unsigned long v850_insert_operand
-  PARAMS ((unsigned long insn, const struct v850_operand *operand,
-          offsetT val, char *file, unsigned int line));
-
 
 /* fixups */
 #define MAX_INSN_FIXUPS (5)
@@ -103,20 +106,26 @@ struct v850_fixup
   int                      opindex;
   bfd_reloc_code_real_type reloc;
 };
-struct v850_fixup fixups[MAX_INSN_FIXUPS];
+
+struct v850_fixup fixups [MAX_INSN_FIXUPS];
 static int fc;
+
 \f
 void
 v850_sdata (int ignore)
 {
-  subseg_set (sdata_section, (subsegT) get_absolute_expression ());
+  obj_elf_section_change_hook();
   
+  subseg_set (sdata_section, (subsegT) get_absolute_expression ());
+
   demand_empty_rest_of_line ();
 }
 
 void
 v850_tdata (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (tdata_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
@@ -125,6 +134,8 @@ v850_tdata (int ignore)
 void
 v850_zdata (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (zdata_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
@@ -133,6 +144,8 @@ v850_zdata (int ignore)
 void
 v850_sbss (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (sbss_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
@@ -141,6 +154,8 @@ v850_sbss (int ignore)
 void
 v850_tbss (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (tbss_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
@@ -149,6 +164,8 @@ v850_tbss (int ignore)
 void
 v850_zbss (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (zbss_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
@@ -157,6 +174,8 @@ v850_zbss (int ignore)
 void
 v850_rosdata (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (rosdata_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
@@ -165,15 +184,18 @@ v850_rosdata (int ignore)
 void
 v850_rozdata (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (rozdata_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
 }
 
-/* start-sanitize-v850e */
 void
 v850_call_table_data (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (call_table_data_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
@@ -182,29 +204,12 @@ v850_call_table_data (int ignore)
 void
 v850_call_table_text (int ignore)
 {
+  obj_elf_section_change_hook();
+  
   subseg_set (call_table_text_section, (subsegT) get_absolute_expression ());
   
   demand_empty_rest_of_line ();
 }
-/* end-sanitize-v850e */
-
-static void
-v850_section (int arg)
-{
-  char   saved_c;
-  char * ptr;
-  
-  for (ptr = input_line_pointer; * ptr != '\n' && * ptr != 0; ptr ++)
-    if (* ptr == ',' && ptr[1] == '.')
-      break;
-
-  saved_c = * ptr;
-  * ptr = ';';
-  
-  obj_elf_section (arg);
-
-  * ptr = saved_c;
-}
 
 void
 v850_bss (int ignore)
@@ -214,7 +219,7 @@ v850_bss (int ignore)
   obj_elf_section_change_hook();
   
   subseg_set (bss_section, (subsegT) temp);
-  
+   
   demand_empty_rest_of_line ();
 }
 
@@ -231,6 +236,338 @@ v850_offset (int ignore)
   demand_empty_rest_of_line ();
 }
 
+/* Copied from obj_elf_common() in gas/config/obj-elf.c */
+static void
+v850_comm (area)
+     int area;
+{
+  char *    name;
+  char      c;
+  char *    p;
+  int       temp;
+  int       size;
+  symbolS * symbolP;
+  int       have_align;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  
+  /* just after name is now '\0' */
+  p = input_line_pointer;
+  *p = c;
+  
+  SKIP_WHITESPACE ();
+  
+  if (*input_line_pointer != ',')
+    {
+      as_bad (_("Expected comma after symbol-name"));
+      ignore_rest_of_line ();
+      return;
+    }
+  
+  input_line_pointer ++;               /* skip ',' */
+  
+  if ((temp = get_absolute_expression ()) < 0)
+    {
+      /* xgettext:c-format */
+      as_bad (_(".COMMon length (%d.) < 0! Ignored."), temp);
+      ignore_rest_of_line ();
+      return;
+    }
+  
+  size = temp;
+  *p = 0;
+  symbolP = symbol_find_or_make (name);
+  *p = c;
+  
+  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
+    {
+      as_bad (_("Ignoring attempt to re-define symbol"));
+      ignore_rest_of_line ();
+      return;
+    }
+  
+  if (S_GET_VALUE (symbolP) != 0)
+    {
+      if (S_GET_VALUE (symbolP) != size)
+       {
+         /* xgettext:c-format */
+         as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."),
+                  S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
+       }
+    }
+  
+  know (symbol_get_frag (symbolP) == & zero_address_frag);
+  
+  if (*input_line_pointer != ',')
+    have_align = 0;
+  else
+    {
+      have_align = 1;
+      input_line_pointer++;
+      SKIP_WHITESPACE ();
+    }
+  
+  if (! have_align || *input_line_pointer != '"')
+    {
+      if (! have_align)
+       temp = 0;
+      else
+       {
+         temp = get_absolute_expression ();
+         
+         if (temp < 0)
+           {
+             temp = 0;
+             as_warn (_("Common alignment negative; 0 assumed"));
+           }
+       }
+      
+      if (symbolP->local)
+       {
+         segT   old_sec;
+         int    old_subsec;
+         char * pfrag;
+         int    align;
+         flagword      applicable;
+
+         old_sec = now_seg;
+         old_subsec = now_subseg;
+      
+         applicable = bfd_applicable_section_flags (stdoutput);
+                 
+         applicable &= SEC_ALLOC;
+         
+         switch (area)
+           {
+           case AREA_SDA:
+             if (sbss_section == NULL)
+               {
+                 sbss_section = subseg_new (".sbss", 0);
+             
+                 bfd_set_section_flags (stdoutput, sbss_section, applicable);
+             
+                 seg_info (sbss_section)->bss = 1;
+               }
+             break;
+         
+           case AREA_ZDA:
+             if (zbss_section == NULL)
+               {
+                 zbss_section = subseg_new (".zbss", 0);
+                 
+                 bfd_set_section_flags (stdoutput, sbss_section, applicable);
+             
+                 seg_info (zbss_section)->bss = 1;
+               }
+             break;
+         
+           case AREA_TDA:
+             if (tbss_section == NULL)
+               {
+                 tbss_section = subseg_new (".tbss", 0);
+                 
+                 bfd_set_section_flags (stdoutput, tbss_section, applicable);
+                 
+                 seg_info (tbss_section)->bss = 1;
+               }
+             break;
+           }
+
+         if (temp)
+           {
+             /* convert to a power of 2 alignment */
+             for (align = 0; (temp & 1) == 0; temp >>= 1, ++align)
+               ;
+             
+             if (temp != 1)
+               {
+                 as_bad (_("Common alignment not a power of 2"));
+                 ignore_rest_of_line ();
+                 return;
+               }
+           }
+         else
+           align = 0;
+         
+         switch (area)
+           {
+           case AREA_SDA:
+             record_alignment (sbss_section, align);
+             obj_elf_section_change_hook();
+             subseg_set (sbss_section, 0);
+             break;
+
+           case AREA_ZDA:
+             record_alignment (zbss_section, align);
+             obj_elf_section_change_hook();
+             subseg_set (zbss_section, 0);
+             break;
+
+           case AREA_TDA:
+             record_alignment (tbss_section, align);
+             obj_elf_section_change_hook();
+             subseg_set (tbss_section, 0);
+             break;
+
+           default:
+             abort();
+           }
+         
+         if (align)
+           frag_align (align, 0, 0);
+
+         switch (area)
+           {
+           case AREA_SDA:
+             if (S_GET_SEGMENT (symbolP) == sbss_section)
+               symbol_get_frag (symbolP)->fr_symbol = 0;
+             break;
+
+           case AREA_ZDA:
+             if (S_GET_SEGMENT (symbolP) == zbss_section)
+               symbol_get_frag (symbolP)->fr_symbol = 0;
+             break;
+
+           case AREA_TDA:
+             if (S_GET_SEGMENT (symbolP) == tbss_section)
+               symbol_get_frag (symbolP)->fr_symbol = 0;
+             break;
+
+           default:
+             abort();
+           }
+         
+         symbol_set_frag (symbolP, frag_now);
+         pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
+                           (offsetT) size, (char *) 0);
+         *pfrag = 0;
+         S_SET_SIZE (symbolP, size);
+         
+         switch (area)
+           {
+           case AREA_SDA:
+             S_SET_SEGMENT (symbolP, sbss_section);
+             break;
+             
+           case AREA_ZDA:
+             S_SET_SEGMENT (symbolP, zbss_section);
+             break;
+             
+           case AREA_TDA:
+             S_SET_SEGMENT (symbolP, tbss_section);
+             break;
+             
+           default:
+             abort();
+           }
+           
+         S_CLEAR_EXTERNAL (symbolP);
+         obj_elf_section_change_hook();
+         subseg_set (old_sec, old_subsec);
+       }
+      else
+       {
+       allocate_common:
+         S_SET_VALUE (symbolP, (valueT) size);
+         S_SET_ALIGN (symbolP, temp);
+         S_SET_EXTERNAL (symbolP);
+         
+         switch (area)
+           {
+           case AREA_SDA:
+             if (scommon_section == NULL)
+               {
+                 flagword      applicable;
+                 
+                 applicable = bfd_applicable_section_flags (stdoutput);
+                 
+                 scommon_section = subseg_new (".scommon", 0);
+                 
+                 bfd_set_section_flags (stdoutput, scommon_section, applicable
+                    & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA
+                       | SEC_HAS_CONTENTS) | SEC_IS_COMMON);
+               }
+             S_SET_SEGMENT (symbolP, scommon_section);
+             break;
+             
+           case AREA_ZDA:
+             if (zcommon_section == NULL)
+               {
+                 flagword      applicable;
+                 
+                 applicable = bfd_applicable_section_flags (stdoutput);
+                 
+                 zcommon_section = subseg_new (".zcommon", 0);
+                 
+                 bfd_set_section_flags (stdoutput, zcommon_section, applicable
+                    & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA
+                       | SEC_HAS_CONTENTS) | SEC_IS_COMMON);
+               }
+             S_SET_SEGMENT (symbolP, zcommon_section);
+             break;
+             
+           case AREA_TDA:
+             if (tcommon_section == NULL)
+               {
+                 flagword      applicable;
+                 
+                 applicable = bfd_applicable_section_flags (stdoutput);
+                 
+                 tcommon_section = subseg_new (".tcommon", 0);
+                 
+                 bfd_set_section_flags (stdoutput, tcommon_section, applicable
+                    & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA
+                       | SEC_HAS_CONTENTS) | SEC_IS_COMMON);
+               }
+             S_SET_SEGMENT (symbolP, tcommon_section);
+             break;
+             
+           default:
+             abort();
+           }
+       }
+    }
+  else
+    {
+      input_line_pointer++;
+      /* @@ Some use the dot, some don't.  Can we get some consistency??  */
+      if (*input_line_pointer == '.')
+       input_line_pointer++;
+      /* @@ Some say data, some say bss.  */
+      if (strncmp (input_line_pointer, "bss\"", 4)
+         && strncmp (input_line_pointer, "data\"", 5))
+       {
+         while (*--input_line_pointer != '"')
+           ;
+         input_line_pointer--;
+         goto bad_common_segment;
+       }
+      while (*input_line_pointer++ != '"')
+       ;
+      goto allocate_common;
+    }
+
+  symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
+
+  demand_empty_rest_of_line ();
+  return;
+
+  {
+  bad_common_segment:
+    p = input_line_pointer;
+    while (*p && *p != '\n')
+      p++;
+    c = *p;
+    *p = '\0';
+    as_bad (_("bad .common segment %s"), input_line_pointer + 1);
+    *p = c;
+    input_line_pointer = p;
+    ignore_rest_of_line ();
+    return;
+  }
+}
+
 void
 set_machine (int number)
 {
@@ -240,12 +577,8 @@ set_machine (int number)
   switch (machine)
     {
     case 0: processor_mask = PROCESSOR_V850; break;
-/* start-sanitize-v850e */
-    case bfd_mach_v850e: processor_mask = PROCESSOR_V850E; break;
-/* end-sanitize-v850e */
-/* start-sanitize-v850eq */
-    case bfd_mach_v850eq: processor_mask = PROCESSOR_V850EQ; break;
-/* end-sanitize-v850eq */
+    case bfd_mach_v850e:  processor_mask = PROCESSOR_V850E; break;
+    case bfd_mach_v850ea: processor_mask = PROCESSOR_V850EA; break;
     }
 }
 
@@ -262,17 +595,15 @@ const pseudo_typeS md_pseudo_table[] =
   {"rozdata", v850_rozdata, 0},
   {"bss",     v850_bss,     0},
   {"offset",  v850_offset,  0},
-  {"section", v850_section, 0},
   {"word",    cons,         4},
+  {"zcomm",   v850_comm,    AREA_ZDA},
+  {"scomm",   v850_comm,    AREA_SDA},
+  {"tcomm",   v850_comm,    AREA_TDA},
   {"v850",    set_machine,  0},
-/* start-sanitize-v850e */
   {"call_table_data", v850_call_table_data, 0},
   {"call_table_text", v850_call_table_text, 0},
   {"v850e",           set_machine,          bfd_mach_v850e},
-/* end-sanitize-v850e */
-/* start-sanitize-v850eq */
-  {"v850eq",          set_machine,          bfd_mach_v850eq},
-/* end-sanitize-v850eq */
+  {"v850ea",          set_machine,          bfd_mach_v850ea},
   { NULL,     NULL,         0}
 };
 
@@ -327,13 +658,11 @@ static const struct reg_name pre_defined_registers[] =
 
 static const struct reg_name system_registers[] = 
 {
-/* start-sanitize-v850e */
   { "ctbp",  20 },
   { "ctpc",  16 },
   { "ctpsw", 17 },
   { "dbpc",  18 },
   { "dbpsw", 19 },
-/* end-sanitize-v850e */
   { "ecr",    4 },
   { "eipc",   0 },
   { "eipsw",  1 },
@@ -343,6 +672,13 @@ static const struct reg_name system_registers[] =
 };
 #define SYSREG_NAME_CNT        (sizeof (system_registers) / sizeof (struct reg_name))
 
+static const struct reg_name system_list_registers[] =
+{
+  {"PS",      5 },
+  {"SR",      0 + 1}
+};
+#define SYSREGLIST_NAME_CNT    (sizeof (system_list_registers) / sizeof (struct reg_name))
+
 static const struct reg_name cc_names[] =
 {
   { "c",  0x1 },
@@ -375,14 +711,36 @@ static const struct reg_name cc_names[] =
    number from the array on success, or -1 on failure. */
 
 static int
-reg_name_search (regs, regcount, name)
+reg_name_search (regs, regcount, name, accept_numbers)
      const struct reg_name * regs;
      int                     regcount;
      const char *            name;
+     boolean                 accept_numbers;
 {
   int middle, low, high;
   int cmp;
+  symbolS * symbolP;
 
+  /* If the register name is a symbol, then evaluate it.  */
+  if ((symbolP = symbol_find (name)) != NULL)
+    {
+      /* If the symbol is an alias for another name then use that.
+        If the symbol is an alias for a number, then return the number.  */
+      if (symbol_equated_p (symbolP))
+       {
+         name = S_GET_NAME (symbol_get_value_expression (symbolP)->X_add_symbol);
+       }
+      else if (accept_numbers)
+       {
+         int reg = S_GET_VALUE (symbolP);
+         
+         if (reg >= 0 && reg <= 31)
+           return reg;
+       }
+
+      /* Otherwise drop through and try parsing name normally.  */
+    }
+  
   low = 0;
   high = regcount - 1;
 
@@ -426,7 +784,8 @@ register_name (expressionP)
 
   c = get_symbol_end ();
 
-  reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
+  reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT,
+                               name, FALSE);
 
   * input_line_pointer = c;    /* put back the delimiting char */
   
@@ -453,18 +812,23 @@ register_name (expressionP)
 
 /* Summary of system_register_name().
  *
- * in: Input_line_pointer points to 1st char of operand.
+ * in:  Input_line_pointer points to 1st char of operand.
+ *      expressionP points to an expression structure to be filled in.
+ *      accept_numbers is true iff numerical register names may be used.
+ *      accept_list_names is true iff the special names PS and SR may be 
+ *      accepted.
  *
- * out: A expressionS.
+ * out: A expressionS structure in expressionP.
  *     The operand may have been a register: in this case, X_op == O_register,
  *     X_add_number is set to the register number, and truth is returned.
  *     Input_line_pointer->(next non-blank) char after operand, or is in
  *     its original state.
  */
 static boolean
-system_register_name (expressionP, accept_numbers)
+system_register_name (expressionP, accept_numbers, accept_list_names)
      expressionS * expressionP;
      boolean       accept_numbers;
+     boolean       accept_list_names;
 {
   int    reg_number;
   char * name;
@@ -475,7 +839,8 @@ system_register_name (expressionP, accept_numbers)
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
-  reg_number = reg_name_search (system_registers, SYSREG_NAME_CNT, name);
+  reg_number = reg_name_search (system_registers, SYSREG_NAME_CNT, name,
+                               accept_numbers);
 
   * input_line_pointer = c;   /* put back the delimiting char */
   
@@ -485,21 +850,29 @@ system_register_name (expressionP, accept_numbers)
       input_line_pointer   = start; /* reset input_line pointer */
 
       if (isdigit (* input_line_pointer))
-       reg_number = strtol (input_line_pointer, & input_line_pointer, 10);
-
-      /* Make sure that the register number is allowable. */
-      if (   reg_number < 0
-         || reg_number > 5
-/* start-sanitize-v850e */
-         && reg_number < 16
-         || reg_number > 20
-/* end-sanitize-v850e */
-            )
        {
-         reg_number = -1;
+         reg_number = strtol (input_line_pointer, & input_line_pointer, 10);
+
+         /* Make sure that the register number is allowable. */
+         if (   reg_number < 0
+                || reg_number > 5
+                && reg_number < 16
+                || reg_number > 20
+                )
+           {
+             reg_number = -1;
+           }
+       }
+      else if (accept_list_names)
+       {
+         c = get_symbol_end ();
+         reg_number = reg_name_search (system_list_registers,
+                                       SYSREGLIST_NAME_CNT, name, FALSE);
+
+         * input_line_pointer = c;   /* put back the delimiting char */
        }
     }
-      
+  
   /* look to see if it's in the register table */
   if (reg_number >= 0) 
     {
@@ -544,7 +917,7 @@ cc_name (expressionP)
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
-  reg_number = reg_name_search (cc_names, CC_NAME_CNT, name);
+  reg_number = reg_name_search (cc_names, CC_NAME_CNT, name, FALSE);
 
   * input_line_pointer = c;   /* put back the delimiting char */
   
@@ -577,16 +950,16 @@ skip_white_space (void)
     ++ input_line_pointer;
 }
 
-/* start-sanitize-v850e */
 /* Summary of parse_register_list ().
  *
  * in: Input_line_pointer  points to 1st char of a list of registers.
  *     insn                is the partially constructed instruction.
  *     operand             is the operand being inserted.
  *
- * out: True if the parse completed successfully, False otherwise.
- *      If the parse completes the correct bit fields in the
- *      instruction will be filled in.
+ * out: NULL if the parse completed successfully, otherwise a
+ *      pointer to an error message is returned.  If the parse
+ *      completes the correct bit fields in the instruction
+ *      will be filled in.
  *
  * Parses register lists with the syntax:
  *
@@ -611,10 +984,8 @@ parse_register_list
 )
 {
   static int  type1_regs[ 32 ] = { 30,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
-/* start-sanitize-v850eq */
   static int  type2_regs[ 32 ] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
   static int  type3_regs[ 32 ] = {  3,  2,  1,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 13, 12,  7,  6,  5,  4, 11, 10,  9,  8 };
-/* end-sanitize-v850eq */
   int *       regs;
   expressionS exp;
 
@@ -623,19 +994,17 @@ parse_register_list
   switch (operand->shift)
     {
     case 0xffe00001: regs = type1_regs; break;
-/* start-sanitize-v850eq */
     case 0xfff8000f: regs = type2_regs; break;
     case 0xfff8001f: regs = type3_regs; break;
-/* end-sanitize-v850eq */
     default:
-      as_bad ("unknown operand shift: %x\n", operand->shift );             
-      return "internal failure in parse_register_list";
+      as_bad (_("unknown operand shift: %x\n"), operand->shift);
+      return _("internal failure in parse_register_list");
     }
 
-  skip_white_space();
+  skip_white_space ();
 
   /* If the expression starts with a curly brace it is a register list.
-     Otherwise it is a constant expression ,whoes bits indicate which
+     Otherwise it is a constant expressionwhoes bits indicate which
      registers are to be included in the list.  */
   
   if (* input_line_pointer != '{')
@@ -647,14 +1016,12 @@ parse_register_list
       expression (& exp);
       
       if (exp.X_op != O_constant)
-       return "constant expression or register list expected";
+       return _("constant expression or register list expected");
 
-/* start-sanitize-v850eq */
       if (regs == type1_regs)
-/* end-sanitize-v850eq */
        {
          if (exp.X_add_number & 0xFFFFF000)
-           return "high bits set in register list expression";
+           return _("high bits set in register list expression");
          
          for (reg = 20; reg < 32; reg ++)
            if (exp.X_add_number & (1 << (reg - 20)))
@@ -664,11 +1031,10 @@ parse_register_list
                    * insn |= (1 << i);
              }
        }
-/* start-sanitize-v850eq */
       else if (regs == type2_regs)
        {
          if (exp.X_add_number & 0xFFFE0000)
-           return "high bits set in register list expression";
+           return _("high bits set in register list expression");
          
          for (reg = 1; reg < 16; reg ++)
            if (exp.X_add_number & (1 << (reg - 1)))
@@ -687,7 +1053,7 @@ parse_register_list
       else /* regs == type3_regs */
        {
          if (exp.X_add_number & 0xFFFE0000)
-           return "high bits set in register list expression";
+           return _("high bits set in register list expression");
          
          for (reg = 16; reg < 32; reg ++)
            if (exp.X_add_number & (1 << (reg - 16)))
@@ -700,21 +1066,22 @@ parse_register_list
          if (exp.X_add_number & (1 << 16))
            * insn |= (1 << 19);
        }
-/* end-sanitize-v850eq */
 
       return NULL;
     }
 
   input_line_pointer ++;
 
-  /* Parse the register list until a terminator (closing curly brace or new-line) is found.  */
+  /* Parse the register list until a terminator (closing curly brace or
+     new-line) is found.  */
   for (;;)
     {
       if (register_name (& exp))
        {
          int  i;
          
-         /* Locate the given register in the list, and if it is there, insert the corresponding bit into the instruction.  */
+         /* Locate the given register in the list, and if it is there,
+            insert the corresponding bit into the instruction.  */
          for (i = 0; i < 32; i++)
            {
              if (regs[ i ] == exp.X_add_number)
@@ -726,24 +1093,26 @@ parse_register_list
 
          if (i == 32)
            {
-             return "illegal register included in list";
+             return _("illegal register included in list");
            }
        }
-      else if (system_register_name (& exp, true))
+      else if (system_register_name (& exp, true, true))
        {
          if (regs == type1_regs)
            {
-             return "system registers cannot be included in list";
+             return _("system registers cannot be included in list");
            }
          else if (exp.X_add_number == 5)
            {
              if (regs == type2_regs)
-               return "PSW cannot be included in list";
+               return _("PSW cannot be included in list");
              else
                * insn |= 0x8;
            }
-         else
+         else if (exp.X_add_number < 4)
            * insn |= 0x80000;
+         else
+           return _("High value system registers cannot be included in list");
        }
       else if (* input_line_pointer == '}')
        {
@@ -767,7 +1136,7 @@ parse_register_list
          /* Get the second register in the range.  */
          if (! register_name (& exp2))
            {
-             return "second register should follow dash in register list";
+             return _("second register should follow dash in register list");
              exp2.X_add_number = exp.X_add_number;
            }
 
@@ -776,7 +1145,8 @@ parse_register_list
            {
              int  i;
          
-             /* Locate the given register in the list, and if it is there, insert the corresponding bit into the instruction.  */
+             /* Locate the given register in the list, and if it is there,
+                insert the corresponding bit into the instruction.  */
              for (i = 0; i < 32; i++)
                {
                  if (regs[ i ] == j)
@@ -787,9 +1157,7 @@ parse_register_list
                }
 
              if (i == 32)
-               {
-                 return "illegal register included in list";
-               }
+               return _("illegal register included in list");
            }
        }
       else
@@ -797,12 +1165,11 @@ parse_register_list
          break;
        }
 
-      skip_white_space();
+      skip_white_space ();
     }
 
   return NULL;
 }
-/* end-sanitize-v850e */
 
 CONST char * md_shortopts = "m:";
 
@@ -817,65 +1184,63 @@ void
 md_show_usage (stream)
   FILE * stream;
 {
-  fprintf (stream, "V850 options:\n");
-  fprintf (stream, "\t-wsigned_overflow    Warn if signed immediate values overflow\n");
-  fprintf (stream, "\t-wunsigned_overflow  Warn if unsigned immediate values overflow\n");
-  fprintf (stream, "\t-mv850               The code is targeted at the v850\n");
-/* start-sanitize-v850e */
-  fprintf (stream, "\t-mv850e              The code is targeted at the v850e\n");
-/* end-sanitize-v850e */
-/* start-sanitize-v850eq */
-  fprintf (stream, "\t-mv850eq             The code is targeted at the v850eq\n");
-/* end-sanitize-v850eq */
-} 
+  fprintf (stream, _(" V850 options:\n"));
+  fprintf (stream, _("  -mwarn-signed-overflow    Warn if signed immediate values overflow\n"));
+  fprintf (stream, _("  -mwarn-unsigned-overflow  Warn if unsigned immediate values overflow\n"));
+  fprintf (stream, _("  -mv850                    The code is targeted at the v850\n"));
+  fprintf (stream, _("  -mv850e                   The code is targeted at the v850e\n"));
+  fprintf (stream, _("  -mv850ea                  The code is targeted at the v850ea\n"));
+  fprintf (stream, _("  -mv850any                 The code is generic, despite any processor specific instructions\n"));
+}
 
 int
 md_parse_option (c, arg)
      int    c;
      char * arg;
 {
-  switch (c)
+  if (c != 'm')
     {
-    case 'w':
-      if (strcmp (arg, "signed_overflow") == 0)
-       {
-         warn_signed_overflows = TRUE;
-         return 1;
-       }
-      else if (strcmp (arg, "unsigned_overflow") == 0)
-       {
-         warn_unsigned_overflows = TRUE;
-         return 1;
-       }
-      break;
+      /* xgettext:c-format */
+      fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg);
+      return 0;
+    }
 
-    case 'm':
-      if (strcmp (arg, "v850") == 0)
-       {
-         machine = 0;
-         return 1;
-       }
-/* start-sanitize-v850e */
-      else if (strcmp (arg, "v850e") == 0)
-       {
-         machine = bfd_mach_v850e;
-         processor_mask = PROCESSOR_V850 | PROCESSOR_V850E;
-         
-         return 1;
-       }
-/* end-sanitize-v850e */
-/* start-sanitize-v850eq */
-      else if (strcmp (arg, "v850eq") == 0)
-       {
-         machine = bfd_mach_v850eq;
-         processor_mask = PROCESSOR_V850EQ;
-         return 1;
-       }
-/* end-sanitize-v850eq */
-      break;
+  if (strcmp (arg, "warn-signed-overflow") == 0)
+    {
+      warn_signed_overflows = TRUE;
+    }
+  else if (strcmp (arg, "warn-unsigned-overflow") == 0)
+    {
+      warn_unsigned_overflows = TRUE;
+    }
+  else if (strcmp (arg, "v850") == 0)
+    {
+      machine = 0;
+      processor_mask = PROCESSOR_V850;
+    }
+  else if (strcmp (arg, "v850e") == 0)
+    {
+      machine = bfd_mach_v850e;
+      processor_mask = PROCESSOR_V850E;
+    }
+  else if (strcmp (arg, "v850ea") == 0)
+    {
+      machine = bfd_mach_v850ea;
+      processor_mask = PROCESSOR_V850EA;
+    }
+  else if (strcmp (arg, "v850any") == 0)
+    {
+      machine = 0;                       /* Tell the world that this is for any v850 chip.  */
+      processor_mask = PROCESSOR_V850EA; /* But support instructions for the extended versions.  */
+    }
+  else
+    {
+      /* xgettext:c-format */
+      fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg);
+      return 0;
     }
   
-  return 0;
+  return 1;
 }
 
 symbolS *
@@ -908,7 +1273,7 @@ md_atof (type, litp, sizep)
 
     default:
       *sizep = 0;
-      return "bad call to md_atof";
+      return _("bad call to md_atof");
     }
   
   t = atof_ieee (input_line_pointer, type, words);
@@ -935,32 +1300,49 @@ md_convert_frag (abfd, sec, fragP)
   fragS *    fragP;
 {
   subseg_change (sec, 0);
-  if (fragP->fr_subtype == 0)
+  
+  /* In range conditional or unconditional branch.  */
+  if (fragP->fr_subtype == 0 || fragP->fr_subtype == 2)
     {
       fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_UNUSED + (int)fragP->fr_opcode);
       fragP->fr_var = 0;
       fragP->fr_fix += 2;
     }
+  /* Out of range conditional branch.  Emit a branch around a jump.  */
   else if (fragP->fr_subtype == 1)
     {
+      unsigned char *buffer = 
+       (unsigned char *) (fragP->fr_fix + fragP->fr_literal);
+
       /* Reverse the condition of the first branch.  */
-      fragP->fr_literal[0] &= 0xf7;
+      buffer[0] ^= 0x08;
       /* Mask off all the displacement bits.  */
-      fragP->fr_literal[0] &= 0x8f;
-      fragP->fr_literal[1] &= 0x07;
+      buffer[0] &= 0x8f;
+      buffer[1] &= 0x07;
       /* Now set the displacement bits so that we branch
         around the unconditional branch.  */
-      fragP->fr_literal[0] |= 0x30;
+      buffer[0] |= 0x30;
 
       /* Now create the unconditional branch + fixup to the final
         target.  */
-      md_number_to_chars (&fragP->fr_literal[2], 0x00000780, 4);
+      md_number_to_chars (buffer + 2, 0x00000780, 4);
       fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
-              fragP->fr_offset, 1, BFD_RELOC_UNUSED + (int)fragP->fr_opcode + 1);
+              fragP->fr_offset, 1, BFD_RELOC_UNUSED +
+              (int) fragP->fr_opcode + 1);
       fragP->fr_var = 0;
       fragP->fr_fix += 6;
     }
+  /* Out of range unconditional branch.  Emit a jump.  */
+  else if (fragP->fr_subtype == 3)
+    {
+      md_number_to_chars (fragP->fr_fix + fragP->fr_literal, 0x00000780, 4);
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
+              fragP->fr_offset, 1, BFD_RELOC_UNUSED +
+              (int) fragP->fr_opcode + 1);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 4;
+    }
   else
     abort ();
 }
@@ -981,7 +1363,36 @@ md_begin ()
   register const struct v850_opcode * op;
   flagword                            applicable;
 
-  
+  if (strncmp (TARGET_CPU, "v850ea", 6) == 0)
+    {
+      if (machine == -1)
+       machine = bfd_mach_v850ea;
+      
+      if (processor_mask == -1)
+       processor_mask = PROCESSOR_V850EA;
+    }
+  else if (strncmp (TARGET_CPU, "v850e", 5) == 0)
+    {
+      if (machine == -1)
+       machine        = bfd_mach_v850e;
+      
+      if (processor_mask == -1)
+       processor_mask = PROCESSOR_V850E;
+    }
+  else
+  if (strncmp (TARGET_CPU, "v850", 4) == 0)
+    {
+      if (machine == -1)
+       machine        = 0;
+      
+      if (processor_mask == -1)
+       processor_mask = PROCESSOR_V850;
+    }
+  else
+    /* xgettext:c-format */
+    as_bad (_("Unable to determine default target processor from string: %s"), 
+            TARGET_CPU);
+
   v850_hash = hash_new();
 
   /* Insert unique names into hash table.  The V850 instruction set
@@ -1003,66 +1414,51 @@ md_begin ()
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine);
 
   applicable = bfd_applicable_section_flags (stdoutput);
-
-  sdata_section = subseg_new (".sdata", 0);
-  bfd_set_section_flags (stdoutput, sdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS));
-  
-  tdata_section = subseg_new (".tdata", 0);
-  bfd_set_section_flags (stdoutput, tdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS));
-  
-  zdata_section = subseg_new (".zdata", 0);
-  bfd_set_section_flags (stdoutput, zdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS));
-  
-  sbss_section = subseg_new (".sbss", 0);
-  bfd_set_section_flags (stdoutput, sbss_section, applicable & SEC_ALLOC);
   
-  tbss_section = subseg_new (".tbss", 0);
-  bfd_set_section_flags (stdoutput, tbss_section, applicable & SEC_ALLOC);
-  
-  zbss_section = subseg_new (".zbss", 0);
-  bfd_set_section_flags (stdoutput, zbss_section, applicable & SEC_ALLOC);
-  
-  rosdata_section = subseg_new (".rosdata", 0);
-  bfd_set_section_flags (stdoutput, rosdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY));
-                        
-  rozdata_section = subseg_new (".rozdata", 0);
-  bfd_set_section_flags (stdoutput, rozdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY));
-
-/* start-sanitize-v850e */
   call_table_data_section = subseg_new (".call_table_data", 0);
-  bfd_set_section_flags (stdoutput, call_table_data_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS));
+  bfd_set_section_flags (stdoutput, call_table_data_section,
+                        applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC
+                                      | SEC_DATA | SEC_HAS_CONTENTS));
   
   call_table_text_section = subseg_new (".call_table_text", 0);
-  bfd_set_section_flags (stdoutput, call_table_text_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE));
-/* end-sanitize-v850e */
+  bfd_set_section_flags (stdoutput, call_table_text_section,
+                        applicable & (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+                                      | SEC_CODE));
+  
+  /* Restore text section as the current default.  */
+  subseg_set (text_section, 0);
 }
 
 
-/* start-sanitize-v850e */
 static bfd_reloc_code_real_type
 handle_ctoff (const struct v850_operand * operand)
 {
   if (operand == NULL)
     return BFD_RELOC_V850_CALLT_16_16_OFFSET;
 
-  assert (operand->bits == 6);
-  assert (operand->shift == 0);
+  if (   operand->bits  != 6
+      || operand->shift != 0)
+    {
+      as_bad (_("ctoff() relocation used on an instruction which does not support it"));
+      return BFD_RELOC_64;  /* Used to indicate an error condition.  */
+    }
       
   return BFD_RELOC_V850_CALLT_6_7_OFFSET;
 }
-/* end-sanitize-v850e */
 
 static bfd_reloc_code_real_type
 handle_sdaoff (const struct v850_operand * operand)
 {
   if (operand == NULL)                             return BFD_RELOC_V850_SDA_16_16_OFFSET;
   if (operand->bits == 15 && operand->shift == 17) return BFD_RELOC_V850_SDA_15_16_OFFSET;
-  /* start-sanitize-v850e */
   if (operand->bits == -1)                         return BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET;
-  /* end-sanitize-v850e */
   
-  assert (operand->bits == 16);
-  assert (operand->shift == 16);
+  if (   operand->bits  != 16
+      || operand->shift != 16)
+    {
+      as_bad (_("sdaoff() relocation used on an instruction which does not support it"));
+      return BFD_RELOC_64;  /* Used to indicate an error condition.  */
+    }
   
   return BFD_RELOC_V850_SDA_16_16_OFFSET;
 }
@@ -1072,12 +1468,14 @@ handle_zdaoff (const struct v850_operand * operand)
 {
   if (operand == NULL)                             return BFD_RELOC_V850_ZDA_16_16_OFFSET;
   if (operand->bits == 15 && operand->shift == 17) return BFD_RELOC_V850_ZDA_15_16_OFFSET;
-  /* start-sanitize-v850e */
   if (operand->bits == -1)                         return BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET;
-  /* end-sanitize-v850e */
-  
-  assert (operand->bits == 16);
-  assert (operand->shift == 16);
+
+  if (   operand->bits  != 16
+      || operand->shift != 16)
+    {
+      as_bad (_("zdaoff() relocation used on an instruction which does not support it"));
+      return BFD_RELOC_64;  /* Used to indicate an error condition.  */
+    }
   
   return BFD_RELOC_V850_ZDA_16_16_OFFSET;
 }
@@ -1087,13 +1485,15 @@ handle_tdaoff (const struct v850_operand * operand)
 {
   if (operand == NULL)                               return BFD_RELOC_V850_TDA_7_7_OFFSET;  /* data item, not an instruction.  */
   if (operand->bits == 6 && operand->shift == 1)     return BFD_RELOC_V850_TDA_6_8_OFFSET;  /* sld.w/sst.w, operand: D8_6  */
-  /* start-sanitize-v850e */
   if (operand->bits == 4 && operand->insert != NULL) return BFD_RELOC_V850_TDA_4_5_OFFSET;  /* sld.hu, operand: D5-4 */
   if (operand->bits == 4 && operand->insert == NULL) return BFD_RELOC_V850_TDA_4_4_OFFSET;  /* sld.bu, operand: D4   */
-  /* end-sanitize-v850e */
   if (operand->bits == 16 && operand->shift == 16)   return BFD_RELOC_V850_TDA_16_16_OFFSET; /* set1 & chums, operands: D16 */
   
-  assert (operand->bits == 7);
+  if (operand->bits != 7)
+    {
+      as_bad (_("tdaoff() relocation used on an instruction which does not support it"));
+      return BFD_RELOC_64;  /* Used to indicate an error condition.  */
+    }
   
   return  operand->insert != NULL
     ? BFD_RELOC_V850_TDA_7_8_OFFSET     /* sld.h/sst.h, operand: D8_7 */
@@ -1130,11 +1530,8 @@ v850_reloc_prefix (const struct v850_operand * operand)
   CHECK_ ("sdaoff", handle_sdaoff (operand));
   CHECK_ ("zdaoff", handle_zdaoff (operand));
   CHECK_ ("tdaoff", handle_tdaoff (operand));
-
-/* start-sanitize-v850e */
-  CHECK_ ("hilo", BFD_RELOC_32);
+  CHECK_ ("hilo",   BFD_RELOC_32);
   CHECK_ ("ctoff",  handle_ctoff (operand));
-/* end-sanitize-v850e */
   
   /* Restore skipped parenthesis.  */
   if (paren_skipped)
@@ -1143,6 +1540,118 @@ v850_reloc_prefix (const struct v850_operand * operand)
   return BFD_RELOC_UNUSED;
 }
 
+/* Insert an operand value into an instruction.  */
+
+static unsigned long
+v850_insert_operand (insn, operand, val, file, line, str)
+     unsigned long               insn;
+     const struct v850_operand * operand;
+     offsetT                     val;
+     char *                      file;
+     unsigned int                line;
+     char *                      str;
+{
+  if (operand->insert)
+    {
+      const char * message = NULL;
+      
+      insn = operand->insert (insn, val, & message);
+      if (message != NULL)
+       {
+         if ((operand->flags & V850_OPERAND_SIGNED)
+             && ! warn_signed_overflows
+             && strstr (message, "out of range") != NULL)
+           {
+             /* skip warning... */
+           }
+         else if ((operand->flags & V850_OPERAND_SIGNED) == 0
+                  && ! warn_unsigned_overflows
+                  && strstr (message, "out of range") != NULL)
+           {
+             /* skip warning... */
+           }
+         else if (str)
+           {
+             if (file == (char *) NULL)
+               as_warn ("%s: %s", str, message);
+             else
+               as_warn_where (file, line, "%s: %s", str, message);
+           }
+         else
+           {
+             if (file == (char *) NULL)
+               as_warn (message);
+             else
+               as_warn_where (file, line, message);
+           }
+       }
+    }
+  else
+    {
+      if (operand->bits != 32)
+       {
+         long    min, max;
+         offsetT test;
+
+         if ((operand->flags & V850_OPERAND_SIGNED) != 0)
+           {
+             if (! warn_signed_overflows)
+               max = (1 << operand->bits) - 1;
+             else
+               max = (1 << (operand->bits - 1)) - 1;
+             
+             min = - (1 << (operand->bits - 1));
+           }
+         else
+           {
+             max = (1 << operand->bits) - 1;
+             
+             if (! warn_unsigned_overflows)
+               min = - (1 << (operand->bits - 1));
+             else
+               min = 0;
+           }
+         
+         if (val < (offsetT) min || val > (offsetT) max)
+           {
+             /* xgettext:c-format */
+             const char * err = _("operand out of range (%s not between %ld and %ld)");
+             char         buf[100];
+             
+             /* Restore min and mix to expected values for decimal ranges.  */
+             if ((operand->flags & V850_OPERAND_SIGNED)
+                 && ! warn_signed_overflows)
+               max = (1 << (operand->bits - 1)) - 1;
+
+             if (! (operand->flags & V850_OPERAND_SIGNED)
+                 && ! warn_unsigned_overflows)
+               min = 0;
+
+             if (str)
+               {
+                 sprintf (buf, "%s: ", str);
+                 
+                 sprint_value (buf + strlen (buf), val);
+               }
+             else
+               sprint_value (buf, val);
+             
+             if (file == (char *) NULL)
+               as_warn (err, buf, min, max);
+             else
+               as_warn_where (file, line, err, buf, min, max);
+           }
+       }
+
+      insn |= (((long) val & ((1 << operand->bits) - 1)) << operand->shift);
+    }
+  
+  return insn;
+}
+
+\f
+static char                 copy_of_instruction [128];
+
 void
 md_assemble (str) 
      char * str;
@@ -1163,6 +1672,9 @@ md_assemble (str)
   unsigned                  extra_data_len;
   unsigned long             extra_data;
   char *                   saved_input_line_pointer;
+
+  
+  strncpy (copy_of_instruction, str, sizeof (copy_of_instruction) - 1);
   
   /* Get the opcode.  */
   for (s = str; *s != '\0' && ! isspace (*s); s++)
@@ -1172,10 +1684,11 @@ md_assemble (str)
     *s++ = '\0';
 
   /* find the first opcode with the proper name */
-  opcode = (struct v850_opcode *)hash_find (v850_hash, str);
+  opcode = (struct v850_opcode *) hash_find (v850_hash, str);
   if (opcode == NULL)
     {
-      as_bad ("Unrecognized opcode: `%s'", str);
+      /* xgettext:c-format */
+      as_bad (_("Unrecognized opcode: `%s'"), str);
       ignore_rest_of_line ();
       return;
     }
@@ -1196,7 +1709,7 @@ md_assemble (str)
       
       if ((opcode->processors & processor_mask) == 0)
        {
-         errmsg = "Target processor does not support this instruction.";
+         errmsg = _("Target processor does not support this instruction.");
          goto error;
        }
       
@@ -1208,7 +1721,7 @@ md_assemble (str)
 
       input_line_pointer = str = start_of_operands;
 
-      for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
+      for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr ++)
        {
          const struct v850_operand * operand;
          char *                      hold;
@@ -1228,7 +1741,7 @@ md_assemble (str)
          errmsg = NULL;
 
          while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
-           ++str;
+           ++ str;
 
          if (operand->flags & V850_OPERAND_RELAX)
            relaxable = 1;
@@ -1237,11 +1750,16 @@ md_assemble (str)
          hold = input_line_pointer;
          input_line_pointer = str;
          
-/* fprintf (stderr, "operand: %s   index = %d, opcode = %s\n", input_line_pointer, opindex_ptr - opcode->operands, opcode->name ); */
-
          /* lo(), hi(), hi0(), etc... */
          if ((reloc = v850_reloc_prefix (operand)) != BFD_RELOC_UNUSED)
            {
+             /* This is a fake reloc, used to indicate an error condition.  */
+             if (reloc == BFD_RELOC_64)
+               {
+                 match = 1;
+                 goto error;
+               }
+                
              expression (& ex);
 
              if (ex.X_op == O_constant)
@@ -1249,7 +1767,8 @@ md_assemble (str)
                  switch (reloc)
                    {
                    case BFD_RELOC_V850_ZDA_16_16_OFFSET:
-                     /* To cope with "not1 7, zdaoff(0xfffff006)[r0]"  and the like.  */
+                     /* To cope with "not1 7, zdaoff(0xfffff006)[r0]"
+                        and the like.  */
                      /* Fall through.  */
                      
                    case BFD_RELOC_LO16:
@@ -1277,11 +1796,10 @@ md_assemble (str)
                        break;
                      }
                    
-/* start-sanitize-v850e */
                    case BFD_RELOC_32:
                      if ((operand->flags & V850E_IMMEDIATE32) == 0)
                        {
-                         errmsg = "use bigger instruction";
+                         errmsg = _("immediate operand is too large");
                          goto error;
                        }
                      
@@ -1290,16 +1808,20 @@ md_assemble (str)
                      extra_data            = ex.X_add_number;
                      ex.X_add_number       = 0;
                      break;
-/* end-sanitize-v850e */
                      
                    default:
                      fprintf (stderr, "reloc: %d\n", reloc);
-                     as_bad ("AAARG -> unhandled constant reloc");
+                     as_bad (_("AAARG -> unhandled constant reloc"));
                      break;
                    }
 
-                 insn = v850_insert_operand (insn, operand, ex.X_add_number,
-                                             (char *) NULL, 0);
+                 if (fc > MAX_INSN_FIXUPS)
+                   as_fatal (_("too many fixups"));
+                 
+                 fixups[ fc ].exp     = ex;
+                 fixups[ fc ].opindex = * opindex_ptr;
+                 fixups[ fc ].reloc   = reloc;
+                 fc++;
                }
              else
                {
@@ -1307,18 +1829,17 @@ md_assemble (str)
                    {
                      if ((operand->flags & V850E_IMMEDIATE32) == 0)
                        {
-                         errmsg = "use bigger instruction";
+                         errmsg = _("immediate operand is too large");
                          goto error;
                        }
                      
                      extra_data_after_insn = true;
                      extra_data_len        = 4;
                      extra_data            = ex.X_add_number;
-                     ex.X_add_number       = 0;
                    }
                      
                  if (fc > MAX_INSN_FIXUPS)
-                   as_fatal ("too many fixups");
+                   as_fatal (_("too many fixups"));
 
                  fixups[ fc ].exp     = ex;
                  fixups[ fc ].opindex = * opindex_ptr;
@@ -1334,20 +1855,24 @@ md_assemble (str)
                {
                  if (!register_name (& ex))
                    {
-                     errmsg = "invalid register name";
+                     errmsg = _("invalid register name");
                    }
-
-                 if ((operand->flags & V850_NOT_R0)
+                 else if ((operand->flags & V850_NOT_R0)
                      && ex.X_add_number == 0)
                    {
-                     errmsg = "register r0 cannot be used here";
+                     errmsg = _("register r0 cannot be used here");
+                     
+                     /* Force an error message to be generated by
+                        skipping over any following potential matches
+                        for this opcode.  */
+                     opcode += 3;
                    }
                }
              else if ((operand->flags & V850_OPERAND_SRG) != 0) 
                {
-                 if (!system_register_name (& ex, true))
+                 if (!system_register_name (& ex, true, false))
                    {
-                     errmsg = "invalid system register name";
+                     errmsg = _("invalid system register name");
                    }
                }
              else if ((operand->flags & V850_OPERAND_EP) != 0)
@@ -1360,7 +1885,7 @@ md_assemble (str)
                      /* Put things back the way we found them.  */
                      *input_line_pointer = c;
                      input_line_pointer = start;
-                     errmsg = "expected EP register";
+                     errmsg = _("expected EP register");
                      goto error;
                    }
                  
@@ -1369,22 +1894,22 @@ md_assemble (str)
                  input_line_pointer = hold;
              
                  while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
-                   ++str;
+                   ++ str;
                  continue;
                }
              else if ((operand->flags & V850_OPERAND_CC) != 0) 
                {
                  if (!cc_name (& ex))
                    {
-                     errmsg = "invalid condition code name";
+                     errmsg = _("invalid condition code name");
                    }
                }
-/* start-sanitize-v850e */
              else if (operand->flags & V850E_PUSH_POP) 
                {
                  errmsg = parse_register_list (& insn, operand);
                  
-                 /* The parse_register_list() function has already done everything, so fake a dummy expression.  */
+                 /* The parse_register_list() function has already done
+                    everything, so fake a dummy expression.  */
                  ex.X_op         = O_constant;
                  ex.X_add_number = 0;
                }
@@ -1393,15 +1918,15 @@ md_assemble (str)
                  expression (& ex);
 
                  if (ex.X_op != O_constant)
-                   errmsg = "constant expression expected";
+                   errmsg = _("constant expression expected");
                  else if (ex.X_add_number & 0xffff0000)
                    {
                      if (ex.X_add_number & 0xffff)
-                       errmsg = "constant too big to fit into instruction";
+                       errmsg = _("constant too big to fit into instruction");
                      else if ((insn & 0x001fffc0) == 0x00130780)
                        ex.X_add_number >>= 16;
                      else
-                       errmsg = "constant too big to fit into instruction";
+                       errmsg = _("constant too big to fit into instruction");
                    }
                  
                  extra_data_after_insn = true;
@@ -1414,78 +1939,120 @@ md_assemble (str)
                  expression (& ex);
                  
                  if (ex.X_op != O_constant)
-                   errmsg = "constant expression expected";
+                   errmsg = _("constant expression expected");
                  
                  extra_data_after_insn = true;
                  extra_data_len        = 4;
                  extra_data            = ex.X_add_number;
                  ex.X_add_number       = 0;
                }
-/* end-sanitize-v850e */
-             else if (register_name (&ex)
+             else if (register_name (& ex)
                       && (operand->flags & V850_OPERAND_REG) == 0)
                {
-                 errmsg = "syntax error: register not expected";
+                 char c;
+                 int  exists = 0;
+                 
+                 /* It is possible that an alias has been defined that
+                    matches a register name.  For example the code may
+                    include a ".set ZERO, 0" directive, which matches
+                    the register name "zero".  Attempt to reparse the
+                    field as an expression, and only complain if we
+                    cannot generate a constant.  */
+
+                 input_line_pointer = str;
+
+                 c = get_symbol_end ();
+                 
+                 if (symbol_find (str) != NULL)
+                   exists = 1;
+                 
+                 * input_line_pointer = c;
+                 input_line_pointer = str;
+                 
+                 expression (& ex);
+
+                 if (ex.X_op != O_constant)
+                   {
+                     /* If this register is actually occuring too early on
+                        the parsing of the instruction, (because another
+                        field is missing) then report this.  */
+                     if (opindex_ptr[1] != 0
+                         && (v850_operands [opindex_ptr [1]].flags & V850_OPERAND_REG))
+                       errmsg = _("syntax error: value is missing before the register name");
+                     else
+                       errmsg = _("syntax error: register not expected");
+
+                     /* If we created a symbol in the process of this test then
+                        delete it now, so that it will not be output with the real
+                        symbols... */
+                     if (exists == 0
+                         && ex.X_op == O_symbol)
+                       symbol_remove (ex.X_add_symbol,
+                                      & symbol_rootP, & symbol_lastP);
+                   }
                }
-             else if (system_register_name (& ex, false)
+             else if (system_register_name (& ex, false, false)
                       && (operand->flags & V850_OPERAND_SRG) == 0)
                {
-                 errmsg = "syntax error: system register not expected";
+                 errmsg = _("syntax error: system register not expected");
                }
              else if (cc_name (&ex)
                       && (operand->flags & V850_OPERAND_CC) == 0)
                {
-                 errmsg = "syntax error: condition code not expected";
+                 errmsg = _("syntax error: condition code not expected");
                }
              else
                {
                  expression (& ex);
-/* start-sanitize-v850e */
                  /* Special case:
                     If we are assembling a MOV instruction (or a CALLT.... :-)
-                    and the immediate value does not fit into the bits available
-                    then create a fake error so that the next MOV instruction
-                     will be selected.  This one has a 32 bit immediate field.  */
+                    and the immediate value does not fit into the bits
+                    available then create a fake error so that the next MOV
+                    instruction will be selected.  This one has a 32 bit
+                    immediate field.  */
 
                  if (((insn & 0x07e0) == 0x0200)
                      && ex.X_op == O_constant
-                     && (ex.X_add_number < (- (1 << (operand->bits - 1))) || ex.X_add_number > ((1 << operand->bits) - 1)))
-                   errmsg = "use bigger instruction";
-/* end-sanitize-v850e */
+                     && (ex.X_add_number < (- (1 << (operand->bits - 1)))
+                         || ex.X_add_number > ((1 << operand->bits) - 1)))
+                   errmsg = _("immediate operand is too large");
                }
 
              if (errmsg)
                goto error;
              
-/* fprintf (stderr, "insn: %x, operand %d, op: %d, add_number: %d\n", insn, opindex_ptr - opcode->operands, ex.X_op, ex.X_add_number ); */
+/* fprintf (stderr, " insn: %x, operand %d, op: %d, add_number: %d\n",
+   insn, opindex_ptr - opcode->operands, ex.X_op, ex.X_add_number); */
 
              switch (ex.X_op) 
                {
                case O_illegal:
-                 errmsg = "illegal operand";
+                 errmsg = _("illegal operand");
                  goto error;
                case O_absent:
-                 errmsg = "missing operand";
+                 errmsg = _("missing operand");
                  goto error;
                case O_register:
                  if ((operand->flags & (V850_OPERAND_REG | V850_OPERAND_SRG)) == 0)
                    {
-                     errmsg = "invalid operand";
+                     errmsg = _("invalid operand");
                      goto error;
                    }
                  insn = v850_insert_operand (insn, operand, ex.X_add_number,
-                                             (char *) NULL, 0);
+                                             (char *) NULL, 0,
+                                             copy_of_instruction);
                  break;
 
                case O_constant:
                  insn = v850_insert_operand (insn, operand, ex.X_add_number,
-                                             (char *) NULL, 0);
+                                             (char *) NULL, 0,
+                                             copy_of_instruction);
                  break;
 
                default:
                  /* We need to generate a fixup for this expression.  */
                  if (fc >= MAX_INSN_FIXUPS)
-                   as_fatal ("too many fixups");
+                   as_fatal (_("too many fixups"));
 
                  fixups[ fc ].exp     = ex;
                  fixups[ fc ].opindex = * opindex_ptr;
@@ -1508,13 +2075,24 @@ md_assemble (str)
       if (match == 0)
         {
          next_opcode = opcode + 1;
-         if (next_opcode->name != NULL && strcmp (next_opcode->name, opcode->name) == 0)
+         if (next_opcode->name != NULL
+             && strcmp (next_opcode->name, opcode->name) == 0)
            {
              opcode = next_opcode;
+
+             /* Skip versions that are not supported by the target
+                processor.  */
+             if ((opcode->processors & processor_mask) == 0)
+               goto error;
+             
              continue;
            }
          
-         as_bad (errmsg);
+         as_bad ("%s: %s", copy_of_instruction, errmsg);
+         
+         if (* input_line_pointer == ']')
+           ++ input_line_pointer;
+         
          ignore_rest_of_line ();
          input_line_pointer = saved_input_line_pointer;
          return;
@@ -1526,36 +2104,48 @@ md_assemble (str)
     ++str;
 
   if (*str != '\0')
-    as_bad ("junk at end of line: `%s'", str);
+    /* xgettext:c-format */
+    as_bad (_("junk at end of line: `%s'"), str);
 
   input_line_pointer = str;
 
-  /* Write out the instruction.
-
-     Four byte insns have an opcode with the two high bits on.  */ 
+  /* Write out the instruction. */
+  
   if (relaxable && fc > 0)
     {
-      f = frag_var (rs_machine_dependent, 6, 4, 0,
-                   fixups[0].exp.X_add_symbol,
-                   fixups[0].exp.X_add_number,
-                   (char *)fixups[0].opindex);
       insn_size = 2;
-      md_number_to_chars (f, insn, insn_size);
-      md_number_to_chars (f + 2, 0, 4);
       fc = 0;
+
+      if (!strcmp (opcode->name, "br"))
+       {
+         f = frag_var (rs_machine_dependent, 4, 2, 2,
+                       fixups[0].exp.X_add_symbol,
+                       fixups[0].exp.X_add_number,
+                       (char *)fixups[0].opindex);
+         md_number_to_chars (f, insn, insn_size);
+         md_number_to_chars (f + 2, 0, 2);
+       }
+      else
+       {
+         f = frag_var (rs_machine_dependent, 6, 4, 0,
+                       fixups[0].exp.X_add_symbol,
+                       fixups[0].exp.X_add_number,
+                       (char *)fixups[0].opindex);
+         md_number_to_chars (f, insn, insn_size);
+         md_number_to_chars (f + 2, 0, 4);
+       }
     }
   else 
     {
+      /* Four byte insns have an opcode with the two high bits on.  */
       if ((insn & 0x0600) == 0x0600)
        insn_size = 4;
       else
        insn_size = 2;
 
-/* start-sanitize-v850e */
       /* Special case: 32 bit MOV */
       if ((insn & 0xffe0) == 0x0620)
        insn_size = 2;
-/* end-sanitize-v850e */
       
       f = frag_more (insn_size);
       
@@ -1588,7 +2178,8 @@ md_assemble (str)
       
       if (reloc != BFD_RELOC_UNUSED)
        {
-         reloc_howto_type * reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
+         reloc_howto_type * reloc_howto = bfd_reloc_type_lookup (stdoutput,
+                                                                 reloc);
          int                size;
          int                address;
          fixS *             fixP;
@@ -1598,8 +2189,10 @@ md_assemble (str)
          
          size = bfd_get_reloc_size (reloc_howto);
 
-         if (size != 2 && size != 4) /* XXX this will abort on an R_V850_8 reloc - is this reloc actually used ? */
-           abort();
+         /* XXX This will abort on an R_V850_8 reloc -
+            is this reloc actually used ? */
+         if (size != 2 && size != 4) 
+           abort ();
 
          address = (f - frag_now->fr_literal) + insn_size - size;
 
@@ -1629,7 +2222,8 @@ md_assemble (str)
                       f - frag_now->fr_literal, 4,
                       & fixups[i].exp,
                       1 /* FIXME: V850_OPERAND_RELATIVE ??? */,
-                      (bfd_reloc_code_real_type) (fixups[i].opindex + (int) BFD_RELOC_UNUSED)
+                      (bfd_reloc_code_real_type) (fixups[i].opindex
+                                                  + (int) BFD_RELOC_UNUSED)
                       );
        }
     }
@@ -1649,21 +2243,28 @@ tc_gen_reloc (seg, fixp)
   arelent * reloc;
   
   reloc              = (arelent *) xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr = & fixp->fx_addsy->bsym;
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr= symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address     = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto       = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
 
   if (reloc->howto == (reloc_howto_type *) NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                    "reloc %d not supported by object file format", (int)fixp->fx_r_type);
+                   /* xgettext:c-format */
+                    _("reloc %d not supported by object file format"),
+                   (int) fixp->fx_r_type);
 
       xfree (reloc);
       
       return NULL;
     }
   
-  reloc->addend = fixp->fx_addnumber;
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
+    reloc->addend = fixp->fx_offset;
+  else
+    reloc->addend = fixp->fx_addnumber;
   
   return reloc;
 }
@@ -1674,21 +2275,31 @@ md_estimate_size_before_relax (fragp, seg)
      fragS * fragp;
      asection * seg;
 {
-  fragp->fr_var = 4;
+  if (fragp->fr_subtype == 0)
+    fragp->fr_var = 4;
+  else if (fragp->fr_subtype == 2)
+    fragp->fr_var = 2;
+  else
+    abort ();
   return 2;
 } 
 
 long
-md_pcrel_from (fixp)
+v850_pcrel_from_section (fixp, section)
      fixS * fixp;
+     segT   section;
 {
   /* If the symbol is undefined, or in a section other than our own,
      then let the linker figure it out.  */
-  if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy))
+  if (fixp->fx_addsy != (symbolS *) NULL
+      && (! S_IS_DEFINED (fixp->fx_addsy)
+         || (S_GET_SEGMENT (fixp->fx_addsy) != section)))
     {
-      /* The symbol is undefined.  Let the linker figure it out.  */
+      /* The symbol is undefined/not in our section.
+        Let the linker figure it out.  */
       return 0;
     }
+
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
@@ -1701,6 +2312,13 @@ md_apply_fix3 (fixp, valuep, seg)
   valueT value;
   char * where;
 
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    {
+      fixp->fx_done = 0;
+      return 1;
+    }
+
   if (fixp->fx_addsy == (symbolS *) NULL)
     {
       value = * valuep;
@@ -1719,7 +2337,7 @@ md_apply_fix3 (fixp, valuep, seg)
            {
              /* We don't actually support subtracting a symbol.  */
              as_bad_where (fixp->fx_file, fixp->fx_line,
-                           "expression too complex");
+                           _("expression too complex"));
            }
        }
     }
@@ -1742,7 +2360,7 @@ md_apply_fix3 (fixp, valuep, seg)
 
       insn = bfd_getl32 ((unsigned char *) where);
       insn = v850_insert_operand (insn, operand, (offsetT) value,
-                                 fixp->fx_file, fixp->fx_line);
+                                 fixp->fx_file, fixp->fx_line, NULL);
       bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
 
       if (fixp->fx_done)
@@ -1762,8 +2380,8 @@ md_apply_fix3 (fixp, valuep, seg)
        {
          /* fprintf (stderr, "bits: %d, insn: %x\n", operand->bits, insn); */
          
-         as_bad_where(fixp->fx_file, fixp->fx_line,
-                      "unresolved expression that must be resolved");
+         as_bad_where (fixp->fx_file, fixp->fx_line,
+                      _("unresolved expression that must be resolved"));
          fixp->fx_done = 1;
          return 1;
        }
@@ -1772,8 +2390,9 @@ md_apply_fix3 (fixp, valuep, seg)
     {
       /* We still have to insert the value into memory!  */
       where = fixp->fx_frag->fr_literal + fixp->fx_where;
+
       if (fixp->fx_size == 1)
-       *where = value & 0xff;
+       * where = value & 0xff;
       else if (fixp->fx_size == 2)
        bfd_putl16 (value & 0xffff, (unsigned char *) where);
       else if (fixp->fx_size == 4)
@@ -1785,76 +2404,6 @@ md_apply_fix3 (fixp, valuep, seg)
 }
 
 \f
-/* Insert an operand value into an instruction.  */
-
-static unsigned long
-v850_insert_operand (insn, operand, val, file, line)
-     unsigned long insn;
-     const struct v850_operand * operand;
-     offsetT val;
-     char *file;
-     unsigned int line;
-{
-  if (operand->insert)
-    {
-      const char * message = NULL;
-      
-      insn = (*operand->insert) (insn, val, & message);
-      if (message != NULL)
-       {
-         if (file == (char *) NULL)
-           as_warn (message);
-         else
-           as_warn_where (file, line, message);
-       }
-    }
-  else
-    {
-      if (operand->bits != 32)
-       {
-         long    min, max;
-         offsetT test;
-
-         if ((operand->flags & V850_OPERAND_SIGNED) != 0)
-           {
-             if (! warn_signed_overflows)
-               max = (1 << operand->bits) - 1;
-             else
-               max = (1 << (operand->bits - 1)) - 1;
-             
-             min = - (1 << (operand->bits - 1));
-           }
-         else
-           {
-             max = (1 << operand->bits) - 1;
-             
-             if (! warn_unsigned_overflows)
-               min = - (1 << (operand->bits - 1));
-             else
-               min = 0;
-           }
-         
-         test = val;
-         
-         if (test < (offsetT) min || test > (offsetT) max)
-           {
-             const char * err = "operand out of range (%s not between %ld and %ld)";
-             char         buf[100];
-             
-             sprint_value (buf, test);
-             if (file == (char *) NULL)
-               as_warn (err, buf, min, max);
-             else
-               as_warn_where (file, line, err, buf, min, max);
-           }
-       }
-
-      insn |= (((long) val & ((1 << operand->bits) - 1)) << operand->shift);
-    }
-  
-  return insn;
-}
-
 /* Parse a cons expression.  We have to handle hi(), lo(), etc
    on the v850.  */
 void
@@ -1893,3 +2442,38 @@ cons_fix_new_v850 (frag, where, size, exp)
   else
     fix_new (frag, where, size, NULL, 0, 0, hold_cons_reloc);
 }
+boolean
+v850_fix_adjustable (fixP)
+    fixS *fixP;
+{
+  if (fixP->fx_addsy == NULL)
+    return 1;
+  /* Prevent all adjustments to global symbols. */
+  if (S_IS_EXTERN (fixP->fx_addsy))
+    return 0;
+  if (S_IS_WEAK (fixP->fx_addsy))
+    return 0;
+  /* Don't adjust function names */
+  if (S_IS_FUNCTION (fixP->fx_addsy))
+    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)
+    return 0;
+  return 1;
+}
+int
+v850_force_relocation (fixp)
+      struct fix *fixp;
+{
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 1;
+  return 0;
+}