merge from gcc
[external/binutils.git] / gas / config / tc-v850.c
index 1f157d7..e0ac162 100644 (file)
@@ -1,11 +1,12 @@
 /* tc-v850.c -- Assembler code for the NEC V850
-   Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007, 2009  Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
-#include <stdio.h>
-#include <ctype.h>
 #include "as.h"
+#include "safe-ctype.h"
 #include "subsegs.h"
 #include "opcode/v850.h"
 #include "dwarf2dbg.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)
 
@@ -36,8 +32,8 @@
 static bfd_reloc_code_real_type hold_cons_reloc = BFD_RELOC_UNUSED;
 
 /* Set to TRUE if we want to be pedantic about signed overflows.  */
-static boolean warn_signed_overflows   = FALSE;
-static boolean warn_unsigned_overflows = FALSE;
+static bfd_boolean warn_signed_overflows   = FALSE;
+static bfd_boolean warn_unsigned_overflows = FALSE;
 
 /* Indicates the target BFD machine number.  */
 static int machine = -1;
@@ -46,7 +42,8 @@ static int machine = -1;
 static int processor_mask = -1;
 \f
 /* Structure to hold information about predefined registers.  */
-struct reg_name {
+struct reg_name
+{
   const char *name;
   int value;
 };
@@ -72,7 +69,8 @@ const char EXP_CHARS[] = "eE";
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 \f
-const relax_typeS md_relax_table[] = {
+const relax_typeS md_relax_table[] =
+{
   /* Conditional branches.  */
   {0xff,     -0x100,    2, 1},
   {0x1fffff, -0x200000, 6, 0},
@@ -81,23 +79,13 @@ const relax_typeS md_relax_table[] = {
   {0x1fffff, -0x200000, 4, 0},
 };
 
-static segT sdata_section = NULL;
-static segT tdata_section = NULL;
-static segT zdata_section = NULL;
-static segT sbss_section = NULL;
-static segT tbss_section = NULL;
-static segT zbss_section = NULL;
-static segT rosdata_section = NULL;
-static segT rozdata_section = NULL;
-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;
+static int  v850_relax = 0;
 
 /* Fixups.  */
-#define MAX_INSN_FIXUPS (5)
-struct v850_fixup {
+#define MAX_INSN_FIXUPS   5
+
+struct v850_fixup
+{
   expressionS exp;
   int opindex;
   bfd_reloc_code_real_type reloc;
@@ -105,128 +93,104 @@ struct v850_fixup {
 
 struct v850_fixup fixups[MAX_INSN_FIXUPS];
 static int fc;
-\f
-void
-v850_sdata (int ignore ATTRIBUTE_UNUSED)
-{
-  obj_elf_section_change_hook ();
-
-  subseg_set (sdata_section, (subsegT) get_absolute_expression ());
 
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_tdata (int ignore ATTRIBUTE_UNUSED)
+struct v850_seg_entry
 {
-  obj_elf_section_change_hook ();
-
-  subseg_set (tdata_section, (subsegT) get_absolute_expression ());
-
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_zdata (int ignore ATTRIBUTE_UNUSED)
-{
-  obj_elf_section_change_hook ();
-
-  subseg_set (zdata_section, (subsegT) get_absolute_expression ());
-
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_sbss (int ignore ATTRIBUTE_UNUSED)
-{
-  obj_elf_section_change_hook ();
-
-  subseg_set (sbss_section, (subsegT) get_absolute_expression ());
-
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_tbss (int ignore ATTRIBUTE_UNUSED)
-{
-  obj_elf_section_change_hook ();
-
-  subseg_set (tbss_section, (subsegT) get_absolute_expression ());
-
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_zbss (int ignore ATTRIBUTE_UNUSED)
-{
-  obj_elf_section_change_hook ();
-
-  subseg_set (zbss_section, (subsegT) get_absolute_expression ());
-
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_rosdata (int ignore ATTRIBUTE_UNUSED)
-{
-  obj_elf_section_change_hook ();
-
-  subseg_set (rosdata_section, (subsegT) get_absolute_expression ());
-
-  demand_empty_rest_of_line ();
-}
+  segT s;
+  const char *name;
+  flagword flags;
+};
 
-void
-v850_rozdata (int ignore ATTRIBUTE_UNUSED)
+struct v850_seg_entry v850_seg_table[] =
 {
-  obj_elf_section_change_hook ();
+  { NULL, ".sdata",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS
+    | SEC_SMALL_DATA },
+  { NULL, ".tdata",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS },
+  { NULL, ".zdata",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS },
+  { NULL, ".sbss",
+    SEC_ALLOC | SEC_SMALL_DATA },
+  { NULL, ".tbss",
+    SEC_ALLOC },
+  { NULL, ".zbss",
+    SEC_ALLOC},
+  { NULL, ".rosdata",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | SEC_DATA
+    | SEC_HAS_CONTENTS | SEC_SMALL_DATA },
+  { NULL, ".rozdata",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | SEC_DATA
+    | SEC_HAS_CONTENTS },
+  { NULL, ".scommon",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS
+    | SEC_SMALL_DATA | SEC_IS_COMMON },
+  { NULL, ".tcommon",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS
+    | SEC_IS_COMMON },
+  { NULL, ".zcommon",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS
+    | SEC_IS_COMMON },
+  { NULL, ".call_table_data",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS },
+  { NULL, ".call_table_text",
+    SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | SEC_CODE
+    | SEC_HAS_CONTENTS},
+  { NULL, ".bss",
+    SEC_ALLOC }
+};
 
-  subseg_set (rozdata_section, (subsegT) get_absolute_expression ());
+#define SDATA_SECTION          0
+#define TDATA_SECTION          1
+#define ZDATA_SECTION          2
+#define SBSS_SECTION           3
+#define TBSS_SECTION           4
+#define ZBSS_SECTION           5
+#define ROSDATA_SECTION                6
+#define ROZDATA_SECTION                7
+#define SCOMMON_SECTION                8
+#define TCOMMON_SECTION                9
+#define ZCOMMON_SECTION                10
+#define CALL_TABLE_DATA_SECTION        11
+#define CALL_TABLE_TEXT_SECTION        12
+#define BSS_SECTION            13
 
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_call_table_data (int ignore ATTRIBUTE_UNUSED)
+static void
+do_v850_seg (int i, subsegT sub)
 {
-  obj_elf_section_change_hook ();
-
-  subseg_set (call_table_data_section, (subsegT) get_absolute_expression ());
+  struct v850_seg_entry *seg = v850_seg_table + i;
 
-  demand_empty_rest_of_line ();
-}
-
-void
-v850_call_table_text (int ignore ATTRIBUTE_UNUSED)
-{
   obj_elf_section_change_hook ();
 
-  subseg_set (call_table_text_section, (subsegT) get_absolute_expression ());
-
-  demand_empty_rest_of_line ();
+  if (seg->s != NULL)
+    subseg_set (seg->s, sub);
+  else
+    {
+      seg->s = subseg_new (seg->name, sub);
+      bfd_set_section_flags (stdoutput, seg->s, seg->flags);
+      if ((seg->flags & SEC_LOAD) == 0)
+       seg_info (seg->s)->bss = 1;
+    }
 }
 
-void
-v850_bss (int ignore ATTRIBUTE_UNUSED)
+static void
+v850_seg (int i)
 {
-  register int temp = get_absolute_expression ();
-
-  obj_elf_section_change_hook ();
-
-  subseg_set (bss_section, (subsegT) temp);
+  subsegT sub = get_absolute_expression ();
 
+  do_v850_seg (i, sub);
   demand_empty_rest_of_line ();
 }
 
-void
+static void
 v850_offset (int ignore ATTRIBUTE_UNUSED)
 {
+  char *pfrag;
   int temp = get_absolute_expression ();
 
-  temp -= frag_now_fix ();
-
-  if (temp > 0)
-    (void) frag_more (temp);
+  pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, (symbolS *)0,
+                   (offsetT) temp, (char *) 0);
+  *pfrag = 0;
 
   demand_empty_rest_of_line ();
 }
@@ -234,8 +198,7 @@ v850_offset (int ignore ATTRIBUTE_UNUSED)
 /* Copied from obj_elf_common() in gas/config/obj-elf.c.  */
 
 static void
-v850_comm (area)
-     int area;
+v850_comm (int area)
 {
   char *name;
   char c;
@@ -287,11 +250,9 @@ v850_comm (area)
   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);
-       }
+       /* 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);
@@ -337,37 +298,16 @@ v850_comm (area)
 
          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;
-               }
+           case SCOMMON_SECTION:
+             do_v850_seg (SBSS_SECTION, 0);
              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;
-               }
+           case ZCOMMON_SECTION:
+             do_v850_seg (ZBSS_SECTION, 0);
              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;
-               }
+           case TCOMMON_SECTION:
+             do_v850_seg (TBSS_SECTION, 0);
              break;
            }
 
@@ -387,47 +327,25 @@ v850_comm (area)
          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 ();
-           }
+         record_alignment (now_seg, align);
 
          if (align)
            frag_align (align, 0, 0);
 
          switch (area)
            {
-           case AREA_SDA:
-             if (S_GET_SEGMENT (symbolP) == sbss_section)
+           case SCOMMON_SECTION:
+             if (S_GET_SEGMENT (symbolP) == v850_seg_table[SBSS_SECTION].s)
                symbol_get_frag (symbolP)->fr_symbol = 0;
              break;
 
-           case AREA_ZDA:
-             if (S_GET_SEGMENT (symbolP) == zbss_section)
+           case ZCOMMON_SECTION:
+             if (S_GET_SEGMENT (symbolP) == v850_seg_table[ZBSS_SECTION].s)
                symbol_get_frag (symbolP)->fr_symbol = 0;
              break;
 
-           case AREA_TDA:
-             if (S_GET_SEGMENT (symbolP) == tbss_section)
+           case TCOMMON_SECTION:
+             if (S_GET_SEGMENT (symbolP) == v850_seg_table[TBSS_SECTION].s)
                symbol_get_frag (symbolP)->fr_symbol = 0;
              break;
 
@@ -443,16 +361,16 @@ v850_comm (area)
 
          switch (area)
            {
-           case AREA_SDA:
-             S_SET_SEGMENT (symbolP, sbss_section);
+           case SCOMMON_SECTION:
+             S_SET_SEGMENT (symbolP, v850_seg_table[SBSS_SECTION].s);
              break;
 
-           case AREA_ZDA:
-             S_SET_SEGMENT (symbolP, zbss_section);
+           case ZCOMMON_SECTION:
+             S_SET_SEGMENT (symbolP, v850_seg_table[ZBSS_SECTION].s);
              break;
 
-           case AREA_TDA:
-             S_SET_SEGMENT (symbolP, tbss_section);
+           case TCOMMON_SECTION:
+             S_SET_SEGMENT (symbolP, v850_seg_table[TBSS_SECTION].s);
              break;
 
            default:
@@ -465,66 +383,32 @@ v850_comm (area)
        }
       else
        {
+         segT   old_sec;
+         int    old_subsec;
+
        allocate_common:
+         old_sec = now_seg;
+         old_subsec = now_subseg;
+
          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 =
-                   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 =
-                   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 =
-                   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);
+           case SCOMMON_SECTION:
+           case ZCOMMON_SECTION:
+           case TCOMMON_SECTION:
+             do_v850_seg (area, 0);
+             S_SET_SEGMENT (symbolP, v850_seg_table[area].s);
              break;
 
            default:
              abort ();
            }
+
+         obj_elf_section_change_hook ();
+         subseg_set (old_sec, old_subsec);
        }
     }
   else
@@ -544,8 +428,10 @@ v850_comm (area)
          input_line_pointer--;
          goto bad_common_segment;
        }
+
       while (*input_line_pointer++ != '"')
        ;
+
       goto allocate_common;
     }
 
@@ -569,7 +455,7 @@ v850_comm (area)
   }
 }
 
-void
+static void
 set_machine (int number)
 {
   machine = number;
@@ -577,47 +463,82 @@ set_machine (int number)
 
   switch (machine)
     {
-    case 0:               processor_mask = PROCESSOR_V850;   break;
+    case 0:              processor_mask = PROCESSOR_V850;   break;
     case bfd_mach_v850e:  processor_mask = PROCESSOR_V850E;  break;
-    case bfd_mach_v850ea: processor_mask = PROCESSOR_V850EA; break;
+    case bfd_mach_v850e1: processor_mask = PROCESSOR_V850E;  break;
+    }
+}
+
+static void
+v850_longcode (int type)
+{
+  expressionS ex;
+
+  if (! v850_relax)
+    {
+      if (type == 1)
+       as_warn (_(".longcall pseudo-op seen when not relaxing"));
+      else
+       as_warn (_(".longjump pseudo-op seen when not relaxing"));
+    }
+
+  expression (&ex);
+
+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
+    {
+      as_bad (_("bad .longcall format"));
+      ignore_rest_of_line ();
+
+      return;
     }
+
+  if (type == 1)
+    fix_new_exp (frag_now, frag_now_fix (), 4, & ex, 1,
+                BFD_RELOC_V850_LONGCALL);
+  else
+    fix_new_exp (frag_now, frag_now_fix (), 4, & ex, 1,
+                BFD_RELOC_V850_LONGJUMP);
+
+  demand_empty_rest_of_line ();
 }
 
 /* The target specific pseudo-ops which we support.  */
-const pseudo_typeS md_pseudo_table[] = {
-  {"sdata",   v850_sdata,   0},
-  {"tdata",   v850_tdata,   0},
-  {"zdata",   v850_zdata,   0},
-  {"sbss",    v850_sbss,    0},
-  {"tbss",    v850_tbss,    0},
-  {"zbss",    v850_zbss,    0},
-  {"rosdata", v850_rosdata, 0},
-  {"rozdata", v850_rozdata, 0},
-  {"bss",     v850_bss,     0},
-  {"offset",  v850_offset,  0},
-  {"word",    cons,         4},
-  {"zcomm",   v850_comm,    AREA_ZDA},
-  {"scomm",   v850_comm,    AREA_SDA},
-  {"tcomm",   v850_comm,    AREA_TDA},
-  {"v850",    set_machine,  0},
-  {"call_table_data", v850_call_table_data, 0},
-  {"call_table_text", v850_call_table_text, 0},
-  {"v850e",           set_machine,          bfd_mach_v850e},
-  {"v850ea",          set_machine,          bfd_mach_v850ea},
-  {"file",    dwarf2_directive_file },
-  {"loc",     dwarf2_directive_loc },
-  { NULL,     NULL,         0}
+const pseudo_typeS md_pseudo_table[] =
+{
+  { "sdata",           v850_seg,               SDATA_SECTION           },
+  { "tdata",           v850_seg,               TDATA_SECTION           },
+  { "zdata",           v850_seg,               ZDATA_SECTION           },
+  { "sbss",            v850_seg,               SBSS_SECTION            },
+  { "tbss",            v850_seg,               TBSS_SECTION            },
+  { "zbss",            v850_seg,               ZBSS_SECTION            },
+  { "rosdata",         v850_seg,               ROSDATA_SECTION         },
+  { "rozdata",         v850_seg,               ROZDATA_SECTION         },
+  { "bss",             v850_seg,               BSS_SECTION             },
+  { "offset",          v850_offset,            0                       },
+  { "word",            cons,                   4                       },
+  { "zcomm",           v850_comm,              ZCOMMON_SECTION         },
+  { "scomm",           v850_comm,              SCOMMON_SECTION         },
+  { "tcomm",           v850_comm,              TCOMMON_SECTION         },
+  { "v850",            set_machine,            0                       },
+  { "call_table_data", v850_seg,               CALL_TABLE_DATA_SECTION },
+  { "call_table_text", v850_seg,               CALL_TABLE_TEXT_SECTION },
+  { "v850e",           set_machine,            bfd_mach_v850e          },
+  { "v850e1",          set_machine,            bfd_mach_v850e1         },
+  { "longcall",                v850_longcode,          1                       },
+  { "longjump",                v850_longcode,          2                       },
+  { NULL,              NULL,                   0                       }
 };
 
 /* Opcode hash table.  */
 static struct hash_control *v850_hash;
 
 /* This table is sorted.  Suitable for searching by a binary search.  */
-static const struct reg_name pre_defined_registers[] = {
-  { "ep",  30 },               /* ep - element ptr */
-  { "gp",   4 },               /* gp - global ptr  */
-  { "hp",   2 },               /* hp - handler stack ptr  */
-  { "lp",  31 },               /* lp - link ptr  */
+static const struct reg_name pre_defined_registers[] =
+{
+  { "ep",  30 },               /* ep - element ptr.  */
+  { "gp",   4 },               /* gp - global ptr.  */
+  { "hp",   2 },               /* hp - handler stack ptr.  */
+  { "lp",  31 },               /* lp - link ptr.  */
   { "r0",   0 },
   { "r1",   1 },
   { "r10", 10 },
@@ -650,20 +571,28 @@ static const struct reg_name pre_defined_registers[] = {
   { "r7",   7 },
   { "r8",   8 },
   { "r9",   9 },
-  { "sp",   3 },               /* sp - stack ptr  */
-  { "tp",   5 },               /* tp - text ptr  */
+  { "sp",   3 },               /* sp - stack ptr.  */
+  { "tp",   5 },               /* tp - text ptr.  */
   { "zero", 0 },
 };
 
 #define REG_NAME_CNT                                           \
   (sizeof (pre_defined_registers) / sizeof (struct reg_name))
 
-static const struct reg_name system_registers[] = {
+static const struct reg_name system_registers[] =
+{
+  { "asid",  23 },
+  { "bpc",   22 },
+  { "bpav",  24 },
+  { "bpam",  25 },
+  { "bpdv",  26 },
+  { "bpdm",  27 },
   { "ctbp",  20 },
   { "ctpc",  16 },
   { "ctpsw", 17 },
   { "dbpc",  18 },
   { "dbpsw", 19 },
+  { "dir",   21 },
   { "ecr",    4 },
   { "eipc",   0 },
   { "eipsw",  1 },
@@ -675,7 +604,8 @@ 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[] = {
+static const struct reg_name system_list_registers[] =
+{
   {"PS",      5 },
   {"SR",      0 + 1}
 };
@@ -683,7 +613,8 @@ static const struct reg_name system_list_registers[] = {
 #define SYSREGLIST_NAME_CNT                                    \
   (sizeof (system_list_registers) / sizeof (struct reg_name))
 
-static const struct reg_name cc_names[] = {
+static const struct reg_name cc_names[] =
+{
   { "c",  0x1 },
   { "e",  0x2 },
   { "ge", 0xe },
@@ -716,11 +647,10 @@ static const struct reg_name cc_names[] = {
    success, or -1 on failure.  */
 
 static int
-reg_name_search (regs, regcount, name, accept_numbers)
-     const struct reg_name *regs;
-     int regcount;
-     const char *name;
-     boolean accept_numbers;
+reg_name_search (const struct reg_name *regs,
+                int regcount,
+                const char *name,
+                bfd_boolean accept_numbers)
 {
   int middle, low, high;
   int cmp;
@@ -732,10 +662,8 @@ reg_name_search (regs, regcount, name, accept_numbers)
       /* 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);
-       }
+       name
+         = S_GET_NAME (symbol_get_value_expression (symbolP)->X_add_symbol);
       else if (accept_numbers)
        {
          int reg = S_GET_VALUE (symbolP);
@@ -766,18 +694,17 @@ reg_name_search (regs, regcount, name, accept_numbers)
 }
 
 /* Summary of register_name().
- *
- * in: Input_line_pointer points to 1st char of operand.
- *
- * out: A expressionS.
- *     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
-register_name (expressionP)
-     expressionS *expressionP;
+
+   in: Input_line_pointer points to 1st char of operand.
+
+   out: An expressionS.
+       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 bfd_boolean
+register_name (expressionS *expressionP)
 {
   int reg_number;
   char *name;
@@ -798,43 +725,42 @@ register_name (expressionP)
   /* Look to see if it's in the register table.  */
   if (reg_number >= 0)
     {
-      expressionP->X_op         = O_register;
+      expressionP->X_op                = O_register;
       expressionP->X_add_number = reg_number;
 
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol  = NULL;
 
-      return true;
+      return TRUE;
     }
   else
     {
       /* Reset the line as if we had not done anything.  */
       input_line_pointer = start;
 
-      return false;
+      return FALSE;
     }
 }
 
 /* Summary of system_register_name().
- *
- * 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 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, accept_list_names)
-     expressionS *expressionP;
-     boolean accept_numbers;
-     boolean accept_list_names;
+
+   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: An 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 bfd_boolean
+system_register_name (expressionS *expressionP,
+                     bfd_boolean accept_numbers,
+                     bfd_boolean accept_list_names)
 {
   int reg_number;
   char *name;
@@ -857,17 +783,15 @@ system_register_name (expressionP, accept_numbers, accept_list_names)
       /* Reset input_line pointer.  */
       input_line_pointer = start;
 
-      if (isdigit (*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 && reg_number < 16)
-             || reg_number > 20)
-           {
-             reg_number = -1;
-           }
+             || reg_number > 27)
+           reg_number = -1;
        }
       else if (accept_list_names)
        {
@@ -883,37 +807,36 @@ system_register_name (expressionP, accept_numbers, accept_list_names)
   /* Look to see if it's in the register table.  */
   if (reg_number >= 0)
     {
-      expressionP->X_op         = O_register;
+      expressionP->X_op                = O_register;
       expressionP->X_add_number = reg_number;
 
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol  = NULL;
 
-      return true;
+      return TRUE;
     }
   else
     {
       /* Reset the line as if we had not done anything.  */
       input_line_pointer = start;
 
-      return false;
+      return FALSE;
     }
 }
 
 /* Summary of cc_name().
- *
- * in: INPUT_LINE_POINTER points to 1st char of operand.
- *
- * out: A expressionS.
- *     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
-cc_name (expressionP)
-     expressionS *expressionP;
+
+   in: INPUT_LINE_POINTER points to 1st char of operand.
+
+   out: An expressionS.
+       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 bfd_boolean
+cc_name (expressionS *expressionP)
 {
   int reg_number;
   char *name;
@@ -932,21 +855,21 @@ cc_name (expressionP)
   /* Look to see if it's in the register table.  */
   if (reg_number >= 0)
     {
-      expressionP->X_op         = O_constant;
+      expressionP->X_op                = O_constant;
       expressionP->X_add_number = reg_number;
 
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol  = NULL;
 
-      return true;
+      return TRUE;
     }
   else
     {
       /* Reset the line as if we had not done anything.  */
       input_line_pointer = start;
 
-      return false;
+      return FALSE;
     }
 }
 
@@ -959,44 +882,46 @@ skip_white_space (void)
 }
 
 /* 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: 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:
- *
*   { rX }
*   { rX, rY }
*   { rX - rY }
*   { rX - rY, rZ }
*   etc
- *
* and also parses constant epxressions whoes bits indicate the
* registers in the lists.  The LSB in the expression refers to
* the lowest numbered permissable register in the register list,
* and so on upwards.  System registers are considered to be very
* high numbers.  */
+
  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: 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:
+
    { rX }
    { rX, rY }
    { rX - rY }
    { rX - rY, rZ }
    etc
+
  and also parses constant expressions whoes bits indicate the
  registers in the lists.  The LSB in the expression refers to
  the lowest numbered permissible register in the register list,
  and so on upwards.  System registers are considered to be very
  high numbers.  */
 
 static char *
-parse_register_list (insn, operand)
-     unsigned long *insn;
-     const struct v850_operand *operand;
+parse_register_list (unsigned long *insn,
+                    const struct v850_operand *operand)
 {
-  static int type1_regs[32] = {
+  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
   };
-  static int type2_regs[32] = {
+  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] = {
+  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
   };
@@ -1019,7 +944,6 @@ parse_register_list (insn, operand)
   /* If the expression starts with a curly brace it is a register list.
      Otherwise it is a constant expression, whoes bits indicate which
      registers are to be included in the list.  */
-
   if (*input_line_pointer != '{')
     {
       int reg;
@@ -1104,11 +1028,9 @@ parse_register_list (insn, operand)
            }
 
          if (i == 32)
-           {
-             return _("illegal register included in list");
-           }
+           return _("illegal register included in list");
        }
-      else if (system_register_name (&exp, true, true))
+      else if (system_register_name (&exp, TRUE, TRUE))
        {
          if (regs == type1_regs)
            {
@@ -1173,9 +1095,7 @@ parse_register_list (insn, operand)
            }
        }
       else
-       {
-         break;
-       }
+       break;
 
       skip_white_space ();
     }
@@ -1183,48 +1103,40 @@ parse_register_list (insn, operand)
   return NULL;
 }
 
-CONST char *md_shortopts = "m:";
+const char *md_shortopts = "m:";
 
-struct option md_longopts[] = {
+struct option md_longopts[] =
+{
   {NULL, no_argument, NULL, 0}
 };
 
 size_t md_longopts_size = sizeof (md_longopts);
 
 void
-md_show_usage (stream)
-     FILE *stream;
+md_show_usage (FILE *stream)
 {
   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, _("  -mv850e1                  The code is targeted at the v850e1\n"));
   fprintf (stream, _("  -mv850any                 The code is generic, despite any processor specific instructions\n"));
+  fprintf (stream, _("  -mrelax                   Enable relaxation\n"));
 }
 
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+md_parse_option (int c, char *arg)
 {
   if (c != 'm')
-    {
-      if (c != 'a')
-       /* xgettext:c-format  */
-       fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg);
-      return 0;
-    }
+    return 0;
 
   if (strcmp (arg, "warn-signed-overflow") == 0)
-    {
-      warn_signed_overflows = TRUE;
-    }
+    warn_signed_overflows = TRUE;
+
   else if (strcmp (arg, "warn-unsigned-overflow") == 0)
-    {
-      warn_unsigned_overflows = TRUE;
-    }
+    warn_unsigned_overflows = TRUE;
+
   else if (strcmp (arg, "v850") == 0)
     {
       machine = 0;
@@ -1235,10 +1147,10 @@ md_parse_option (c, arg)
       machine = bfd_mach_v850e;
       processor_mask = PROCESSOR_V850E;
     }
-  else if (strcmp (arg, "v850ea") == 0)
+  else if (strcmp (arg, "v850e1") == 0)
     {
-      machine = bfd_mach_v850ea;
-      processor_mask = PROCESSOR_V850EA;
+      machine = bfd_mach_v850e1;
+      processor_mask = PROCESSOR_V850E1;
     }
   else if (strcmp (arg, "v850any") == 0)
     {
@@ -1246,82 +1158,59 @@ md_parse_option (c, arg)
       machine = 0;
 
       /* But support instructions for the extended versions.  */
-      processor_mask = PROCESSOR_V850EA;
+      processor_mask = PROCESSOR_V850E;
+      processor_mask |= PROCESSOR_V850E1;
     }
+  else if (strcmp (arg, "relax") == 0)
+    v850_relax = 1;
   else
-    {
-      /* xgettext:c-format  */
-      fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg);
-      return 0;
-    }
+    return 0;
 
   return 1;
 }
 
 symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 char *
-md_atof (type, litp, sizep)
-     int type;
-     char *litp;
-     int *sizep;
+md_atof (int type, char *litp, int *sizep)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    default:
-      *sizep = 0;
-      return _("bad call to md_atof");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizep = prec * 2;
-
-  for (i = prec - 1; i >= 0; i--)
-    {
-      md_number_to_chars (litp, (valueT) words[i], 2);
-      litp += 2;
-    }
-
-  return NULL;
+  return ieee_md_atof (type, litp, sizep, FALSE);
 }
 
 /* Very gross.  */
 
 void
-md_convert_frag (abfd, sec, fragP)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     asection *sec;
-     fragS *fragP;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+                asection *sec,
+                fragS *fragP)
 {
+  /* This code performs some nasty type punning between the
+     fr_opcode field of the frag structure (a char *) and the
+     fx_r_type field of the fix structure (a bfd_reloc_code_real_type)
+     On a 64bit host this causes problems because these two fields
+     are not the same size, but since we know that we are only
+     ever storing small integers in the fields, it is safe to use
+     a union to convert between them.  */
+  union u
+  {
+    bfd_reloc_code_real_type fx_r_type;
+    char * fr_opcode;
+  }
+  opcode_converter;
   subseg_change (sec, 0);
 
+  opcode_converter.fr_opcode = fragP->fr_opcode;
+      
   /* 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_offset, 1,
+              BFD_RELOC_UNUSED + opcode_converter.fx_r_type);
       fragP->fr_fix += 2;
     }
   /* Out of range conditional branch.  Emit a branch around a jump.  */
@@ -1341,11 +1230,10 @@ md_convert_frag (abfd, sec, fragP)
 
       /* Now create the unconditional branch + fixup to the final
         target.  */
-      md_number_to_chars (buffer + 2, 0x00000780, 4);
+      md_number_to_chars ((char *) 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_var = 0;
+              fragP->fr_offset, 1,
+              BFD_RELOC_UNUSED + opcode_converter.fx_r_type + 1);
       fragP->fr_fix += 6;
     }
   /* Out of range unconditional branch.  Emit a jump.  */
@@ -1353,9 +1241,8 @@ md_convert_frag (abfd, sec, fragP)
     {
       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_offset, 1,
+              BFD_RELOC_UNUSED + opcode_converter.fx_r_type + 1);
       fragP->fr_fix += 4;
     }
   else
@@ -1363,28 +1250,25 @@ md_convert_frag (abfd, sec, fragP)
 }
 
 valueT
-md_section_align (seg, addr)
-     asection *seg;
-     valueT addr;
+md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
 
 void
-md_begin ()
+md_begin (void)
 {
   char *prev_name = "";
-  register const struct v850_opcode *op;
-  flagword applicable;
+  const struct v850_opcode *op;
 
-  if (strncmp (TARGET_CPU, "v850ea", 6) == 0)
+  if (strncmp (TARGET_CPU, "v850e1", 6) == 0)
     {
       if (machine == -1)
-       machine = bfd_mach_v850ea;
+       machine = bfd_mach_v850e1;
 
       if (processor_mask == -1)
-       processor_mask = PROCESSOR_V850EA;
+       processor_mask = PROCESSOR_V850E1;
     }
   else if (strncmp (TARGET_CPU, "v850e", 5) == 0)
     {
@@ -1405,7 +1289,7 @@ md_begin ()
   else
     /* xgettext:c-format  */
     as_bad (_("Unable to determine default target processor from string: %s"),
-            TARGET_CPU);
+           TARGET_CPU);
 
   v850_hash = hash_new ();
 
@@ -1413,7 +1297,6 @@ md_begin ()
      has many identical opcode names that have different opcodes based
      on the operands.  This hash table then provides a quick index to
      the first opcode with a particular name in the opcode table.  */
-
   op = v850_opcodes;
   while (op->name)
     {
@@ -1425,22 +1308,27 @@ md_begin ()
       op++;
     }
 
+  v850_seg_table[BSS_SECTION].s = bss_section;
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine);
+}
 
-  applicable = bfd_applicable_section_flags (stdoutput);
-
-  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));
-
-  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));
+static bfd_reloc_code_real_type
+handle_lo16 (const struct v850_operand *operand)
+{
+  if (operand != NULL)
+    {
+      if (operand->bits == -1)
+       return BFD_RELOC_V850_LO16_SPLIT_OFFSET;
 
-  /* Restore text section as the current default.  */
-  subseg_set (text_section, 0);
+      if (!(operand->bits == 16 && operand->shift == 16)
+         && !(operand->bits == 15 && operand->shift == 17))
+       {
+         as_bad (_("lo() relocation used on an instruction which does "
+                   "not support it"));
+         return BFD_RELOC_64;  /* Used to indicate an error condition.  */
+       }
+    }
+  return BFD_RELOC_LO16;
 }
 
 static bfd_reloc_code_real_type
@@ -1512,19 +1400,19 @@ handle_tdaoff (const struct v850_operand *operand)
     return BFD_RELOC_V850_TDA_7_7_OFFSET;
 
   if (operand->bits == 6 && operand->shift == 1)
-    /* sld.w/sst.w, operand: D8_6  */
+    /* sld.w/sst.w, operand: D8_6.  */
     return BFD_RELOC_V850_TDA_6_8_OFFSET;
 
   if (operand->bits == 4 && operand->insert != NULL)
-    /* sld.hu, operand: D5-4  */
+    /* sld.hu, operand: D5-4.  */
     return BFD_RELOC_V850_TDA_4_5_OFFSET;
 
   if (operand->bits == 4 && operand->insert == NULL)
-    /* sld.bu, operand: D4   */
+    /* sld.bu, operand: D4.   */
     return BFD_RELOC_V850_TDA_4_4_OFFSET;
 
   if (operand->bits == 16 && operand->shift == 16)
-    /* set1 & chums, operands: D16  */
+    /* set1 & chums, operands: D16.  */
     return BFD_RELOC_V850_TDA_16_16_OFFSET;
 
   if (operand->bits != 7)
@@ -1535,8 +1423,8 @@ handle_tdaoff (const struct v850_operand *operand)
     }
 
   return  operand->insert != NULL
-    ? BFD_RELOC_V850_TDA_7_8_OFFSET     /* sld.h/sst.h, operand: D8_7  */
-    : BFD_RELOC_V850_TDA_7_7_OFFSET;    /* sld.b/sst.b, opreand: D7    */
+    ? BFD_RELOC_V850_TDA_7_8_OFFSET     /* sld.h/sst.h, operand: D8_7.  */
+    : BFD_RELOC_V850_TDA_7_7_OFFSET;    /* sld.b/sst.b, operand: D7.    */
 }
 
 /* Warning: The code in this function relies upon the definitions
@@ -1546,29 +1434,29 @@ handle_tdaoff (const struct v850_operand *operand)
 static bfd_reloc_code_real_type
 v850_reloc_prefix (const struct v850_operand *operand)
 {
-  boolean paren_skipped = false;
+  bfd_boolean paren_skipped = FALSE;
 
   /* Skip leading opening parenthesis.  */
   if (*input_line_pointer == '(')
     {
       ++input_line_pointer;
-      paren_skipped = true;
+      paren_skipped = TRUE;
     }
 
 #define CHECK_(name, reloc)                                            \
