[AArch64] Add support for :tlsdesc: and TLSDESC_ADR_PREL21
[deliverable/binutils-gdb.git] / gas / config / tc-mn10300.c
index 3f9e9cee7d2dbb8d793992fb6b04bdfd9b663626..1a244aba897bc871efd5fee38e4a5d1b7e42cc40 100644 (file)
@@ -1,12 +1,11 @@
 /* tc-mn10300.c -- Assembler code for the Matsushita 10300
 /* tc-mn10300.c -- Assembler code for the Matsushita 10300
-
-   Copyright (C) 1996, 1997, 1998 Free Software Foundation.
+   Copyright (C) 1996-2015 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/mn10300.h"
 #include "opcode/mn10300.h"
+#include "dwarf2dbg.h"
+#include "libiberty.h"
 \f
 /* Structure to hold information about predefined registers.  */
 struct reg_name
 \f
 /* Structure to hold information about predefined registers.  */
 struct reg_name
@@ -32,71 +32,71 @@ 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 */
+const relax_typeS md_relax_table[] =
+{
+  /* The plus values for the bCC and fBCC instructions in the table below
+     are because the branch instruction is translated into a jump
+     instruction that is now +2 or +3 bytes further on in memory, and the
+     correct size of jump instruction must be selected.  */
+  /* bCC relaxing.  */
   {0x7f, -0x80, 2, 1},
   {0x7f, -0x80, 2, 1},
-  {0x7fff, -0x8000, 5, 2},
+  {0x7fff + 2, -0x8000 + 2, 5, 2},
   {0x7fffffff, -0x80000000, 7, 0},
 
   {0x7fffffff, -0x80000000, 7, 0},
 
-  /* bCC relaxing (uncommon cases) */
+  /* bCC relaxing (uncommon cases for 3byte length instructions)  */
   {0x7f, -0x80, 3, 4},
   {0x7f, -0x80, 3, 4},
-  {0x7fff, -0x8000, 6, 5},
+  {0x7fff + 3, -0x8000 + 3, 6, 5},
   {0x7fffffff, -0x80000000, 8, 0},
 
   {0x7fffffff, -0x80000000, 8, 0},
 
-  /* call relaxing */
+  /* call relaxing */
   {0x7fff, -0x8000, 5, 7},
   {0x7fffffff, -0x80000000, 7, 0},
 
   {0x7fff, -0x8000, 5, 7},
   {0x7fffffff, -0x80000000, 7, 0},
 
-  /* calls relaxing */
+  /* calls relaxing */
   {0x7fff, -0x8000, 4, 9},
   {0x7fffffff, -0x80000000, 6, 0},
 
   {0x7fff, -0x8000, 4, 9},
   {0x7fffffff, -0x80000000, 6, 0},
 
-  /* jmp relaxing */
+  /* jmp relaxing */
   {0x7f, -0x80, 2, 11},
   {0x7fff, -0x8000, 3, 12},
   {0x7fffffff, -0x80000000, 5, 0},
 
   {0x7f, -0x80, 2, 11},
   {0x7fff, -0x8000, 3, 12},
   {0x7fffffff, -0x80000000, 5, 0},
 
+  /* fbCC relaxing.  */
+  {0x7f, -0x80, 3, 14},
+  {0x7fff + 3, -0x8000 + 3, 6, 15},
+  {0x7fffffff, -0x80000000, 8, 0},
+
 };
 
 };
 
-/* local functions */
-static void mn10300_insert_operand PARAMS ((unsigned long *, unsigned long *,
-                                           const struct mn10300_operand *,
-                                           offsetT, char *, unsigned,
-                                           unsigned));
-static unsigned long check_operand PARAMS ((unsigned long,
-                                           const struct mn10300_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));
-static void set_arch_mach PARAMS ((int));
+/*  Set linkrelax here to avoid fixups in most sections.  */
+int linkrelax = 1;
 
 static int current_machine;
 
 
 static int current_machine;
 
-/* fixups */
-#define MAX_INSN_FIXUPS (5)
+/* Fixups.  */
+#define MAX_INSN_FIXUPS 5
+
 struct mn10300_fixup
 {
   expressionS exp;
 struct mn10300_fixup
 {
   expressionS exp;
@@ -111,23 +111,22 @@ static int fc;
 int mn10300_reg_operands[MN10300_MAX_OPERANDS];
 \f
 const char *md_shortopts = "";
 int mn10300_reg_operands[MN10300_MAX_OPERANDS];
 \f
 const char *md_shortopts = "";
-struct option md_longopts[] = {
-  {NULL, no_argument, NULL, 0}
-};
-size_t md_longopts_size = sizeof(md_longopts); 
 
 
-/* The target specific pseudo-ops which we support.  */
-const pseudo_typeS md_pseudo_table[] =
+struct option md_longopts[] =
 {
 {
-  { "am30",    set_arch_mach,          300 },
-  { "mn10300", set_arch_mach,          300 },
-  {NULL, 0, 0}
+  {NULL, no_argument, NULL, 0}
 };
 
 };
 
+size_t md_longopts_size = sizeof (md_longopts);
+
+#define HAVE_AM33_2 (current_machine == AM33_2)
+#define HAVE_AM33   (current_machine == AM33 || HAVE_AM33_2)
+#define HAVE_AM30   (current_machine == AM30)
+
 /* Opcode hash table.  */
 static struct hash_control *mn10300_hash;
 
 /* Opcode hash table.  */
 static struct hash_control *mn10300_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 },
@@ -135,7 +134,6 @@ 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))
 
 static const struct reg_name address_registers[] =
 {
 
 static const struct reg_name address_registers[] =
 {
@@ -144,258 +142,329 @@ 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))
 
 
+static const struct reg_name r_registers[] =
+{
+  { "a0", 8 },
+  { "a1", 9 },
+  { "a2", 10 },
+  { "a3", 11 },
+  { "d0", 12 },
+  { "d1", 13 },
+  { "d2", 14 },
+  { "d3", 15 },
+  { "e0", 0 },
+  { "e1", 1 },
+  { "e10", 10 },
+  { "e11", 11 },
+  { "e12", 12 },
+  { "e13", 13 },
+  { "e14", 14 },
+  { "e15", 15 },
+  { "e2", 2 },
+  { "e3", 3 },
+  { "e4", 4 },
+  { "e5", 5 },
+  { "e6", 6 },
+  { "e7", 7 },
+  { "e8", 8 },
+  { "e9", 9 },
+  { "r0", 0 },
+  { "r1", 1 },
+  { "r10", 10 },
+  { "r11", 11 },
+  { "r12", 12 },
+  { "r13", 13 },
+  { "r14", 14 },
+  { "r15", 15 },
+  { "r2", 2 },
+  { "r3", 3 },
+  { "r4", 4 },
+  { "r5", 5 },
+  { "r6", 6 },
+  { "r7", 7 },
+  { "r8", 8 },
+  { "r9", 9 },
+};
+
+static const struct reg_name xr_registers[] =
+{
+  { "mcrh", 2 },
+  { "mcrl", 3 },
+  { "mcvf", 4 },
+  { "mdrq", 1 },
+  { "sp", 0 },
+  { "xr0", 0 },
+  { "xr1", 1 },
+  { "xr10", 10 },
+  { "xr11", 11 },
+  { "xr12", 12 },
+  { "xr13", 13 },
+  { "xr14", 14 },
+  { "xr15", 15 },
+  { "xr2", 2 },
+  { "xr3", 3 },
+  { "xr4", 4 },
+  { "xr5", 5 },
+  { "xr6", 6 },
+  { "xr7", 7 },
+  { "xr8", 8 },
+  { "xr9", 9 },
+};
+
+static const struct reg_name float_registers[] =
+{
+  { "fs0", 0 },
+  { "fs1", 1 },
+  { "fs10", 10 },
+  { "fs11", 11 },
+  { "fs12", 12 },
+  { "fs13", 13 },
+  { "fs14", 14 },
+  { "fs15", 15 },
+  { "fs16", 16 },
+  { "fs17", 17 },
+  { "fs18", 18 },
+  { "fs19", 19 },
+  { "fs2",   2 },
+  { "fs20", 20 },
+  { "fs21", 21 },
+  { "fs22", 22 },
+  { "fs23", 23 },
+  { "fs24", 24 },
+  { "fs25", 25 },
+  { "fs26", 26 },
+  { "fs27", 27 },
+  { "fs28", 28 },
+  { "fs29", 29 },
+  { "fs3",   3 },
+  { "fs30", 30 },
+  { "fs31", 31 },
+  { "fs4",   4 },
+  { "fs5",   5 },
+  { "fs6",   6 },
+  { "fs7",   7 },
+  { "fs8",   8 },
+  { "fs9",   9 },
+};
+
+static const struct reg_name double_registers[] =
+{
+  { "fd0",   0 },
+  { "fd10", 10 },
+  { "fd12", 12 },
+  { "fd14", 14 },
+  { "fd16", 16 },
+  { "fd18", 18 },
+  { "fd2",   2 },
+  { "fd20", 20 },
+  { "fd22", 22 },
+  { "fd24", 24 },
+  { "fd26", 26 },
+  { "fd28", 28 },
+  { "fd30", 30 },
+  { "fd4",   4 },
+  { "fd6",   6 },
+  { "fd8",   8 },
+};
 
 
+/* We abuse the `value' field, that would be otherwise unused, to
+   encode the architecture on which (access to) the register was
+   introduced.  FIXME: we should probably warn when we encounter a
+   register name when assembling for an architecture that doesn't
+   support it, before parsing it as a symbol name.  */
 static const struct reg_name other_registers[] =
 {
 static const struct reg_name other_registers[] =
 {
+  { "epsw", AM33 },
   { "mdr", 0 },
   { "mdr", 0 },
+  { "pc", AM33 },
   { "psw", 0 },
   { "sp", 0 },
   { "psw", 0 },
   { "sp", 0 },
+  { "ssp", 0 },
+  { "usp", 0 },
 };
 };
