gas/riscv: Produce version 3 DWARF CIE by default
[deliverable/binutils-gdb.git] / gas / config / tc-mmix.c
index f4a95f1634a47da1419c8a7662d9783b11e0fe97..1514b6d0607d41a4e57afefa20e0d05e37eb2075 100644 (file)
@@ -1,11 +1,11 @@
 /* tc-mmix.c -- Assembler for Don Knuth's MMIX.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.
+   Copyright (C) 2001-2019 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -15,8 +15,8 @@
 
    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.  */
 
 /* Knuth's assembler mmixal does not provide a relocatable format; mmo is
    to be considered a final link-format.  In the final link, we make mmo,
    compatible syntax, but the main purpose is to serve GCC.  */
 
 
-#include <stdio.h>
-#include <limits.h>
 #include "as.h"
+#include <limits.h>
 #include "subsegs.h"
-#include "bfd.h"
 #include "elf/mmix.h"
 #include "opcode/mmix.h"
 #include "safe-ctype.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 *);
@@ -110,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
@@ -180,7 +186,7 @@ int mmix_next_semicolon_is_eoln = 1;
 
 /* Do we have a BSPEC in progress?  */
 static int doing_bspec = 0;
-static char *bspec_file;
+static const char *bspec_file;
 static unsigned int bspec_line;
 
 struct option md_longopts[] =
@@ -389,9 +395,9 @@ const char line_comment_chars[] = "*#";
 
 const char line_separator_chars[] = ";";
 
-const char mmix_exp_chars[] = "eE";
+const char EXP_CHARS[] = "eE";
 
-const char mmix_flt_chars[] = "rf";
+const char FLT_CHARS[] = "rf";
 
 
 /* Fill in the offset-related part of GETA or Bcc.  */
@@ -581,8 +587,10 @@ get_putget_operands (struct mmix_opcode *insn, char *operands,
            p++;
          sregp = p;
          input_line_pointer = sregp;
-         c = get_symbol_end ();
+         c = get_symbol_name (&sregp);
          sregend = input_line_pointer;
+         if (c == '"')
+           ++ input_line_pointer;
        }
     }
   else
@@ -590,10 +598,10 @@ get_putget_operands (struct mmix_opcode *insn, char *operands,
       expp_sreg = &exp[0];
       expp_reg = &exp[1];
 
-      sregp = p;
-      c = get_symbol_end ();
-      sregend = p = input_line_pointer;
-      *p = c;
+      c = get_symbol_name (&sregp);
+      sregend = input_line_pointer;
+      restore_line_pointer (c);
+      p = input_line_pointer;
 
       /* Skip whitespace */
       while (*p == ' ' || *p == '\t')
@@ -632,7 +640,7 @@ get_putget_operands (struct mmix_opcode *insn, char *operands,
 /* Handle MMIX-specific option.  */
 
 int
-md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
@@ -1366,6 +1374,9 @@ md_assemble (char *str)
             pass expressions as symbols and use fix_new, not fix_new_exp.  */
          sym = make_expr_symbol (exp + 1);
 
+         /* Mark the symbol as being OK for a reloc.  */
+         symbol_get_bfdsym (sym)->flags |= BSF_KEEP;
+
          /* Now we know it can be a "base address plus offset".  Add
             proper fixup types so we can handle this later, when we've
             parsed everything.  */
@@ -1466,8 +1477,8 @@ md_assemble (char *str)
                && ((exp[1].X_op == O_register
                     && exp[1].X_add_number < 512)
                    || (exp[1].X_op == O_constant
-                       && exp[1].X_add_number < 0
-                       && exp[1].X_add_number > 4)
+                       && (exp[1].X_add_number < 0
+                           || exp[1].X_add_number > 4))
                    || (exp[1].X_op != O_register
                        && exp[1].X_op != O_constant))))
          {
@@ -1671,7 +1682,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
@@ -1682,7 +1696,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'"),
@@ -1724,7 +1738,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'"),
@@ -1796,12 +1810,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
@@ -1809,49 +1826,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:
@@ -1925,11 +1941,9 @@ s_prefix (int unused ATTRIBUTE_UNUSED)
 
   SKIP_WHITESPACE ();
 
-  p = input_line_pointer;
-
-  c = get_symbol_end ();
-
-  /* Reseting prefix?  */
+  c = get_symbol_name (&p);
+  
+  /* Resetting prefix?  */
   if (*p == ':' && p[1] == 0)
     mmix_current_prefix = NULL;
   else
@@ -1947,7 +1961,7 @@ s_prefix (int unused ATTRIBUTE_UNUSED)
       mmix_current_prefix = p;
     }
 
