Fix overflow detection in the Z80 assembler.
[binutils-gdb.git] / gas / config / tc-mn10200.c
index 7bbc5725710e0bd538470bbe4ec5f61d93bda607..6323e54dc27091e0c4f821d2943983f83d3c4b64 100644 (file)
@@ -1,12 +1,11 @@
 /* tc-mn10200.c -- Assembler code for the Matsushita 10200
 /* tc-mn10200.c -- Assembler code for the Matsushita 10200
-
-   Copyright (C) 1996, 1997 Free Software Foundation.
+   Copyright (C) 1996-2021 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
 
    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,
    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
 
    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 "as.h"
-#include "subsegs.h"     
+#include "safe-ctype.h"
+#include "subsegs.h"
 #include "opcode/mn10200.h"
 \f
 /* Structure to hold information about predefined registers.  */
 #include "opcode/mn10200.h"
 \f
 /* Structure to hold information about predefined registers.  */
@@ -32,75 +30,69 @@ struct reg_name
   int value;
 };
 
   int value;
 };
 
-/* Generic assembler global variables which must be defined by all targets. */
+/* Generic assembler global variables which must be defined by all
+   targets.  */
 
 
-/* Characters which always start a comment. */
+/* Characters which always start a comment.  */
 const char comment_chars[] = "#";
 
 /* Characters which start a comment at the beginning of a line.  */
 const char line_comment_chars[] = ";#";
 
 const char comment_chars[] = "#";
 
 /* Characters which start a comment at the beginning of a line.  */
 const char line_comment_chars[] = ";#";
 
-/* Characters which may be used to separate multiple commands on a 
+/* Characters which may be used to separate multiple commands on a
    single line.  */
 const char line_separator_chars[] = ";";
 
    single line.  */
 const char line_separator_chars[] = ";";
 
-/* Characters which are used to indicate an exponent in a floating 
+/* Characters which are used to indicate an exponent in a floating
    point number.  */
 const char EXP_CHARS[] = "eE";
 
    point number.  */
 const char EXP_CHARS[] = "eE";
 
-/* Characters which mean that a number is a floating point constant, 
+/* Characters which mean that a number is a floating point constant,
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 \f
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 \f
-
-const relax_typeS md_relax_table[] = {
-  /* bCC relaxing */
-  {0x7f, -0x80, 2, 1},
-  {0x7fff, -0x8000, 5, 2},
-  {0x7fffff, -0x8000000, 7, 0},
-  /* bCCx relaxing */
-  {0x7f, -0x80, 3, 4},
-  {0x7fff, -0x8000, 6, 5},
-  {0x7fffff, -0x8000000, 8, 0},
-  /* jsr relaxing */
-  {0x7fff, -0x8000, 3, 7},
-  {0x7fffff, -0x8000000, 5, 0},
-  /* jmp relaxing */
-  {0x7f, -0x80, 2, 9},
-  {0x7fff, -0x8000, 3, 10},
-  {0x7fffff, -0x8000000, 5, 0},
+const relax_typeS md_relax_table[] =
+ {
+  /* bCC relaxing  */
+  {0x81, -0x7e, 2, 1},
+  {0x8004, -0x7ffb, 5, 2},
+  {0x800006, -0x7ffff9, 7, 0},
+  /* bCCx relaxing  */
+  {0x81, -0x7e, 3, 4},
+  {0x8004, -0x7ffb, 6, 5},
+  {0x800006, -0x7ffff9, 8, 0},
+  /* jsr relaxing  */
+  {0x8004, -0x7ffb, 3, 7},
+  {0x800006, -0x7ffff9, 5, 0},
+  /* jmp relaxing  */
+  {0x81, -0x7e, 2, 9},
+  {0x8004, -0x7ffb, 3, 10},
+  {0x800006, -0x7ffff9, 5, 0},
 
 };
 
 };
-/* local functions */
-static void mn10200_insert_operand PARAMS ((unsigned long *, unsigned long *,
-                                           const struct mn10200_operand *,
-                                           offsetT, char *, unsigned,
-                                           unsigned));
-static unsigned long check_operand PARAMS ((unsigned long,
-                                           const struct mn10200_operand *,
-                                           offsetT));
-static int reg_name_search PARAMS ((const struct reg_name *, int, const char *));
-static boolean data_register_name PARAMS ((expressionS *expressionP));
-static boolean address_register_name PARAMS ((expressionS *expressionP));
-static boolean other_register_name PARAMS ((expressionS *expressionP));
-
-
-/* fixups */
-#define MAX_INSN_FIXUPS (5)
+
+
+/* Fixups.  */
+#define MAX_INSN_FIXUPS 5
+
 struct mn10200_fixup
 {
   expressionS exp;
   int opindex;
   bfd_reloc_code_real_type reloc;
 };
 struct mn10200_fixup
 {
   expressionS exp;
   int opindex;
   bfd_reloc_code_real_type reloc;
 };
+
 struct mn10200_fixup fixups[MAX_INSN_FIXUPS];
 static int fc;
 \f
 const char *md_shortopts = "";
 struct mn10200_fixup fixups[MAX_INSN_FIXUPS];
 static int fc;
 \f
 const char *md_shortopts = "";