-#define OTHER_REG_NAME_CNT     (sizeof(other_registers) / sizeof(struct reg_name))
 
 
-/* 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. */
+#define OTHER_REG_NAME_CNT     ARRAY_SIZE (other_registers)
+
+/* Perform a binary search of the given register table REGS to see
+   if NAME is a valid regiter 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 low, high;
 
   low = 0;
   high = regcount - 1;
 
   do
     {
 
   low = 0;
   high = regcount - 1;
 
   do
     {
+      int cmp, middle;
+
       middle = (low + high) / 2;
       cmp = strcasecmp (name, regs[middle].name);
       if (cmp < 0)
        high = middle - 1;
       else if (cmp > 0)
        low = middle + 1;
       middle = (low + high) / 2;
       cmp = strcasecmp (name, regs[middle].name);
       if (cmp < 0)
        high = middle - 1;
       else if (cmp > 0)
        low = middle + 1;
-      else 
-         return regs[middle].value;
+      else
+       return regs[middle].value;
     }
   while (low <= high);
     }
   while (low <= high);
+
   return -1;
 }
 
   return -1;
 }
 
-
-
-/* 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;
+/* Looks at the current position in the input line to see if it is
+   the name of a register in TABLE.  If it is, then the name is
+   converted into an expression returned in EXPRESSIONP (with X_op
+   set to O_register and X_add_number set to the register number), the
+   input pointer is left pointing at the first non-blank character after
+   the name and the function returns TRUE.  Otherwise the input pointer
+   is left alone and the function returns FALSE.  */
+
+static bfd_boolean
+get_register_name (expressionS *           expressionP,
+                  const struct reg_name * table,
+                  size_t                  table_length)
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
 {
   int reg_number;
   char *name;
   char *start;
   char c;
 
-  /* Find the spelling of the operand */
+  /* Find the spelling of the operand */
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
-  reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
+  reg_number = reg_name_search (table, table_length, name);
 
 
-  /* look to see if it's in the register table */
-  if (reg_number >= 0) 
+  /* Put back the delimiting char.  */
+  *input_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;
-    }
-  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;
+
+      return TRUE;
     }
     }
+
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return FALSE;
 }
 
 }
 
-/* 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;
+static bfd_boolean
+r_register_name (expressionS *expressionP)
 {
 {
-  int reg_number;
-  char *name;
-  char *start;
-  char c;
+  return get_register_name (expressionP, r_registers, ARRAY_SIZE (r_registers));
+}
 
 
-  /* Find the spelling of the operand */
-  start = name = input_line_pointer;
 
 
-  c = get_symbol_end ();
-  reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name);
+static bfd_boolean
+xr_register_name (expressionS *expressionP)
+{
+  return get_register_name (expressionP, xr_registers, ARRAY_SIZE (xr_registers));
+}
 
 
-  /* 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;
+static bfd_boolean
+data_register_name (expressionS *expressionP)
+{
+  return get_register_name (expressionP, data_registers, ARRAY_SIZE (data_registers));
+}
 
 
-      /* make the rest nice */
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_op_symbol = NULL;
-      *input_line_pointer = c; /* put back the delimiting char */
-      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;
-    }
+static bfd_boolean
+address_register_name (expressionS *expressionP)
+{
+  return get_register_name (expressionP, address_registers, ARRAY_SIZE (address_registers));
+}
+
+static bfd_boolean
+float_register_name (expressionS *expressionP)
+{
+  return get_register_name (expressionP, float_registers, ARRAY_SIZE (float_registers));
+}
+
+static bfd_boolean
+double_register_name (expressionS *expressionP)
+{
+  return get_register_name (expressionP, double_registers, ARRAY_SIZE (double_registers));
 }
 
 }
 
-/* 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;
+static bfd_boolean
+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 */
+  /* Find the spelling of the operand */
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
-  reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
+  reg_number = reg_name_search (other_registers, ARRAY_SIZE (other_registers), name);
+
+  /* Put back the delimiting char.  */
+  *input_line_pointer = c;
 
 
-  /* look to see if it's in the register table */
-  if (reg_number >= 0) 
+  /* Look to see if it's in the register table.  */
+  if (reg_number == 0
+      || (reg_number == AM33 && HAVE_AM33))
     {
       expressionP->X_op = O_register;
     {
       expressionP->X_op = O_register;
-      expressionP->X_add_number = reg_number;
+      expressionP->X_add_number = 0;
 
 
-      /* 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;
-    }
-  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;
+
+      return TRUE;
     }
     }
+
+  /* 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, _("MN10300 options:\n\
+  fprintf (stream, _("MN10300 assembler options:\n\
 none yet\n"));
 none yet\n"));
-} 
+}
 
 int
 
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+md_parse_option (int c ATTRIBUTE_UNUSED, 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;
 }
 
 char *
 {
   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);
 }
 
 }
 
-
 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];
 {
   static unsigned long label_count = 0;
   char buf[40];
@@ -452,7 +521,7 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_literal[offset] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
       fragP->fr_literal[offset] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
-      sprintf (buf, ".%s_%d", FAKE_LABEL_NAME, label_count++);
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
       fix_new (fragP, fragP->fr_fix + 1, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
       fix_new (fragP, fragP->fr_fix + 1, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
@@ -509,7 +578,7 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_literal[offset] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
       fragP->fr_literal[offset] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
-      sprintf (buf, ".%s_%d", FAKE_LABEL_NAME, label_count++);
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
       fix_new (fragP, fragP->fr_fix + 1, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
       fix_new (fragP, fragP->fr_fix + 1, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
@@ -555,7 +624,7 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_literal[offset + 1] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
       fragP->fr_literal[offset + 1] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
-      sprintf (buf, ".%s_%d", FAKE_LABEL_NAME, label_count++);
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
       fix_new (fragP, fragP->fr_fix + 2, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
       fix_new (fragP, fragP->fr_fix + 2, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
@@ -591,7 +660,7 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_literal[offset + 1] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
       fragP->fr_literal[offset + 1] = opcode;
 
       /* Create a fixup for the reversed conditional branch.  */
-      sprintf (buf, ".%s_%d", FAKE_LABEL_NAME, label_count++);
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
       fix_new (fragP, fragP->fr_fix + 2, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
       fix_new (fragP, fragP->fr_fix + 2, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
@@ -607,6 +676,7 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 6)
     {
       int offset = fragP->fr_fix;
   else if (fragP->fr_subtype == 6)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xcd;
       fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
               fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
       fragP->fr_literal[offset] = 0xcd;
       fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
               fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
@@ -616,9 +686,12 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 7)
     {
       int offset = fragP->fr_fix;
   else if (fragP->fr_subtype == 7)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xdd;
       fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3];
       fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4];
       fragP->fr_literal[offset] = 0xdd;
       fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3];
       fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4];
+      fragP->fr_literal[offset + 3] = 0;
+      fragP->fr_literal[offset + 4] = 0;
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
               fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
               fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
@@ -628,6 +701,7 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 8)
     {
       int offset = fragP->fr_fix;
   else if (fragP->fr_subtype == 8)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xfa;
       fragP->fr_literal[offset + 1] = 0xff;
       fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
       fragP->fr_literal[offset] = 0xfa;
       fragP->fr_literal[offset + 1] = 0xff;
       fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
@@ -638,6 +712,7 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 9)
     {
       int offset = fragP->fr_fix;
   else if (fragP->fr_subtype == 9)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xfc;
       fragP->fr_literal[offset + 1] = 0xff;
 
       fragP->fr_literal[offset] = 0xfc;
       fragP->fr_literal[offset + 1] = 0xff;
 
@@ -657,9 +732,10 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 11)
     {
       int offset = fragP->fr_fix;
   else if (fragP->fr_subtype == 11)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xcc;
 
       fragP->fr_literal[offset] = 0xcc;
 
-      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+      fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
               fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
               fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
       fragP->fr_var = 0;
       fragP->fr_fix += 3;
@@ -667,6 +743,7 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 12)
     {
       int offset = fragP->fr_fix;
   else if (fragP->fr_subtype == 12)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xdc;
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
       fragP->fr_literal[offset] = 0xdc;
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
@@ -674,26 +751,170 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
+  else if (fragP->fr_subtype == 13)
+    {
+      fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 3;
+    }
+  else if (fragP->fr_subtype == 14)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xd0:
+         opcode = 0xd1;
+         break;
+       case 0xd1:
+         opcode = 0xd0;
+         break;
+       case 0xd2:
+         opcode = 0xdc;
+         break;
+       case 0xd3:
+         opcode = 0xdb;
+         break;
+       case 0xd4:
+         opcode = 0xda;
+         break;
+       case 0xd5:
+         opcode = 0xd9;
+         break;
+       case 0xd6:
+         opcode = 0xd8;
+         break;
+       case 0xd7:
+         opcode = 0xdd;
+         break;
+       case 0xd8:
+         opcode = 0xd6;
+         break;
+       case 0xd9:
+         opcode = 0xd5;
+         break;
+       case 0xda:
+         opcode = 0xd4;
+         break;
+       case 0xdb:
+         opcode = 0xd3;
+         break;
+       case 0xdc:
+         opcode = 0xd2;
+         break;
+       case 0xdd:
+         opcode = 0xd7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* 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, 0, fragP->fr_next),
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xcc;
+      fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 6;
+    }
+  else if (fragP->fr_subtype == 15)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xd0:
+         opcode = 0xd1;
+         break;
+       case 0xd1:
+         opcode = 0xd0;
+         break;
+       case 0xd2:
+         opcode = 0xdc;
+         break;
+       case 0xd3:
+         opcode = 0xdb;
+         break;
+       case 0xd4:
+         opcode = 0xda;
+         break;
+       case 0xd5:
+         opcode = 0xd9;
+         break;
+       case 0xd6:
+         opcode = 0xd8;
+         break;
+       case 0xd7:
+         opcode = 0xdd;
+         break;
+       case 0xd8:
+         opcode = 0xd6;
+         break;
+       case 0xd9:
+         opcode = 0xd5;
+         break;
+       case 0xda:
+         opcode = 0xd4;
+         break;
+       case 0xdb:
+         opcode = 0xd3;
+         break;
+       case 0xdc:
+         opcode = 0xd2;
+         break;
+       case 0xdd:
+         opcode = 0xd7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* 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, 0, fragP->fr_next),
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xdc;
+      fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 8;
+    }
   else
     abort ();
 }
 
 valueT
   else
     abort ();
 }
 
 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);
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
+
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
 
 void
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
 
 void
