]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/read.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / read.c
index 8f93c2ba2b461a22440889e67875fb40a34275f4..cf704b31ca3f63e599756ce9bbd7685860ebb7e5 100644 (file)
@@ -1,5 +1,5 @@
 /* read.c - read a source file -
-   Copyright (C) 1986-2020 Free Software Foundation, Inc.
+   Copyright (C) 1986-2021 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -40,6 +40,8 @@
 #include "dw2gencfi.h"
 #include "wchar.h"
 
+#include <limits.h>
+
 #ifndef TC_START_LABEL
 #define TC_START_LABEL(STR, NUL_CHAR, NEXT_CHAR) (NEXT_CHAR == ':')
 #endif
@@ -293,7 +295,53 @@ address_bytes (void)
 
 /* Set up pseudo-op tables.  */
 
-static struct hash_control *po_hash;
+struct po_entry
+{
+  const char *poc_name;
+
+  const pseudo_typeS *pop;
+};
+
+typedef struct po_entry po_entry_t;
+
+/* Hash function for a po_entry.  */
+
+static hashval_t
+hash_po_entry (const void *e)
+{
+  const po_entry_t *entry = (const po_entry_t *) e;
+  return htab_hash_string (entry->poc_name);
+}
+
+/* Equality function for a po_entry.  */
+
+static int
+eq_po_entry (const void *a, const void *b)
+{
+  const po_entry_t *ea = (const po_entry_t *) a;
+  const po_entry_t *eb = (const po_entry_t *) b;
+
+  return strcmp (ea->poc_name, eb->poc_name) == 0;
+}
+
+static po_entry_t *
+po_entry_alloc (const char *poc_name, const pseudo_typeS *pop)
+{
+  po_entry_t *entry = XNEW (po_entry_t);
+  entry->poc_name = poc_name;
+  entry->pop = pop;
+  return entry;
+}
+
+static const pseudo_typeS *
+po_entry_find (htab_t table, const char *poc_name)
+{
+  po_entry_t needle = { poc_name, NULL };
+  po_entry_t *entry = htab_find (table, &needle);
+  return entry != NULL ? entry->pop : NULL;
+}
+
+static struct htab *po_hash;
 
 static const pseudo_typeS potable[] = {
   {"abort", s_abort, 0},
@@ -417,6 +465,7 @@ static const pseudo_typeS potable[] = {
   {"noformat", s_ignore, 0},
   {"nolist", listing_list, 0}, /* Turn listing off.  */
   {"nopage", listing_nopage, 0},
+  {"nop", s_nop, 0},
   {"nops", s_nops, 0},
   {"octa", cons, 16},
   {"offset", s_struct, 0},
@@ -512,14 +561,17 @@ static const char *pop_table_name;
 void
 pop_insert (const pseudo_typeS *table)
 {
-  const char *errtxt;
   const pseudo_typeS *pop;
   for (pop = table; pop->poc_name; pop++)
     {
-      errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
-      if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists")))
-       as_fatal (_("error constructing %s pseudo-op table: %s"), pop_table_name,
-                 errtxt);
+      po_entry_t *elt = po_entry_alloc (pop->poc_name, pop);
+      if (htab_insert (po_hash, elt, 0) != NULL)
+       {
+         free (elt);
+         if (!pop_override_ok)
+           as_fatal (_("error constructing %s pseudo-op table"),
+                     pop_table_name);
+       }
     }
 }
 
@@ -538,7 +590,8 @@ pop_insert (const pseudo_typeS *table)
 static void
 pobegin (void)
 {
-  po_hash = hash_new ();
+  po_hash = htab_create_alloc (16, hash_po_entry, eq_po_entry, NULL,
+                              xcalloc, xfree);
 
   /* Do the target-specific pseudo ops.  */
   pop_table_name = "md";
@@ -816,8 +869,8 @@ read_a_source_file (const char *name)
   char nul_char;
   char next_char;
   char *s;             /* String of symbol, '\0' appended.  */
-  int temp;
-  pseudo_typeS *pop;
+  long temp;
+  const pseudo_typeS *pop;
 
 #ifdef WARN_COMMENTS
   found_comment = 0;
@@ -953,8 +1006,7 @@ read_a_source_file (const char *name)
                      else
                        line_label = symbol_create (line_start,
                                                    absolute_section,
-                                                   (valueT) 0,
-                                                   &zero_address_frag);
+                                                   &zero_address_frag, 0);
 
                      next_char = restore_line_pointer (nul_char);
                      if (next_char == ':')
@@ -1067,7 +1119,7 @@ read_a_source_file (const char *name)
                    {
                      /* The MRI assembler uses pseudo-ops without
                         a period.  */
-                     pop = (pseudo_typeS *) hash_find (po_hash, s);
+                     pop = po_entry_find (po_hash, s);
                      if (pop != NULL && pop->poc_handler == NULL)
                        pop = NULL;
                    }
@@ -1082,7 +1134,7 @@ read_a_source_file (const char *name)
                         already know that the pseudo-op begins with a '.'.  */
 
                      if (pop == NULL)
-                       pop = (pseudo_typeS *) hash_find (po_hash, s + 1);
+                       pop = po_entry_find (po_hash, s + 1);
                      if (pop && !pop->poc_handler)
                        pop = NULL;
 
@@ -1212,10 +1264,24 @@ read_a_source_file (const char *name)
              /* Read the whole number.  */
              while (ISDIGIT (*input_line_pointer))
                {
-                 temp = (temp * 10) + *input_line_pointer - '0';
+                 const long digit = *input_line_pointer - '0';
+                 if (temp > (LONG_MAX - digit) / 10)
+                   {
+                     as_bad (_("local label too large near %s"), backup);
+                     temp = -1;
+                     break;
+                   }
+                 temp = temp * 10 + digit;
                  ++input_line_pointer;
                }
 
+             /* Overflow: stop processing the label.  */
+             if (temp == -1)
+               {
+                 ignore_rest_of_line ();
+                 continue;
+               }
+
              if (LOCAL_LABELS_DOLLAR
                  && *input_line_pointer == '$'
                  && *(input_line_pointer + 1) == ':')
@@ -1224,7 +1290,7 @@ read_a_source_file (const char *name)
 
                  if (dollar_label_defined (temp))
                    {
-                     as_fatal (_("label \"%d$\" redefined"), temp);
+                     as_fatal (_("label \"%ld$\" redefined"), temp);
                    }
 
                  define_dollar_label (temp);
@@ -2481,7 +2547,7 @@ bss_alloc (symbolS *symbolP, addressT size, unsigned int align)
     symbol_get_frag (symbolP)->fr_symbol = NULL;
 
   symbol_set_frag (symbolP, frag_now);
-  pfrag = frag_var (rs_org, 1, 1, 0, symbolP, size, NULL);
+  pfrag = frag_var (rs_org, 1, 1, 0, symbolP, size * OCTETS_PER_BYTE, NULL);
   *pfrag = 0;
 
 #ifdef S_SET_SIZE
@@ -2723,10 +2789,10 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
        }
 
       if (((NO_PSEUDO_DOT || flag_m68k_mri)
-          && hash_find (po_hash, name) != NULL)
+          && po_entry_find (po_hash, name) != NULL)
          || (!flag_m68k_mri
              && *name == '.'
-             && hash_find (po_hash, name + 1) != NULL))
+             && po_entry_find (po_hash, name + 1) != NULL))
        as_warn_where (file,
                 line,
                 _("attempt to redefine pseudo-op `%s' ignored"),
@@ -3437,6 +3503,61 @@ s_space (int mult)
     mri_comment_end (stop, stopc);
 }
 