-  *input_line_pointer = c;
+  (void) restore_line_pointer (c);
 
   mmix_handle_rest_of_empty_line ();
 }
@@ -1987,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.  */
@@ -2004,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
@@ -2024,13 +2057,15 @@ s_greg (int unused ATTRIBUTE_UNUSED)
 {
   char *p;
   char c;
-  p = input_line_pointer;
 
   /* This will skip over what can be a symbol and zero out the next
      character, which we assume is a ',' or other meaningful delimiter.
      What comes after that is the initializer expression for the
      register.  */
-  c = get_symbol_end ();
+  c = get_symbol_name (&p);
+
+  if (c == '"')
+    c = * ++ input_line_pointer;
 
   if (! is_end_of_line[(unsigned char) c])
     input_line_pointer++;
@@ -2095,9 +2130,8 @@ s_bspec (int unused ATTRIBUTE_UNUSED)
       if (sec == NULL)
        as_fatal (_("can't create section %s"), newsecname);
 
-      if (!bfd_set_section_flags (stdoutput, sec,
-                                 bfd_get_section_flags (stdoutput, sec)
-                                 | SEC_READONLY))
+      if (!bfd_set_section_flags (sec,
+                                 bfd_section_flags (sec) | SEC_READONLY))
        as_fatal (_("can't set section flags for section %s"), newsecname);
     }
 
@@ -2106,7 +2140,7 @@ s_bspec (int unused ATTRIBUTE_UNUSED)
   subseg_set (sec, 0);
 
   /* Save position for missing ESPEC.  */
-  as_where (&bspec_file, &bspec_line);
+  bspec_file = as_where (&bspec_line);
 
   doing_bspec = 1;
 }
@@ -2237,45 +2271,17 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
    emitted is stored in *sizeP .  An error message is returned, or NULL on
    OK.  */
 
-char *
+const char *
 md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-      /* FIXME: Having 'f' in mmix_flt_chars (and here) makes it
-        problematic to also have a forward reference in an expression.
-        The testsuite wants it, and it's customary.
-        We'll deal with the real problems when they come; we share the
-        problem with most other ports.  */
-    case 'f':
-    case 'r':
-      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 = 0; i < prec; i++)
-    {
-      md_number_to_chars (litP, (valueT) words[i], 2);
-      litP += 2;
-    }
-  return NULL;
+  if (type == 'r')
+    type = 'f';
+  /* FIXME: Having 'f' in FLT_CHARS (and here) makes it
+     problematic to also have a forward reference in an expression.
+     The testsuite wants it, and it's customary.
+     We'll deal with the real problems when they come; we share the
+     problem with most other ports.  */
+  return ieee_md_atof (type, litP, sizeP, TRUE);
 }
 
 /* Convert variable-sized frags into one or more fixups.  */