-  if (strncmp (input_line_pointer, name##"(", strlen (name) + 1) == 0) \
+  if (strncmp (input_line_pointer, name "(", strlen (name) + 1) == 0)  \
     {                                                                  \
       input_line_pointer += strlen (name);                             \
       return reloc;                                                    \
     }
 
-  CHECK_ ("hi0",    BFD_RELOC_HI16         );
-  CHECK_ ("hi",     BFD_RELOC_HI16_S       );
-  CHECK_ ("lo",     BFD_RELOC_LO16         );
+  CHECK_ ("hi0",    BFD_RELOC_HI16        );
+  CHECK_ ("hi",            BFD_RELOC_HI16_S       );
+  CHECK_ ("lo",            handle_lo16 (operand)  );
   CHECK_ ("sdaoff", handle_sdaoff (operand));
   CHECK_ ("zdaoff", handle_zdaoff (operand));
   CHECK_ ("tdaoff", handle_tdaoff (operand));
-  CHECK_ ("hilo",   BFD_RELOC_32           );
+  CHECK_ ("hilo",   BFD_RELOC_32          );
   CHECK_ ("ctoff",  handle_ctoff (operand) );
 
   /* Restore skipped parenthesis.  */
@@ -1581,13 +1469,12 @@ v850_reloc_prefix (const struct v850_operand *operand)
 /* 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;
+v850_insert_operand (unsigned long insn,
+                    const struct v850_operand *operand,
+                    offsetT val,
+                    char *file,
+                    unsigned int line,
+                    char *str)
 {
   if (operand->insert)
     {
@@ -1618,9 +1505,9 @@ v850_insert_operand (insn, operand, val, file, line, str)
          else
            {
              if (file == (char *) NULL)
-               as_warn (message);
+               as_warn ("%s", message);
              else
-               as_warn_where (file, line, message);
+               as_warn_where (file, line, "%s", message);
            }
        }
     }
@@ -1649,12 +1536,26 @@ v850_insert_operand (insn, operand, val, file, line, str)
                min = 0;
            }
 
-         if (val < (offsetT) min || val > (offsetT) max)
+         /* Some people write constants with the sign extension done by
+            hand but only up to 32 bits.  This shouldn't really be valid,
+            but, to permit this code to assemble on a 64-bit host, we
+            sign extend the 32-bit value to 64 bits if so doing makes the
+            value valid.  */
+         if (val > max
+             && (offsetT) (val - 0x80000000 - 0x80000000) >= min
+             && (offsetT) (val - 0x80000000 - 0x80000000) <= max)
+           val = val - 0x80000000 - 0x80000000;
+
+         /* Similarly, people write expressions like ~(1<<15), and expect
+            this to be OK for a 32-bit unsigned value.  */
+         else if (val < min
+                  && (offsetT) (val + 0x80000000 + 0x80000000) >= min
+                  && (offsetT) (val + 0x80000000 + 0x80000000) <= max)
+           val = val + 0x80000000 + 0x80000000;
+
+         else 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];
+             char buf [128];
 
              /* Restore min and mix to expected values for decimal ranges.  */
              if ((operand->flags & V850_OPERAND_SIGNED)
@@ -1666,18 +1567,12 @@ v850_insert_operand (insn, operand, val, file, line, str)
                min = 0;
 
              if (str)
-               {
-                 sprintf (buf, "%s: ", str);
-
-                 sprint_value (buf + strlen (buf), val);
-               }
+               sprintf (buf, "%s: ", str);
              else
-               sprint_value (buf, val);
+               buf[0] = 0;
+             strcat (buf, _("operand"));
 
-             if (file == (char *) NULL)
-               as_warn (err, buf, min, max);
-             else
-               as_warn_where (file, line, err, buf, min, max);
+             as_bad_value_out_of_range (buf, val, (offsetT) min, (offsetT) max, file, line);
            }
        }
 