+void
+s_nop (int ignore ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+  fragS *start;
+  addressT start_off;
+  offsetT frag_off;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+#ifdef md_cons_align
+  md_cons_align (1);
+#endif
+
+  SKIP_WHITESPACE ();
+  expression (&exp);
+  demand_empty_rest_of_line ();
+
+  start = frag_now;
+  start_off = frag_now_fix ();
+  do
+    {
+#ifdef md_emit_single_noop
+      md_emit_single_noop;
+#else
+      char *nop;
+
+#ifndef md_single_noop_insn
+#define md_single_noop_insn "nop"
+#endif
+      /* md_assemble might modify its argument, so
+        we must pass it a string that is writable.  */
+      if (asprintf (&nop, "%s", md_single_noop_insn) < 0)
+       as_fatal ("%s", xstrerror (errno));
+
+      /* Some targets assume that they can update input_line_pointer
+        inside md_assemble, and, worse, that they can leave it
+        assigned to the string pointer that was provided as an
+        argument.  So preserve ilp here.  */
+      char *saved_ilp = input_line_pointer;
+      md_assemble (nop);
+      input_line_pointer = saved_ilp;
+      free (nop);
+#endif
+#ifdef md_flush_pending_output
+      md_flush_pending_output ();
+#endif
+    } while (exp.X_op == O_constant
+            && exp.X_add_number > 0
+            && frag_offset_ignore_align_p (start, frag_now, &frag_off)
+            && frag_off + frag_now_fix () < start_off + exp.X_add_number);
+}
+
 void
 s_nops (int ignore ATTRIBUTE_UNUSED)
 {
@@ -3451,8 +3572,12 @@ s_nops (int ignore ATTRIBUTE_UNUSED)
   md_cons_align (1);
 #endif
 
+  SKIP_WHITESPACE ();
   expression (&exp);
+  /* Note - this expression is tested for an absolute value in
+     write.c:relax_segment().  */
 
+  SKIP_WHITESPACE ();
   if (*input_line_pointer == ',')
     {
       ++input_line_pointer;
@@ -3464,29 +3589,30 @@ s_nops (int ignore ATTRIBUTE_UNUSED)
       val.X_add_number = 0;
     }
 
-  if (val.X_op == O_constant)
+  if (val.X_op != O_constant)
     {
-      if (val.X_add_number < 0)
-       {
-         as_warn (_("negative nop control byte, ignored"));
-         val.X_add_number = 0;
-       }
-
-      if (!need_pass_2)
-       {
-         /* Store the no-op instruction control byte in the first byte
-            of frag.  */
-         char *p;
-         symbolS *sym = make_expr_symbol (&exp);
-         p = frag_var (rs_space_nop, 1, 1, (relax_substateT) 0,
-                       sym, (offsetT) 0, (char *) 0);
-         *p = val.X_add_number;
-       }
+      as_bad (_("unsupported variable nop control in .nops directive"));
+      val.X_op = O_constant;
+      val.X_add_number = 0;
+    }
+  else if (val.X_add_number < 0)
+    {
+      as_warn (_("negative nop control byte, ignored"));
+      val.X_add_number = 0;
     }
-  else
-    as_bad (_("unsupported variable nop control in .nops directive"));
 
   demand_empty_rest_of_line ();
+
+  if (need_pass_2)
+    /* Ignore this directive if we are going to perform a second pass.  */
+    return;
+
+  /* Store the no-op instruction control byte in the first byte of frag.  */
+  char *p;
+  symbolS *sym = make_expr_symbol (&exp);
+  p = frag_var (rs_space_nop, 1, 1, (relax_substateT) 0,
+               sym, (offsetT) 0, (char *) 0);
+  *p = val.X_add_number;
 }
 
 /* This is like s_space, but the value is a floating point number with
@@ -5138,7 +5264,7 @@ output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size, int sign)
 /* Generate the appropriate fragments for a given expression to emit a
    leb128 value.  SIGN is 1 for sleb, 0 for uleb.  */
 
-static void
+void
 emit_leb128_expr (expressionS *exp, int sign)
 {
   operatorT op = exp->X_op;
@@ -5360,6 +5486,11 @@ stringer (int bits_appendzero)
          while (is_a_char (c = next_char_of_string ()))
            stringer_append_char (c, bitsize);
 
+         /* Treat "a" "b" as "ab".  Even if we are appending zeros.  */
+         SKIP_ALL_WHITESPACE ();
+         if (*input_line_pointer == '"')
+           break;
+
          if (append_zero)
            stringer_append_char (0, bitsize);
 
@@ -6112,7 +6243,7 @@ s_ignore (int arg ATTRIBUTE_UNUSED)
 void
 read_print_statistics (FILE *file)
 {
-  hash_print_statistics (file, "pseudo-op table", po_hash);
+  htab_print_statistics (file, "pseudo-op table", po_hash);
 }
 
 /* Inserts the given line into the input stream.