-struct option md_longopts[] = {
+
+struct option md_longopts[] =
+{
   {NULL, no_argument, NULL, 0}
 };
   {NULL, no_argument, NULL, 0}
 };
-size_t md_longopts_size = sizeof(md_longopts); 
+
+size_t md_longopts_size = sizeof (md_longopts);
 
 /* The target specific pseudo-ops which we support.  */
 const pseudo_typeS md_pseudo_table[] =
 
 /* The target specific pseudo-ops which we support.  */
 const pseudo_typeS md_pseudo_table[] =
@@ -109,9 +101,9 @@ const pseudo_typeS md_pseudo_table[] =
 };
 
 /* Opcode hash table.  */
 };
 
 /* Opcode hash table.  */
-static struct hash_control *mn10200_hash;
+static htab_t mn10200_hash;
 
 
-/* This table is sorted. Suitable for searching by a binary search. */
+/* This table is sorted. Suitable for searching by a binary search.  */
 static const struct reg_name data_registers[] =
 {
   { "d0", 0 },
 static const struct reg_name data_registers[] =
 {
   { "d0", 0 },
@@ -119,7 +111,8 @@ static const struct reg_name data_registers[] =
   { "d2", 2 },
   { "d3", 3 },
 };
   { "d2", 2 },
   { "d3", 3 },
 };
-#define DATA_REG_NAME_CNT      (sizeof(data_registers) / sizeof(struct reg_name))
+#define DATA_REG_NAME_CNT                              \
+  (sizeof (data_registers) / sizeof (struct reg_name))
 
 static const struct reg_name address_registers[] =
 {
 
 static const struct reg_name address_registers[] =
 {
@@ -128,24 +121,25 @@ static const struct reg_name address_registers[] =
   { "a2", 2 },
   { "a3", 3 },
 };
   { "a2", 2 },
   { "a3", 3 },
 };
-#define ADDRESS_REG_NAME_CNT   (sizeof(address_registers) / sizeof(struct reg_name))
+#define ADDRESS_REG_NAME_CNT                                   \
+  (sizeof (address_registers) / sizeof (struct reg_name))
 
 static const struct reg_name other_registers[] =
 {
   { "mdr", 0 },
   { "psw", 0 },
 };
 
 static const struct reg_name other_registers[] =
 {
   { "mdr", 0 },
   { "psw", 0 },
 };
-#define OTHER_REG_NAME_CNT     (sizeof(other_registers) / sizeof(struct reg_name))
+#define OTHER_REG_NAME_CNT                             \
+  (sizeof (other_registers) / sizeof (struct reg_name))
 
 /* reg_name_search does a binary search of the given register table
 
 /* reg_name_search does a binary search of the given register table
-   to see if "name" is a valid regiter name.  Returns the register
-   number from the array on success, or -1 on failure. */
+   to see if "name" is a valid register name.  Returns the register
+   number from the array on success, or -1 on failure.  */
 
 static int
 
 static int
-reg_name_search (regs, regcount, name)
-     const struct reg_name *regs;
-     int regcount;
-     const char *name;
+reg_name_search (const struct reg_name *regs,
+                int regcount,
+                const char *name)
 {
   int middle, low, high;
   int cmp;
 {
   int middle, low, high;
   int cmp;
@@ -161,228 +155,184 @@ reg_name_search (regs, regcount, name)
        high = middle - 1;
       else if (cmp > 0)
        low = middle + 1;
        high = middle - 1;
       else if (cmp > 0)
        low = middle + 1;
-      else 
-         return regs[middle].value;
+      else
+       return regs[middle].value;
     }
   while (low <= high);
   return -1;
 }
 
     }
   while (low <= high);
   return -1;
 }
 
-
 /* Summary of register_name().
 /* 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
-data_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 bool
+data_register_name (expressionS *expressionP)
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
-  /* Find the spelling of the operand */
-  start = name = input_line_pointer;
-
-  c = get_symbol_end ();
+  /* Find the spelling of the operand.  */
+  start = input_line_pointer;
+  c = get_symbol_name (&name);
   reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
 
   reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
 
-  /* look to see if it's in the register table */
-  if (reg_number >= 0) 
+  /* Put back the delimiting char.  */
+  (void) restore_line_pointer (c);
+
+  /* Look to see if it's in the register table.  */
+  if (reg_number >= 0)
     {
       expressionP->X_op = O_register;
       expressionP->X_add_number = reg_number;
 
     {
       expressionP->X_op = O_register;
       expressionP->X_add_number = reg_number;
 
-      /* make the rest nice */
+      /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
-      *input_line_pointer = c; /* put back the delimiting char */
+
       return true;
     }
       return true;
     }
-  else
-    {
-      /* reset the line as if we had not done anything */
-      *input_line_pointer = c;   /* put back the delimiting char */
-      input_line_pointer = start; /* reset input_line pointer */
-      return false;
-    }
+
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return false;
 }
 
 /* Summary of register_name().
 }
 
 /* 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
-address_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 bool
+address_register_name (expressionS *expressionP)
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
-  /* Find the spelling of the operand */
-  start = name = input_line_pointer;
-
-  c = get_symbol_end ();
+  /* Find the spelling of the operand.  */
+  start = input_line_pointer;
+  c = get_symbol_name (&name);
   reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name);
 
   reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name);
 