@@ -1690,8 +1585,7 @@ v850_insert_operand (insn, operand, val, file, line, str)
 static char copy_of_instruction[128];
 
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
   char *s;
   char *start_of_operands;
@@ -1702,11 +1596,10 @@ md_assemble (str)
   int relaxable = 0;
   unsigned long insn;
   unsigned long insn_size;
-  unsigned long total_insn_size = 0;
   char *f;
   int i;
   int match;
-  boolean extra_data_after_insn = false;
+  bfd_boolean extra_data_after_insn = FALSE;
   unsigned extra_data_len = 0;
   unsigned long extra_data = 0;
   char *saved_input_line_pointer;
@@ -1714,7 +1607,7 @@ md_assemble (str)
   strncpy (copy_of_instruction, str, sizeof (copy_of_instruction) - 1);
 
   /* Get the opcode.  */
-  for (s = str; *s != '\0' && ! isspace (*s); s++)
+  for (s = str; *s != '\0' && ! ISSPACE (*s); s++)
     continue;
 
   if (*s != '\0')
@@ -1731,7 +1624,7 @@ md_assemble (str)
     }
 
   str = s;
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   start_of_operands = str;
@@ -1754,7 +1647,7 @@ md_assemble (str)
       fc = 0;
       next_opindex = 0;
       insn = opcode->opcode;