-md_begin ()
+md_begin (void)
 {
   char *prev_name = "";
 {
   char *prev_name = "";
-  register const struct mn10300_opcode *op;
+  const struct mn10300_opcode *op;
 
 
-  mn10300_hash = hash_new();
+  mn10300_hash = hash_new ();
 
   /* Insert unique names into hash table.  The MN10300 instruction set
      has many identical opcode names that have different opcodes based
 
   /* Insert unique names into hash table.  The MN10300 instruction set
      has many identical opcode names that have different opcodes based
@@ -703,7 +924,7 @@ md_begin ()
   op = mn10300_opcodes;
   while (op->name)
     {
   op = mn10300_opcodes;
   while (op->name)
     {
-      if (strcmp (prev_name, op->name)) 
+      if (strcmp (prev_name, op->name))
        {
          prev_name = (char *) op->name;
          hash_insert (mn10300_hash, op->name, (char *) op);
        {
          prev_name = (char *) op->name;
          hash_insert (mn10300_hash, op->name, (char *) op);
@@ -711,94 +932,377 @@ md_begin ()
       op++;
     }
 
       op++;
     }
 
-  /* This is both a simplification (we don't have to write md_apply_fix)
-     and support for future optimizations (branch shortening and similar
-     stuff in the linker).  */
-  linkrelax = 1;
-
   /* Set the default machine type.  */
   /* Set the default machine type.  */
-  if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, 300))
+#ifdef TE_LINUX
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, AM33_2))
+    as_warn (_("could not set architecture and machine"));
+
+  current_machine = AM33_2;
+#else  
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, MN103))
     as_warn (_("could not set architecture and machine"));
 
     as_warn (_("could not set architecture and machine"));
 
-  current_machine = 300;
+  current_machine = MN103;
+#endif
 }
 
 }
 
