ChangeLog rotatation and copyright year update
[deliverable/binutils-gdb.git] / gas / config / tc-mmix.c
index 46415888e6ae54252d47cd80f217c2e1841d443e..971c5342772ba0c5382a46743a9398d49195900a 100644 (file)
@@ -1,6 +1,5 @@
 /* tc-mmix.c -- Assembler for Don Knuth's MMIX.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation.
+   Copyright (C) 2001-2015 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -27,8 +26,8 @@
    compatible syntax, but the main purpose is to serve GCC.  */
 
 
-#include <limits.h>
 #include "as.h"
+#include <limits.h>
 #include "subsegs.h"
 #include "elf/mmix.h"
 #include "opcode/mmix.h"
    for example assert something of what it became or make a relocation.  */
 
 enum mmix_fixup_action
- {
-   mmix_fixup_byte,
-   mmix_fixup_register,
-   mmix_fixup_register_or_adjust_for_byte
- };
+{
+  mmix_fixup_byte,
+  mmix_fixup_register,
+  mmix_fixup_register_or_adjust_for_byte
+};
 
 static int get_spec_regno (char *);
 static int get_operands (int, char *, expressionS *);
@@ -109,6 +108,14 @@ static struct
    expressionS exp;
  } mmix_raw_gregs[MAX_GREGS];
 
+static struct loc_assert_s
+ {
+   segT old_seg;
+   symbolS *loc_sym;
+   fragS *frag;
+   struct loc_assert_s *next;
+ } *loc_asserts = NULL;
+
 /* Fixups for all unique GREG registers.  We store the fixups here in
    md_convert_frag, then we use the array to convert
    BFD_RELOC_MMIX_BASE_PLUS_OFFSET fixups in tc_gen_reloc.  The index is
@@ -1673,7 +1680,10 @@ md_assemble (char *str)
       break;
 
     case mmix_operands_xyz_opt:
-      /* SWYM, TRIP, TRAP: zero, one, two or three operands.  */
+      /* SWYM, TRIP, TRAP: zero, one, two or three operands.  It's
+        unspecified whether operands are registers or constants, but
+        when we find register syntax, we require operands to be literal and
+        within 0..255.  */
       if (n_operands == 0 && ! mmix_gnu_syntax)
        /* Zeros are in place - nothing needs to be done for zero
           operands.  We don't allow this in GNU syntax mode, because it
@@ -1684,7 +1694,7 @@ md_assemble (char *str)
        {
          if (exp[0].X_op == O_constant)
            {
-             if (exp[0].X_add_number > 255*255*255
+             if (exp[0].X_add_number > 255*256*256
                  || exp[0].X_add_number < 0)
                {
                  as_bad (_("invalid operands to opcode %s: `%s'"),
@@ -1726,7 +1736,7 @@ md_assemble (char *str)
 
          if (exp[1].X_op == O_constant)
            {
-             if (exp[1].X_add_number > 255*255
+             if (exp[1].X_add_number > 255*256
                  || exp[1].X_add_number < 0)
                {
                  as_bad (_("invalid operands to opcode %s: `%s'"),
@@ -1798,12 +1808,15 @@ md_assemble (char *str)
            fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 3,
                         1, exp + 2, 0, BFD_RELOC_8);
        }
-      else if (n_operands <= 3
-              && (strcmp (instruction->name, "trip") == 0
-                  || strcmp (instruction->name, "trap") == 0))
+      else
        {
-         /* The meaning of operands to TRIP and TRAP are not defined, so
-            we add combinations not handled above here as we find them.  */
+         /* We can't get here for other cases.  */
+         gas_assert (n_operands <= 3);
+
+         /* The meaning of operands to TRIP and TRAP is not defined (and
+            SWYM operands aren't enforced in mmixal, so let's avoid
+            that).  We add combinations not handled above here as we find
+            them and as they're reported.  */
          if (n_operands == 3)
            {
              /* Don't require non-register operands.  Always generate
@@ -1811,49 +1824,48 @@ md_assemble (char *str)
                 maintenance problems.  TRIP is supposed to be a rare
                 instruction, so the overhead should not matter.  We
                 aren't allowed to fix_new_exp for an expression which is
-                an  O_register at this point, however.  */
+                an O_register at this point, however.
+
+                Don't use BFD_RELOC_MMIX_REG_OR_BYTE as that modifies
+                the insn for a register in the Z field and we want
+                consistency.  */
              if (exp[0].X_op == O_register)
                opcodep[1] = exp[0].X_add_number;
              else
                fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 1,
-                            1, exp, 0, BFD_RELOC_MMIX_REG_OR_BYTE);
+                            1, exp, 0, BFD_RELOC_8);
              if (exp[1].X_op == O_register)
                opcodep[2] = exp[1].X_add_number;
              else
                fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 2,