-      extra_data_after_insn = false;
+      extra_data_after_insn = FALSE;
 
       input_line_pointer = str = start_of_operands;
 
@@ -1766,9 +1659,7 @@ md_assemble (str)
          bfd_reloc_code_real_type reloc;
 
          if (next_opindex == 0)
-           {
-             operand = &v850_operands[*opindex_ptr];
-           }
+           operand = &v850_operands[*opindex_ptr];
          else
            {
              operand = &v850_operands[next_opindex];
@@ -1809,6 +1700,7 @@ md_assemble (str)
                      /* Fall through.  */
 
                    case BFD_RELOC_LO16:
+                   case BFD_RELOC_V850_LO16_SPLIT_OFFSET:
                      {
                        /* Truncate, then sign extend the value.  */
                        ex.X_add_number = SEXT16 (ex.X_add_number);
@@ -1840,10 +1732,9 @@ md_assemble (str)
                          goto error;
                        }
 
-                     extra_data_after_insn = true;
-                     extra_data_len        = 4;
-                     extra_data            = ex.X_add_number;
-                     ex.X_add_number       = 0;
+                     extra_data_after_insn = TRUE;
+                     extra_data_len        = 4;
+                     extra_data            = 0;
                      break;
 
                    default:
@@ -1870,9 +1761,9 @@ md_assemble (str)
                          goto error;
                        }
 