-void
-md_assemble (str) 
-     char *str;
+static symbolS *GOT_symbol;
+
+static inline int
+mn10300_PIC_related_p (symbolS *sym)
 {
 {
-  char *s;
-  struct mn10300_opcode *opcode;
-  struct mn10300_opcode *next_opcode;
-  const unsigned char *opindex_ptr;
-  int next_opindex, relaxable;
-  unsigned long insn, extension, size = 0;
-  char *f;
-  int i;
-  int match;
+  expressionS *exp;
 
 
-  /* Get the opcode.  */
-  for (s = str; *s != '\0' && ! isspace (*s); s++)
-    ;
-  if (*s != '\0')
-    *s++ = '\0';
+  if (! sym)
+    return 0;
 
 
-  /* find the first opcode with the proper name */
-  opcode = (struct mn10300_opcode *)hash_find (mn10300_hash, str);
-  if (opcode == NULL)
-    {
-      as_bad (_("Unrecognized opcode: `%s'"), str);
-      return;
-    }
+  if (sym == GOT_symbol)
+    return 1;
 
 
-  str = s;
-  while (isspace (*str))
-    ++str;
+  exp = symbol_get_value_expression (sym);
 
 
-  input_line_pointer = str;
+  return (exp->X_op == O_PIC_reloc
+         || mn10300_PIC_related_p (exp->X_add_symbol)
+         || mn10300_PIC_related_p (exp->X_op_symbol));
+}
 
 
-  for(;;)
+static inline int
+mn10300_check_fixup (struct mn10300_fixup *fixup)
+{
+  expressionS *exp = &fixup->exp;
+
+ repeat:
+  switch (exp->X_op)
     {
     {
-      const char *errmsg;
-      int op_idx;
-      char *hold;
-      int extra_shift = 0;
+    case O_add:
+    case O_subtract: /* If we're sufficiently unlucky that the label
+                       and the expression that references it happen
+                       to end up in different frags, the subtract
+                       won't be simplified within expression().  */
+      /* The PIC-related operand must be the first operand of a sum.  */
+      if (exp != &fixup->exp || mn10300_PIC_related_p (exp->X_op_symbol))
+       return 1;
 
 
+      if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
+       fixup->reloc = BFD_RELOC_32_GOT_PCREL;
 
 
-      errmsg = _("Invalid opcode/operands");
+      exp = symbol_get_value_expression (exp->X_add_symbol);
+      goto repeat;
 
 
-      /* Reset the array of register operands.  */
-      memset (mn10300_reg_operands, -1, sizeof (mn10300_reg_operands));
+    case O_symbol:
+      if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
+       fixup->reloc = BFD_RELOC_32_GOT_PCREL;
+      break;
 
 
-      relaxable = 0;
-      fc = 0;
-      match = 0;
-      next_opindex = 0;
-      insn = opcode->opcode;
-      extension = 0;
+    case O_PIC_reloc:
+      fixup->reloc = exp->X_md;
+      exp->X_op = O_symbol;
+      if (fixup->reloc == BFD_RELOC_32_PLT_PCREL
+         && fixup->opindex >= 0
+         && (mn10300_operands[fixup->opindex].flags
+             & MN10300_OPERAND_RELAX))
+       return 1;
+      break;
 
 
-      /* If the instruction is not available on the current machine
-        then it can not possibly match.  */
-      if (opcode->machine
-         && (opcode->machine != current_machine))
-       goto error;
+    default:
+      return (mn10300_PIC_related_p (exp->X_add_symbol)
+             || mn10300_PIC_related_p (exp->X_op_symbol));
+    }
 
 
-      for (op_idx = 1, opindex_ptr = opcode->operands;
-          *opindex_ptr != 0;
-          opindex_ptr++, op_idx++)
-       {
-         const struct mn10300_operand *operand;
-         expressionS ex;
+  return 0;
+}
 
 
-         if (next_opindex == 0)
-           {
-             operand = &mn10300_operands[*opindex_ptr];
-           }
-         else
-           {
-             operand = &mn10300_operands[next_opindex];
-             next_opindex = 0;
-           }
+void
+mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+                     bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
+{
+  struct mn10300_fixup fixup;
+
+  fixup.opindex = -1;
+  fixup.exp = *exp;
+  fixup.reloc = BFD_RELOC_UNUSED;
+
+  mn10300_check_fixup (&fixup);
+
+  if (fixup.reloc == BFD_RELOC_MN10300_GOT32)
+    switch (size)
+      {
+      case 2:
+       fixup.reloc = BFD_RELOC_MN10300_GOT16;
+       break;
+
+      case 3:
+       fixup.reloc = BFD_RELOC_MN10300_GOT24;
+       break;
+
+      case 4:
+       break;
+
+      default:
+       goto error;
+      }
+  else if (fixup.reloc == BFD_RELOC_UNUSED)
+    switch (size)
+      {
+      case 1:
+       fixup.reloc = BFD_RELOC_8;
+       break;
+
+      case 2:
+       fixup.reloc = BFD_RELOC_16;
+       break;
+
+      case 3:
+       fixup.reloc = BFD_RELOC_24;
+       break;
+
+      case 4:
+       fixup.reloc = BFD_RELOC_32;
+       break;
+
+      default:
+       goto error;
+      }
+  else if (size != 4)
+    {
+    error:
+      as_bad (_("unsupported BFD relocation size %u"), size);
+      fixup.reloc = BFD_RELOC_UNUSED;
+    }
+    
+  fix_new_exp (frag, off, size, &fixup.exp, 0, fixup.reloc);
+}
+
+static bfd_boolean
+check_operand (const struct mn10300_operand *operand,
+              offsetT val)
+{
+  /* No need to check 32bit operands for a bit.  Note that
+     MN10300_OPERAND_SPLIT is an implicit 32bit operand.  */
+  if (operand->bits != 32
+      && (operand->flags & MN10300_OPERAND_SPLIT) == 0)
+    {
+      long min, max;
+      offsetT test;
+      int bits;
+
+      bits = operand->bits;
+      if (operand->flags & MN10300_OPERAND_24BIT)
+       bits = 24;
+
+      if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
+       {
+         max = (1 << (bits - 1)) - 1;
+         min = - (1 << (bits - 1));
+       }
+      else
+       {
+         max = (1 << bits) - 1;
+         min = 0;
+       }
+
+      test = val;
+
+      if (test < (offsetT) min || test > (offsetT) max)
+       return FALSE;
+    }
+  return TRUE;
+}
+
+/* Insert an operand value into an instruction.  */
+
+static void
+mn10300_insert_operand (unsigned long *insnp,
+                       unsigned long *extensionp,
+                       const struct mn10300_operand *operand,
+                       offsetT val,
+                       char *file,
+                       unsigned int line,
+                       unsigned int shift)
+{
+  /* No need to check 32bit operands for a bit.  Note that
+     MN10300_OPERAND_SPLIT is an implicit 32bit operand.  */
+  if (operand->bits != 32
+      && (operand->flags & MN10300_OPERAND_SPLIT) == 0)
+    {
+      long min, max;
+      offsetT test;
+      int bits;
+
+      bits = operand->bits;
+      if (operand->flags & MN10300_OPERAND_24BIT)
+       bits = 24;
+
+      if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
+       {
+         max = (1 << (bits - 1)) - 1;
+         min = - (1 << (bits - 1));
+       }
+      else
+       {
+         max = (1 << 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 & MN10300_OPERAND_SPLIT) != 0)
+    {
+      *insnp |= (val >> (32 - operand->bits)) & ((1 << operand->bits) - 1);
+      *extensionp |= ((val & ((1 << (32 - operand->bits)) - 1))
+                     << operand->shift);
+    }
+  else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
+    {
+      *insnp |= (val >> (24 - operand->bits)) & ((1 << operand->bits) - 1);
+      *extensionp |= ((val & ((1 << (24 - operand->bits)) - 1))
+                     << operand->shift);
+    }
+  else if ((operand->flags & (MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG)))
+    {
+      /* See devo/opcodes/m10300-opc.c just before #define FSM0 for an
+         explanation of these variables.  Note that FMT-implied shifts
+        are not taken into account for FP registers.  */
+      unsigned long mask_low, mask_high;
+      int shl_low, shr_high, shl_high;
+
+      switch (operand->bits)
+       {
+       case 5:
+         /* Handle regular FP registers.  */
+         if (operand->shift >= 0)
+           {
+             /* This is an `m' register.  */
+             shl_low = operand->shift;
+             shl_high = 8 + (8 & shl_low) + (shl_low & 4) / 4;
+           }
+         else
+           {
+             /* This is an `n' register.  */
+             shl_low = -operand->shift;
+             shl_high = shl_low / 4;
+           }
+
+         mask_low = 0x0f;
+         mask_high = 0x10;
+         shr_high = 4;
+         break;
+
+       case 3:
+         /* Handle accumulators.  */
+         shl_low = -operand->shift;
+         shl_high = 0;
+         mask_low = 0x03;
+         mask_high = 0x04;
+         shr_high = 2;
+         break;
+
+       default:
+         abort ();
+       }
+      *insnp |= ((((val & mask_high) >> shr_high) << shl_high)
+                | ((val & mask_low) << shl_low));
+    }
+  else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0)
+    {
+      *insnp |= (((long) val & ((1 << operand->bits) - 1))
+                << (operand->shift + shift));
+
+      if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
+       *insnp |= (((long) val & ((1 << operand->bits) - 1))
+                  << (operand->shift + shift + operand->bits));
+    }
+  else
+    {
+      *extensionp |= (((long) val & ((1 << operand->bits) - 1))
+                     << (operand->shift + shift));
+
+      if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
+       *extensionp |= (((long) val & ((1 << operand->bits) - 1))
+                       << (operand->shift + shift + operand->bits));
+    }
+}
+
+void
+md_assemble (char *str)
+{
+  char *s;
+  struct mn10300_opcode *opcode;
+  struct mn10300_opcode *next_opcode;
+  const unsigned char *opindex_ptr;
+  int next_opindex, relaxable;
+  unsigned long insn, extension, size = 0;
+  char *f;
+  int i;
+  int match;
+
+  /* Get the opcode.  */
+  for (s = str; *s != '\0' && !ISSPACE (*s); s++)
+    ;
+  if (*s != '\0')
+    *s++ = '\0';
+
+  /* Find the first opcode with the proper name.  */
+  opcode = (struct mn10300_opcode *) hash_find (mn10300_hash, str);
+  if (opcode == NULL)
+    {
+      as_bad (_("Unrecognized opcode: `%s'"), str);
+      return;
+    }
+
+  str = s;
+  while (ISSPACE (*str))
+    ++str;
+
+  input_line_pointer = str;
+
+  for (;;)
+    {
+      const char *errmsg;
+      int op_idx;
+      char *hold;
+      int extra_shift = 0;
+
+      errmsg = _("Invalid opcode/operands");
+
+      /* Reset the array of register operands.  */
+      memset (mn10300_reg_operands, -1, sizeof (mn10300_reg_operands));
+
+      relaxable = 0;
+      fc = 0;
+      match = 0;
+      next_opindex = 0;
+      insn = opcode->opcode;
+      extension = 0;
+
+      /* If the instruction is not available on the current machine
+        then it can not possibly match.  */
+      if (opcode->machine
+         && !(opcode->machine == AM33_2 && HAVE_AM33_2)
+         && !(opcode->machine == AM33 && HAVE_AM33)
+         && !(opcode->machine == AM30 && HAVE_AM30))
+       goto error;
+
+      for (op_idx = 1, opindex_ptr = opcode->operands;
+          *opindex_ptr != 0;
+          opindex_ptr++, op_idx++)
+       {
+         const struct mn10300_operand *operand;
+         expressionS ex;
+
+         if (next_opindex == 0)
+           {
+             operand = &mn10300_operands[*opindex_ptr];
+           }
+         else
+           {
+             operand = &mn10300_operands[next_opindex];
+             next_opindex = 0;
+           }
 
          while (*str == ' ' || *str == ',')
            ++str;
 
          while (*str == ' ' || *str == ',')
            ++str;
@@ -806,7 +1310,7 @@ md_assemble (str)
          if (operand->flags & MN10300_OPERAND_RELAX)
            relaxable = 1;
 
          if (operand->flags & MN10300_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;
 
@@ -855,6 +1359,143 @@ md_assemble (str)
              *input_line_pointer = c;
              goto keep_going;
            }
              *input_line_pointer = c;
              goto keep_going;
            }
+         else if (operand->flags & MN10300_OPERAND_RREG)
+           {
+             if (!r_register_name (&ex))
+               {
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+           }
+         else if (operand->flags & MN10300_OPERAND_XRREG)
+           {
+             if (!xr_register_name (&ex))
+               {
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+           }
+         else if (operand->flags & MN10300_OPERAND_FSREG)
+           {
+             if (!float_register_name (&ex))
+               {
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+           }
+         else if (operand->flags & MN10300_OPERAND_FDREG)
+           {
+             if (!double_register_name (&ex))
+               {
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+           }
+         else if (operand->flags & MN10300_OPERAND_FPCR)
+           {
+             char *start = input_line_pointer;
+             char c = get_symbol_end ();
+
+             if (strcasecmp (start, "fpcr") != 0)
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             *input_line_pointer = c;
+             goto keep_going;
+           }
+         else if (operand->flags & MN10300_OPERAND_USP)
+           {
+             char *start = input_line_pointer;
+             char c = get_symbol_end ();
+
+             if (strcasecmp (start, "usp") != 0)
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             *input_line_pointer = c;
+             goto keep_going;
+           }
+         else if (operand->flags & MN10300_OPERAND_SSP)
+           {
+             char *start = input_line_pointer;
+             char c = get_symbol_end ();
+
+             if (strcasecmp (start, "ssp") != 0)
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             *input_line_pointer = c;
+             goto keep_going;
+           }
+         else if (operand->flags & MN10300_OPERAND_MSP)
+           {
+             char *start = input_line_pointer;
+             char c = get_symbol_end ();
+
+             if (strcasecmp (start, "msp") != 0)
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             *input_line_pointer = c;
+             goto keep_going;
+           }
+         else if (operand->flags & MN10300_OPERAND_PC)
+           {
+             char *start = input_line_pointer;
+             char c = get_symbol_end ();
+
+             if (strcasecmp (start, "pc") != 0)
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             *input_line_pointer = c;
+             goto keep_going;
+           }
+         else if (operand->flags & MN10300_OPERAND_EPSW)
+           {
+             char *start = input_line_pointer;
+             char c = get_symbol_end ();
+
+             if (strcasecmp (start, "epsw") != 0)
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             *input_line_pointer = c;
+             goto keep_going;
+           }
+         else if (operand->flags & MN10300_OPERAND_PLUS)
+           {
+             if (*input_line_pointer != '+')
+               {
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             input_line_pointer++;
+             goto keep_going;
+           }
          else if (operand->flags & MN10300_OPERAND_PSW)
            {
              char *start = input_line_pointer;
          else if (operand->flags & MN10300_OPERAND_PSW)
            {
              char *start = input_line_pointer;
@@ -897,10 +1538,10 @@ md_assemble (str)
 
              /* Eat the '['.  */
              input_line_pointer++;
 
              /* Eat the '['.  */
              input_line_pointer++;
-            
+
              /* We used to reject a null register list here; however,
              /* We used to reject a null register list here; however,
-                we accept it now so the compiler can emit "call" instructions
-                for all calls to named functions.
+                we accept it now so the compiler can emit "call"
+                instructions for all calls to named functions.
 
                 The linker can then fill in the appropriate bits for the
                 register list and stack size or change the instruction
 
                 The linker can then fill in the appropriate bits for the
                 register list and stack size or change the instruction
@@ -921,24 +1562,48 @@ md_assemble (str)
                      value |= 0x80;
                      *input_line_pointer = c;
                    }
                      value |= 0x80;
                      *input_line_pointer = c;
                    }
-                 else if (strcasecmp (start, "d3") == 0)
+                 else if (strcasecmp (start, "d3") == 0)
+                   {
+                     value |= 0x40;
+                     *input_line_pointer = c;
+                   }
+                 else if (strcasecmp (start, "a2") == 0)
+                   {
+                     value |= 0x20;
+                     *input_line_pointer = c;
+                   }
+                 else if (strcasecmp (start, "a3") == 0)
+                   {
+                     value |= 0x10;
+                     *input_line_pointer = c;
+                   }
+                 else if (strcasecmp (start, "other") == 0)
+                   {
+                     value |= 0x08;
+                     *input_line_pointer = c;
+                   }
+                 else if (HAVE_AM33
+                          && strcasecmp (start, "exreg0") == 0)
                    {
                    {
-                     value |= 0x40;
+                     value |= 0x04;
                      *input_line_pointer = c;
                    }
                      *input_line_pointer = c;
                    }
-                 else if (strcasecmp (start, "a2") == 0)
+                 else if (HAVE_AM33
+                          && strcasecmp (start, "exreg1") == 0)
                    {
                    {
-                     value |= 0x20;
+                     value |= 0x02;
                      *input_line_pointer = c;
                    }
                      *input_line_pointer = c;
                    }
-                 else if (strcasecmp (start, "a3") == 0)
+                 else if (HAVE_AM33
+                          && strcasecmp (start, "exother") == 0)
                    {
                    {
-                     value |= 0x10;
+                     value |= 0x01;
                      *input_line_pointer = c;
                    }
                      *input_line_pointer = c;
                    }
-                 else if (strcasecmp (start, "other") == 0)
+                 else if (HAVE_AM33
+                          && strcasecmp (start, "all") == 0)
                    {
                    {
-                     value |= 0x08;
+                     value |= 0xff;
                      *input_line_pointer = c;
                    }
                  else
                      *input_line_pointer = c;
                    }
                  else
@@ -949,8 +1614,8 @@ md_assemble (str)
                    }
                }
              input_line_pointer++;
                    }
                }
              input_line_pointer++;
-              mn10300_insert_operand (&insn, &extension, operand,
-                                      value, (char *) NULL, 0, 0);
+              mn10300_insert_operand (& insn, & extension, operand,
+                                      value, NULL, 0, 0);
              goto keep_going;
 
            }
              goto keep_going;
 
            }
@@ -972,6 +1637,30 @@ md_assemble (str)
              str = hold;
              goto error;
            }
              str = hold;
              goto error;
            }
+         else if (HAVE_AM33 && r_register_name (&ex))
+           {
+             input_line_pointer = hold;
+             str = hold;
+             goto error;
+           }
+         else if (HAVE_AM33 && xr_register_name (&ex))
+           {
+             input_line_pointer = hold;
+             str = hold;
+             goto error;
+           }
+         else if (HAVE_AM33_2 && float_register_name (&ex))
+           {
+             input_line_pointer = hold;
+             str = hold;
+             goto error;
+           }
+         else if (HAVE_AM33_2 && double_register_name (&ex))
+           {
+             input_line_pointer = hold;
+             str = hold;
+             goto error;
+           }
          else if (*str == ')' || *str == '(')
            {
              input_line_pointer = hold;
          else if (*str == ')' || *str == '(')
            {
              input_line_pointer = hold;
@@ -983,7 +1672,7 @@ md_assemble (str)
              expression (&ex);
            }
 
              expression (&ex);
            }
 
-         switch (ex.X_op) 
+         switch (ex.X_op)
            {
            case O_illegal:
              errmsg = _("illegal operand");
            {
            case O_illegal:
              errmsg = _("illegal operand");
@@ -996,13 +1685,17 @@ md_assemble (str)
                int mask;
 
                mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG;
                int mask;
 
                mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG;
+               if (HAVE_AM33)
+                 mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG;
+               if (HAVE_AM33_2)
+                 mask |= MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG;
                if ((operand->flags & mask) == 0)
                  {
                    input_line_pointer = hold;
                    str = hold;
                    goto error;
                  }
                if ((operand->flags & mask) == 0)
                  {
                    input_line_pointer = hold;
                    str = hold;
                    goto error;
                  }
-               
+
                if (opcode->format == FMT_D1 || opcode->format == FMT_S1)
                  extra_shift = 8;
                else if (opcode->format == FMT_D2
                if (opcode->format == FMT_D1 || opcode->format == FMT_S1)
                  extra_shift = 8;
                else if (opcode->format == FMT_D2
@@ -1012,13 +1705,16 @@ md_assemble (str)
                         || opcode->format == FMT_S6
                         || opcode->format == FMT_D5)
                  extra_shift = 16;
                         || opcode->format == FMT_S6
                         || opcode->format == FMT_D5)
                  extra_shift = 16;
+               else if (opcode->format == FMT_D7)
+                 extra_shift = 8;
+               else if (opcode->format == FMT_D8 || opcode->format == FMT_D9)
+                 extra_shift = 8;
                else
                  extra_shift = 0;
                else
                  extra_shift = 0;
-             
-               mn10300_insert_operand (&insn, &extension, operand,
-                                       ex.X_add_number, (char *) NULL,
-                                       0, extra_shift);
 
 
+               mn10300_insert_operand (& insn, & extension, operand,
+                                       ex.X_add_number, NULL,
+                                       0, extra_shift);
 
                /* And note the register number in the register array.  */
                mn10300_reg_operands[op_idx - 1] = ex.X_add_number;
 
                /* And note the register number in the register array.  */
                mn10300_reg_operands[op_idx - 1] = ex.X_add_number;
@@ -1031,16 +1727,15 @@ md_assemble (str)
                 then promote it (ie this opcode does not match).  */
              if (operand->flags
                  & (MN10300_OPERAND_PROMOTE | MN10300_OPERAND_RELAX)
                 then promote it (ie this opcode does not match).  */
              if (operand->flags
                  & (MN10300_OPERAND_PROMOTE | MN10300_OPERAND_RELAX)
-                 && ! check_operand (insn, operand, ex.X_add_number))
+                 && !check_operand (operand, ex.X_add_number))
                {
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
 
                {
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
 
-             mn10300_insert_operand (&insn, &extension, operand,
-                                     ex.X_add_number, (char *) NULL,
-                                     0, 0);
+             mn10300_insert_operand (& insn, & extension, operand,
+                                     ex.X_add_number, NULL, 0, 0);
              break;
 
            default:
              break;
 
            default:
@@ -1059,6 +1754,8 @@ md_assemble (str)
              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;
+             if (mn10300_check_fixup (& fixups[fc]))
+               goto error;
              ++fc;
              break;
            }
              ++fc;
              break;
            }
@@ -1069,7 +1766,6 @@ keep_going:
 
          while (*str == ' ' || *str == ',')
            ++str;
 
          while (*str == ' ' || *str == ',')
            ++str;
-
        }
 
       /* Make sure we used all the operands!  */
        }
 
       /* Make sure we used all the operands!  */
@@ -1080,8 +1776,6 @@ keep_going:
         that they do indeed not match.  */
       if (opcode->no_match_operands)
        {
         that they do indeed not match.  */
       if (opcode->no_match_operands)
        {
-         int i;
-
          /* Look at each operand to see if it's marked.  */
          for (i = 0; i < MN10300_MAX_OPERANDS; i++)
            {
          /* Look at each operand to see if it's marked.  */
          for (i = 0; i < MN10300_MAX_OPERANDS; i++)
            {
@@ -1107,21 +1801,21 @@ 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')
@@ -1139,6 +1833,17 @@ keep_going:
   if (opcode->format == FMT_S2 || opcode->format == FMT_D1)
     size = 3;
 
   if (opcode->format == FMT_S2 || opcode->format == FMT_D1)
     size = 3;
 
+  if (opcode->format == FMT_D6)
+    size = 3;
+
+  if (opcode->format == FMT_D7 || opcode->format == FMT_D10)
+    size = 4;
+
+  if (opcode->format == FMT_D8)
+    size = 6;
+
+  if (opcode->format == FMT_D9)
+    size = 7;
 
   if (opcode->format == FMT_S4)
     size = 5;
 
   if (opcode->format == FMT_S4)
     size = 5;
@@ -1149,14 +1854,36 @@ keep_going:
   if (opcode->format == FMT_D2)
     size = 4;
 
   if (opcode->format == FMT_D2)
     size = 4;
 
+  if (opcode->format == FMT_D3)
+    size = 5;
+
   if (opcode->format == FMT_D4)
     size = 6;
 
   if (relaxable && fc > 0)
     {
   if (opcode->format == FMT_D4)
     size = 6;
 
   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;
       int type;
 
       int type;
 
-      /* bCC */
+      /* We want to anchor the line info to the previous frag (if
+        there isn't one, create it), so that, when the insn is
+        resized, we still get the right address for the beginning of
+        the region.  */
+      f = frag_more (0);
+      dwarf2_emit_insn (0);
+
+      /* bCC  */
       if (size == 2)
        {
          /* Handle bra specially.  Basically treat it like jmp so
       if (size == 2)
        {
          /* Handle bra specially.  Basically treat it like jmp so
@@ -1171,24 +1898,27 @@ keep_going:
          else
            type = 0;
        }
          else
            type = 0;
        }
-      /* call */
+      /* call  */
       else if (size == 5)
       else if (size == 5)
-        type = 6;
-      /* calls */
+       type = 6;
+      /* calls  */
       else if (size == 4)
        type = 8;
       else if (size == 4)
        type = 8;
-      /* jmp */
+      /* jmp  */
       else if (size == 3 && opcode->opcode == 0xcc0000)
        type = 10;
       else if (size == 3 && opcode->opcode == 0xcc0000)
        type = 10;
-      /* bCC (uncommon cases) */
+      else if (size == 3 && (opcode->opcode & 0xfff000) == 0xf8d000)
+       type = 13;
+      /* bCC (uncommon cases)  */
       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);
+
       /* This is pretty hokey.  We basically just care about the
         opcode, so we have to write out the first word big endian.
 
       /* This is pretty hokey.  We basically just care about the
         opcode, so we have to write out the first word big endian.
 
@@ -1223,6 +1953,9 @@ keep_going:
       if (opcode->format == FMT_S0
          || opcode->format == FMT_S1
          || opcode->format == FMT_D0
       if (opcode->format == FMT_S0
          || opcode->format == FMT_S1
          || opcode->format == FMT_D0
+         || opcode->format == FMT_D6
+         || opcode->format == FMT_D7
+         || opcode->format == FMT_D10
          || opcode->format == FMT_D1)
        {
          number_to_chars_bigendian (f, insn, size);
          || opcode->format == FMT_D1)
        {
          number_to_chars_bigendian (f, insn, size);
@@ -1283,87 +2016,111 @@ keep_going:
             is really two 8bit immediates.  */
          number_to_chars_bigendian (f, insn, 4);
        }
             is really two 8bit immediates.  */
          number_to_chars_bigendian (f, insn, 4);
        }
+      else if (opcode->format == FMT_D3)
+       {
+         number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+         number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+         number_to_chars_bigendian (f + 4, extension & 0xff, 1);
+       }
       else if (opcode->format == FMT_D4)
        {
          unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
       else if (opcode->format == FMT_D4)
        {
          unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
+
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_littleendian (f + 2, temp, 4);
        }
       else if (opcode->format == FMT_D5)
        {
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_littleendian (f + 2, temp, 4);
        }
       else if (opcode->format == FMT_D5)
        {
-         unsigned long temp = ((insn & 0xffff) << 16)
-                               | ((extension >> 8) & 0xffff);
+         unsigned long temp = (((insn & 0xffff) << 16)
+                               | ((extension >> 8) & 0xffff));
+
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_littleendian (f + 2, temp, 4);
          number_to_chars_bigendian (f + 6, extension & 0xff, 1);
        }
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_littleendian (f + 2, temp, 4);
          number_to_chars_bigendian (f + 6, extension & 0xff, 1);
        }
+      else if (opcode->format == FMT_D8)
+       {
+         unsigned long temp = ((insn & 0xff) << 16) | (extension & 0xffff);
+
+         number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
+         number_to_chars_bigendian (f + 3, (temp & 0xff), 1);
+         number_to_chars_littleendian (f + 4, temp >> 8, 2);
+       }
+      else if (opcode->format == FMT_D9)
+       {
+         unsigned long temp = ((insn & 0xff) << 24) | (extension & 0xffffff);
+
+         number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
+         number_to_chars_littleendian (f + 3, temp, 4);
+       }
 
       /* Create any fixups.  */
       for (i = 0; i < fc; i++)
        {
          const struct mn10300_operand *operand;
 
       /* Create any fixups.  */
       for (i = 0; i < fc; i++)
        {
          const struct mn10300_operand *operand;
+         int reloc_size;
 
          operand = &mn10300_operands[fixups[i].opindex];
 
          operand = &mn10300_operands[fixups[i].opindex];
-         if (fixups[i].reloc != BFD_RELOC_UNUSED)
+         if (fixups[i].reloc != BFD_RELOC_UNUSED
+             && fixups[i].reloc != BFD_RELOC_32_GOT_PCREL
+             && fixups[i].reloc != BFD_RELOC_32_GOTOFF
+             && fixups[i].reloc != BFD_RELOC_32_PLT_PCREL
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GD
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LD
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LDO
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GOTIE
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_IE
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LE
+             && fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
            {
              reloc_howto_type *reloc_howto;
            {
              reloc_howto_type *reloc_howto;
-             int size;
              int offset;
              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 - size;
-             fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
-                                 size, &fixups[i].exp,
-                                 reloc_howto->pc_relative,
-                                 fixups[i].reloc);
+             fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+                          reloc_size, &fixups[i].exp,
+                          reloc_howto->pc_relative,
+                          fixups[i].reloc);
            }
          else
            {
            }
          else
            {
-             int reloc, pcrel, reloc_size, offset;
+             int reloc, pcrel, offset;
              fixS *fixP;
 
              reloc = BFD_RELOC_NONE;
              fixS *fixP;
 
              reloc = BFD_RELOC_NONE;
+             if (fixups[i].reloc != BFD_RELOC_UNUSED)
+               reloc = fixups[i].reloc;
              /* How big is the reloc?  Remember SPLIT relocs are
                 implicitly 32bits.  */
              if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
                reloc_size = 32;
              /* How big is the reloc?  Remember SPLIT relocs are
                 implicitly 32bits.  */
              if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
                reloc_size = 32;
+             else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
+               reloc_size = 24;
              else
                reloc_size = operand->bits;
 
              /* Is the reloc pc-relative?  */
              pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
              else
                reloc_size = operand->bits;
 
              /* Is the reloc pc-relative?  */
              pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
+             if (reloc != BFD_RELOC_NONE)
+               pcrel = bfd_reloc_type_lookup (stdoutput, reloc)->pc_relative;
 
 
-             /* Gross.  This disgusting hack is to make sure we
-                get the right offset for the 16/32 bit reloc in 
-                "call" instructions.  Basically they're a pain
-                because the reloc isn't at the end of the instruction.  */
-             if ((size == 5 || size == 7)
-                 && (((insn >> 24) & 0xff) == 0xcd
-                     || ((insn >> 24) & 0xff) == 0xdd))
-               size -= 2;
-
-             /* Similarly for certain bit instructions which don't
-                hav their 32bit reloc at the tail of the instruction.  */
-             if (size == 7
-                 && (((insn >> 16) & 0xffff) == 0xfe00
-                     || ((insn >> 16) & 0xffff) == 0xfe01
-                     || ((insn >> 16) & 0xffff) == 0xfe02))
-               size -= 1;
-       
-             offset = size - reloc_size / 8;
+             offset = size - (reloc_size + operand->shift) / 8;
 
              /* Choose a proper BFD relocation type.  */
 
              /* Choose a proper BFD relocation type.  */
-             if (pcrel)
+             if (reloc != BFD_RELOC_NONE)
+               ;
+             else if (pcrel)
                {
                  if (reloc_size == 32)
                    reloc = BFD_RELOC_32_PCREL;
                {
                  if (reloc_size == 32)
                    reloc = BFD_RELOC_32_PCREL;
@@ -1386,264 +2143,497 @@ keep_going:
                    abort ();
                }
 
                    abort ();
                }
 
-             /* Convert the size of the reloc into what fix_new_exp wants.  */
-             reloc_size = reloc_size / 8;
-             if (reloc_size == 8)
-               reloc_size = 0;
-             else if (reloc_size == 16)
-               reloc_size = 1;
-             else if (reloc_size == 32)
-               reloc_size = 2;
-
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
-                                 reloc_size, &fixups[i].exp, pcrel,
+                                 reloc_size / 8, &fixups[i].exp, pcrel,
                                  ((bfd_reloc_code_real_type) reloc));
 
              if (pcrel)
                fixP->fx_offset += offset;
            }
        }
                                  ((bfd_reloc_code_real_type) reloc));
 
              if (pcrel)
                fixP->fx_offset += offset;
            }
        }
+
+      dwarf2_emit_insn (size);
     }
     }
+
+  /* Label this frag as one that contains instructions.  */
+  frag_now->tc_frag_data = TRUE;
 }
 
 }
 
+/* If while processing a fixup, a reloc really needs to be created
+   then it is done here.  */
 
 
-/* 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 **
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 {
 {
+  static arelent * no_relocs = NULL;
+  static arelent * relocs[MAX_RELOC_EXPANSION + 1];
   arelent *reloc;
   arelent *reloc;
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+
+  reloc = xmalloc (sizeof (arelent));
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
-  if (reloc->howto == (reloc_howto_type *) NULL)
+  if (reloc->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
     {
       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 %d not supported by object file format"),
+                   (int) fixp->fx_r_type);
+      free (reloc);
+      return & no_relocs;
     }
     }
+
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+  relocs[0] = reloc;
+  relocs[1] = NULL;
+
+  if (fixp->fx_subsy
+      && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
+    {
+      fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
+      fixp->fx_subsy = NULL;
+    }
 
   if (fixp->fx_addsy && fixp->fx_subsy)
     {
 
   if (fixp->fx_addsy && fixp->fx_subsy)
     {
-    
-      if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
-         || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
+      asection *asec, *ssec;
+
+      asec = S_GET_SEGMENT (fixp->fx_addsy);
+      ssec = S_GET_SEGMENT (fixp->fx_subsy);
+
+      /* If we have a difference between two (non-absolute) symbols we must
+        generate two relocs (one for each symbol) and allow the linker to
+        resolve them - relaxation may change the distances between symbols,
+        even local symbols defined in the same section.  */
+      if (ssec != absolute_section || asec != absolute_section)
        {
        {
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       "Difference of symbols in different sections is not supported");
-         return NULL;
+         arelent * reloc2 = xmalloc (sizeof * reloc);
+
+         relocs[0] = reloc2;
+         relocs[1] = reloc;
+
+         reloc2->address = reloc->address;
+         reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_MN10300_SYM_DIFF);
+         reloc2->addend = - S_GET_VALUE (fixp->fx_subsy);
+         reloc2->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+
+         reloc->addend = fixp->fx_offset; 
+         if (asec == absolute_section)
+           {
+             reloc->addend += S_GET_VALUE (fixp->fx_addsy);
+             reloc->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+           }
+         else
+           {
+             reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+             *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+           }
+
+         fixp->fx_pcrel = 0;
+         fixp->fx_done = 1;
+         return relocs;
        }
        }
+      else
+       {
+         char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
+
+         reloc->addend = (S_GET_VALUE (fixp->fx_addsy)
+                          - S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset);
+
+         switch (fixp->fx_r_type)
+           {
+           case BFD_RELOC_8:
+             md_number_to_chars (fixpos, reloc->addend, 1);
+             break;
 
 
-      reloc->sym_ptr_ptr = &bfd_abs_symbol;
-      reloc->addend = (S_GET_VALUE (fixp->fx_addsy)
-                      - S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset);
+           case BFD_RELOC_16:
+             md_number_to_chars (fixpos, reloc->addend, 2);
+             break;
+
+           case BFD_RELOC_24:
+             md_number_to_chars (fixpos, reloc->addend, 3);
+             break;
+
+           case BFD_RELOC_32:
+             md_number_to_chars (fixpos, reloc->addend, 4);
+             break;
+
+           default:
+             reloc->sym_ptr_ptr
+               = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
+             return relocs;
+           }
+
+         free (reloc);
+         return & no_relocs;
+       }
     }
     }
-  else 
+  else
     {
     {
-      reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       reloc->addend = fixp->fx_offset;
     }
       reloc->addend = fixp->fx_offset;
     }
-  return reloc;
+  return relocs;
+}
+
+/* Returns true iff the symbol attached to the frag is at a known location
+   in the given section, (and hence the relocation to it can be relaxed by
+   the assembler).  */
+static inline bfd_boolean
+has_known_symbol_location (fragS * fragp, asection * sec)
+{
+  symbolS * sym = fragp->fr_symbol;
+  
+  return sym != NULL
+    && S_IS_DEFINED (sym)
+    && ! S_IS_WEAK (sym)
+    && S_GET_SEGMENT (sym) == sec;
 }
 
 int
 }
 
 int
