[gas/ChangeLog]
[deliverable/binutils-gdb.git] / gas / config / tc-mn10300.c
index 301a42bac493ed28d4bccdcf45811aea2f41c0cf..ed17e9cd57897fdf5e53c2908226987eb9a8fe68 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-mn10300.c -- Assembler code for the Matsushita 10300
-   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -19,8 +20,8 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include "as.h"
+#include "safe-ctype.h"
 #include "subsegs.h"
 #include "opcode/mn10300.h"
 #include "dwarf2dbg.h"
@@ -32,8 +33,6 @@ struct reg_name
   int value;
 };
 
-struct dwarf2_line_info debug_line;
-
 /* Generic assembler global variables which must be defined by all
    targets.  */
 
@@ -93,7 +92,7 @@ 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));
+static void set_arch_mach PARAMS ((unsigned int));
 
 /*  Set linkrelax here to avoid fixups in most sections.  */
 int linkrelax = 1;
@@ -213,6 +212,7 @@ static const struct reg_name xr_registers[] =
   { "mcrl", 3 },
   { "mcvf", 4 },
   { "mdrq", 1 },
+  { "pc", 0 },
   { "sp", 0 },
   { "xr0", 0 },
   { "xr1", 1 },
@@ -280,7 +280,7 @@ 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
@@ -302,6 +302,9 @@ r_register_name (expressionP)
   c = get_symbol_end ();
   reg_number = reg_name_search (r_registers, R_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)
     {
@@ -312,27 +315,19 @@ r_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
       return true;
     }
-  else
-    {
-      /* Reset the line as if we had not done anything.  */
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
 
-      /* Reset input_line pointer.  */
-      input_line_pointer = start;
-      return false;
-    }
+  /* 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.
+ * 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
@@ -354,6 +349,9 @@ xr_register_name (expressionP)
   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)
     {
@@ -364,27 +362,19 @@ xr_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
       return true;
     }
-  else
-    {
-      /* Reset the line as if we had not done anything.  */
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
 
-      /* Reset input_line pointer.  */
-      input_line_pointer = start;
-      return false;
-    }
+  /* 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.
+ * 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
@@ -406,6 +396,9 @@ data_register_name (expressionP)
   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)
     {
@@ -416,27 +409,19 @@ data_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
       return true;
     }
-  else
-    {
-      /* Reset the line as if we had not done anything.  */
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
 
-      /* Reset input_line pointer.  */
-      input_line_pointer = start;
-      return false;
-    }
+  /* 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.
+ * 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
@@ -458,6 +443,9 @@ address_register_name (expressionP)
   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)
     {
@@ -468,28 +456,19 @@ address_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
       return true;
     }
-  else
-    {
-      /* Reset the line as if we had not done anything.  */
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
 
-      /* Reset input_line pointer.  */
-      input_line_pointer = start;
-
-      return false;
-    }
+  /* 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.
+ * 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
@@ -511,6 +490,9 @@ other_register_name (expressionP)
   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)
     {
@@ -521,20 +503,12 @@ other_register_name (expressionP)
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
 
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
       return true;
     }
-  else
-    {
-      /* Reset the line as if we had not done anything.  */
-      /* Put back the delimiting char.  */
-      *input_line_pointer = c;
 
-      /* Reset input_line pointer.  */
-      input_line_pointer = start;
-      return false;
-    }
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return false;
 }
 
 void
@@ -937,13 +911,13 @@ md_assemble (str)
   struct mn10300_opcode *next_opcode;
   const unsigned char *opindex_ptr;
   int next_opindex, relaxable;
-  unsigned long insn, extension, size = 0, real_size;
+  unsigned long insn, extension, size = 0;
   char *f;
   int i;
   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';
@@ -957,7 +931,7 @@ md_assemble (str)
     }
 
   str = s;
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   input_line_pointer = str;
@@ -1471,7 +1445,7 @@ keep_going:
       break;
     }
 
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   if (*str != '\0')
@@ -1513,12 +1487,17 @@ keep_going:
   if (opcode->format == FMT_D4)
     size = 6;
 
-  real_size = size;
-
   if (relaxable && fc > 0)
     {
       int type;
 
+      /* 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)
        {
@@ -1729,24 +1708,7 @@ keep_going:
              /* Is the reloc pc-relative?  */
              pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
 
-             /* 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.  */
              if (pcrel)
@@ -1789,21 +1751,8 @@ keep_going:
                fixP->fx_offset += offset;
            }
        }
-    }
-
-  if (debug_type == DEBUG_DWARF2)
-    {
-      bfd_vma addr;
 
-      /* First update the notion of the current source line.  */
-      dwarf2_where (&debug_line);
-
-      /* We want the offset of the start of this instruction within the
-         the current frag.  */
-      addr = frag_now->fr_address + frag_now_fix () - real_size;
-
-      /* And record the information.  */
-      dwarf2_gen_line_info (addr, &debug_line);
+      dwarf2_emit_insn (size);
     }
 }
 