-                     extra_data_after_insn = true;
-                     extra_data_len        = 4;
-                     extra_data            = ex.X_add_number;
+                     extra_data_after_insn = TRUE;
+                     extra_data_len        = 4;
+                     extra_data            = ex.X_add_number;
                    }
 
                  if (fc > MAX_INSN_FIXUPS)
@@ -1891,9 +1782,7 @@ md_assemble (str)
              if ((operand->flags & V850_OPERAND_REG) != 0)
                {
                  if (!register_name (&ex))
-                   {
-                     errmsg = _("invalid register name");
-                   }
+                   errmsg = _("invalid register name");
                  else if ((operand->flags & V850_NOT_R0)
                           && ex.X_add_number == 0)
                    {
@@ -1907,10 +1796,8 @@ md_assemble (str)
                }
              else if ((operand->flags & V850_OPERAND_SRG) != 0)
                {
-                 if (!system_register_name (&ex, true, false))
-                   {
-                     errmsg = _("invalid system register name");
-                   }
+                 if (!system_register_name (&ex, TRUE, FALSE))
+                   errmsg = _("invalid system register name");
                }
              else if ((operand->flags & V850_OPERAND_EP) != 0)
                {
@@ -1938,9 +1825,7 @@ md_assemble (str)
              else if ((operand->flags & V850_OPERAND_CC) != 0)
                {
                  if (!cc_name (&ex))
-                   {
-                     errmsg = _("invalid condition code name");
-                   }
+                   errmsg = _("invalid condition code name");
                }
              else if (operand->flags & V850E_PUSH_POP)
                {
@@ -1948,7 +1833,7 @@ md_assemble (str)
 
                  /* The parse_register_list() function has already done
                     everything, so fake a dummy expression.  */
-                 ex.X_op         = O_constant;
+                 ex.X_op         = O_constant;
                  ex.X_add_number = 0;
                }
              else if (operand->flags & V850E_IMMEDIATE16)
@@ -1967,10 +1852,10 @@ md_assemble (str)
                        errmsg = _("constant too big to fit into instruction");
                    }
 
-                 extra_data_after_insn = true;
-                 extra_data_len        = 2;
-                 extra_data            = ex.X_add_number;
-                 ex.X_add_number       = 0;
+                 extra_data_after_insn = TRUE;
+                 extra_data_len        = 2;
+                 extra_data            = ex.X_add_number;
+                 ex.X_add_number       = 0;
                }
              else if (operand->flags & V850E_IMMEDIATE32)
                {
@@ -1979,10 +1864,10 @@ md_assemble (str)
                  if (ex.X_op != O_constant)
                    errmsg = _("constant expression expected");
 
-                 extra_data_after_insn = true;
-                 extra_data_len        = 4;
-                 extra_data            = ex.X_add_number;
-                 ex.X_add_number       = 0;
+                 extra_data_after_insn = TRUE;
+                 extra_data_len        = 4;
+                 extra_data            = ex.X_add_number;
+                 ex.X_add_number       = 0;
                }
              else if (register_name (&ex)
                       && (operand->flags & V850_OPERAND_REG) == 0)