-  /* look to see if it's in the register table */
-  if (reg_number >= 0) 
+  /* Put back the delimiting char.  */
+  (void) restore_line_pointer (c);
+
+  /* Look to see if it's in the register table.  */
+  if (reg_number >= 0)
     {
       expressionP->X_op = O_register;
       expressionP->X_add_number = reg_number;
 
     {
       expressionP->X_op = O_register;
       expressionP->X_add_number = reg_number;
 
-      /* make the rest nice */
+      /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
-      *input_line_pointer = c; /* put back the delimiting char */
+
       return true;
     }
       return true;
     }
-  else
-    {
-      /* reset the line as if we had not done anything */
-      *input_line_pointer = c;   /* put back the delimiting char */
-      input_line_pointer = start; /* reset input_line pointer */
-      return false;
-    }
+
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return false;
 }
 
 /* Summary of register_name().
 }
 
 /* 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
-other_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 bool
+other_register_name (expressionS *expressionP)
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
-  /* Find the spelling of the operand */
-  start = name = input_line_pointer;
-
-  c = get_symbol_end ();
+  /* Find the spelling of the operand.  */
+  start = input_line_pointer;
+  c = get_symbol_name (&name);
   reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
 
   reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
 
-  /* look to see if it's in the register table */
-  if (reg_number >= 0) 
+  /* Put back the delimiting char.  */
+  (void) restore_line_pointer (c);
+
+  /* Look to see if it's in the register table.  */
+  if (reg_number >= 0)
     {
       expressionP->X_op = O_register;
       expressionP->X_add_number = reg_number;
 
     {
       expressionP->X_op = O_register;
       expressionP->X_add_number = reg_number;
 
-      /* make the rest nice */
+      /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
-      *input_line_pointer = c; /* put back the delimiting char */
+
       return true;
     }
       return true;
     }
-  else
-    {
-      /* reset the line as if we had not done anything */
-      *input_line_pointer = c;   /* put back the delimiting char */
-      input_line_pointer = start; /* reset input_line pointer */
-      return false;
-    }
+
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return false;
 }
 
 void
 }
 
 void
-md_show_usage (stream)
-  FILE *stream;
+md_show_usage (FILE *stream)
 {
 {
-  fprintf(stream, "MN10200 options:\n\
-none yet\n");
-} 
+  fprintf (stream, _("MN10200 options:\n\
+none yet\n"));
+}
 
 int
 
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+md_parse_option (int c ATTRIBUTE_UNUSED,
+                const char *arg ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 symbolS *
 {
   return 0;
 }
 
 symbolS *
-md_undefined_symbol (name)
-  char *name;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 {
   return 0;
 }
 
-char *
-md_atof (type, litp, sizep)
-  int type;
-  char *litp;
-  int *sizep;
+const char *
+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);
 }
 
 }
 
-
 void
 void
-md_convert_frag (abfd, sec, fragP)
-  bfd *abfd;
-  asection *sec;
-  fragS *fragP;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+                asection *sec,
+                fragS *fragP)
 {
 {
+  static unsigned long label_count = 0;
+  char buf[40];
+
   subseg_change (sec, 0);
   if (fragP->fr_subtype == 0)
     {
       fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
   subseg_change (sec, 0);
   if (fragP->fr_subtype == 0)
     {
       fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
-              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 2;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 2;
     }
@@ -429,15 +379,17 @@ md_convert_frag (abfd, sec, fragP)
        }
       fragP->fr_literal[offset] = opcode;
 
        }
       fragP->fr_literal[offset] = opcode;
 
-      /* Set the displacement bits so that we branch around
-        the unconditional branch.  */
-      fragP->fr_literal[offset + 1] = 0x5;
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 1, 1,
+              symbol_new (buf, sec, fragP->fr_next, 0),
+              fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 2] = 0xfc;
       fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 2] = 0xfc;
       fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
-              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
@@ -484,23 +436,25 @@ md_convert_frag (abfd, sec, fragP)
        }
       fragP->fr_literal[offset] = opcode;
 
        }
       fragP->fr_literal[offset] = opcode;
 
-      /* Set the displacement bits so that we branch around
-        the unconditional branch.  */
-      fragP->fr_literal[offset + 1] = 0x7;
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 1, 1,
+              symbol_new (buf, sec, fragP->fr_next, 0),
+              fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 2] = 0xf4;
       fragP->fr_literal[offset + 3] = 0xe0;
       fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 2] = 0xf4;
       fragP->fr_literal[offset + 3] = 0xe0;
       fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
-              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 7;
     }
   else if (fragP->fr_subtype == 3)
     {
       fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
       fragP->fr_var = 0;
       fragP->fr_fix += 7;
     }
   else if (fragP->fr_subtype == 3)
     {
       fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
-              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
     }
@@ -523,6 +477,7 @@ md_convert_frag (abfd, sec, fragP)
          break;
        case 0xff:
          opcode = 0xfe;
          break;
        case 0xff:
          opcode = 0xfe;
+         break;
        case 0xe8:
          opcode = 0xe9;
          break;
        case 0xe8:
          opcode = 0xe9;
          break;