-                            1, exp + 1, 0, BFD_RELOC_MMIX_REG_OR_BYTE);
+                            1, exp + 1, 0, BFD_RELOC_8);
              if (exp[2].X_op == O_register)
                opcodep[3] = exp[2].X_add_number;
              else
                fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 3,
-                            1, exp + 2, 0, BFD_RELOC_MMIX_REG_OR_BYTE);
+                            1, exp + 2, 0, BFD_RELOC_8);
            }
          else if (n_operands == 2)
            {
              if (exp[0].X_op == O_register)
-               opcodep[2] = exp[0].X_add_number;
+               opcodep[1] = exp[0].X_add_number;
              else
-               fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 2,
-                            1, exp, 0, BFD_RELOC_MMIX_REG_OR_BYTE);
+               fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 1,
+                            1, exp, 0, BFD_RELOC_8);
              if (exp[1].X_op == O_register)
                opcodep[3] = exp[1].X_add_number;
              else
-               fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 3,
-                            1, exp + 1, 0, BFD_RELOC_MMIX_REG_OR_BYTE);
+               fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 2,
+                            2, exp + 1, 0, BFD_RELOC_16);
            }
          else
            {
-             as_bad (_("unsupported operands to %s: `%s'"),
-                     instruction->name, operands);
-             return;
+             /* We can't get here for other cases.  */
+             gas_assert (n_operands == 1 && exp[0].X_op == O_register);
+
+             opcodep[3] = exp[0].X_add_number;
            }
        }
-      else
-       {
-         as_bad (_("invalid operands to opcode %s: `%s'"),
-                 instruction->name, operands);
-         return;
-       }
       break;
 
     case mmix_operands_resume:
@@ -1989,10 +2001,11 @@ static void
 mmix_greg_internal (char *label)
 {
   expressionS *expP = &mmix_raw_gregs[n_of_raw_gregs].exp;
+  segT section;
 
   /* Don't set the section to register contents section before the
      expression has been parsed; it may refer to the current position.  */
-  expression (expP);
+  section = expression (expP);
 
   /* FIXME: Check that no expression refers to the register contents
      section.  May need to be done in elf64-mmix.c.  */
@@ -2006,6 +2019,24 @@ mmix_greg_internal (char *label)
       expP->X_op_symbol = NULL;
     }
 
+  if (section == undefined_section)
+    {
+      /* This is an error or a LOC with an expression involving
+        forward references.  For the expression to be correctly
+        evaluated, we need to force a proper symbol; gas loses track
+        of the segment for "local symbols".  */
+      if (expP->X_op == O_add)
+       {
+         symbol_get_value_expression (expP->X_op_symbol);
+         symbol_get_value_expression (expP->X_add_symbol);
+       }
+      else
+       {
+         gas_assert (expP->X_op == O_symbol);
+         symbol_get_value_expression (expP->X_add_symbol);
+       }
+    }
+
   /* We must handle prefixes here, as we save the labels and expressions
      to be output later.  */
   mmix_raw_gregs[n_of_raw_gregs].label
@@ -2976,7 +3007,7 @@ mmix_handle_mmixal (void)
         it the same alignment and address as the associated instruction.  */
 
       /* Make room for the label including the ending nul.  */
-      int len_0 = s - label + 1;
+      size_t len_0 = s - label + 1;
 
       /* Save this label on the MMIX symbol obstack.  Saving it on an
         obstack is needless for "IS"-pseudos, but it's harmless and we
@@ -3452,6 +3483,7 @@ mmix_md_end (void)
   fragS *fragP;
   symbolS *mainsym;
   asection *regsec;
+  struct loc_assert_s *loc_assert;
   int i;
 
   /* The first frag of GREG:s going into the register contents section.  */
@@ -3509,6 +3541,38 @@ mmix_md_end (void)
       S_SET_EXTERNAL (mainsym);
     }
 