@@ -2011,7 +1896,7 @@ md_assemble (str)
 
                  if (ex.X_op != O_constant)
                    {
-                     /* If this register is actually occuring too early on
+                     /* If this register is actually occurring too early on
                         the parsing of the instruction, (because another
                         field is missing) then report this.  */
                      if (opindex_ptr[1] != 0
@@ -2030,43 +1915,34 @@ md_assemble (str)
                                       &symbol_rootP, &symbol_lastP);
                    }
                }
-             else if (system_register_name (&ex, false, 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);
                  /* 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.  */
+                    If we are assembling a MOV instruction 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)
+                     && operand->bits == 5 /* Do not match the CALLT instruction.  */
                      && ex.X_op == O_constant
                      && (ex.X_add_number < (-(1 << (operand->bits - 1)))
-                         || ex.X_add_number > ((1 << operand->bits) - 1)))
+                         || ex.X_add_number > ((1 << (operand->bits - 1)) - 1)))
                    errmsg = _("immediate operand is too large");
                }
 
              if (errmsg)
                goto error;
 
-#if 0
-             fprintf (stderr,
-                      " insn: %x, operand %d, op: %d, add_number: %d\n",
-                      insn, opindex_ptr - opcode->operands,
-                      ex.X_op, ex.X_add_number);
-#endif
-
              switch (ex.X_op)
                {
                case O_illegal:
@@ -2083,14 +1959,12 @@ md_assemble (str)
                      goto error;
                    }
                  insn = v850_insert_operand (insn, operand, ex.X_add_number,
-                                             (char *) NULL, 0,
-                                             copy_of_instruction);
+                                             NULL, 0, copy_of_instruction);
                  break;
 
                case O_constant:
                  insn = v850_insert_operand (insn, operand, ex.X_add_number,
-                                             (char *) NULL, 0,
-                                             copy_of_instruction);
+                                             NULL, 0, copy_of_instruction);
                  break;
 
                default:
@@ -2144,7 +2018,7 @@ md_assemble (str)
       break;
     }
 
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   if (*str != '\0')
@@ -2153,10 +2027,29 @@ md_assemble (str)
 
   input_line_pointer = str;
 
+  /* Tie dwarf2 debug info to the address at the start of the insn.
+     We can't do this after the insn has been output as the current
+     frag may have been closed off.  eg. by frag_var.  */
+  dwarf2_emit_insn (0);
+
   /* Write out the instruction.  */
 
   if (relaxable && fc > 0)
     {
+      /* On a 64-bit host the size of an 'int' is not the same
+        as the size of a pointer, so we need a union to convert
+        the opindex field of the fr_cgen structure into a char *
+        so that it can be stored in the frag.  We do not have
+        to worry about loosing accuracy as we are not going to
+        be even close to the 32bit limit of the int.  */
+      union
+      {
+       int opindex;
+       char * ptr;
+      }
+      opindex_converter;
+
+      opindex_converter.opindex = fixups[0].opindex;
       insn_size = 2;
       fc = 0;
 
@@ -2165,7 +2058,7 @@ md_assemble (str)
          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);
+                       opindex_converter.ptr);
          md_number_to_chars (f, insn, insn_size);
          md_number_to_chars (f + 2, 0, 2);
        }
@@ -2174,11 +2067,10 @@ md_assemble (str)
          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);
+                       opindex_converter.ptr);
          md_number_to_chars (f, insn, insn_size);
          md_number_to_chars (f + 2, 0, 4);
        }
-      total_insn_size = insn_size;
     }
   else
     {
@@ -2193,18 +2085,14 @@ md_assemble (str)
        insn_size = 2;
 
       f = frag_more (insn_size);
-      total_insn_size = insn_size;
-
       md_number_to_chars (f, insn, insn_size);
 
       if (extra_data_after_insn)
        {
          f = frag_more (extra_data_len);
-         total_insn_size += extra_data_len;
-
          md_number_to_chars (f, extra_data, extra_data_len);
 
-         extra_data_after_insn = false;
+         extra_data_after_insn = FALSE;
        }
     }
 
@@ -2251,9 +2139,12 @@ md_assemble (str)
                              reloc_howto->pc_relative,
                              reloc);
 
+         fixP->tc_fix_data = (void *) operand;
+
          switch (reloc)
            {
            case BFD_RELOC_LO16:
+           case BFD_RELOC_V850_LO16_SPLIT_OFFSET:
            case BFD_RELOC_HI16:
            case BFD_RELOC_HI16_S:
              fixP->fx_no_overflow = 1;
@@ -2267,34 +2158,46 @@ md_assemble (str)
          fix_new_exp (frag_now,
                       f - frag_now->fr_literal, 4,
                       & fixups[i].exp,
-                      1 /* FIXME: V850_OPERAND_RELATIVE ???  */,
+                      (operand->flags & V850_OPERAND_DISP) != 0,
                       (bfd_reloc_code_real_type) (fixups[i].opindex
                                                   + (int) BFD_RELOC_UNUSED));
        }
     }
 
   input_line_pointer = saved_input_line_pointer;
-
-  dwarf2_emit_insn (total_insn_size);
 }
 
 /* If while processing a fixup, a reloc really needs to be created
    then it is done here.  */
 
 arelent *
-tc_gen_reloc (seg, fixp)
-     asection *seg ATTRIBUTE_UNUSED;
-     fixS *fixp;
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *reloc;
 
-  reloc               = (arelent *) xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr  = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc                      = xmalloc (sizeof (arelent));
+  reloc->sym_ptr_ptr  = 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)
+  if (   fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_V850_LONGCALL
+      || fixp->fx_r_type == BFD_RELOC_V850_LONGJUMP
+      || fixp->fx_r_type == BFD_RELOC_V850_ALIGN)
+    reloc->addend = fixp->fx_offset;
+  else
+    {
+      if (fixp->fx_r_type == BFD_RELOC_32
+         && fixp->fx_pcrel)
+       fixp->fx_r_type = BFD_RELOC_32_PCREL;
+
+      reloc->addend = fixp->fx_addnumber;
+    }
+
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+
+  if (reloc->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    /* xgettext:c-format  */
@@ -2306,35 +2209,37 @@ tc_gen_reloc (seg, fixp)
       return NULL;
     }
 
-  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;
 }
 
-/* Assume everything will fit in two bytes, then expand as necessary.  */
+void
+v850_handle_align (fragS * frag)
+{
+  if (v850_relax
+      && frag->fr_type == rs_align
+      && frag->fr_address + frag->fr_fix > 0
+      && frag->fr_offset > 1
+      && now_seg != bss_section
+      && now_seg != v850_seg_table[SBSS_SECTION].s
+      && now_seg != v850_seg_table[TBSS_SECTION].s
+      && now_seg != v850_seg_table[ZBSS_SECTION].s)
+    fix_new (frag, frag->fr_fix, 2, & abs_symbol, frag->fr_offset, 0,
+            BFD_RELOC_V850_ALIGN);
+}
+
+/* Return current size of variable part of frag.  */
 
 int
-md_estimate_size_before_relax (fragp, seg)
-     fragS *fragp;
-     asection *seg ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS *fragp, asection *seg ATTRIBUTE_UNUSED)
 {
-  if (fragp->fr_subtype == 0)
-    fragp->fr_var = 4;
-  else if (fragp->fr_subtype == 2)
-    fragp->fr_var = 2;
-  else
+  if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
     abort ();
-  return 2;
+
+  return md_relax_table[fragp->fr_subtype].rlx_length;
 }
 
 long
-v850_pcrel_from_section (fixp, section)
-     fixS *fixp;
-     segT section;
+v850_pcrel_from_section (fixS *fixp, segT section)
 {
   /* If the symbol is undefined, or in a section other than our own,
      or it is weak (in which case it may well be in another section,
@@ -2348,114 +2253,134 @@ v850_pcrel_from_section (fixp, section)
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
-int
-md_apply_fix3 (fixp, valuep, seg)
-     fixS *fixp;
-     valueT *valuep;
-     segT seg ATTRIBUTE_UNUSED;
+void
+md_apply_fix (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
 {
-  valueT value;
+  valueT value = * valueP;
   char *where;
 
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+  if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixP->fx_r_type == BFD_RELOC_V850_LONGCALL
+      || fixP->fx_r_type == BFD_RELOC_V850_LONGJUMP
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     {
-      fixp->fx_done = 0;
-      return 1;
+      fixP->fx_done = 0;
+      return;
     }
 
-  if (fixp->fx_addsy == (symbolS *) NULL)
-    {
-      value = *valuep;
-      fixp->fx_done = 1;
-    }
-  else if (fixp->fx_pcrel)
-    value = *valuep;
+  if (fixP->fx_addsy == (symbolS *) NULL)
+    fixP->fx_addnumber = value,
+    fixP->fx_done = 1;
+
+  else if (fixP->fx_pcrel)
+    fixP->fx_addnumber = fixP->fx_offset;
+
   else
     {
-      value = fixp->fx_offset;
-      if (fixp->fx_subsy != (symbolS *) NULL)
+      value = fixP->fx_offset;
+      if (fixP->fx_subsy != (symbolS *) NULL)
        {
-         if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
-           value -= S_GET_VALUE (fixp->fx_subsy);
+         if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
+           value -= S_GET_VALUE (fixP->fx_subsy);
          else
-           {
-             /* We don't actually support subtracting a symbol.  */
-             as_bad_where (fixp->fx_file, fixp->fx_line,
-                           _("expression too complex"));
-           }
+           /* We don't actually support subtracting a symbol.  */
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("expression too complex"));
        }
