remove some duplicate #include's.
[deliverable/binutils-gdb.git] / gas / config / tc-mn10300.c
index 725f4f2581837f239359f38ed36ff6f59f6e6317..a1cacf104882baac8e4fada890b965e337f32455 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mn10300.c -- Assembler code for the Matsushita 10300
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006  Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
-#include <stdio.h>
-#include <ctype.h>
 #include "as.h"
+#include "safe-ctype.h"
 #include "subsegs.h"
 #include "opcode/mn10300.h"
 #include "dwarf2dbg.h"
@@ -54,15 +53,20 @@ const char EXP_CHARS[] = "eE";
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 \f
-const relax_typeS md_relax_table[] = {
+const relax_typeS md_relax_table[] =
+{
+  /* 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},
-  {0x7fff, -0x8000, 5, 2},
+  {0x7fff + 2, -0x8000 + 2, 5, 2},
   {0x7fffffff, -0x80000000, 7, 0},
 
-  /* bCC relaxing (uncommon cases)  */
+  /* bCC relaxing (uncommon cases for 3byte length instructions)  */
   {0x7f, -0x80, 3, 4},
-  {0x7fff, -0x8000, 6, 5},
+  {0x7fff + 3, -0x8000 + 3, 6, 5},
   {0x7fffffff, -0x80000000, 8, 0},
 
   /* call relaxing  */
@@ -78,6 +82,11 @@ const relax_typeS md_relax_table[] = {
   {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.  */
@@ -89,10 +98,12 @@ 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 ((unsigned int));
+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;
@@ -123,15 +134,15 @@ size_t md_longopts_size = sizeof (md_longopts);
 /* The target specific pseudo-ops which we support.  */
 const pseudo_typeS md_pseudo_table[] =
 {
-  { "file",     dwarf2_directive_file,  0 },
-  { "loc",      dwarf2_directive_loc,   0 },
   { "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}
 };
 
-#define HAVE_AM33 (current_machine == AM33)
+#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.  */
@@ -212,7 +223,6 @@ static const struct reg_name xr_registers[] =
   { "mcrl", 3 },
   { "mcvf", 4 },
   { "mdrq", 1 },
-  { "pc", 0 },
   { "sp", 0 },
   { "xr0", 0 },
   { "xr1", 1 },
@@ -235,9 +245,16 @@ static const struct reg_name xr_registers[] =
 #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 },
 };
@@ -245,6 +262,69 @@ static const struct reg_name other_registers[] =
 #define OTHER_REG_NAME_CNT                             \
   (sizeof (other_registers) / sizeof (struct reg_name))
 
+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 },
+};
+
+#define FLOAT_REG_NAME_CNT \
+  (sizeof (float_registers) / sizeof (struct reg_name))
+
+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 },
+};
+
+#define DOUBLE_REG_NAME_CNT \
+  (sizeof (double_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.  */
@@ -280,14 +360,14 @@ reg_name_search (regs, regcount, name)
  *
  * in: Input_line_pointer points to 1st char of operand.
  *
- * out: A expressionS.
+ * 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 boolean
+static bfd_boolean
 r_register_name (expressionP)
      expressionS *expressionP;
 {
@@ -315,26 +395,26 @@ r_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 
 /* Summary of register_name().
  *
  * in: Input_line_pointer points to 1st char of operand.
  *
- * out: A expressionS.
+ * 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 boolean
+static bfd_boolean
 xr_register_name (expressionP)
      expressionS *expressionP;
 {
@@ -362,26 +442,26 @@ xr_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 
 /* Summary of register_name().
  *
  * in: Input_line_pointer points to 1st char of operand.
  *
- * out: A expressionS.
+ * 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 boolean
+static bfd_boolean
 data_register_name (expressionP)
      expressionS *expressionP;
 {
@@ -409,26 +489,26 @@ data_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 
 /* Summary of register_name().
  *
  * in: Input_line_pointer points to 1st char of operand.
  *
- * out: A expressionS.
+ * 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 boolean
+static bfd_boolean
 address_register_name (expressionP)
      expressionS *expressionP;
 {
@@ -456,26 +536,26 @@ address_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 
 /* Summary of register_name().
  *
  * in: Input_line_pointer points to 1st char of operand.
  *
- * out: A expressionS.
+ * 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 boolean
+static bfd_boolean
 other_register_name (expressionP)
      expressionS *expressionP;
 {
@@ -493,6 +573,102 @@ other_register_name (expressionP)
   /* 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;
+}
+
+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;
+{
+  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;
+}
+
+/* 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 (expressionP)
+     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 (double_registers, DOUBLE_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)
     {
@@ -503,12 +679,12 @@ other_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 
 void
@@ -858,6 +1034,151 @@ md_convert_frag (abfd, sec, fragP)
       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 ();
 }
@@ -896,10 +1217,151 @@ md_begin ()
     }
 
   /* Set the default machine type.  */
+#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"));
 
   current_machine = MN103;
+#endif
+}
+
+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;
+{
+  expressionS *exp;
+
+  if (! sym)
+    return 0;
+
+  if (sym == GOT_symbol)
+    return 1;
+
+  exp = symbol_get_value_expression (sym);
+
+  return (exp->X_op == O_PIC_reloc
+         || mn10300_PIC_related_p (exp->X_add_symbol)
+         || mn10300_PIC_related_p (exp->X_op_symbol));
+}
+
+static inline int
+mn10300_check_fixup (fixup)
+     struct mn10300_fixup *fixup;
+{
+  expressionS *exp = &fixup->exp;
+
+ repeat:
+  switch (exp->X_op)
+    {
+    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;
+
+      exp = symbol_get_value_expression (exp->X_add_symbol);
+      goto repeat;
+
+    case O_symbol:
+      if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
+       fixup->reloc = BFD_RELOC_32_GOT_PCREL;
+      break;
+
+    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;
+
+    default:
+      return (mn10300_PIC_related_p (exp->X_add_symbol)
+             || mn10300_PIC_related_p (exp->X_op_symbol));
+    }
+
+  return 0;
+}
+
+void
+mn10300_cons_fix_new (frag, off, size, exp)
+     fragS *frag;
+     int off, size;
+     expressionS *exp;
+{
+  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);
 }
 
 void
@@ -917,7 +1379,7 @@ md_assemble (str)
   int match;
 
   /* Get the opcode.  */
-  for (s = str; *s != '\0' && !isspace (*s); s++)
+  for (s = str; *s != '\0' && !ISSPACE (*s); s++)
     ;
   if (*s != '\0')
     *s++ = '\0';
@@ -931,7 +1393,7 @@ md_assemble (str)
     }
 
   str = s;
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   input_line_pointer = str;
@@ -958,6 +1420,7 @@ md_assemble (str)
       /* 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;
@@ -1052,6 +1515,39 @@ md_assemble (str)
                  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;
@@ -1291,6 +1787,18 @@ md_assemble (str)
              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;
@@ -1317,6 +1825,8 @@ md_assemble (str)
                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;
@@ -1383,6 +1893,8 @@ md_assemble (str)
              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;
            }
@@ -1445,7 +1957,7 @@ keep_going:
       break;
     }
 
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   if (*str != '\0')
@@ -1484,11 +1996,26 @@ keep_going:
   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)
     {
+      /* 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;
 
       /* We want to anchor the line info to the previous frag (if
@@ -1522,14 +2049,17 @@ keep_going:
       /* jmp  */
       else if (size == 3 && opcode->opcode == 0xcc0000)
        type = 10;