+  /* Check that we didn't LOC into the unknown, or rather that when it
+     was unknown, we actually change sections.  */
+  for (loc_assert = loc_asserts;
+       loc_assert != NULL;
+       loc_assert = loc_assert->next)
+    {
+      segT actual_seg;
+
+      resolve_symbol_value (loc_assert->loc_sym);
+      actual_seg = S_GET_SEGMENT (loc_assert->loc_sym);
+      if (actual_seg != loc_assert->old_seg)
+       {
+         char *fnam;
+         unsigned int line;
+         int e_valid = expr_symbol_where (loc_assert->loc_sym, &fnam, &line);
+
+         gas_assert (e_valid == 1);
+         as_bad_where (fnam, line,
+                       _("LOC to section unknown or indeterminable "
+                         "at first pass"));
+
+         /* Patch up the generic location data to avoid cascading
+            error messages from later passes.  (See original in
+            write.c:relax_segment.)  */
+         fragP = loc_assert->frag;
+         fragP->fr_type = rs_align;
+         fragP->fr_subtype = 0;
+         fragP->fr_offset = 0;
+         fragP->fr_fix = 0;
+       }
+    }
+
   if (n_of_raw_gregs != 0)
     {
       /* Emit GREGs.  They are collected in order of appearance, but must
@@ -3887,13 +3951,30 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
 
   if (exp.X_op == O_illegal
       || exp.X_op == O_absent
-      || exp.X_op == O_big
-      || section == undefined_section)
+      || exp.X_op == O_big)
     {
       as_bad (_("invalid LOC expression"));
       return;
     }
 
+  if (section == undefined_section)
+    {
+      /* This is an error or a LOC with an expression involving
+        forward references.  For the expression to be correctly
+        evaluated, we need to force a proper symbol; gas loses track
+        of the segment for "local symbols".  */
+      if (exp.X_op == O_add)
+       {
+         symbol_get_value_expression (exp.X_op_symbol);
+         symbol_get_value_expression (exp.X_add_symbol);
+       }
+      else
+       {
+         gas_assert (exp.X_op == O_symbol);
+         symbol_get_value_expression (exp.X_add_symbol);
+       }
+    }
+
   if (section == absolute_section)
     {
       /* Translate a constant into a suitable section.  */
@@ -3965,7 +4046,9 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
        }
     }
 
-  if (section != now_seg)
+  /* If we can't deduce the section, it must be the current one.
+     Below, we arrange to assert this.  */
+  if (section != now_seg && section != undefined_section)
     {
       obj_elf_section_change_hook ();
       subseg_set (section, 0);
@@ -3976,16 +4059,42 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
 
   if (exp.X_op != O_absent)
     {
+      symbolS *esym = NULL;
+
       if (exp.X_op != O_constant && exp.X_op != O_symbol)
        {
          /* Handle complex expressions.  */
-         sym = make_expr_symbol (&exp);
+         esym = sym = make_expr_symbol (&exp);
          off = 0;
        }
       else
        {
          sym = exp.X_add_symbol;
          off = exp.X_add_number;
+
+         if (section == undefined_section)
+           {
+             /* We need an expr_symbol when tracking sections.  In
+                order to make this an expr_symbol with file and line
+                tracked, we have to make the exp non-trivial; not an
+                O_symbol with .X_add_number == 0.  The constant part
+                is unused.  */
+             exp.X_add_number = 1;
+             esym = make_expr_symbol (&exp);
+           }
+       }
+
+      /* Track the LOC's where we couldn't deduce the section: assert
+        that we weren't supposed to change section.  */
+      if (section == undefined_section)
+       {
+         struct loc_assert_s *next = loc_asserts;
+         loc_asserts
+           = (struct loc_assert_s *) xmalloc (sizeof (*loc_asserts));
+         loc_asserts->next = next;
+         loc_asserts->old_seg = now_seg;
+         loc_asserts->loc_sym = esym;
+         loc_asserts->frag = frag_now;
        }
 
       p = frag_var (rs_org, 1, 1, (relax_substateT) 0, sym, off, (char *) 0);
@@ -4003,7 +4112,6 @@ static void
 mmix_byte (void)
 {
   unsigned int c;
-  char *start;
 
   if (now_seg == text_section)
     text_has_contents = 1;
@@ -4017,7 +4125,6 @@ mmix_byte (void)
        {
        case '\"':
          ++input_line_pointer;
-         start = input_line_pointer;
          while (is_a_char (c = next_char_of_string ()))
            {
              FRAG_APPEND_1_CHAR (c);
@@ -4093,7 +4200,6 @@ static void
 mmix_cons (int nbytes)
 {
   expressionS exp;
-  char *start;
 
   /* If we don't have any contents, then it's ok to have a specified start
      address that is not a multiple of the max data size.  We will then
@@ -4174,7 +4280,6 @@ mmix_cons (int nbytes)
               bytes.  */
          case '\"':
            ++input_line_pointer;
-           start = input_line_pointer;
            while (is_a_char (c = next_char_of_string ()))
              {
                exp.X_op = O_constant;
This page took 0.027925 seconds and 4 git commands to generate.