+      fixP->fx_addnumber = value;
     }
 
-  if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED)
+  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
       int opindex;
       const struct v850_operand *operand;
       unsigned long insn;
 
-      opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
+      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
       operand = &v850_operands[opindex];
 
       /* Fetch the instruction, insert the fully resolved operand
-         value, and stuff the instruction back again.
+        value, and stuff the instruction back again.
 
         Note the instruction has been stored in little endian
         format!  */
-      where = fixp->fx_frag->fr_literal + fixp->fx_where;
+      where = fixP->fx_frag->fr_literal + fixP->fx_where;
 
       insn = bfd_getl32 ((unsigned char *) where);
       insn = v850_insert_operand (insn, operand, (offsetT) value,
-                                 fixp->fx_file, fixp->fx_line, NULL);
+                                 fixP->fx_file, fixP->fx_line, NULL);
       bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
 
-      if (fixp->fx_done)
-       {
-         /* Nothing else to do here.  */
-         return 1;
-       }
+      if (fixP->fx_done)
+       /* Nothing else to do here.  */
+       return;
 
       /* Determine a BFD reloc value based on the operand information.
         We are only prepared to turn a few of the operands into relocs.  */
 
       if (operand->bits == 22)
-       fixp->fx_r_type = BFD_RELOC_V850_22_PCREL;
+       fixP->fx_r_type = BFD_RELOC_V850_22_PCREL;
       else if (operand->bits == 9)
-       fixp->fx_r_type = BFD_RELOC_V850_9_PCREL;
+       fixP->fx_r_type = BFD_RELOC_V850_9_PCREL;
       else
        {
-#if 0
-         fprintf (stderr, "bits: %d, insn: %x\n", operand->bits, insn);
-#endif
-
-         as_bad_where (fixp->fx_file, fixp->fx_line,
+         as_bad_where (fixP->fx_file, fixP->fx_line,
                        _("unresolved expression that must be resolved"));
-         fixp->fx_done = 1;
-         return 1;
+         fixP->fx_done = 1;
+         return;
        }
     }
-  else if (fixp->fx_done)
+  else if (fixP->fx_done)
     {
       /* 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;
-      else if (fixp->fx_size == 2)
-       bfd_putl16 (value & 0xffff, (unsigned char *) where);
-      else if (fixp->fx_size == 4)
-       bfd_putl32 (value, (unsigned char *) where);
-    }
+      where = fixP->fx_frag->fr_literal + fixP->fx_where;
 
-  fixp->fx_addnumber = value;
-  return 1;
+      if (fixP->tc_fix_data != NULL
+         && ((struct v850_operand *) fixP->tc_fix_data)->insert != NULL)
+       {
+         const char * message = NULL;
+         struct v850_operand * operand = (struct v850_operand *) fixP->tc_fix_data;
+         unsigned long insn;
+
+         /* The variable "where" currently points at the exact point inside
+            the insn where we need to insert the value.  But we need to
+            extract the entire insn so we probably need to move "where"
+            back a few bytes.  */
+         if (fixP->fx_size == 2)
+           where -= 2;
+         else if (fixP->fx_size == 1)
+           where -= 3;
+
+         insn = bfd_getl32 ((unsigned char *) where);
+
+         /* Use the operand's insertion procedure, if present, in order to
+            make sure that the value is correctly stored in the insn.  */
+         insn = operand->insert (insn, (offsetT) value, & message);
+         /* Ignore message even if it is set.  */
+
+         bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+       }
+      else
+       {
+         if (fixP->fx_r_type == BFD_RELOC_V850_LO16_SPLIT_OFFSET)
+           bfd_putl32 (((value << 16) & 0xfffe0000)
+                       | ((value << 5) & 0x20)
+                       | (bfd_getl32 (where) & ~0xfffe0020), where);
+         else if (fixP->fx_size == 1)
+           *where = value & 0xff;
+         else if (fixP->fx_size == 2)
+           bfd_putl16 (value & 0xffff, (unsigned char *) where);
+         else if (fixP->fx_size == 4)
+           bfd_putl32 (value, (unsigned char *) where);
+       }
+    }
 }
 \f
 /* Parse a cons expression.  We have to handle hi(), lo(), etc
    on the v850.  */
 
 void
-parse_cons_expression_v850 (exp)
-     expressionS *exp;
+parse_cons_expression_v850 (expressionS *exp)
 {
   /* See if there's a reloc prefix like hi() we have to handle.  */
   hold_cons_reloc = v850_reloc_prefix (NULL);
@@ -2469,11 +2394,10 @@ parse_cons_expression_v850 (exp)
    appropriate one based on the size of the expression.  */
 
 void
-cons_fix_new_v850 (frag, where, size, exp)
-     fragS *frag;
-     int where;
-     int size;
-     expressionS *exp;
+cons_fix_new_v850 (fragS *frag,
+                  int where,
+                  int size,
+                  expressionS *exp)
 {
   if (hold_cons_reloc == BFD_RELOC_UNUSED)
     {
@@ -2493,21 +2417,12 @@ cons_fix_new_v850 (frag, where, size, exp)
   hold_cons_reloc = BFD_RELOC_UNUSED;
 }
 
-boolean
-v850_fix_adjustable (fixP)
-     fixS *fixP;
+bfd_boolean
+v850_fix_adjustable (fixS *fixP)
 {
   if (fixP->fx_addsy == NULL)
     return 1;
 
-  /* Prevent all adjustments to global symbols.  */
-  if (S_IS_EXTERN (fixP->fx_addsy))
-    return 0;
-
-  /* Similarly for weak symbols.  */
-  if (S_IS_WEAK (fixP->fx_addsy))
-    return 0;
-
   /* Don't adjust function names.  */
   if (S_IS_FUNCTION (fixP->fx_addsy))
     return 0;
@@ -2521,15 +2436,19 @@ v850_fix_adjustable (fixP)
 }
 
 int
-v850_force_relocation (fixP)
-     struct fix *fixP;
+v850_force_relocation (struct fix *fixP)
 {
-  if (fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy))
+  if (fixP->fx_r_type == BFD_RELOC_V850_LONGCALL
+      || fixP->fx_r_type == BFD_RELOC_V850_LONGJUMP)
     return 1;
 
-  if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+  if (v850_relax
+      && (fixP->fx_pcrel
+         || fixP->fx_r_type == BFD_RELOC_V850_ALIGN
+         || fixP->fx_r_type == BFD_RELOC_V850_22_PCREL
+         || fixP->fx_r_type == BFD_RELOC_V850_9_PCREL
+         || fixP->fx_r_type >= BFD_RELOC_UNUSED))
     return 1;
 
-  return 0;
+  return generic_force_reloc (fixP);
 }