-md_estimate_size_before_relax (fragp, seg)
-     fragS *fragp;
-     asection *seg;
+md_estimate_size_before_relax (fragS *fragp, asection *seg)
 {
 {
-  if (fragp->fr_subtype == 0)
-    return 2;
-  if (fragp->fr_subtype == 3)
+  if (fragp->fr_subtype == 6
+      && ! has_known_symbol_location (fragp, seg))
+    fragp->fr_subtype = 7;
+  else if (fragp->fr_subtype == 8
+          && ! has_known_symbol_location (fragp, seg))
+    fragp->fr_subtype = 9;
+  else if (fragp->fr_subtype == 10
+          && ! has_known_symbol_location (fragp, seg))
+    fragp->fr_subtype = 12;
+
+  if (fragp->fr_subtype == 13)
     return 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 7;
-       }
-      else
-       return 5;
-    }
-  if (fragp->fr_subtype == 8)
+
+  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)
+{
+  if (fixp->fx_addsy != (symbolS *) NULL
+      && (!S_IS_DEFINED (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
+    /* The symbol is undefined or weak.  Let the linker figure it out.  */
+    return 0;
+
+  return fixp->fx_frag->fr_address + fixp->fx_where;
+}
+
+void
+md_apply_fix (fixS * fixP, valueT * valP, segT seg)
+{
+  char * fixpos = fixP->fx_where + fixP->fx_frag->fr_literal;
+  int size = 0;
+  int value = (int) * valP;
+
+  gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+
+  /* This should never happen.  */
+  if (seg->flags & SEC_ALLOC)
+    abort ();
+
+  /* The value we are passed in *valuep includes the symbol values.
+     If we are doing this relocation the code in write.c is going to
+     call bfd_install_relocation, which is also going to use the symbol
+     value.  That means that if the reloc is fully resolved we want to
+     use *valuep since bfd_install_relocation is not being used.
+
+     However, if the reloc is not fully resolved we do not want to use
+     *valuep, and must use fx_offset instead.  However, if the reloc
+     is PC relative, we do want to use *valuep since it includes the
+     result of md_pcrel_from.  */
+  if (fixP->fx_addsy != NULL && ! fixP->fx_pcrel)
+    value = fixP->fx_offset;
+
+  /* If the fix is relative to a symbol which is not defined, or not
+     in the same segment as the fix, we cannot resolve it here.  */
+  if (fixP->fx_addsy != NULL
+      && (! S_IS_DEFINED (fixP->fx_addsy)
+         || (S_GET_SEGMENT (fixP->fx_addsy) != seg)))
     {
     {
-      if (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol))
-       {
-         fragp->fr_subtype = 9;
-         return 6;
-       }
-      else
-       return 4;
+      fixP->fx_done = 0;
+      return;
     }
     }
-  if (fragp->fr_subtype == 10)
+
+  switch (fixP->fx_r_type)
     {
     {
-      if (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol))
-       {
-         fragp->fr_subtype = 12;
-         return 5;
-       }
-      else
-       return 2;
+    case BFD_RELOC_8:
+    case BFD_RELOC_8_PCREL:
+      size = 1;
+      break;
+
+    case BFD_RELOC_16:
+    case BFD_RELOC_16_PCREL:
+      size = 2;
+      break;
+
+    case BFD_RELOC_32:
+    case BFD_RELOC_32_PCREL:
+      size = 4;
+      break;
+
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      return;
+
+    case BFD_RELOC_MN10300_ALIGN:
+      fixP->fx_done = 1;
+      return;
+      
+    case BFD_RELOC_NONE:
+    default:
+      as_bad_where (fixP->fx_file, fixP->fx_line,
+                   _("Bad relocation fixup type (%d)"), fixP->fx_r_type);
     }
     }
-} 
 
 
-long
-md_pcrel_from (fixp)
-     fixS *fixp;
+  md_number_to_chars (fixpos, value, size);
+
+  /* If a symbol remains, pass the fixup, as a reloc, onto the linker.  */
+  if (fixP->fx_addsy == NULL)
+    fixP->fx_done = 1;
+}
+
+/* Return zero if the fixup in fixp should be left alone and not
+   adjusted.  */
+
+bfd_boolean
+mn10300_fix_adjustable (struct fix *fixp)
 {
 {
-  return fixp->fx_frag->fr_address;
-#if 0
-  if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy))
+  if (fixp->fx_pcrel)
     {
     {
-      /* The symbol is undefined.  Let the linker figure it out.  */
-      return 0;
+      if (TC_FORCE_RELOCATION_LOCAL (fixp))
+       return FALSE;
     }
     }
