gas/testsuite/
[deliverable/binutils-gdb.git] / gas / read.c
index 93e3ec41b171154d8db1fdcd52281237ec487eff..131937edb24221f6a315b9f6612769a21e4d7c05 100644 (file)
@@ -1,6 +1,7 @@
 /* read.c - read a source file -
    Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
 
@@ -19,14 +20,10 @@ 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.  */
 
-#if 0
-/* If your chars aren't 8 bits, you will change this a bit.
+/* If your chars aren't 8 bits, you will change this a bit (eg. to 0xFF).
    But then, GNU isn't spozed to run on your machine anyway.
    (RMS is so shortsighted sometimes.)  */
-#define MASK_CHAR (0xFF)
-#else
 #define MASK_CHAR ((int)(unsigned char) -1)
-#endif
 
 /* This is the largest known floating point format (for now). It will
    grow when we do 4361 style flonums.  */
@@ -216,6 +213,8 @@ static int dwarf_file_string;
 
 static void do_align (int, char *, int, int);
 static void s_align (int, int);
+static void s_altmacro (int);
+static void s_bad_end (int);
 static int hex_float (int, char *);
 static segT get_known_segmented_expression (expressionS * expP);
 static void pobegin (void);
@@ -251,6 +250,7 @@ static struct hash_control *po_hash;
 static const pseudo_typeS potable[] = {
   {"abort", s_abort, 0},
   {"align", s_align_ptwo, 0},
+  {"altmacro", s_altmacro, 1},
   {"ascii", stringer, 0},
   {"asciz", stringer, 1},
   {"balign", s_align_bytes, 0},
@@ -299,11 +299,13 @@ static const pseudo_typeS potable[] = {
   {"endc", s_endif, 0},
   {"endfunc", s_func, 1},
   {"endif", s_endif, 0},
-  {"endr", s_bad_endr, 0},
+  {"endm", s_bad_end, 0},
+  {"endr", s_bad_end, 1},
 /* endef  */
   {"equ", s_set, 0},
   {"equiv", s_set, 1},
   {"err", s_err, 0},
+  {"error", s_errwarn, 1},
   {"exitm", s_mexit, 0},
 /* extend  */
   {"extern", s_ignore, 0},     /* We treat all undef as ext.  */
@@ -351,6 +353,7 @@ static const pseudo_typeS potable[] = {
   {"mri", s_mri, 0},
   {".mri", s_mri, 0},  /* Special case so .mri works in MRI mode.  */
   {"name", s_ignore, 0},
+  {"noaltmacro", s_altmacro, 0},
   {"noformat", s_ignore, 0},
   {"nolist", listing_list, 0}, /* Turn listing off.  */
   {"nopage", listing_nopage, 0},
@@ -408,6 +411,7 @@ static const pseudo_typeS potable[] = {
   {"xdef", s_globl, 0},
   {"xref", s_ignore, 0},
   {"xstabs", s_xstab, 's'},
+  {"warning", s_errwarn, 0},
   {"word", cons, 2},
   {"zero", s_space, 0},
   {NULL, NULL, 0}                      /* End sentinel.  */
@@ -1077,6 +1081,29 @@ read_a_source_file (char *name)
 #endif
 }
 
+/* Convert O_constant expression EXP into the equivalent O_big representation.
+   Take the sign of the number from X_unsigned rather than X_add_number.  */
+
+static void
+convert_to_bignum (expressionS *exp)
+{
+  valueT value;
+  unsigned int i;
+
+  value = exp->X_add_number;
+  for (i = 0; i < sizeof (exp->X_add_number) / CHARS_PER_LITTLENUM; i++)
+    {
+      generic_bignum[i] = value & LITTLENUM_MASK;
+      value >>= LITTLENUM_NUMBER_OF_BITS;
+    }
+  /* Add a sequence of sign bits if the top bit of X_add_number is not
+     the sign of the original value.  */
+  if ((exp->X_add_number < 0) != !exp->X_unsigned)
+    generic_bignum[i++] = exp->X_unsigned ? 0 : LITTLENUM_MASK;
+  exp->X_op = O_big;
+  exp->X_add_number = i;
+}
+
 /* For most MRI pseudo-ops, the line actually ends at the first
    nonquoted space.  This function looks for that point, stuffs a null
    in, and sets *STOPCP to the character that used to be there, and
@@ -1190,10 +1217,17 @@ do_align (int n, char *fill, int len, int max)
    fill pattern.  BYTES_P is non-zero if the alignment value should be
    interpreted as the byte boundary, rather than the power of 2.  */
 
+#ifdef BFD_ASSEMBLER
+#define ALIGN_LIMIT (stdoutput->arch_info->bits_per_address - 1)
+#else
+#define ALIGN_LIMIT 15
+#endif
+
 static void
 s_align (int arg, int bytes_p)
 {
-  register unsigned int align;
+  unsigned int align_limit = ALIGN_LIMIT;
+  unsigned int align;
   char *stop = NULL;
   char stopc;
   offsetT fill = 0;
@@ -1232,9 +1266,9 @@ s_align (int arg, int bytes_p)
        }
     }
 
-  if (align > 15)
+  if (align > align_limit)
     {
-      align = 15;
+      align = align_limit;
       as_warn (_("alignment too large: %u assumed"), align);
     }
 
@@ -1320,6 +1354,15 @@ s_align_ptwo (int arg)
   s_align (arg, 0);
 }
 
+/* Switch in and out of alternate macro mode.  */
+
+void
+s_altmacro (int on)
+{
+  demand_empty_rest_of_line ();
+  macro_set_alternate (on);
+}
+
 symbolS *
 s_comm_internal (int param,
                 symbolS *(*comm_parse_extra) (int, symbolS *, addressT))
@@ -1356,7 +1399,6 @@ s_comm_internal (int param,
   if (*input_line_pointer == ',')
     input_line_pointer++;
 
-  *p = 0;
   temp = get_absolute_expr (&exp);
   size = temp;
 #ifdef BFD_ASSEMBLER
@@ -1365,18 +1407,17 @@ s_comm_internal (int param,
   if (exp.X_op == O_absent)
     {
       as_bad (_("missing size expression"));
-      *p = c;
       ignore_rest_of_line ();
       goto out;
     }
   else if (temp != size || !exp.X_unsigned)
     {
       as_warn (_("size (%ld) out of range, ignored"), (long) temp);
-      *p = c;
       ignore_rest_of_line ();
       goto out;
     }
 
+  *p = 0;
   symbolP = symbol_find_or_make (name);
   if (S_IS_DEFINED (symbolP) && !S_IS_COMMON (symbolP))
     {
@@ -1558,7 +1599,7 @@ s_data (int ignore ATTRIBUTE_UNUSED)
    .file.  */
 
 void
-s_app_file_string (char *file)
+s_app_file_string (char *file, int appfile)
 {
 #ifdef LISTING
   if (listing)
@@ -1566,7 +1607,7 @@ s_app_file_string (char *file)
 #endif
   register_dependency (file);
 #ifdef obj_app_file
-  obj_app_file (file);
+  obj_app_file (file, appfile);
 #endif
 }
 
@@ -1594,7 +1635,7 @@ s_app_file (int appfile)
 
       demand_empty_rest_of_line ();
       if (!may_omit)
-       s_app_file_string (s);
+       s_app_file_string (s, appfile);
     }
 }
 
@@ -1653,6 +1694,43 @@ s_err (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Handle the .error and .warning pseudo-ops.  */
+
+void
+s_errwarn (int err)
+{
+  int len;
+  /* The purpose for the conditional assignment is not to
+     internationalize the directive itself, but that we need a
+     self-contained message, one that can be passed like the
+     demand_copy_C_string return value, and with no assumption on the
+     location of the name of the directive within the message.  */
+  char *msg
+    = (err ? _(".error directive invoked in source file")
+       : _(".warning directive invoked in source file"));
+
+  if (!is_it_end_of_statement ())
+    {
+      if (*input_line_pointer != '\"')
+       {
+         as_bad (_("%s argument must be a string"),
+                 err ? ".error" : ".warning");
+         discard_rest_of_line ();
+         return;
+       }
+
+      msg = demand_copy_C_string (&len);
+      if (msg == NULL)
+       return;
+    }
+
+  if (err)
+    as_bad ("%s", msg);
+  else
+    as_warn ("%s", msg);
+  demand_empty_rest_of_line ();
+}
+
 /* Handle the MRI fail pseudo-op.  */
 
 void
@@ -2583,12 +2661,14 @@ s_purgem (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
-/* Handle the .rept pseudo-op.  */
+/* Handle the .endm/.endr pseudo-ops.  */
 
-void
-s_bad_endr (int ignore ATTRIBUTE_UNUSED)
+static void
+s_bad_end (int endr)
 {
-  as_warn (_(".endr encountered without preceeding .rept, .irc, or .irp"));
+  as_warn (_(".end%c encountered without preceeding %s"),
+          endr ? 'r' : 'm',
+          endr ? ".rept, .irp, or .irpc" : ".macro");
   demand_empty_rest_of_line ();
 }
 
@@ -3485,22 +3565,9 @@ emit_expr (expressionS *exp, unsigned int nbytes)
      pass to md_number_to_chars, handle it as a bignum.  */
   if (op == O_constant && nbytes > sizeof (valueT))
     {
-      valueT val;
-      int gencnt;
-
-      if (!exp->X_unsigned && exp->X_add_number < 0)
-       extra_digit = (valueT) -1;
-      val = (valueT) exp->X_add_number;
-      gencnt = 0;
-      do
-       {
-         generic_bignum[gencnt] = val & LITTLENUM_MASK;
-         val >>= LITTLENUM_NUMBER_OF_BITS;
-         ++gencnt;
-       }
-      while (val != 0);
-      op = exp->X_op = O_big;
-      exp->X_add_number = gencnt;
+      extra_digit = exp->X_unsigned ? 0 : -1;
+      convert_to_bignum (exp);
+      op = O_big;
     }
 
   if (op == O_constant)
@@ -4220,36 +4287,48 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
   unsigned byte;
 
   /* Strip leading sign extensions off the bignum.  */
-  while (size > 0 && bignum[size - 1] == (LITTLENUM_TYPE) -1)
+  while (size > 1
+        && bignum[size - 1] == LITTLENUM_MASK
+        && bignum[size - 2] > LITTLENUM_MASK / 2)
     size--;
 
   do
     {
-      if (loaded < 7 && size > 0)
-       {
-         val |= (*bignum << loaded);
-         loaded += 8 * CHARS_PER_LITTLENUM;
-         size--;
-         bignum++;
-       }
-
-      byte = val & 0x7f;
-      loaded -= 7;
-      val >>= 7;
+      /* OR in the next part of the littlenum.  */
+      val |= (*bignum << loaded);
+      loaded += LITTLENUM_NUMBER_OF_BITS;
+      size--;
+      bignum++;
 
-      if (size == 0)
+      /* Add bytes until there are less than 7 bits left in VAL
+        or until every non-sign bit has been written.  */
+      do
        {
-         if ((val == 0 && (byte & 0x40) == 0)
-             || (~(val | ~(((valueT) 1 << loaded) - 1)) == 0
-                 && (byte & 0x40) != 0))
+         byte = val & 0x7f;
+         loaded -= 7;
+         val >>= 7;
+         if (size > 0
+             || val != ((byte & 0x40) == 0 ? 0 : ((valueT) 1 << loaded) - 1))
            byte |= 0x80;
+
+         if (orig)
+           *p = byte;
+         p++;
        }
+      while ((byte & 0x80) != 0 && loaded >= 7);
+    }
+  while (size > 0);
 
+  /* Mop up any left-over bits (of which there will be less than 7).  */
+  if ((byte & 0x80) != 0)
+    {
+      /* Sign-extend VAL.  */
+      if (val & (1 << (loaded - 1)))
+       val |= ~0 << loaded;
       if (orig)
-       *p = byte;
+       *p = val & 0x7f;
       p++;
     }
-  while (byte & 0x80);
 
   return p - orig;
 }
@@ -4328,6 +4407,16 @@ emit_leb128_expr (expressionS *exp, int sign)
       as_warn (_("register value used as expression"));
       op = O_constant;
     }
+  else if (op == O_constant
+          && sign
+          && (exp->X_add_number < 0) != !exp->X_unsigned)
+    {
+      /* We're outputting a signed leb128 and the sign of X_add_number
+        doesn't reflect the sign of the original value.  Convert EXP
+        to a correctly-extended bignum instead.  */
+      convert_to_bignum (exp);
+      op = O_big;
+    }
 
   /* Let check_eh_frame know that data is being emitted.  nbytes == -1 is
      a signal that this is leb128 data.  It shouldn't optimize this away.  */
@@ -4911,13 +5000,13 @@ s_incbin (int x ATTRIBUTE_UNUSED)
        }
       file_len = ftell (binfile);
 
-      /* If a count was not specified use the size of the file.  */
+      /* If a count was not specified use the remainder of the file.  */
       if (count == 0)
-       count = file_len;
+       count = file_len - skip;
 
-      if (skip + count > file_len)
+      if (skip < 0 || count < 0 || file_len < 0 || skip + count > file_len)
        {
-         as_bad (_("skip (%ld) + count (%ld) larger than file size (%ld)"),
+         as_bad (_("skip (%ld) or count (%ld) invalid for file size (%ld)"),
                  skip, count, file_len);
          goto done;
        }
This page took 0.049442 seconds and 4 git commands to generate.