+      else if (size == 3 && (opcode->opcode & 0xfff000) == 0xf8d000)
+       type = 13;
       /* bCC (uncommon cases)  */
       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,
-                   (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.
@@ -1628,6 +2158,12 @@ keep_going:
             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);
@@ -1666,7 +2202,11 @@ keep_going:
          const struct mn10300_operand *operand;
 
          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_GOT32)
            {
              reloc_howto_type *reloc_howto;
              int size;
@@ -1696,6 +2236,8 @@ keep_going:
              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)
@@ -1707,11 +2249,15 @@ keep_going:
 
              /* 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;
 
              offset = size - (reloc_size + operand->shift) / 8;
 
              /* 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;
@@ -1777,8 +2323,17 @@ tc_gen_reloc (seg, fixp)
     }
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
+  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;
+    }
+
   if (fixp->fx_addsy && 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
@@ -1797,7 +2352,7 @@ tc_gen_reloc (seg, fixp)
              reloc->howto = bfd_reloc_type_lookup (stdoutput,
                                                    BFD_RELOC_8_PCREL);
              return reloc;
-             
+
            case BFD_RELOC_16:
              reloc->howto = bfd_reloc_type_lookup (stdoutput,
                                                    BFD_RELOC_16_PCREL);
@@ -1824,12 +2379,43 @@ tc_gen_reloc (seg, fixp)
        {
          as_bad_where (fixp->fx_file, fixp->fx_line,
                        "Difference of symbols in different sections is not supported");
-         return NULL;
+       }
+      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;
+
+           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 reloc;
+           }
        }
 
-      reloc->sym_ptr_ptr = (asymbol **) &bfd_abs_symbol;
-      reloc->addend = (S_GET_VALUE (fixp->fx_addsy)
-                      - S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset);
+      if (reloc->sym_ptr_ptr)
+       free (reloc->sym_ptr_ptr);
+      free (reloc);
+      return NULL;
     }
   else
     {
@@ -1858,6 +2444,8 @@ md_estimate_size_before_relax (fragp, seg)
                || seg != S_GET_SEGMENT (fragp->fr_symbol)))
     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 ();
 
@@ -1876,49 +2464,46 @@ md_pcrel_from (fixp)
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
-int
-md_apply_fix3 (fixp, valuep, seg)
-     fixS *fixp;
-     valueT *valuep;
+void
+md_apply_fix (fixP, valP, seg)
+     fixS * fixP;
+     valueT * valP;
      segT seg;
 {
-  char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
+  char * fixpos = fixP->fx_where + fixP->fx_frag->fr_literal;
   int size = 0;
-  int value;
+  int value = (int) * valP;
 
-  assert (fixp->fx_r_type < BFD_RELOC_UNUSED);
+  assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
 
   /* This should never happen.  */
   if (seg->flags & SEC_ALLOC)
