]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - gas/config/tc-mn10300.c
Imported binutils-2.20
[msp430-binutils.git] / gas / config / tc-mn10300.c
index 64d1f6dd38d5766b7997f809201a5c0644a0cbf7..9ac44ad5a6d442da7975a8138ce1d5dad67a6c72 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mn10300.c -- Assembler code for the Matsushita 10300
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007 Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -24,6 +24,7 @@
 #include "subsegs.h"
 #include "opcode/mn10300.h"
 #include "dwarf2dbg.h"
+#include "libiberty.h"
 \f
 /* Structure to hold information about predefined registers.  */
 struct reg_name
@@ -59,7 +60,7 @@ const relax_typeS md_relax_table[] =
      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  */
+  /* bCC relaxing.  */
   {0x7f, -0x80, 2, 1},
   {0x7fff + 2, -0x8000 + 2, 5, 2},
   {0x7fffffff, -0x80000000, 7, 0},
@@ -69,49 +70,34 @@ const relax_typeS md_relax_table[] =
   {0x7fff + 3, -0x8000 + 3, 6, 5},
   {0x7fffffff, -0x80000000, 8, 0},
 
-  /* call relaxing  */
+  /* call relaxing.  */
   {0x7fff, -0x8000, 5, 7},
   {0x7fffffff, -0x80000000, 7, 0},
 
-  /* calls relaxing  */
+  /* calls relaxing.  */
   {0x7fff, -0x8000, 4, 9},
   {0x7fffffff, -0x80000000, 6, 0},
 
-  /* jmp relaxing  */
+  /* jmp relaxing.  */
   {0x7f, -0x80, 2, 11},
   {0x7fff, -0x8000, 3, 12},
   {0x7fffffff, -0x80000000, 5, 0},
 
-  /* fbCC relaxing  */
+  /* 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 bfd_boolean data_register_name PARAMS ((expressionS *expressionP));
-static bfd_boolean address_register_name PARAMS ((expressionS *expressionP));
-static bfd_boolean other_register_name PARAMS ((expressionS *expressionP));
-static bfd_boolean r_register_name PARAMS ((expressionS *expressionP));
-static bfd_boolean xr_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;
 
 /* Fixups.  */
-#define MAX_INSN_FIXUPS (5)
+#define MAX_INSN_FIXUPS 5
+
 struct mn10300_fixup
 {
   expressionS exp;
@@ -126,24 +112,17 @@ static int fc;
 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,          AM30 },
-  { "am33",    set_arch_mach,          AM33 },
-  { "am33_2",  (void (*) PARAMS ((int))) set_arch_mach, AM33_2 },
-  { "mn10300", set_arch_mach,          MN103 },
-  {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)
+#define HAVE_AM33   (current_machine == AM33 || HAVE_AM33_2)
+#define HAVE_AM30   (current_machine == AM30)
 
 /* Opcode hash table.  */
 static struct hash_control *mn10300_hash;
@@ -156,8 +135,6 @@ static const struct reg_name data_registers[] =
   { "d2", 2 },
   { "d3", 3 },
 };
-#define DATA_REG_NAME_CNT                              \
-  (sizeof (data_registers) / sizeof (struct reg_name))
 
 static const struct reg_name address_registers[] =
 {
@@ -167,9 +144,6 @@ static const struct reg_name address_registers[] =
   { "a3", 3 },
 };
 
-#define ADDRESS_REG_NAME_CNT                                   \
-  (sizeof (address_registers) / sizeof (struct reg_name))
-
 static const struct reg_name r_registers[] =
 {
   { "a0", 8 },
@@ -214,9 +188,6 @@ static const struct reg_name r_registers[] =
   { "r9", 9 },
 };
 
-#define R_REG_NAME_CNT                                 \
-  (sizeof (r_registers) / sizeof (struct reg_name))
-
 static const struct reg_name xr_registers[] =
 {
   { "mcrh", 2 },
@@ -242,26 +213,6 @@ static const struct reg_name xr_registers[] =
   { "xr9", 9 },
 };
 