@@ -570,15 +525,17 @@ md_convert_frag (abfd, sec, fragP)
        }
       fragP->fr_literal[offset + 1] = opcode;
 
        }
       fragP->fr_literal[offset + 1] = opcode;
 
-      /* Set the displacement bits so that we branch around
-        the unconditional branch.  */
-      fragP->fr_literal[offset + 2] = 0x6;
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 2, 1,
+              symbol_new (buf, sec, fragP->fr_next, 0),
+              fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 3] = 0xfc;
       fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 3] = 0xfc;
       fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
-              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 6;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 6;
     }
@@ -601,6 +558,7 @@ md_convert_frag (abfd, sec, fragP)
          break;
        case 0xff:
          opcode = 0xfe;
          break;
        case 0xff:
          opcode = 0xfe;
+         break;
        case 0xe8:
          opcode = 0xe9;
          break;
        case 0xe8:
          opcode = 0xe9;
          break;
@@ -648,23 +606,25 @@ md_convert_frag (abfd, sec, fragP)
        }
       fragP->fr_literal[offset + 1] = opcode;
 
        }
       fragP->fr_literal[offset + 1] = opcode;
 
-      /* Set the displacement bits so that we branch around
-        the unconditional branch.  */
-      fragP->fr_literal[offset + 2] = 0x8;
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 2, 1,
+              symbol_new (buf, sec, fragP->fr_next, 0),
+              fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 3] = 0xf4;
       fragP->fr_literal[offset + 4] = 0xe0;
       fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol,
 
       /* Now create the unconditional branch + fixup to the
         final target.  */
       fragP->fr_literal[offset + 3] = 0xf4;
       fragP->fr_literal[offset + 4] = 0xe0;
       fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol,
-              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 8;
     }
   else if (fragP->fr_subtype == 6)
     {
       fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
       fragP->fr_var = 0;
       fragP->fr_fix += 8;
     }
   else if (fragP->fr_subtype == 6)
     {
       fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
-              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
     }
@@ -675,7 +635,7 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_literal[offset + 1] = 0xe1;
 
       fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
       fragP->fr_literal[offset + 1] = 0xe1;
 
       fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
-              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
@@ -683,7 +643,7 @@ md_convert_frag (abfd, sec, fragP)
     {
       fragP->fr_literal[fragP->fr_fix] = 0xea;
       fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
     {
       fragP->fr_literal[fragP->fr_fix] = 0xea;
       fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
-              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 2;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 2;
     }
@@ -693,7 +653,7 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_literal[offset] = 0xfc;
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
       fragP->fr_literal[offset] = 0xfc;
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
-              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
     }
@@ -704,7 +664,7 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_literal[offset + 1] = 0xe0;
 
       fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
       fragP->fr_literal[offset + 1] = 0xe0;
 
       fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
-              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+              fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
@@ -713,21 +673,19 @@ md_convert_frag (abfd, sec, fragP)
 }
 
 valueT
 }
 
 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));
+  int align = bfd_section_alignment (seg);
+  return ((addr + (1 << align) - 1) & -(1 << align));
 }
 
 void
 }
 
 void