-      abort ();
+    abort ();
 
   /* The value we are passed in *valuep includes the symbol values.
-     Since we are using BFD_ASSEMBLER, 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.
+     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 == (symbolS *) NULL || fixp->fx_pcrel)
-    value = *valuep;
-  else
-    value = fixp->fx_offset;
+  if (fixP->fx_addsy != (symbolS *) 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 (fixP->fx_addsy != NULL
+      && (! S_IS_DEFINED (fixP->fx_addsy)
+         || (S_GET_SEGMENT (fixP->fx_addsy) != seg)))
     {
-      fixp->fx_done = 0;
-      return 0;
+      fixP->fx_done = 0;
+      return;
     }
 
-  switch (fixp->fx_r_type)
+  switch (fixP->fx_r_type)
     {
     case BFD_RELOC_8:
     case BFD_RELOC_8_PCREL:
@@ -1937,57 +2522,30 @@ md_apply_fix3 (fixp, valuep, seg)
 
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
-      fixp->fx_done = 0;
-      return 1;
+      fixP->fx_done = 0;
+      return;
 
     case BFD_RELOC_NONE:
     default:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("Bad relocation fixup type (%d)"), fixp->fx_r_type);
+      as_bad_where (fixP->fx_file, fixP->fx_line,
+                   _("Bad relocation fixup type (%d)"), fixP->fx_r_type);
     }
 
   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 0;
-}
-
-/* Return nonzero if the fixup in FIXP will require a relocation,
-   even it if appears that the fixup could be completely handled
-   within GAS.  */
-
-int
-mn10300_force_relocation (fixp)
-     struct fix *fixp;
-{
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-    return 1;
-
-  /* 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)
-      && fixp->fx_subsy
-      && S_GET_SEGMENT (fixp->fx_addsy) == S_GET_SEGMENT (fixp->fx_subsy))
-    return 1;
-
-  return 0;
+  if (fixP->fx_addsy == NULL)
+    fixP->fx_done = 1;
 }
 
 /* Return zero if the fixup in fixp should be left alone and not
    adjusted.  */
 
-boolean
+bfd_boolean
 mn10300_fix_adjustable (fixp)
      struct fix *fixp;
 {
-  /* Prevent all adjustments to global symbols.  */
-  if (S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
+  if (! TC_RELOC_RTSYM_LOC_FIXUP (fixp))
     return 0;
 
   if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
@@ -2001,6 +2559,15 @@ mn10300_fix_adjustable (fixp)
   if (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_CODE)
     return 0;
 
+  /* 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;
 }
 
@@ -2043,17 +2610,7 @@ mn10300_insert_operand (insnp, extensionp, operand, val, file, line, shift)
       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);
-       }
+       as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
     }
 
   if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
@@ -2068,6 +2625,51 @@ mn10300_insert_operand (insnp, extensionp, operand, val, file, line, shift)
       *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))
@@ -2130,10 +2732,95 @@ check_operand (insn, operand, val)
 
 static void
 set_arch_mach (mach)
-     unsigned int mach;
+     int mach;
 {
   if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
     as_warn (_("could not set architecture and machine"));
 
   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;
+{
+  int len = strlen (what);
+
+  if (strncmp (cont, what, strlen (what)) == 0
+      && ! is_part_of_name (cont[len]))
+    return cont + len;
+
+  return NULL;
+}  
+
+int
+mn10300_parse_name (name, exprP, mode, nextcharP)
+     char const *name;
+     expressionS *exprP;
+     enum expr_mode mode;
+     char *nextcharP;
+{
+  char *next = input_line_pointer;
+  char *next_end;
+  int reloc_type;
+  segT segment;
+
+  exprP->X_op_symbol = NULL;
+
+  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)
+       {
+         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
+       {
+         exprP->X_op = O_symbol;
+         exprP->X_add_number = 0;
+       }
+
+      return 1;
+    }
+
+  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
+    goto no_suffix;
+
+  *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;
+}
This page took 0.044798 seconds and 4 git commands to generate.