-#define XR_REG_NAME_CNT                                        \
-  (sizeof (xr_registers) / sizeof (struct reg_name))
-
-/* 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[] =
-{
-  { "epsw", AM33 },
-  { "mdr", 0 },
-  { "pc", AM33 },
-  { "psw", 0 },
-  { "sp", 0 },
-};
-
-#define OTHER_REG_NAME_CNT                             \
-  (sizeof (other_registers) / sizeof (struct reg_name))
-
 static const struct reg_name float_registers[] =
 {
   { "fs0", 0 },
@@ -298,9 +249,6 @@ static const struct reg_name float_registers[] =
   { "fs9",   9 },
 };
 
-#define FLOAT_REG_NAME_CNT \
-  (sizeof (float_registers) / sizeof (struct reg_name))
-
 static const struct reg_name double_registers[] =
 {
   { "fd0",   0 },
@@ -321,28 +269,40 @@ static const struct reg_name double_registers[] =
   { "fd8",   8 },
 };
 
-#define DOUBLE_REG_NAME_CNT \
-  (sizeof (double_registers) / sizeof (struct reg_name))
+/* 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[] =
+{
+  { "epsw", AM33 },
+  { "mdr", 0 },
+  { "pc", AM33 },
+  { "psw", 0 },
+  { "sp", 0 },
+};
 
+#define OTHER_REG_NAME_CNT     ARRAY_SIZE (other_registers)
 
-/* 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.  */
+/* 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
-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
     {
+      int cmp, middle;
+
       middle = (low + high) / 2;
       cmp = strcasecmp (name, regs[middle].name);
       if (cmp < 0)
@@ -353,23 +313,22 @@ reg_name_search (regs, regcount, name)
        return regs[middle].value;
     }
   while (low <= high);
+
   return -1;
 }
 
-/* Summary of register_name().
- *
- * in: Input_line_pointer points to 1st char of operand.
- *
- * out: An expressionS.
- *     The operand may have been a register: in this case, X_op == O_register,
- *     X_add_number is set to the register number, and truth is returned.
- *     Input_line_pointer->(next non-blank) char after operand, or is in
- *     its original state.
- */
+/* 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
-r_register_name (expressionP)
-     expressionS *expressionP;
+get_register_name (expressionS *           expressionP,
+                  const struct reg_name * table,
+                  size_t                  table_length)
 {
   int reg_number;
   char *name;
@@ -380,7 +339,7 @@ r_register_name (expressionP)
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
-  reg_number = reg_name_search (r_registers, R_REG_NAME_CNT, name);
+  reg_number = reg_name_search (table, table_length, name);
 
   /* Put back the delimiting char.  */
   *input_line_pointer = c;
@@ -403,257 +362,45 @@ r_register_name (expressionP)
   return FALSE;
 }
 
-/* Summary of register_name().
- *
- * in: Input_line_pointer points to 1st char of operand.
- *
- * out: An expressionS.
- *     The operand may have been a register: in this case, X_op == O_register,
- *     X_add_number is set to the register number, and truth is returned.
- *     Input_line_pointer->(next non-blank) char after operand, or is in
- *     its original state.
- */
-
 static bfd_boolean
-xr_register_name (expressionP)
-     expressionS *expressionP;
+r_register_name (expressionS *expressionP)
 {
-  int reg_number;
-  char *name;
-  char *start;
-  char c;
-
-  /* Find the spelling of the operand.  */
-  start = name = input_line_pointer;
-
-  c = get_symbol_end ();
-  reg_number = reg_name_search (xr_registers, XR_REG_NAME_CNT, name);
-
-  /* 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;
-
-      /* Make the rest nice.  */
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_op_symbol = NULL;
-
-      return TRUE;
-    }
-
-  /* Reset the line as if we had not done anything.  */
-  input_line_pointer = start;
-  return FALSE;
+  return get_register_name (expressionP, r_registers, ARRAY_SIZE (r_registers));
 }
 
-/* Summary of register_name().
- *
- * in: Input_line_pointer points to 1st char of operand.
- *
- * out: An expressionS.
- *     The operand may have been a register: in this case, X_op == O_register,
- *     X_add_number is set to the register number, and truth is returned.
- *     Input_line_pointer->(next non-blank) char after operand, or is in
- *     its original state.
- */
 
 static bfd_boolean
-data_register_name (expressionP)
-     expressionS *expressionP;
+xr_register_name (expressionS *expressionP)
 {
-  int reg_number;
-  char *name;
-  char *start;
-  char c;
-
-  /* Find the spelling of the operand.  */
-  start = name = input_line_pointer;
-
-  c = get_symbol_end ();
-  reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
-
-  /* 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;
-
-      /* Make the rest nice.  */
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_op_symbol = NULL;
-
-      return TRUE;
-    }
-
-  /* Reset the line as if we had not done anything.  */
-  input_line_pointer = start;
-  return FALSE;
+  return get_register_name (expressionP, xr_registers, ARRAY_SIZE (xr_registers));
 }
 