@@ -2365,7 +2371,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED,
       if (fragP->tc_frag_data == NULL)
        {
          /* We must initialize data that's supposed to be "fixed up" to
-            avoid emitting garbage, because md_apply_fix3 won't do
+            avoid emitting garbage, because md_apply_fix won't do
             anything for undefined symbols.  */
          md_number_to_chars (var_partp, 0, 8);
          tmpfixP
@@ -2413,7 +2419,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED,
    Note that this function isn't called when linkrelax != 0.  */
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT segment)
+md_apply_fix (fixS *fixP, valueT *valP, segT segment)
 {
   char *buf  = fixP->fx_where + fixP->fx_frag->fr_literal;
   /* Note: use offsetT because it is signed, valueT is unsigned.  */
@@ -2631,7 +2637,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
      than just helping the user around this limitation here; hopefully the
      code using the local expression is around.  Putting the LOCAL
      semantics in a relocation still seems right; a section didn't do.  */
-  if (bfd_section_size (section->owner, section) == 0)
+  if (bfd_section_size (section) == 0)
     as_bad_where
       (fixP->fx_file, fixP->fx_line,
        fixP->fx_r_type == BFD_RELOC_MMIX_LOCAL
@@ -2652,7 +2658,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
 
       if (addsy == NULL || bfd_is_abs_section (addsec))
        {
-         /* Resolve this reloc now, as md_apply_fix3 would have done (not
+         /* Resolve this reloc now, as md_apply_fix would have done (not
             called if -linkrelax).  There is no point in keeping a reloc
             to an absolute symbol.  No reloc that is subject to
             relaxation must be to an absolute symbol; difference
@@ -2701,7 +2707,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
         resolve the relocation here.  */
       if (addsy != NULL
          && (bfd_is_und_section (addsec)
-             || strcmp (bfd_get_section_name (addsec->owner, addsec),
+             || strcmp (bfd_section_name (addsec),
                         MMIX_REG_CONTENTS_SECTION_NAME) == 0))
        {
          code = fixP->fx_r_type;
@@ -2728,7 +2734,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
 
     case BFD_RELOC_MMIX_BASE_PLUS_OFFSET:
       if (addsy != NULL
-         && strcmp (bfd_get_section_name (addsec->owner, addsec),
+         && strcmp (bfd_section_name (addsec),
                     MMIX_REG_CONTENTS_SECTION_NAME) == 0)
        {
          /* This changed into a register; the relocation is for the
@@ -2831,7 +2837,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
     case BFD_RELOC_MMIX_REG:
       if (addsy != NULL
          && (bfd_is_und_section (addsec)
-             || strcmp (bfd_get_section_name (addsec->owner, addsec),
+             || strcmp (bfd_section_name (addsec),
                         MMIX_REG_CONTENTS_SECTION_NAME) == 0))
        {
          code = fixP->fx_r_type;
@@ -2852,9 +2858,9 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
        }
       /* FALLTHROUGH.  */
 
-      /* The others are supposed to be handled by md_apply_fix3.
+      /* The others are supposed to be handled by md_apply_fix.
         FIXME: ... which isn't called when -linkrelax.  Move over
-        md_apply_fix3 code here for everything reasonable.  */
+        md_apply_fix code here for everything reasonable.  */
     badop:
     default:
       as_bad_where
@@ -2867,9 +2873,9 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
       return NULL;
     }
 
-  relP = (arelent *) xmalloc (sizeof (arelent));
-  assert (relP != 0);
-  relP->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  relP = XNEW (arelent);
+  gas_assert (relP != 0);
+  relP->sym_ptr_ptr = XNEW (asymbol *);
   *relP->sym_ptr_ptr = baddsy;
   relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
 
@@ -2900,8 +2906,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
 void
 mmix_handle_mmixal (void)
 {
-  char *s0 = input_line_pointer;
-  char *s;
+  char *insn;
+  char *s = input_line_pointer;
   char *label = NULL;
   char c;
 
@@ -2911,44 +2917,20 @@ mmix_handle_mmixal (void)
   if (mmix_gnu_syntax)
     return;
 
-  /* If the first character is a '.', then it's a pseudodirective, not a
-     label.  Make GAS not handle label-without-colon on this line.  We
-     also don't do mmixal-specific stuff on this line.  */
-  if (input_line_pointer[0] == '.')
-    {
-      label_without_colon_this_line = 0;
-      return;
-    }
-
-  /* Don't handle empty lines here.  */
-  while (1)
-    {
-      if (*s0 == 0 || is_end_of_line[(unsigned int) *s0])
-       return;
-
-      if (! ISSPACE (*s0))
-       break;
-
-      s0++;
-    }
-
   /* If we're on a line with a label, check if it's a mmixal fb-label.
      Save an indicator and skip the label; it must be set only after all
      fb-labels of expressions are evaluated.  */
-  if (ISDIGIT (input_line_pointer[0])
-      && input_line_pointer[1] == 'H'
-      && ISSPACE (input_line_pointer[2]))
+  if (ISDIGIT (s[0]) && s[1] == 'H' && ISSPACE (s[2]))
     {
-      char *s;
-      current_fb_label = input_line_pointer[0] - '0';
+      current_fb_label = s[0] - '0';
 
       /* We have to skip the label, but also preserve the newlineness of
         the previous character, since the caller checks that.  It's a
         mess we blame on the caller.  */
-      input_line_pointer[1] = input_line_pointer[-1];
-      input_line_pointer += 2;
+      s[1] = s[-1];
+      s += 2;
+      input_line_pointer = s;
 
-      s = input_line_pointer;
       while (*s && ISSPACE (*s) && ! is_end_of_line[(unsigned int) *s])
        s++;
 
@@ -2956,48 +2938,75 @@ mmix_handle_mmixal (void)
         caller is about to bump the counters.  Adjust the error messages.  */
       if (is_end_of_line[(unsigned int) *s])
        {
-         char *name;
          unsigned int line;
-         as_where (&name, &line);
+         const char * name = as_where (&line);
          as_bad_where (name, line + 1,
                        _("[0-9]H labels may not appear alone on a line"));
          current_fb_label = -1;
        }
       if (*s == '.')
        {
-         char *name;
          unsigned int line;
-         as_where (&name, &line);
+         const char * name  = as_where (&line);
          as_bad_where (name, line + 1,
                        _("[0-9]H labels do not mix with dot-pseudos"));
          current_fb_label = -1;
        }
+
+      /* Back off to the last space before the opcode so we don't handle
+        the opcode as a label.  */
+      s--;
     }
   else
+    current_fb_label = -1;
+
+  if (*s == '.')
     {
-      current_fb_label = -1;
-      if (is_name_beginner (input_line_pointer[0]))
-       label = input_line_pointer;
+      /* If the first character is a '.', then it's a pseudodirective, not a
+        label.  Make GAS not handle label-without-colon on this line.  We
+        also don't do mmixal-specific stuff on this line.  */
+      label_without_colon_this_line = 0;
+      return;
     }
 
-  s0 = input_line_pointer;
-  /* Skip over label.  */
-  while (*s0 && is_part_of_name (*s0))
-    s0++;
-
-  /* Remove trailing ":" off labels, as they'd otherwise be considered
-     part of the name.  But don't do it for local labels.  */
-  if (s0 != input_line_pointer && s0[-1] == ':'
-      && (s0 - 2 != input_line_pointer
-         || ! ISDIGIT (s0[-2])))
-    s0[-1] = ' ';
-  else if (label != NULL)
+  if (*s == 0 || is_end_of_line[(unsigned int) *s])
+    /* We avoid handling empty lines here.  */
+    return;
+
+  if (is_name_beginner (*s))
+    label = s;
+
+  /* If there is a label, skip over it.  */
+  while (*s && is_part_of_name (*s))
+    s++;
+
+  /* Find the start of the instruction or pseudo following the label,
+     if there is one.  */
+  for (insn = s;
+       *insn && ISSPACE (*insn) && ! is_end_of_line[(unsigned int) *insn];
+       insn++)
+    /* Empty */
+    ;
+
+  /* Remove a trailing ":" off labels, as they'd otherwise be considered
+     part of the name.  But don't do this for local labels.  */
+  if (s != input_line_pointer && s[-1] == ':'
+      && (s - 2 != input_line_pointer
+         || ! ISDIGIT (s[-2])))
+    s[-1] = ' ';
+  else if (label != NULL
+          /* For a lone label on a line, we don't attach it to the next
+             instruction or MMIXAL-pseudo (getting its alignment).  Thus
+             is acts like a "normal" :-ended label.  Ditto if it's
+             followed by a non-MMIXAL pseudo.  */
+          && !is_end_of_line[(unsigned int) *insn]
+          && *insn != '.')
     {
       /* For labels that don't end in ":", we save it so we can later give
         it the same alignment and address as the associated instruction.  */
 
       /* Make room for the label including the ending nul.  */
-      int len_0 = s0 - 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
@@ -3007,14 +3016,10 @@ mmix_handle_mmixal (void)
       pending_label[len_0 - 1] = 0;
     }
 
-  while (*s0 && ISSPACE (*s0) && ! is_end_of_line[(unsigned int) *s0])
-    s0++;
-
-  if (pending_label != NULL && is_end_of_line[(unsigned int) *s0])
-    /* Whoops, this was actually a lone label on a line.  Like :-ended
-       labels, we don't attach such labels to the next instruction or
-       pseudo.  */
-    pending_label = NULL;
+  /* If we have a non-MMIXAL pseudo, we have not business with the rest of
+     the line.  */
+  if (*insn == '.')
+    return;
 
   /* Find local labels of operands.  Look for "[0-9][FB]" where the
      characters before and after are not part of words.  Break if a single
@@ -3026,7 +3031,6 @@ mmix_handle_mmixal (void)
 
   /* First make sure we don't have any of the magic characters on the line
      appearing as input.  */
-  s = s0;
   while (*s)
     {
       c = *s++;
@@ -3037,7 +3041,7 @@ mmix_handle_mmixal (void)
     }
 
   /* Scan again, this time looking for ';' after operands.  */
-  s = s0;
+  s = insn;
 
   /* Skip the insn.  */
   while (*s
@@ -3077,7 +3081,9 @@ mmix_handle_mmixal (void)
        {
          if ((s[1] != 'B' && s[1] != 'F')
              || is_part_of_name (s[-1])
-             || is_part_of_name (s[2]))
+             || is_part_of_name (s[2])
+             /* Don't treat e.g. #1F as a local-label reference.  */
+             || (s != input_line_pointer && s[-1] == '#'))
            s++;
          else
            {
@@ -3103,7 +3109,7 @@ mmix_handle_mmixal (void)
 
   /* Make IS into an EQU by replacing it with "= ".  Only match upper-case
      though; let lower-case be a syntax error.  */
-  s = s0;
+  s = insn;
   if (s[0] == 'I' && s[1] == 'S' && ISSPACE (s[2]))
     {
       *s = '=';
@@ -3267,10 +3273,10 @@ mmix_force_relocation (fixS *fixP)
   if (linkrelax)
     return 1;
 
-  /* All our pcrel relocations are must-keep.  Note that md_apply_fix3 is
+  /* All our pcrel relocations are must-keep.  Note that md_apply_fix is
      called *after* this, and will handle getting rid of the presumed
      reloc; a relocation isn't *forced* other than to be handled by
-     md_apply_fix3 (or tc_gen_reloc if linkrelax).  */
+     md_apply_fix (or tc_gen_reloc if linkrelax).  */
   if (fixP->fx_pcrel)
     return 1;
 
@@ -3309,7 +3315,7 @@ mmix_adjust_symtab (void)
       {
        if (sym == regsec)
          {
-           if (S_IS_EXTERN (sym) || symbol_used_in_reloc_p (sym))
+           if (S_IS_EXTERNAL (sym) || symbol_used_in_reloc_p (sym))
              abort ();
            symbol_remove (sym, &symbol_rootP, &symbol_lastP);
          }
@@ -3406,7 +3412,7 @@ mmix_md_relax_frag (segT seg, fragS *fragP, long stretch)
        fragP->fr_subtype = ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO);
       }
       /* FALLTHROUGH.  */
-    
+
       /* See if this PUSHJ is redirectable to a stub.  */
     case ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO):
       {
@@ -3475,6 +3481,8 @@ 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.  */
@@ -3532,6 +3540,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)
+       {
+         const 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
@@ -3539,9 +3579,9 @@ mmix_md_end (void)
         and the same allocation order (within a file) as mmixal.  */
       segT this_segment = now_seg;
       subsegT this_subsegment = now_subseg;
-      asection *regsec
-       = bfd_make_section_old_way (stdoutput,
-                                   MMIX_REG_CONTENTS_SECTION_NAME);
+
+      regsec = bfd_make_section_old_way (stdoutput,
+                                        MMIX_REG_CONTENTS_SECTION_NAME);
       subseg_set (regsec, 0);
 
       /* Finally emit the initialization-value.  Emit a variable frag, which
@@ -3568,6 +3608,11 @@ mmix_md_end (void)
       subseg_set (this_segment, this_subsegment);
     }
 
+  regsec = bfd_get_section_by_name (stdoutput, MMIX_REG_CONTENTS_SECTION_NAME);
+  /* Mark the section symbol as being OK for a reloc.  */
+  if (regsec != NULL)
+    regsec->symbol->flags |= BSF_KEEP;
+
   /* Iterate over frags resulting from GREGs and move those that evidently
      have the same value together and point one to another.
 
@@ -3729,7 +3774,7 @@ mmix_frob_file (void)
 
       if (gregs == NULL)
        {
-         gregs = xmalloc (sizeof (*gregs));
+         gregs = XNEW (struct mmix_symbol_gregs);
          gregs->n_gregs = 0;
          symbol_set_tc (sym, &gregs);
          all_greg_symbols[n_greg_symbols++] = gregs;
@@ -3747,18 +3792,11 @@ mmix_frob_file (void)
 
   if (real_reg_section != NULL)
     {
-      asection **secpp;
-
       /* FIXME: Pass error state gracefully.  */
-      if (bfd_get_section_flags (stdoutput, real_reg_section) & SEC_HAS_CONTENTS)
+      if (bfd_section_flags (real_reg_section) & SEC_HAS_CONTENTS)
        as_fatal (_("register section has contents\n"));
 
-      /* Really remove the section.  */
-      for (secpp = &stdoutput->sections;
-          *secpp != real_reg_section;
-          secpp = &(*secpp)->next)
-       ;
-      bfd_section_list_remove (stdoutput, secpp);
+      bfd_section_list_remove (stdoutput, real_reg_section);
       --stdoutput->section_count;
     }
 
@@ -3774,7 +3812,7 @@ int
 mmix_parse_predefined_name (char *name, expressionS *expP)
 {
   char *canon_name;
-  char *handler_charp;
+  const char *handler_charp;
   const char handler_chars[] = "DVWIOUZX";
   symbolS *symp;
 
@@ -3885,7 +3923,7 @@ mmix_md_elf_section_change_hook (void)
   if (doing_bspec)
     as_bad (_("section change from within a BSPEC/ESPEC pair is not supported"));
 
-  last_alignment = bfd_get_section_alignment (now_seg->owner, now_seg);
+  last_alignment = bfd_section_alignment (now_seg);
   want_unaligned = 0;
 }
 
@@ -3912,20 +3950,39 @@ 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.  */
 
       if (exp.X_add_number < ((offsetT) 0x20 << 56))
        {
-         /* Lower than Data_Segment - assume it's .text.  */
+         /* Lower than Data_Segment or in the reserved area (the
+            segment number is >= 0x80, appearing negative) - assume
+            it's .text.  */
          section = text_section;
 
          /* Save the lowest seen location, so we can pass on this
@@ -3937,8 +3994,8 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
             this one), we org at (this - lower).  There's an implicit
             "LOC 0" before any entered code.  FIXME: handled by spurious
             settings of text_has_contents.  */
-         if (exp.X_add_number < 0
-             || exp.X_add_number < (offsetT) lowest_text_loc)
+         if (lowest_text_loc != (bfd_vma) -1
+             && (bfd_vma) exp.X_add_number < lowest_text_loc)
            {
              as_bad (_("LOC expression stepping backwards is not supported"));
              exp.X_op = O_absent;
@@ -3961,7 +4018,8 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
        }
       else
        {
-         /* Do the same for the .data section.  */
+         /* Do the same for the .data section, except we don't have
+            to worry about exp.X_add_number carrying a sign.  */
          section = data_section;
 
          if (exp.X_add_number < (offsetT) lowest_data_loc)
@@ -3987,7 +4045,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);
@@ -3998,16 +4058,41 @@ 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 = XNEW (struct loc_assert_s);
+         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);
@@ -4025,7 +4110,6 @@ static void
 mmix_byte (void)
 {
   unsigned int c;
-  char *start;
 
   if (now_seg == text_section)
     text_has_contents = 1;
@@ -4039,7 +4123,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);
@@ -4115,7 +4198,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
@@ -4196,7 +4278,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.086569 seconds and 4 git commands to generate.