-  return fixp->fx_frag->fr_address + fixp->fx_where;
-#endif
+  /* Non-relative relocs can (and must) be adjusted if they do
+     not meet the criteria below, or the generic criteria.  */
+  else if (TC_FORCE_RELOCATION (fixp))
+    return FALSE;
+
+  /* Do not adjust relocations involving symbols in code sections,
+     because it breaks linker relaxations.  This could be fixed in the
+     linker, but this fix is simpler, and it pretty much only affects
+     object size a little bit.  */
+  if (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_CODE)
+    return FALSE;
+
+  /* Likewise, do not adjust symbols that won't be merged, or debug
+     symbols, because they too break relaxation.  We do want to adjust
+     other mergable symbols, like .rodata, because code relaxations
+     need section-relative symbols to properly relax them.  */
+  if (! (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE))
+    return FALSE;
+
+  if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0)
+    return FALSE;
+
+  return TRUE;
 }
 
 }
 
-int
-md_apply_fix3 (fixp, valuep, seg)
-     fixS *fixp;
-     valueT *valuep;
-     segT seg;
+static void
+set_arch_mach (int mach)
 {
 {
-  /* We shouldn't ever get here because linkrelax is nonzero.  */
-  abort ();
-  fixp->fx_done = 1;
-  return 0;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
+    as_warn (_("could not set architecture and machine"));
+
+  current_machine = mach;
 }
 
 }
 