-/* Summary of register_name().
- *
- * in: Input_line_pointer points to 1st char of operand.
- *
- * out: An expressionS.
- *     The operand may have been a register: in this case, X_op == O_register,
- *     X_add_number is set to the register number, and truth is returned.
- *     Input_line_pointer->(next non-blank) char after operand, or is in
- *     its original state.
- */
-
 static bfd_boolean
-address_register_name (expressionP)
-     expressionS *expressionP;
+data_register_name (expressionS *expressionP)
 {
-  int reg_number;
-  char *name;
-  char *start;
-  char c;
-
-  /* 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);
-
-  /* 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;
-
-      /* Make the rest nice.  */
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_op_symbol = NULL;
-
-      return TRUE;
-    }
-
-  /* Reset the line as if we had not done anything.  */
-  input_line_pointer = start;
-  return FALSE;
+  return get_register_name (expressionP, data_registers, ARRAY_SIZE (data_registers));
 }
 
-/* Summary of register_name().
- *
- * in: Input_line_pointer points to 1st char of operand.
- *
- * out: An expressionS.
- *     The operand may have been a register: in this case, X_op == O_register,
- *     X_add_number is set to the register number, and truth is returned.
- *     Input_line_pointer->(next non-blank) char after operand, or is in
- *     its original state.
- */
-
 static bfd_boolean
-other_register_name (expressionP)
-     expressionS *expressionP;
+address_register_name (expressionS *expressionP)
 {
-  int reg_number;
-  char *name;
-  char *start;
-  char c;
-
-  /* Find the spelling of the operand.  */
-  start = name = input_line_pointer;
-
-  c = get_symbol_end ();
-  reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
-
-  /* Put back the delimiting char.  */
-  *input_line_pointer = c;
-
-  /* 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_add_number = 0;
-
-      /* Make the rest nice.  */
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_op_symbol = NULL;
-
-      return TRUE;
-    }
-
-  /* Reset the line as if we had not done anything.  */
-  input_line_pointer = start;
-  return FALSE;
+  return get_register_name (expressionP, address_registers, ARRAY_SIZE (address_registers));
 }
 
-static bfd_boolean double_register_name PARAMS ((expressionS *));
-static bfd_boolean float_register_name  PARAMS ((expressionS *));
-
-/* Summary of float_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 bfd_boolean
-float_register_name (expressionP)
-     expressionS *expressionP;
+float_register_name (expressionS *expressionP)
 {
-  int reg_number;
-  char *name;
-  char *start;
-  char c;
-
-  /* Find the spelling of the operand.  */
-  start = name = input_line_pointer;
-
-  c = get_symbol_end ();
-  reg_number = reg_name_search (float_registers, FLOAT_REG_NAME_CNT, name);
-
-  /* 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;
-
-      /* Make the rest nice.  */
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_op_symbol = NULL;
-
-      return TRUE;
-    }
-
-  /* Reset the line as if we had not done anything.  */
-  input_line_pointer = start;
-  return FALSE;
+  return get_register_name (expressionP, float_registers, ARRAY_SIZE (float_registers));
 }
 
-/* Summary of double_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 bfd_boolean
+double_register_name (expressionS *expressionP)
+{
+  return get_register_name (expressionP, double_registers, ARRAY_SIZE (double_registers));
+}
 
 static bfd_boolean
-double_register_name (expressionP)
-     expressionS *expressionP;
+other_register_name (expressionS *expressionP)
 {
   int reg_number;
   char *name;
@@ -664,16 +411,17 @@ double_register_name (expressionP)
   start = name = input_line_pointer;
 
   c = get_symbol_end ();
-  reg_number = reg_name_search (double_registers, DOUBLE_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;
+  *input_line_pointer = c;
 
   /* Look to see if it's in the register table.  */
-  if (reg_number >= 0)
+  if (reg_number == 0
+      || (reg_number == AM33 && HAVE_AM33))
     {
       expressionP->X_op = O_register;
-      expressionP->X_add_number = reg_number;
+      expressionP->X_add_number = 0;
 
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
@@ -688,74 +436,34 @@ double_register_name (expressionP)
 }
 
 void