-md_begin ()
+md_begin (void)
 {
 {
-  char *prev_name = "";
-  register const struct mn10200_opcode *op;
+  const char *prev_name = "";
+  const struct mn10200_opcode *op;
 
 
-  mn10200_hash = hash_new();
+  mn10200_hash = str_htab_create ();
 
   /* Insert unique names into hash table.  The MN10200 instruction set
      has many identical opcode names that have different opcodes based
 
   /* Insert unique names into hash table.  The MN10200 instruction set
      has many identical opcode names that have different opcodes based
@@ -737,10 +695,10 @@ md_begin ()
   op = mn10200_opcodes;
   while (op->name)
     {
   op = mn10200_opcodes;
   while (op->name)
     {
-      if (strcmp (prev_name, op->name)) 
+      if (strcmp (prev_name, op->name))
        {
          prev_name = (char *) op->name;
        {
          prev_name = (char *) op->name;
-         hash_insert (mn10200_hash, op->name, (char *) op);
+         str_hash_insert (mn10200_hash, op->name, op, 0);
        }
       op++;
     }
        }
       op++;
     }
@@ -751,9 +709,169 @@ md_begin ()
   linkrelax = 1;
 }
 
   linkrelax = 1;
 }
 
+static unsigned long
+check_operand (unsigned long insn ATTRIBUTE_UNUSED,
+              const struct mn10200_operand *operand,
+              offsetT val)
+{
+  /* No need to check 24bit or 32bit operands for a bit.  */
+  if (operand->bits < 24
+      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
+    {
+      long min, max;
+      offsetT test;
+
+      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
+       {
+         max = (1 << (operand->bits - 1)) - 1;
+         min = - (1 << (operand->bits - 1));
+       }
+      else
+       {
+         max = (1 << operand->bits) - 1;
+         min = 0;
+       }
+
+      test = val;
+
+      if (test < (offsetT) min || test > (offsetT) max)
+       return 0;
+      else
+       return 1;
+    }
+  return 1;
+}
+/* If while processing a fixup, a reloc really needs to be created
+   Then it is done here.  */
+
+arelent *
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
+{
+  arelent *reloc;
+  reloc = XNEW (arelent);
+
+  if (fixp->fx_subsy != NULL)
+    {
+      if (S_GET_SEGMENT (fixp->fx_addsy) == S_GET_SEGMENT (fixp->fx_subsy)
+         && S_IS_DEFINED (fixp->fx_subsy))
+       {
+         fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
+         fixp->fx_subsy = NULL;
+       }
+      else
+       /* FIXME: We should try more ways to resolve difference expressions
+          here.  At least this is better than silently ignoring the
+          subtrahend.  */
+       as_bad_where (fixp->fx_file, fixp->fx_line,
+                     _("can't resolve `%s' {%s section} - `%s' {%s section}"),
+                     fixp->fx_addsy ? S_GET_NAME (fixp->fx_addsy) : "0",
+                     segment_name (fixp->fx_addsy
+                                   ? S_GET_SEGMENT (fixp->fx_addsy)
+                                   : absolute_section),
+                     S_GET_NAME (fixp->fx_subsy),
+                     segment_name (S_GET_SEGMENT (fixp->fx_addsy)));
+    }
+
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+  if (reloc->howto == NULL)
+    {
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                   _("reloc %d not supported by object file format"),
+                   (int) fixp->fx_r_type);
+      return NULL;
+    }
+  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+  reloc->addend = fixp->fx_offset;
+  return reloc;
+}
+
+int
+md_estimate_size_before_relax (fragS *fragp, asection *seg)
+{
+  if (fragp->fr_subtype == 6
+      && (!S_IS_DEFINED (fragp->fr_symbol)
+         || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+    fragp->fr_subtype = 7;
+  else if (fragp->fr_subtype == 8
+          && (!S_IS_DEFINED (fragp->fr_symbol)
+              || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+    fragp->fr_subtype = 10;
+
+  if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
+    abort ();
+
+  return md_relax_table[fragp->fr_subtype].rlx_length;
+}
+
+long
+md_pcrel_from (fixS *fixp)
+{
+  return fixp->fx_frag->fr_address;
+}
+
+void
+md_apply_fix (fixS * fixP, valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
+{
+  /* We shouldn't ever get here because linkrelax is nonzero.  */
+  abort ();
+  fixP->fx_done = 1;
+}
+
+/* Insert an operand value into an instruction.  */
+
+static void
+mn10200_insert_operand (unsigned long *insnp,
+                       unsigned long *extensionp,
+                       const struct mn10200_operand *operand,
+                       offsetT val,
+                       char *file,
+                       unsigned int line,
+                       unsigned int shift)
+{
+  /* No need to check 24 or 32bit operands for a bit.  */
+  if (operand->bits < 24
+      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
+    {
+      long min, max;
+      offsetT test;
+
+      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
+       {
+         max = (1 << (operand->bits - 1)) - 1;
+         min = - (1 << (operand->bits - 1));
+       }
+      else
+       {
+         max = (1 << operand->bits) - 1;
+         min = 0;
+       }
+
+      test = val;
+
+      if (test < (offsetT) min || test > (offsetT) max)
+       as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
+    }
+
+  if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0)
+    {
+      *insnp |= (((long) val & ((1 << operand->bits) - 1))
+                << (operand->shift + shift));
+
+      if ((operand->flags & MN10200_OPERAND_REPEATED) != 0)
+       *insnp |= (((long) val & ((1 << operand->bits) - 1))
+                  << (operand->shift + shift + 2));
+    }
+  else
+    {
+      *extensionp |= (val >> 16) & 0xff;
+      *insnp |= val & 0xffff;
+    }
+}
+
 void
 void
-md_assemble (str) 
-     char *str;
+md_assemble (char *str)
 {
   char *s;
   struct mn10200_opcode *opcode;
 {
   char *s;
   struct mn10200_opcode *opcode;
@@ -766,26 +884,26 @@ md_assemble (str)
   int match;
 
   /* Get the opcode.  */
   int match;
 
   /* Get the opcode.  */
-  for (s = str; *s != '\0' && ! isspace (*s); s++)
+  for (s = str; *s != '\0' && !ISSPACE (*s); s++)
     ;
   if (*s != '\0')
     *s++ = '\0';
 
     ;
   if (*s != '\0')
     *s++ = '\0';
 
-  /* find the first opcode with the proper name */
-  opcode = (struct mn10200_opcode *)hash_find (mn10200_hash, str);
+  /* Find the first opcode with the proper name.  */
+  opcode = (struct mn10200_opcode *) str_hash_find (mn10200_hash, str);
   if (opcode == NULL)
     {
   if (opcode == NULL)
     {
-      as_bad ("Unrecognized opcode: `%s'", str);
+      as_bad (_("Unrecognized opcode: `%s'"), str);
       return;
     }
 
   str = s;
       return;
     }
 
   str = s;
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   input_line_pointer = str;
 
     ++str;
 
   input_line_pointer = str;
 
-  for(;;)
+  for (;;)
     {
       const char *errmsg = NULL;
       int op_idx;
     {
       const char *errmsg = NULL;
       int op_idx;
@@ -823,7 +941,7 @@ md_assemble (str)
          if (operand->flags & MN10200_OPERAND_RELAX)
            relaxable = 1;
 
          if (operand->flags & MN10200_OPERAND_RELAX)
            relaxable = 1;
 
-         /* Gather the operand. */
+         /* Gather the operand.  */
          hold = input_line_pointer;
          input_line_pointer = str;
 
          hold = input_line_pointer;
          input_line_pointer = str;
 
@@ -859,32 +977,32 @@ md_assemble (str)
            }
          else if (operand->flags & MN10200_OPERAND_PSW)
            {
            }
          else if (operand->flags & MN10200_OPERAND_PSW)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcmp (start, "psw") != 0)
                {
 
              if (strcmp (start, "psw") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10200_OPERAND_MDR)
            {
              goto keep_going;
            }
          else if (operand->flags & MN10200_OPERAND_MDR)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcmp (start, "mdr") != 0)
                {
 
              if (strcmp (start, "mdr") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (data_register_name (&ex))
              goto keep_going;
            }
          else if (data_register_name (&ex))
@@ -916,23 +1034,23 @@ md_assemble (str)
              expression (&ex);
            }
 
              expression (&ex);
            }
 
-         switch (ex.X_op) 
+         switch (ex.X_op)
            {
            case O_illegal:
            {
            case O_illegal:
-             errmsg = "illegal operand";
+             errmsg = _("illegal operand");
              goto error;
            case O_absent:
              goto error;
            case O_absent:
-             errmsg = "missing operand";
+             errmsg = _("missing operand");
              goto error;
            case O_register:
              if ((operand->flags
              goto error;
            case O_register:
              if ((operand->flags
-                   & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0)
+                  & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0)
                {
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
                {
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-               
+
              if (opcode->format == FMT_2 || opcode->format == FMT_5)
                extra_shift = 8;
              else if (opcode->format == FMT_3 || opcode->format == FMT_6
              if (opcode->format == FMT_2 || opcode->format == FMT_5)
                extra_shift = 8;
              else if (opcode->format == FMT_3 || opcode->format == FMT_6
@@ -940,9 +1058,9 @@ md_assemble (str)
                extra_shift = 16;
              else
                extra_shift = 0;
                extra_shift = 16;
              else
                extra_shift = 0;
-             
+
              mn10200_insert_operand (&insn, &extension, operand,
              mn10200_insert_operand (&insn, &extension, operand,
-                                     ex.X_add_number, (char *) NULL,
+                                     ex.X_add_number, NULL,
                                      0, extra_shift);
 
              break;
                                      0, extra_shift);
 
              break;
@@ -951,8 +1069,9 @@ md_assemble (str)
              /* If this operand can be promoted, and it doesn't
                 fit into the allocated bitfield for this insn,
                 then promote it (ie this opcode does not match).  */
              /* If this operand can be promoted, and it doesn't
                 fit into the allocated bitfield for this insn,
                 then promote it (ie this opcode does not match).  */
-             if (operand->flags & MN10200_OPERAND_PROMOTE
-                 && ! check_operand (insn, operand, ex.X_add_number))
+             if (operand->flags
+                 & (MN10200_OPERAND_PROMOTE | MN10200_OPERAND_RELAX)
+                 && !check_operand (insn, operand, ex.X_add_number))
                {
                  input_line_pointer = hold;
                  str = hold;
                {
                  input_line_pointer = hold;
                  str = hold;
@@ -960,7 +1079,7 @@ md_assemble (str)
                }
 
              mn10200_insert_operand (&insn, &extension, operand,
                }
 
              mn10200_insert_operand (&insn, &extension, operand,
-                                     ex.X_add_number, (char *) NULL,
+                                     ex.X_add_number, NULL,
                                      0, 0);
              break;
 
                                      0, 0);
              break;
 
@@ -976,7 +1095,7 @@ md_assemble (str)
 
              /* We need to generate a fixup for this expression.  */
              if (fc >= MAX_INSN_FIXUPS)
 
              /* 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;
              fixups[fc].reloc = BFD_RELOC_UNUSED;
              fixups[fc].exp = ex;
              fixups[fc].opindex = *opindex_ptr;
              fixups[fc].reloc = BFD_RELOC_UNUSED;
@@ -984,7 +1103,7 @@ md_assemble (str)
              break;
            }
 
              break;
            }
 
-keep_going:
+       keep_going:
          str = input_line_pointer;
          input_line_pointer = hold;
 
          str = input_line_pointer;
          input_line_pointer = hold;
 
@@ -999,25 +1118,25 @@ keep_going:
 
     error:
       if (match == 0)
 
     error:
       if (match == 0)
-        {
+       {
          next_opcode = opcode + 1;
          next_opcode = opcode + 1;
-         if (!strcmp(next_opcode->name, opcode->name))
+         if (!strcmp (next_opcode->name, opcode->name))
            {
              opcode = next_opcode;
              continue;
            }
            {
              opcode = next_opcode;
              continue;
            }
-         
+
          as_bad ("%s", errmsg);
          return;
          as_bad ("%s", errmsg);
          return;
-        }
+       }
       break;
     }
       break;
     }
-      
-  while (isspace (*str))
+
+  while (ISSPACE (*str))
     ++str;
 
   if (*str != '\0')
     ++str;
 
   if (*str != '\0')
-    as_bad ("junk at end of line: `%s'", str);
+    as_bad (_("junk at end of line: `%s'"), str);
 
   input_line_pointer = str;
 
 
   input_line_pointer = str;
 
@@ -1033,30 +1152,55 @@ keep_going:
     size = 5;
   else
     abort ();
     size = 5;
   else
     abort ();
-         
-  /* Write out the instruction.  */
 
 
+  /* Write out the instruction.  */
+  dwarf2_emit_insn (size);
   if (relaxable && fc > 0)
     {
   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 losing accuracy as we are not going to
+        be even close to the 32bit limit of the int.  */
+      union
+      {
+       int opindex;
+       char * ptr;
+      }
+      opindex_converter;
       int type;
 
       int type;
 
-      /* bCC */
+      /* bCC  */
       if (size == 2 && opcode->opcode != 0xfc0000)
       if (size == 2 && opcode->opcode != 0xfc0000)
-       type = 0;
-      /* jsr */
+       {
+         /* Handle bra specially.  Basically treat it like jmp so
+            that we automatically handle 8, 16 and 32 bit offsets
+            correctly as well as jumps to an undefined address.
+
+            It is also important to not treat it like other bCC
+            instructions since the long forms of bra is different
+            from other bCC instructions.  */
+         if (opcode->opcode == 0xea00)
+           type = 8;
+         else
+           type = 0;
+       }
+      /* jsr  */
       else if (size == 3 && opcode->opcode == 0xfd0000)
        type = 6;
       else if (size == 3 && opcode->opcode == 0xfd0000)
        type = 6;
-      /* jmp */
+      /* jmp  */
       else if (size == 3 && opcode->opcode == 0xfc0000)
        type = 8;
       else if (size == 3 && opcode->opcode == 0xfc0000)
        type = 8;
-      /* bCCx */
+      /* bCCx  */
       else
        type = 3;
 
       else
        type = 3;
 
+      opindex_converter.opindex = fixups[0].opindex;
       f = frag_var (rs_machine_dependent, 8, 8 - size, type,
                    fixups[0].exp.X_add_symbol,
                    fixups[0].exp.X_add_number,
       f = frag_var (rs_machine_dependent, 8, 8 - size, type,
                    fixups[0].exp.X_add_symbol,
                    fixups[0].exp.X_add_number,
-                   (char *)fixups[0].opindex);
+                   opindex_converter.ptr);
       number_to_chars_bigendian (f, insn, size);
       if (8 - size > 4)
        {
       number_to_chars_bigendian (f, insn, size);
       if (8 - size > 4)
        {
@@ -1066,7 +1210,6 @@ keep_going:
       else
        number_to_chars_bigendian (f + size, 0, 8 - size);
     }
       else
        number_to_chars_bigendian (f + size, 0, 8 - size);
     }
-
   else
     {
       f = frag_more (size);
   else
     {
       f = frag_more (size);
@@ -1090,43 +1233,48 @@ keep_going:
          number_to_chars_littleendian (f + 4, extension & 0xff, 1);
        }
       else
          number_to_chars_littleendian (f + 4, extension & 0xff, 1);
        }
       else
-       {
-         number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
-       }
+       number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
 
       /* Create any fixups.  */
       for (i = 0; i < fc; i++)
        {
          const struct mn10200_operand *operand;
 
       /* Create any fixups.  */
       for (i = 0; i < fc; i++)
        {
          const struct mn10200_operand *operand;
+         int reloc_size;
 
          operand = &mn10200_operands[fixups[i].opindex];
          if (fixups[i].reloc != BFD_RELOC_UNUSED)
            {
              reloc_howto_type *reloc_howto;
 
          operand = &mn10200_operands[fixups[i].opindex];
          if (fixups[i].reloc != BFD_RELOC_UNUSED)
            {
              reloc_howto_type *reloc_howto;
-             int size;
              int offset;
              fixS *fixP;
 
              int offset;
              fixS *fixP;
 
-             reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
+             reloc_howto = bfd_reloc_type_lookup (stdoutput,
+                                                  fixups[i].reloc);
 
              if (!reloc_howto)
 
              if (!reloc_howto)
-               abort();
-         
-             size = bfd_get_reloc_size (reloc_howto);
+               abort ();
+
+             reloc_size = bfd_get_reloc_size (reloc_howto);
 
 
-             if (size < 1 || size > 4)
-               abort();
+             if (reloc_size < 1 || reloc_size > 4)
+               abort ();
 
 
-             offset = 4 - size;
+             offset = 4 - reloc_size;
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
-                                 size,
-                                 &fixups[i].exp, 
+                                 reloc_size,
+                                 &fixups[i].exp,
                                  reloc_howto->pc_relative,
                                  fixups[i].reloc);
                                  reloc_howto->pc_relative,
                                  fixups[i].reloc);
+
+             /* PC-relative offsets are from the first byte of the
+                next instruction, not from the start of the current
+                instruction.  */
+             if (reloc_howto->pc_relative)
+               fixP->fx_offset += reloc_size;
            }
          else
            {
            }
          else
            {
-             int reloc, pcrel, reloc_size, offset;
+             int reloc, pcrel, offset;
              fixS *fixP;
 
              reloc = BFD_RELOC_NONE;
              fixS *fixP;
 
              reloc = BFD_RELOC_NONE;
@@ -1139,7 +1287,6 @@ keep_going:
              /* Is the reloc pc-relative?  */
              pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0;
 
              /* Is the reloc pc-relative?  */
              pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0;
 
-
              /* Choose a proper BFD relocation type.  */
              if (pcrel)
                {
              /* Choose a proper BFD relocation type.  */
              if (pcrel)
                {
@@ -1164,7 +1311,8 @@ keep_going:
                    abort ();
                }
 
                    abort ();
                }
 
-             /* Convert the size of the reloc into what fix_new_exp wants.  */
+             /* Convert the size of the reloc into what fix_new_exp
+                 wants.  */
              reloc_size = reloc_size / 8;
              if (reloc_size == 8)
                reloc_size = 0;
              reloc_size = reloc_size / 8;
              if (reloc_size == 8)
                reloc_size = 0;
@@ -1176,200 +1324,13 @@ keep_going:
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
                                  reloc_size, &fixups[i].exp, pcrel,
                                  ((bfd_reloc_code_real_type) reloc));
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
                                  reloc_size, &fixups[i].exp, pcrel,
                                  ((bfd_reloc_code_real_type) reloc));
+
+             /* PC-relative offsets are from the first byte of the
+                next instruction, not from the start of the current
+                instruction.  */
              if (pcrel)
              if (pcrel)
-               fixP->fx_offset += offset;
+               fixP->fx_offset += 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;
-     fixS *fixp;
-{
-  arelent *reloc;
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-
-  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);
-      return NULL;
-    }
-  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
-
-  if (fixp->fx_addsy && fixp->fx_subsy)
-    {
-      reloc->sym_ptr_ptr = &bfd_abs_symbol;
-      reloc->addend = (S_GET_VALUE (fixp->fx_addsy)
-                      - S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset);
-    }
-  else 
-    {
-      reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
-      reloc->addend = fixp->fx_offset;
-    }
-  return reloc;
-}
-
-int
-md_estimate_size_before_relax (fragp, seg)
-     fragS *fragp;
-     asection *seg;
-{
-  if (fragp->fr_subtype == 0)
-    return 2;
-  if (fragp->fr_subtype == 3)
-    return 3;
-  if (fragp->fr_subtype == 6)
-    {
-      if (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol))
-       {
-         fragp->fr_subtype = 7;
-         return 5;
-       }
-      return 3;
-    }
-  if (fragp->fr_subtype == 8)
-    {
-      if (!S_IS_DEFINED (fragp->fr_symbol))
-       {
-         fragp->fr_subtype = 10;
-         return 5;
-       }
-      return 2;
-    }
-} 
-
-long
-md_pcrel_from (fixp)
-     fixS *fixp;
-{
-  return fixp->fx_frag->fr_address;
-#if 0
-  if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy))
-    {
-      /* The symbol is undefined.  Let the linker figure it out.  */
-      return 0;
-    }
-  return fixp->fx_frag->fr_address + fixp->fx_where;
-#endif
-}
-
-int
-md_apply_fix3 (fixp, valuep, seg)
-     fixS *fixp;
-     valueT *valuep;
-     segT seg;
-{
-  /* We shouldn't ever get here because linkrelax is nonzero.  */
-  abort ();
-  fixp->fx_done = 1;
-  return 0;
-}
-
-/* Insert an operand value into an instruction.  */
-
-static void
-mn10200_insert_operand (insnp, extensionp, operand, val, file, line, shift)
-     unsigned long *insnp;
-     unsigned long *extensionp;
-     const struct mn10200_operand *operand;
-     offsetT val;
-     char *file;
-     unsigned int line;
-     unsigned int shift;
-{
-  /* No need to check 24 or 32bit operands for a bit.  */
-  if (operand->bits < 24
-      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
-    {
-      long min, max;
-      offsetT test;
-
-      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
-       {
-         max = (1 << (operand->bits - 1)) - 1;
-         min = - (1 << (operand->bits - 1));
-       }
-      else
-        {
-          max = (1 << operand->bits) - 1;
-          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);
-        }
-    }
-
-  if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0)
-    {
-      *insnp |= (((long) val & ((1 << operand->bits) - 1))
-                << (operand->shift + shift));
-
-      if ((operand->flags & MN10200_OPERAND_REPEATED) != 0)
-       *insnp |= (((long) val & ((1 << operand->bits) - 1))
-                  << (operand->shift + shift + 2));
-    }
-  else
-    {
-      *extensionp |= (val >> 16) & 0xff;
-      *insnp |= val & 0xffff;
-    }
-}
-
-static unsigned long
-check_operand (insn, operand, val)
-     unsigned long insn;
-     const struct mn10200_operand *operand;
-     offsetT val;
-{
-  /* No need to check 24bit or 32bit operands for a bit.  */
-  if (operand->bits < 24
-      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
-    {
-      long min, max;
-      offsetT test;
-
-      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
-       {
-         max = (1 << (operand->bits - 1)) - 1;
-         min = - (1 << (operand->bits - 1));
-       }
-      else
-        {
-          max = (1 << operand->bits) - 1;
-          min = 0;
-        }
-
-      test = val;
-
-
-      if (test < (offsetT) min || test > (offsetT) max)
-       return 0;
-      else
-       return 1;
-    }
-  return 1;
-}