@@ -1830,18 +1779,89 @@ tc_gen_reloc (seg, fixp)
 
   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
+        section, the difference would have already been simplified
+        to a constant.  */
+      if (S_GET_SEGMENT (fixp->fx_subsy) == seg)
+       {
+         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;
+             
+           case BFD_RELOC_16:
+             reloc->howto = bfd_reloc_type_lookup (stdoutput,
+                                                   BFD_RELOC_16_PCREL);
+             return reloc;
+
+           case BFD_RELOC_24:
+             reloc->howto = bfd_reloc_type_lookup (stdoutput,
+                                                   BFD_RELOC_24_PCREL);
+             return reloc;
+
+           case BFD_RELOC_32:
+             reloc->howto = bfd_reloc_type_lookup (stdoutput,
+                                                   BFD_RELOC_32_PCREL);
+             return reloc;
+
+           default:
+             /* Try to compute the absolute value below.  */
+             break;
+           }
+       }
 
       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");
-         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);
 
-      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);
+         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_symbol;
+             return reloc;
+           }
+       }
+
+      if (reloc->sym_ptr_ptr)
+       free (reloc->sym_ptr_ptr);
+      free (reloc);
+      return NULL;
     }
   else
     {
@@ -1857,44 +1877,23 @@ md_estimate_size_before_relax (fragp, seg)
      fragS *fragp;
      asection *seg;
 {
-  if (fragp->fr_subtype == 0)
-    return 2;
-  if (fragp->fr_subtype == 3)
-    return 3;
-  if (fragp->fr_subtype == 6)
-    {
-      if (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol))
-       {
-         fragp->fr_subtype = 7;
-         return 7;
-       }
-      else
-       return 5;
-    }
-  if (fragp->fr_subtype == 8)
-    {
-      if (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol))
-       {
-         fragp->fr_subtype = 9;
-         return 6;
-       }
-      else
-       return 4;
-    }
-  if (fragp->fr_subtype == 10)
-    {
-      if (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol))
-       {
-         fragp->fr_subtype = 12;
-         return 5;
-       }
-      else
-       return 2;
-    }
-  abort ();
+  if (fragp->fr_subtype == 6
+      && (!S_IS_DEFINED (fragp->fr_symbol)
+         || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+    fragp->fr_subtype = 7;
+  else if (fragp->fr_subtype == 8
+          && (!S_IS_DEFINED (fragp->fr_symbol)
+              || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+    fragp->fr_subtype = 9;
+  else if (fragp->fr_subtype == 10
+          &&  (!S_IS_DEFINED (fragp->fr_symbol)
+               || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+    fragp->fr_subtype = 12;
+
+  if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
+    abort ();
+
+  return md_relax_table[fragp->fr_subtype].rlx_length;
 }
 
 long
@@ -1912,11 +1911,12 @@ md_pcrel_from (fixp)
 int
 md_apply_fix3 (fixp, valuep, seg)
      fixS *fixp;
-     valueT *valuep ATTRIBUTE_UNUSED;
+     valueT *valuep;
      segT seg;
 {
   char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
   int size = 0;
+  int value;
 
   assert (fixp->fx_r_type < BFD_RELOC_UNUSED);
 
@@ -1924,6 +1924,22 @@ md_apply_fix3 (fixp, valuep, seg)
   if (seg->flags & SEC_ALLOC)
       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.
+
+     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 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
@@ -1937,14 +1953,17 @@ md_apply_fix3 (fixp, valuep, seg)
   switch (fixp->fx_r_type)
     {
     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;
 
@@ -1959,11 +1978,13 @@ md_apply_fix3 (fixp, valuep, seg)
                    _("Bad relocation fixup type (%d)"), fixp->fx_r_type);
     }
 
-  md_number_to_chars (fixpos, fixp->fx_offset, size);
+  md_number_to_chars (fixpos, value, size);
 
-  fixp->fx_done = 1;
-  return 0;
+  /* 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,
@@ -1978,6 +1999,15 @@ mn10300_force_relocation (fixp)
       || 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;
 }
 
@@ -1996,6 +2026,13 @@ mn10300_fix_adjustable (fixp)
       || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
 
+  /* 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 1;
 }
 
@@ -2125,17 +2162,10 @@ check_operand (insn, operand, val)
 
 static void
 set_arch_mach (mach)
-     int mach;
+     unsigned int mach;
 {
   if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
     as_warn (_("could not set architecture and machine"));
 
   current_machine = mach;
 }
-
-void
-mn10300_finalize ()
-{
-  if (debug_type == DEBUG_DWARF2)
-    dwarf2_finish ();
-}
This page took 0.031243 seconds and 4 git commands to generate.