-md_show_usage (stream)
-     FILE *stream;
+md_show_usage (FILE *stream)
 {
   fprintf (stream, _("MN10300 assembler options:\n\
 none yet\n"));
 }
 
 int
-md_parse_option (c, arg)
-     int c ATTRIBUTE_UNUSED;
-     char *arg ATTRIBUTE_UNUSED;
+md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 char *
-md_atof (type, litp, sizep)
-     int type;
-     char *litp;
-     int *sizep;
+md_atof (int type, char *litp, int *sizep)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    default:
-      *sizep = 0;
-      return "bad call to md_atof";
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizep = prec * 2;
-
-  for (i = prec - 1; i >= 0; i--)
-    {
-      md_number_to_chars (litp, (valueT) words[i], 2);
-      litp += 2;
-    }
-
-  return NULL;
+  return ieee_md_atof (type, litp, sizep, FALSE);
 }
 
 void
-md_convert_frag (abfd, sec, fragP)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     asection *sec;
-     fragS *fragP;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+                asection *sec,
+                fragS *fragP)
 {
   static unsigned long label_count = 0;
   char buf[40];
@@ -967,6 +675,7 @@ md_convert_frag (abfd, sec, fragP)
   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);
@@ -976,6 +685,7 @@ md_convert_frag (abfd, sec, fragP)
   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];
@@ -988,6 +698,7 @@ md_convert_frag (abfd, sec, fragP)
   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,
@@ -998,6 +709,7 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 9)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xfc;
       fragP->fr_literal[offset + 1] = 0xff;
 
@@ -1017,6 +729,7 @@ md_convert_frag (abfd, sec, fragP)
   else if (fragP->fr_subtype == 11)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xcc;
 
       fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
@@ -1027,6 +740,7 @@ md_convert_frag (abfd, sec, fragP)
   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,
@@ -1184,19 +898,18 @@ md_convert_frag (abfd, sec, fragP)
 }
 
 valueT
-md_section_align (seg, addr)
-     asection *seg;
-     valueT addr;
+md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
+
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
 
 void
-md_begin ()
+md_begin (void)
 {
   char *prev_name = "";
-  register const struct mn10300_opcode *op;
+  const struct mn10300_opcode *op;
 
   mn10300_hash = hash_new ();
 
@@ -1232,12 +945,8 @@ md_begin ()
 
 static symbolS *GOT_symbol;
 
-static inline int mn10300_check_fixup PARAMS ((struct mn10300_fixup *));
-static inline int mn10300_PIC_related_p PARAMS ((symbolS *));
-
 static inline int
-mn10300_PIC_related_p (sym)
-     symbolS *sym;
+mn10300_PIC_related_p (symbolS *sym)
 {
   expressionS *exp;
 
@@ -1255,8 +964,7 @@ mn10300_PIC_related_p (sym)
 }
 
 static inline int
-mn10300_check_fixup (fixup)
-     struct mn10300_fixup *fixup;
+mn10300_check_fixup (struct mn10300_fixup *fixup)
 {
   expressionS *exp = &fixup->exp;
 
@@ -1302,10 +1010,7 @@ mn10300_check_fixup (fixup)
 }
 
 void
-mn10300_cons_fix_new (frag, off, size, exp)
-     fragS *frag;
-     int off, size;
-     expressionS *exp;
+mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
 {
   struct mn10300_fixup fixup;
 
@@ -1347,26 +1052,179 @@ mn10300_cons_fix_new (frag, off, size, exp)
        fixup.reloc = BFD_RELOC_24;
        break;
 
-      case 4:
-       fixup.reloc = BFD_RELOC_32;
-       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));
 
-      default:
-       goto error;
-      }
-  else if (size != 4)
+      if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
+       *insnp |= (((long) val & ((1 << operand->bits) - 1))
+                  << (operand->shift + shift + operand->bits));
+    }
+  else
     {
-    error:
-      as_bad (_("unsupported BFD relocation size %u"), size);
-      fixup.reloc = BFD_RELOC_UNUSED;
+      *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));
     }
-    
-  fix_new_exp (frag, off, size, &fixup.exp, 0, fixup.reloc);
 }
 
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
   char *s;
   struct mn10300_opcode *opcode;
@@ -1752,8 +1610,8 @@ md_assemble (str)
                    }
                }
              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;
 
            }
@@ -1850,8 +1708,8 @@ md_assemble (str)
                else
                  extra_shift = 0;
 