-/* Insert an operand value into an instruction.  */
+static inline char *
+mn10300_end_of_match (char *cont, char *what)
+{
+  int len = strlen (what);
 
 
-static void
-mn10300_insert_operand (insnp, extensionp, operand, val, file, line, shift)
-     unsigned long *insnp;
-     unsigned long *extensionp;
-     const struct mn10300_operand *operand;
-     offsetT val;
-     char *file;
-     unsigned int line;
-     unsigned int shift;
+  if (strncmp (cont, what, strlen (what)) == 0
+      && ! is_part_of_name (cont[len]))
+    return cont + len;
+
+  return NULL;
+}  
+
+int
+mn10300_parse_name (char const *name,
+                   expressionS *exprP,
+                   enum expr_mode mode,
+                   char *nextcharP)
 {
 {
-  /* No need to check 32bit operands for a bit.  Note that
-     MN10300_OPERAND_SPLIT is an implicit 32bit operand.  */
-  if (operand->bits != 32
-      && (operand->flags & MN10300_OPERAND_SPLIT) == 0)
-    {
-      long min, max;
-      offsetT test;
-      int bits;
+  char *next = input_line_pointer;
+  char *next_end;
+  int reloc_type;
+  segT segment;
 
 
-      bits = operand->bits;
+  exprP->X_op_symbol = NULL;
 
 
-      if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
+  if (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
+    {
+      if (! GOT_symbol)
+       GOT_symbol = symbol_find_or_make (name);
+
+      exprP->X_add_symbol = GOT_symbol;
+    no_suffix:
+      /* If we have an absolute symbol or a reg,
+        then we know its value now.  */
+      segment = S_GET_SEGMENT (exprP->X_add_symbol);
+      if (mode != expr_defer && segment == absolute_section)
        {
        {
-         max = (1 << (bits - 1)) - 1;
-         min = - (1 << (bits - 1));
+         exprP->X_op = O_constant;
+         exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
+         exprP->X_add_symbol = NULL;
+       }
+      else if (mode != expr_defer && segment == reg_section)
+       {
+         exprP->X_op = O_register;
+         exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
+         exprP->X_add_symbol = NULL;
        }
       else
        }
       else
-        {
-          max = (1 << 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);
-        }
-    }
+       {
+         exprP->X_op = O_symbol;
+         exprP->X_add_number = 0;
+       }
 
 
-  if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
-    {
-      *insnp |= (val >> (32 - operand->bits)) & ((1 << operand->bits) - 1);
-      *extensionp |= ((val & ((1 << (32 - operand->bits)) - 1))
-                     << operand->shift);
+      return 1;
     }
     }
-  else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0)
-    {
-      *insnp |= (((long) val & ((1 << operand->bits) - 1))
-                << (operand->shift + shift));
 
 
-      if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
-       *insnp |= (((long) val & ((1 << operand->bits) - 1))
-                  << (operand->shift + shift + operand->bits));
-    }
+  exprP->X_add_symbol = symbol_find_or_make (name);
+  
+  if (*nextcharP != '@')
+    goto no_suffix;
+  else if ((next_end = mn10300_end_of_match (next + 1, "GOTOFF")))
+    reloc_type = BFD_RELOC_32_GOTOFF;
+  else if ((next_end = mn10300_end_of_match (next + 1, "GOT")))
+    reloc_type = BFD_RELOC_MN10300_GOT32;
+  else if ((next_end = mn10300_end_of_match (next + 1, "PLT")))
+    reloc_type = BFD_RELOC_32_PLT_PCREL;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tlsgd")))
+    reloc_type = BFD_RELOC_MN10300_TLS_GD;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tlsldm")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LD;
+  else if ((next_end = mn10300_end_of_match (next + 1, "dtpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LDO;
+  else if ((next_end = mn10300_end_of_match (next + 1, "gotntpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_GOTIE;
+  else if ((next_end = mn10300_end_of_match (next + 1, "indntpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_IE;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LE;
   else
   else
-    {
-      *extensionp |= (((long) val & ((1 << operand->bits) - 1))
-                     << (operand->shift + shift));
+    goto no_suffix;
 
 
-      if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
-       *extensionp |= (((long) val & ((1 << operand->bits) - 1))
-                       << (operand->shift + shift + operand->bits));
-    }
+  *input_line_pointer = *nextcharP;
+  input_line_pointer = next_end;
+  *nextcharP = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  exprP->X_op = O_PIC_reloc;
+  exprP->X_add_number = 0;
+  exprP->X_md = reloc_type;
+
+  return 1;
 }
 
 }
 
-static unsigned long
-check_operand (insn, operand, val)
-     unsigned long insn;
-     const struct mn10300_operand *operand;
-     offsetT val;
+/* The target specific pseudo-ops which we support.  */
+const pseudo_typeS md_pseudo_table[] =
 {
 {
-  /* No need to check 32bit operands for a bit.  Note that
-     MN10300_OPERAND_SPLIT is an implicit 32bit operand.  */
-  if (operand->bits != 32
-      && (operand->flags & MN10300_OPERAND_SPLIT) == 0)
+  { "am30",    set_arch_mach,  AM30 },
+  { "am33",    set_arch_mach,  AM33 },
+  { "am33_2",  set_arch_mach,  AM33_2 },
+  { "mn10300", set_arch_mach,  MN103 },
+  {NULL, 0, 0}
+};
+
+/* Returns FALSE if there is some mn10300 specific reason why the
+   subtraction of two same-section symbols cannot be computed by
+   the assembler.  */
+
+bfd_boolean
+mn10300_allow_local_subtract (expressionS * left, expressionS * right, segT section)
+{
+  bfd_boolean result;
+  fragS * left_frag;
+  fragS * right_frag;
+  fragS * frag;
+
+  /* If we are not performing linker relaxation then we have nothing
+     to worry about.  */
+  if (linkrelax == 0)
+    return TRUE;
+
+  /* If the symbols are not in a code section then they are OK.  */
+  if ((section->flags & SEC_CODE) == 0)
+    return TRUE;
+
+  /* Otherwise we have to scan the fragments between the two symbols.
+     If any instructions are found then we have to assume that linker
+     relaxation may change their size and so we must delay resolving
+     the subtraction until the final link.  */
+  left_frag = symbol_get_frag (left->X_add_symbol);
+  right_frag = symbol_get_frag (right->X_add_symbol);
+
+  if (left_frag == right_frag)
+    return ! left_frag->tc_frag_data;
+
+  result = TRUE;
+  for (frag = left_frag; frag != NULL; frag = frag->fr_next)
     {
     {
-      long min, max;
-      offsetT test;
-      int bits;
+      if (frag->tc_frag_data)
+       result = FALSE;
+      if (frag == right_frag)
+       break;
+    }
 
 
-      bits = operand->bits;
+  if (frag == NULL)
+    for (frag = right_frag; frag != NULL; frag = frag->fr_next)
+      {
+       if (frag->tc_frag_data)
+         result = FALSE;
+       if (frag == left_frag)
+         break;
+      }
 
 
-      if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
-       {
-         max = (1 << (bits - 1)) - 1;
-         min = - (1 << (bits - 1));
-       }
-      else
-        {
-          max = (1 << bits) - 1;
-          min = 0;
-        }
+  if (frag == NULL)
+    /* The two symbols are on disjoint fragment chains
+       - we cannot possibly compute their difference.  */
+    return FALSE;
 
 
-      test = val;
+  return result;
+}
 
 
+/* When relaxing, we need to output a reloc for any .align directive
+   that requests alignment to a two byte boundary or larger.  */
 
 
-      if (test < (offsetT) min || test > (offsetT) max)
-       return 0;
-      else
-       return 1;
-    }
-  return 1;
+void
+mn10300_handle_align (fragS *frag)
+{
+  if (linkrelax
+      && (frag->fr_type == rs_align
+         || frag->fr_type == rs_align_code)
+      && frag->fr_address + frag->fr_fix > 0
+      && frag->fr_offset > 1
+      && now_seg != bss_section
+      /* Do not create relocs for the merging sections - such
+        relocs will prevent the contents from being merged.  */
+      && (bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE) == 0)
+    /* Create a new fixup to record the alignment request.  The symbol is
+       irrelevent but must be present so we use the absolute section symbol.
+       The offset from the symbol is used to record the power-of-two alignment
+       value.  The size is set to 0 because the frag may already be aligned,
+       thus causing cvt_frag_to_fill to reduce the size of the frag to zero.  */
+    fix_new (frag, frag->fr_fix, 0, & abs_symbol, frag->fr_offset, FALSE,
+            BFD_RELOC_MN10300_ALIGN);
 }
 
 }
 
-static void
-set_arch_mach (mach)
-     int mach;
+bfd_boolean
+mn10300_force_relocation (struct fix * fixp)
 {
 {
-  if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
-    as_warn (_("could not set architecture and machine"));
+  if (linkrelax
+      && (fixp->fx_pcrel
+         || fixp->fx_r_type == BFD_RELOC_MN10300_ALIGN))
+    return TRUE;
 
 
-  current_machine = mach;
+  return generic_force_reloc (fixp);
 }
 }
This page took 0.053496 seconds and 4 git commands to generate.