-               mn10300_insert_operand (&insn, &extension, operand,
-                                       ex.X_add_number, (char *) NULL,
+               mn10300_insert_operand (& insn, & extension, operand,
+                                       ex.X_add_number, NULL,
                                        0, extra_shift);
 
                /* And note the register number in the register array.  */
@@ -1865,16 +1723,15 @@ md_assemble (str)
                 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;
                }
 
-             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:
@@ -1905,7 +1762,6 @@ keep_going:
 
          while (*str == ' ' || *str == ',')
            ++str;
-
        }
 
       /* Make sure we used all the operands!  */
@@ -2291,85 +2147,80 @@ keep_going:
 
       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.  */
 
-arelent *
-tc_gen_reloc (seg, fixp)
-     asection *seg ATTRIBUTE_UNUSED;
-     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;
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+
+  reloc = xmalloc (sizeof (arelent));
 
   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,
                    _("reloc %d not supported by object file format"),
                    (int) fixp->fx_r_type);
-      return NULL;
+      free (reloc);
+      return & no_relocs;
     }
+
   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 = 0;
+      fixp->fx_subsy = NULL;
     }
 
   if (fixp->fx_addsy && fixp->fx_subsy)
     {
+      asection *asec, *ssec;
+
+      asec = S_GET_SEGMENT (fixp->fx_addsy);
+      ssec = S_GET_SEGMENT (fixp->fx_subsy);
+
       reloc->sym_ptr_ptr = NULL;
 
-      /* If we got a difference between two symbols, and the
-        subtracted symbol is in the current section, use a
-        PC-relative relocation.  If both symbols are in the same
-        section, the difference would have already been simplified
-        to a constant.  */
-      if (S_GET_SEGMENT (fixp->fx_subsy) == seg)
+      /* 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)
        {
-         reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-         *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-         reloc->addend = (reloc->address - S_GET_VALUE (fixp->fx_subsy)
-                          + fixp->fx_offset);
-
-         switch (fixp->fx_r_type)
-           {
-           case BFD_RELOC_8:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_8_PCREL);
-             return reloc;
+         arelent * reloc2 = xmalloc (sizeof * reloc);
 
-           case BFD_RELOC_16:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_16_PCREL);
-             return reloc;
+         relocs[0] = reloc2;
+         relocs[1] = reloc;
 
-           case BFD_RELOC_24:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_24_PCREL);
-             return 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);
 
-           case BFD_RELOC_32:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_32_PCREL);
-             return reloc;
+         reloc->addend = fixp->fx_offset; 
+         if (asec == absolute_section)
+           reloc->addend += S_GET_VALUE (fixp->fx_addsy);
 
-           default:
-             /* Try to compute the absolute value below.  */
-             break;
-           }
-       }
+         reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
 
-      if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
-         || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
-       {
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       "Difference of symbols in different sections is not supported");
+         fixp->fx_pcrel = 0;
+         fixp->fx_done = 1;
+         return relocs;
        }
       else
        {
@@ -2399,44 +2250,54 @@ tc_gen_reloc (seg, fixp)
            default:
              reloc->sym_ptr_ptr
                = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
-             return reloc;
+             return relocs;
            }
-       }
 
-      if (reloc->sym_ptr_ptr)
-       free (reloc->sym_ptr_ptr);
-      free (reloc);
-      return NULL;
+         if (reloc->sym_ptr_ptr)
+           free (reloc->sym_ptr_ptr);
+         free (reloc);
+         return & no_relocs;
+       }
     }
   else
     {
-      reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+      reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
       *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       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
-md_estimate_size_before_relax (fragp, seg)
-     fragS *fragp;
-     asection *seg;
+md_estimate_size_before_relax (fragS *fragp, asection *seg)
 {
   if (fragp->fr_subtype == 6
-      && (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+      && ! has_known_symbol_location (fragp, seg))
     fragp->fr_subtype = 7;
   else if (fragp->fr_subtype == 8
-          && (!S_IS_DEFINED (fragp->fr_symbol)
-              || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+          && ! has_known_symbol_location (fragp, seg))
     fragp->fr_subtype = 9;
   else if (fragp->fr_subtype == 10
-          &&  (!S_IS_DEFINED (fragp->fr_symbol)
-               || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+          && ! has_known_symbol_location (fragp, seg))
     fragp->fr_subtype = 12;
 
   if (fragp->fr_subtype == 13)
     return 3;
+
   if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
     abort ();
 
@@ -2444,28 +2305,24 @@ md_estimate_size_before_relax (fragp, seg)
 }
 
 long
-md_pcrel_from (fixp)
-     fixS *fixp;
+md_pcrel_from (fixS *fixp)
 {
-  if (fixp->fx_addsy != (symbolS *) NULL && !S_IS_DEFINED (fixp->fx_addsy))
-    {
-      /* The symbol is undefined.  Let the linker figure it out.  */
-      return 0;
-    }
+  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 (fixP, valP, seg)
-     fixS * fixP;
-     valueT * valP;
-     segT seg;
+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;
 
-  assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+  gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
 
   /* This should never happen.  */
   if (seg->flags & SEC_ALLOC)
@@ -2481,7 +2338,7 @@ md_apply_fix (fixP, valP, seg)
      *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 != (symbolS *) NULL && ! fixP->fx_pcrel)
+  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
@@ -2516,6 +2373,10 @@ md_apply_fix (fixP, valP, seg)
       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,
@@ -2533,197 +2394,40 @@ md_apply_fix (fixP, valP, seg)
    adjusted.  */
 
 bfd_boolean
-mn10300_fix_adjustable (fixp)
-     struct fix *fixp;
+mn10300_fix_adjustable (struct fix *fixp)
 {
-  if (TC_FORCE_RELOCATION_LOCAL (fixp))
-    return 0;
-
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-    return 0;
+  if (fixp->fx_pcrel)
+    {
+      if (TC_FORCE_RELOCATION_LOCAL (fixp))
+       return FALSE;
+    }
+  /* 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 0;
+    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 0;
-  if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0)
-    return 0;
-
-  return 1;
-}
-
-/* Insert an operand value into an instruction.  */
-
-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;
-{
-  /* 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));
-    }
-}
-
-static unsigned long
-check_operand (insn, operand, val)
-     unsigned long insn ATTRIBUTE_UNUSED;
-     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;
-       }
+  if (! (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE))
+    return FALSE;
 
-      test = val;
+  if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0)
+    return FALSE;
 
-      if (test < (offsetT) min || test > (offsetT) max)
-       return 0;
-      else
-       return 1;
-    }
-  return 1;
+  return TRUE;
 }
 
 static void
-set_arch_mach (mach)
-     int mach;
+set_arch_mach (int mach)
 {
   if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
     as_warn (_("could not set architecture and machine"));
@@ -2731,11 +2435,8 @@ set_arch_mach (mach)
   current_machine = mach;
 }
 
-static inline char * mn10300_end_of_match PARAMS ((char *, char *));
-
 static inline char *
-mn10300_end_of_match (cont, what)
-     char *cont, *what;
+mn10300_end_of_match (char *cont, char *what)
 {
   int len = strlen (what);
 
@@ -2747,11 +2448,10 @@ mn10300_end_of_match (cont, what)
 }  
 
 int
-mn10300_parse_name (name, exprP, mode, nextcharP)
-     char const *name;
-     expressionS *exprP;
-     enum expr_mode mode;
-     char *nextcharP;
+mn10300_parse_name (char const *name,
+                   expressionS *exprP,
+                   enum expr_mode mode,
+                   char *nextcharP)
 {
   char *next = input_line_pointer;
   char *next_end;
@@ -2815,3 +2515,105 @@ mn10300_parse_name (name, exprP, mode, nextcharP)
 
   return 1;
 }
+
+/* The target specific pseudo-ops which we support.  */
+const pseudo_typeS md_pseudo_table[] =
+{
+  { "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)
+    {
+      if (frag->tc_frag_data)
+       result = FALSE;
+      if (frag == right_frag)
+       break;
+    }
+
+  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 (frag == NULL)
+    /* The two symbols are on disjoint fragment chains
+       - we cannot possibly compute their difference.  */
+    return FALSE;
+
+  return result;
+}
+
+/* When relaxing, we need to output a reloc for any .align directive
+   that requests alignment to a two byte boundary or larger.  */
+
+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);
+}
+
+bfd_boolean
+mn10300_force_relocation (struct fix * fixp)
+{
+  if (linkrelax
+      && (fixp->fx_pcrel
+         || fixp->fx_r_type == BFD_RELOC_MN10300_ALIGN))
+    return TRUE;
+
+  return generic_force_reloc (fixp);
+}