x86: don't record full i386_cpu_flags in struct i386_tc_frag_data
[binutils-gdb.git] / gas / read.c
index 7333a2ef47b9e0561769aecc6fabed8ea93748fd..826156db3fe24d534201c979e5250bbcdac7c8b2 100644 (file)
@@ -1,5 +1,5 @@
 /* read.c - read a source file -
-   Copyright (C) 1986-2021 Free Software Foundation, Inc.
+   Copyright (C) 1986-2023 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -38,7 +38,9 @@
 #include "obstack.h"
 #include "ecoff.h"
 #include "dw2gencfi.h"
+#include "codeview.h"
 #include "wchar.h"
+#include "filenames.h"
 
 #include <limits.h>
 
@@ -172,10 +174,10 @@ int target_big_endian = TARGET_BYTES_BIG_ENDIAN;
 const char **include_dirs;
 
 /* How many are in the table.  */
-int include_dir_count;
+size_t include_dir_count;
 
 /* Length of longest in table.  */
-int include_dir_maxlen = 1;
+size_t include_dir_maxlen;
 
 #ifndef WORKING_DOT_WORD
 struct broken_word *broken_words;
@@ -202,8 +204,17 @@ symbolS *mri_common_symbol;
    may be needed.  */
 static int mri_pending_align;
 
+/* Record the current function so that we can issue an error message for
+   misplaced .func,.endfunc, and also so that .endfunc needs no
+   arguments.  */
+static char *current_name;
+static char *current_label;
+
 #ifndef NO_LISTING
 #ifdef OBJ_ELF
+static int dwarf_file;
+static int dwarf_line;
+
 /* This variable is set to be non-zero if the next string we see might
    be the name of the source file in DWARF debugging information.  See
    the comment in emit_expr for the format we look for.  */
@@ -248,6 +259,7 @@ static void s_reloc (int);
 static int hex_float (int, char *);
 static segT get_known_segmented_expression (expressionS * expP);
 static void pobegin (void);
+static void poend (void);
 static size_t get_non_macro_line_sb (sb *);
 static void generate_file_debug (void);
 static char *_find_end_of_line (char *, int, int, int);
@@ -260,9 +272,6 @@ read_begin (void)
   pobegin ();
   obj_read_begin_hook ();
 
-  /* Something close -- but not too close -- to a multiple of 1024.
-     The debugging malloc I'm using has 24 bytes of overhead.  */
-  obstack_begin (&notes, chunksize);
   obstack_begin (&cond_obstack, chunksize);
 
 #ifndef tc_line_separator_chars
@@ -275,6 +284,46 @@ read_begin (void)
 
   if (flag_mri)
     lex_type['?'] = 3;
+  stabs_begin ();
+
+#ifndef WORKING_DOT_WORD
+  broken_words = NULL;
+  new_broken_words = 0;
+#endif
+
+  abs_section_offset = 0;
+
+  line_label = NULL;
+  mri_common_symbol = NULL;
+  mri_pending_align = 0;
+
+  current_name = NULL;
+  current_label = NULL;
+
+#ifndef NO_LISTING
+#ifdef OBJ_ELF
+  dwarf_file = 0;
+  dwarf_line = -1;
+  dwarf_file_string = 0;
+#endif
+#endif
+
+#ifdef HANDLE_BUNDLE
+  bundle_align_p2 = 0;
+  bundle_lock_frag = NULL;
+  bundle_lock_frchain = NULL;
+  bundle_lock_depth = 0;
+#endif
+}
+
+void
+read_end (void)
+{
+  stabs_end ();
+  poend ();
+  _obstack_free (&cond_obstack, NULL);
+  free (current_name);
+  free (current_label);
 }
 \f
 #ifndef TC_ADDRESS_BYTES
@@ -295,53 +344,7 @@ address_bytes (void)
 
 /* Set up pseudo-op tables.  */
 
-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 htab_t po_hash;
 
 static const pseudo_typeS potable[] = {
   {"abort", s_abort, 0},
@@ -412,10 +415,8 @@ static const pseudo_typeS potable[] = {
   {"exitm", s_mexit, 0},
 /* extend  */
   {"extern", s_ignore, 0},     /* We treat all undef as ext.  */
-  {"appfile", s_app_file, 1},
-  {"appline", s_app_line, 1},
   {"fail", s_fail, 0},
-  {"file", s_app_file, 0},
+  {"file", s_file, 0},
   {"fill", s_fill, 0},
   {"float", float_cons, 'f'},
   {"format", s_ignore, 0},
@@ -448,7 +449,7 @@ static const pseudo_typeS potable[] = {
   {"irepc", s_irp, 1},
   {"lcomm", s_lcomm, 0},
   {"lflags", s_ignore, 0},     /* Listing flags.  */
-  {"linefile", s_app_line, 0},
+  {"linefile", s_linefile, 0},
   {"linkonce", s_linkonce, 0},
   {"list", listing_list, 1},   /* Turn listing on.  */
   {"llen", listing_psize, 1},
@@ -556,7 +557,7 @@ get_absolute_expression (void)
   return get_absolute_expr (&exp);
 }
 
-static int pop_override_ok = 0;
+static int pop_override_ok;
 static const char *pop_table_name;
 
 void
@@ -565,10 +566,8 @@ pop_insert (const pseudo_typeS *table)
   const pseudo_typeS *pop;
   for (pop = table; pop->poc_name; pop++)
     {
-      po_entry_t *elt = po_entry_alloc (pop->poc_name, pop);
-      if (htab_insert (po_hash, elt, 0) != NULL)
+      if (str_hash_insert (po_hash, pop->poc_name, pop, 0) != NULL)
        {
-         free (elt);
          if (!pop_override_ok)
            as_fatal (_("error constructing %s pseudo-op table"),
                      pop_table_name);
@@ -591,11 +590,11 @@ pop_insert (const pseudo_typeS *table)
 static void
 pobegin (void)
 {
-  po_hash = htab_create_alloc (16, hash_po_entry, eq_po_entry, NULL,
-                              xcalloc, xfree);
+  po_hash = str_htab_create ();
 
   /* Do the target-specific pseudo ops.  */
   pop_table_name = "md";
+  pop_override_ok = 0;
   md_pop_insert ();
 
   /* Now object specific.  Skip any that were in the target table.  */
@@ -609,9 +608,14 @@ pobegin (void)
 
   /* Now CFI ones.  */
   pop_table_name = "cfi";
-  pop_override_ok = 1;
   cfi_pop_insert ();
 }
+
+static void
+poend (void)
+{
+  htab_delete (po_hash);
+}
 \f
 #define HANDLE_CONDITIONAL_ASSEMBLY(num_read)                          \
   if (ignore_input ())                                                 \
@@ -625,25 +629,6 @@ pobegin (void)
       continue;                                                                \
     }
 
-/* This function is used when scrubbing the characters between #APP
-   and #NO_APP.  */
-
-static char *scrub_string;
-static char *scrub_string_end;
-
-static size_t
-scrub_from_string (char *buf, size_t buflen)
-{
-  size_t copy;
-
-  copy = scrub_string_end - scrub_string;
-  if (copy > buflen)
-    copy = buflen;
-  memcpy (buf, scrub_string, copy);
-  scrub_string += copy;
-  return copy;
-}
-
 /* Helper function of read_a_source_file, which tries to expand a macro.  */
 static int
 try_macro (char term, const char *line)
@@ -658,7 +643,7 @@ try_macro (char term, const char *line)
        as_bad ("%s", err);
       *input_line_pointer++ = term;
       input_scrub_include_sb (&out,
-                             input_line_pointer, 1);
+                             input_line_pointer, expanding_macro);
       sb_kill (&out);
       buffer_limit =
        input_scrub_next_buffer (&input_line_pointer);
@@ -893,9 +878,8 @@ read_a_source_file (const char *name)
 #ifndef NO_LISTING
       /* In order to avoid listing macro expansion lines with labels
         multiple times, keep track of which line was last issued.  */
-      static char *last_eol;
+      char *last_eol = NULL;
 
-      last_eol = NULL;
 #endif
       while (input_line_pointer < buffer_limit)
        {
@@ -926,10 +910,13 @@ read_a_source_file (const char *name)
                  /* Find the end of the current expanded macro line.  */
                  s = find_end_of_line (input_line_pointer, flag_m68k_mri);
 
-                 if (s != last_eol)
+                 if (s != last_eol
+                     && !startswith (input_line_pointer,
+                                     !flag_m68k_mri ? " .linefile "
+                                                    : " linefile "))
                    {
                      char *copy;
-                     int len;
+                     size_t len;
 
                      last_eol = s;
                      /* Copy it for safe keeping.  Also give an indication of
@@ -1120,7 +1107,7 @@ read_a_source_file (const char *name)
                    {
                      /* The MRI assembler uses pseudo-ops without
                         a period.  */
-                     pop = po_entry_find (po_hash, s);
+                     pop = str_hash_find (po_hash, s);
                      if (pop != NULL && pop->poc_handler == NULL)
                        pop = NULL;
                    }
@@ -1135,7 +1122,7 @@ read_a_source_file (const char *name)
                         already know that the pseudo-op begins with a '.'.  */
 
                      if (pop == NULL)
-                       pop = po_entry_find (po_hash, s + 1);
+                       pop = str_hash_find (po_hash, s + 1);
                      if (pop && !pop->poc_handler)
                        pop = NULL;
 
@@ -1266,7 +1253,7 @@ read_a_source_file (const char *name)
              while (ISDIGIT (*input_line_pointer))
                {
                  const long digit = *input_line_pointer - '0';
-                 if (temp > (LONG_MAX - digit) / 10)
+                 if (temp > (INT_MAX - digit) / 10)
                    {
                      as_bad (_("local label too large near %s"), backup);
                      temp = -1;
@@ -1314,10 +1301,7 @@ read_a_source_file (const char *name)
            {                   /* Its a comment.  Better say APP or NO_APP.  */
              sb sbuf;
              char *ends;
-             char *new_buf;
-             char *new_tmp;
-             unsigned int new_length;
-             char *tmp_buf = 0;
+             size_t len;
 
              s = input_line_pointer;
              if (!startswith (s, "APP\n"))
@@ -1330,91 +1314,32 @@ read_a_source_file (const char *name)
              s += 4;
 
              ends = strstr (s, "#NO_APP\n");
+             len = ends ? ends - s : buffer_limit - s;
 
+             sb_build (&sbuf, len + 100);
+             sb_add_buffer (&sbuf, s, len);
              if (!ends)
                {
-                 unsigned int tmp_len;
-                 unsigned int num;
-
                  /* The end of the #APP wasn't in this buffer.  We
                     keep reading in buffers until we find the #NO_APP
                     that goes with this #APP  There is one.  The specs
                     guarantee it...  */
-                 tmp_len = buffer_limit - s;
-                 tmp_buf = XNEWVEC (char, tmp_len + 1);
-                 memcpy (tmp_buf, s, tmp_len);
                  do
                    {
-                     new_tmp = input_scrub_next_buffer (&buffer);
-                     if (!new_tmp)
+                     buffer_limit = input_scrub_next_buffer (&buffer);
+                     if (!buffer_limit)
                        break;
-                     else
-                       buffer_limit = new_tmp;
-                     input_line_pointer = buffer;
                      ends = strstr (buffer, "#NO_APP\n");
-                     if (ends)
-                       num = ends - buffer;
-                     else
-                       num = buffer_limit - buffer;
-
-                     tmp_buf = XRESIZEVEC (char, tmp_buf, tmp_len + num);
-                     memcpy (tmp_buf + tmp_len, buffer, num);
-                     tmp_len += num;
+                     len = ends ? ends - buffer : buffer_limit - buffer;
+                     sb_add_buffer (&sbuf, buffer, len);
                    }
                  while (!ends);
-
-                 input_line_pointer = ends ? ends + 8 : NULL;
-
-                 s = tmp_buf;
-                 ends = s + tmp_len;
-
-               }
-             else
-               {
-                 input_line_pointer = ends + 8;
-               }
-
-             scrub_string = s;
-             scrub_string_end = ends;
-
-             new_length = ends - s;
-             new_buf = XNEWVEC (char, new_length);
-             new_tmp = new_buf;
-             for (;;)
-               {
-                 size_t space;
-                 size_t size;
-
-                 space = (new_buf + new_length) - new_tmp;
-                 size = do_scrub_chars (scrub_from_string, new_tmp, space);
-
-                 if (size < space)
-                   {
-                     new_tmp[size] = 0;
-                     break;
-                   }
-
-                 new_buf = XRESIZEVEC (char, new_buf, new_length + 100);
-                 new_tmp = new_buf + new_length;
-                 new_length += 100;
                }
 
-             free (tmp_buf);
-
-             /* We've "scrubbed" input to the preferred format.  In the
-                process we may have consumed the whole of the remaining
-                file (and included files).  We handle this formatted
-                input similar to that of macro expansion, letting
-                actual macro expansion (possibly nested) and other
-                input expansion work.  Beware that in messages, line
-                numbers and possibly file names will be incorrect.  */
-             new_length = strlen (new_buf);
-             sb_build (&sbuf, new_length);
-             sb_add_buffer (&sbuf, new_buf, new_length);
-             input_scrub_include_sb (&sbuf, input_line_pointer, 0);
+             input_line_pointer = ends ? ends + 8 : NULL;
+             input_scrub_include_sb (&sbuf, input_line_pointer, expanding_none);
              sb_kill (&sbuf);
              buffer_limit = input_scrub_next_buffer (&input_line_pointer);
-             free (new_buf);
              continue;
            }
 
@@ -1693,7 +1618,7 @@ static void
 s_altmacro (int on)
 {
   demand_empty_rest_of_line ();
-  macro_set_alternate (on);
+  flag_macro_alternate = on;
 }
 
 /* Read a symbol name from input_line_pointer.
@@ -1750,7 +1675,10 @@ read_symbol_name (void)
       /* Since quoted symbol names can contain non-ASCII characters,
         check the string and warn if it cannot be recognised by the
         current character set.  */
-      if (mbstowcs (NULL, name, len) == (size_t) -1)
+      /* PR 29447: mbstowcs ignores the third (length) parameter when
+        the first (destination) parameter is NULL.  For clarity sake
+        therefore we pass 0 rather than 'len' as the third parameter.  */
+      if (mbstowcs (NULL, name, 0) == (size_t) -1)
        as_warn (_("symbol name not recognised in the current locale"));
     }
   else if (is_name_beginner (c) || (input_from_string && c == FAKE_LABEL_CHAR))
@@ -1782,6 +1710,7 @@ read_symbol_name (void)
     {
       as_bad (_("expected symbol name"));
       ignore_rest_of_line ();
+      free (start);
       return NULL;
     }
 
@@ -1822,7 +1751,7 @@ s_comm_internal (int param,
       ignore_rest_of_line ();
       goto out;
     }
-  else if (temp != size || !exp.X_unsigned)
+  else if (temp != size || (!exp.X_unsigned && exp.X_add_number < 0))
     {
       as_warn (_("size (%ld) out of range, ignored"), (long) temp);
       ignore_rest_of_line ();
@@ -1940,7 +1869,6 @@ s_mri_common (int small ATTRIBUTE_UNUSED)
   if (S_IS_DEFINED (sym) && !S_IS_COMMON (sym))
     {
       as_bad (_("symbol `%s' is already defined"), S_GET_NAME (sym));
-      ignore_rest_of_line ();
       mri_comment_end (stop, stopc);
       return;
     }
@@ -2001,15 +1929,11 @@ s_data (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
-/* Handle the .appfile pseudo-op.  This is automatically generated by
-   do_scrub_chars when a preprocessor # line comment is seen with a
-   file name.  This default definition may be overridden by the object
-   or CPU specific pseudo-ops.  This function is also the default
-   definition for .file; the APPFILE argument is 1 for .appfile, 0 for
-   .file.  */
+/* Handle the .file pseudo-op.  This default definition may be overridden by
+   the object or CPU specific pseudo-ops.  */
 
 void
-s_app_file_string (char *file, int appfile ATTRIBUTE_UNUSED)
+s_file_string (char *file)
 {
 #ifdef LISTING
   if (listing)
@@ -2017,12 +1941,12 @@ s_app_file_string (char *file, int appfile ATTRIBUTE_UNUSED)
 #endif
   register_dependency (file);
 #ifdef obj_app_file
-  obj_app_file (file, appfile);
+  obj_app_file (file);
 #endif
 }
 
 void
-s_app_file (int appfile)
+s_file (int ignore ATTRIBUTE_UNUSED)
 {
   char *s;
   int length;
@@ -2030,8 +1954,7 @@ s_app_file (int appfile)
   /* Some assemblers tolerate immediately following '"'.  */
   if ((s = demand_copy_string (&length)) != 0)
     {
-      int may_omit
-       = (!new_logical_line_flags (s, -1, 1) && appfile);
+      new_logical_line_flags (s, -1, 1);
 
       /* In MRI mode, the preprocessor may have inserted an extraneous
         backquote.  */
@@ -2041,47 +1964,61 @@ s_app_file (int appfile)
        ++input_line_pointer;
 
       demand_empty_rest_of_line ();
-      if (!may_omit)
-       s_app_file_string (s, appfile);
+      s_file_string (s);
     }
 }
 
-static int
+static bool
 get_linefile_number (int *flag)
 {
+  expressionS exp;
+
   SKIP_WHITESPACE ();
 
   if (*input_line_pointer < '0' || *input_line_pointer > '9')
-    return 0;
+    return false;
+
+  /* Don't mistakenly interpret octal numbers as line numbers.  */
+  if (*input_line_pointer == '0')
+    {
+      *flag = 0;
+      ++input_line_pointer;
+      return true;
+    }
+
+  expression_and_evaluate (&exp);
+  if (exp.X_op != O_constant)
+    return false;
+
+#if defined (BFD64) || LONG_MAX > INT_MAX
+  if (exp.X_add_number < INT_MIN || exp.X_add_number > INT_MAX)
+    return false;
+#endif
 
-  *flag = get_absolute_expression ();
+  *flag = exp.X_add_number;
 
-  return 1;
+  return true;
 }
 
-/* Handle the .appline pseudo-op.  This is automatically generated by
+/* Handle the .linefile pseudo-op.  This is automatically generated by
    do_scrub_chars when a preprocessor # line comment is seen.  This
    default definition may be overridden by the object or CPU specific
    pseudo-ops.  */
 
 void
-s_app_line (int appline)
+s_linefile (int ignore ATTRIBUTE_UNUSED)
 {
   char *file = NULL;
-  int l;
+  int linenum, flags = 0;
 
   /* The given number is that of the next line.  */
-  if (appline)
-    l = get_absolute_expression ();
-  else if (!get_linefile_number (&l))
+  if (!get_linefile_number (&linenum))
     {
       ignore_rest_of_line ();
       return;
     }
 
-  l--;
-
-  if (l < -1)
+  if (linenum < 0)
     /* Some of the back ends can't deal with non-positive line numbers.
        Besides, it's silly.  GCC however will generate a line number of
        zero when it is pre-processing builtins for assembler-with-cpp files:
@@ -2092,77 +2029,82 @@ s_app_line (int appline)
        in the GCC and GDB testsuites.  So we check for negative line numbers
        rather than non-positive line numbers.  */
     as_warn (_("line numbers must be positive; line number %d rejected"),
-            l + 1);
+            linenum);
   else
     {
-      int flags = 0;
       int length = 0;
 
-      if (!appline)
+      SKIP_WHITESPACE ();
+
+      if (*input_line_pointer == '"')
+       file = demand_copy_string (&length);
+      else if (*input_line_pointer == '.')
        {
-         SKIP_WHITESPACE ();
+         /* buffer_and_nest() may insert this form.  */
+         ++input_line_pointer;
+         flags = 1 << 3;
+       }
 
-         if (*input_line_pointer == '"')
-           file = demand_copy_string (&length);
+      if (file)
+       {
+         int this_flag;
 
-         if (file)
-           {
-             int this_flag;
+         while (get_linefile_number (&this_flag))
+           switch (this_flag)
+             {
+               /* From GCC's cpp documentation:
+                  1: start of a new file.
+                  2: returning to a file after having included another file.
+                  3: following text comes from a system header file.
+                  4: following text should be treated as extern "C".
+
+                  4 is nonsensical for the assembler; 3, we don't care about,
+                  so we ignore it just in case a system header file is
+                  included while preprocessing assembly.  So 1 and 2 are all
+                  we care about, and they are mutually incompatible.
+                  new_logical_line_flags() demands this.  */
+             case 1:
+             case 2:
+               if (flags && flags != (1 << this_flag))
+                 as_warn (_("incompatible flag %i in line directive"),
+                          this_flag);
+               else
+                 flags |= 1 << this_flag;
+               break;
 
-             while (get_linefile_number (&this_flag))
-               switch (this_flag)
-                 {
-                   /* From GCC's cpp documentation:
-                      1: start of a new file.
-                      2: returning to a file after having included
-                         another file.
-                      3: following text comes from a system header file.
-                      4: following text should be treated as extern "C".
-
-                      4 is nonsensical for the assembler; 3, we don't
-                      care about, so we ignore it just in case a
-                      system header file is included while
-                      preprocessing assembly.  So 1 and 2 are all we
-                      care about, and they are mutually incompatible.
-                      new_logical_line_flags() demands this.  */
-                 case 1:
-                 case 2:
-                   if (flags && flags != (1 << this_flag))
-                     as_warn (_("incompatible flag %i in line directive"),
-                              this_flag);
-                   else
-                     flags |= 1 << this_flag;
-                   break;
-
-                 case 3:
-                 case 4:
-                   /* We ignore these.  */
-                   break;
-
-                 default:
-                   as_warn (_("unsupported flag %i in line directive"),
-                            this_flag);
-                   break;
-                 }
+             case 3:
+             case 4:
+               /* We ignore these.  */
+               break;
 
-             if (!is_end_of_line[(unsigned char)*input_line_pointer])
-               file = 0;
-           }
-       }
+             default:
+               as_warn (_("unsupported flag %i in line directive"),
+                        this_flag);
+               break;
+             }
 
-      if (appline || file)
+         if (!is_end_of_line[(unsigned char)*input_line_pointer])
+           file = NULL;
+        }
+
+      if (file || flags)
        {
-         new_logical_line_flags (file, l, flags);
+         demand_empty_rest_of_line ();
+
+         /* read_a_source_file() will bump the line number only if the line
+            is terminated by '\n'.  */
+         if (input_line_pointer[-1] == '\n')
+           linenum--;
+
+         new_logical_line_flags (file, linenum, flags);
 #ifdef LISTING
          if (listing)
-           listing_source_line (l);
+           listing_source_line (linenum);
 #endif
+         return;
        }
     }
-  if (appline || file)
-    demand_empty_rest_of_line ();
-  else
-    ignore_rest_of_line ();
+  ignore_rest_of_line ();
 }
 
 /* Handle the .end pseudo-op.  Actually, the real work is done in
@@ -2299,22 +2241,32 @@ s_fill (int ignore ATTRIBUTE_UNUSED)
        as_warn (_("repeat < 0; .fill ignored"));
       size = 0;
     }
-
-  if (size && !need_pass_2)
+  else if (size && !need_pass_2)
     {
-      if (now_seg == absolute_section)
+      if (now_seg == absolute_section && rep_exp.X_op != O_constant)
        {
-         if (rep_exp.X_op != O_constant)
-           as_bad (_("non-constant fill count for absolute section"));
-         else if (fill && rep_exp.X_add_number != 0)
-           as_bad (_("attempt to fill absolute section with non-zero value"));
-         abs_section_offset += rep_exp.X_add_number * size;
+         as_bad (_("non-constant fill count for absolute section"));
+         size = 0;
+       }
+      else if (now_seg == absolute_section && fill && rep_exp.X_add_number != 0)
+       {
+         as_bad (_("attempt to fill absolute section with non-zero value"));
+         size = 0;
        }
       else if (fill
               && (rep_exp.X_op != O_constant || rep_exp.X_add_number != 0)
               && in_bss ())
-       as_bad (_("attempt to fill section `%s' with non-zero value"),
-               segment_name (now_seg));
+       {
+         as_bad (_("attempt to fill section `%s' with non-zero value"),
+                 segment_name (now_seg));
+         size = 0;
+       }
+    }
+
+  if (size && !need_pass_2)
+    {
+      if (now_seg == absolute_section)
+       abs_section_offset += rep_exp.X_add_number * size;
 
       if (rep_exp.X_op == O_constant)
        {
@@ -2436,7 +2388,7 @@ s_irp (int irpc)
 
   sb_kill (&s);
 
-  input_scrub_include_sb (&out, input_line_pointer, 1);
+  input_scrub_include_sb (&out, input_line_pointer, expanding_repeat);
   sb_kill (&out);
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }
@@ -2589,7 +2541,7 @@ parse_align (int align_bytes)
   if (exp.X_op == O_absent)
     goto no_align;
 
-  if (!exp.X_unsigned)
+  if (!exp.X_unsigned && exp.X_add_number < 0)
     {
       as_warn (_("alignment negative; 0 assumed"));
       align = 0;
@@ -2751,13 +2703,8 @@ void
 s_macro (int ignore ATTRIBUTE_UNUSED)
 {
   char *eol;
-  const char * file;
-  unsigned int line;
   sb s;
-  const char *err;
-  const char *name;
-
-  file = as_where (&line);
+  macro_entry *macro;
 
   eol = find_end_of_line (input_line_pointer, 0);
   sb_build (&s, eol - input_line_pointer);
@@ -2768,19 +2715,18 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
     {
       sb label;
       size_t len;
+      const char *name;
 
       name = S_GET_NAME (line_label);
       len = strlen (name);
       sb_build (&label, len);
       sb_add_buffer (&label, name, len);
-      err = define_macro (0, &s, &label, get_macro_line_sb, file, line, &name);
+      macro = define_macro (&s, &label, get_macro_line_sb);
       sb_kill (&label);
     }
   else
-    err = define_macro (0, &s, NULL, get_macro_line_sb, file, line, &name);
-  if (err != NULL)
-    as_bad_where (file, line, err, name);
-  else
+    macro = define_macro (&s, NULL, get_macro_line_sb);
+  if (macro != NULL)
     {
       if (line_label != NULL)
        {
@@ -2790,14 +2736,16 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
        }
 
       if (((NO_PSEUDO_DOT || flag_m68k_mri)
-          && po_entry_find (po_hash, name) != NULL)
+          && str_hash_find (po_hash, macro->name) != NULL)
          || (!flag_m68k_mri
-             && *name == '.'
-             && po_entry_find (po_hash, name + 1) != NULL))
-       as_warn_where (file,
-                line,
-                _("attempt to redefine pseudo-op `%s' ignored"),
-                name);
+             && macro->name[0] == '.'
+             && str_hash_find (po_hash, macro->name + 1) != NULL))
+       {
+         as_warn_where (macro->file, macro->line,
+                        _("attempt to redefine pseudo-op `%s' ignored"),
+                        macro->name);
+         str_hash_delete (macro_hash, macro->name);
+       }
     }
 
   sb_kill (&s);
@@ -2838,7 +2786,6 @@ s_mri (int ignore ATTRIBUTE_UNUSED)
 #ifdef TC_M68K
       flag_m68k_mri = 1;
 #endif
-      macro_mri_mode (1);
     }
   else
     {
@@ -2846,7 +2793,6 @@ s_mri (int ignore ATTRIBUTE_UNUSED)
 #ifdef TC_M68K
       flag_m68k_mri = 0;
 #endif
-      macro_mri_mode (0);
     }
 
   /* Operator precedence changes in m68k MRI mode, so we need to
@@ -3106,14 +3052,17 @@ s_rept (int ignore ATTRIBUTE_UNUSED)
 
   count = (size_t) get_absolute_expression ();
 
-  do_repeat (count, "REPT", "ENDR");
+  do_repeat (count, "REPT", "ENDR", NULL);
 }
 
 /* This function provides a generic repeat block implementation.   It allows
-   different directives to be used as the start/end keys.  */
+   different directives to be used as the start/end keys.  Any text matching
+   the optional EXPANDER in the block is replaced by the remaining iteration
+   count.  */
 
 void
-do_repeat (size_t count, const char *start, const char *end)
+do_repeat (size_t count, const char *start, const char *end,
+          const char *expander)
 {
   sb one;
   sb many;
@@ -3128,49 +3077,20 @@ do_repeat (size_t count, const char *start, const char *end)
   if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
     {
       as_bad (_("%s without %s"), start, end);
+      sb_kill (&one);
       return;
     }
 
-  sb_build (&many, count * one.len);
-  while (count-- > 0)
-    sb_add_sb (&many, &one);
-
-  sb_kill (&one);
-
-  input_scrub_include_sb (&many, input_line_pointer, 1);
-  sb_kill (&many);
-  buffer_limit = input_scrub_next_buffer (&input_line_pointer);
-}
-
-/* Like do_repeat except that any text matching EXPANDER in the
-   block is replaced by the iteration count.  */
-
-void
-do_repeat_with_expander (size_t count,
-                        const char * start,
-                        const char * end,
-                        const char * expander)
-{
-  sb one;
-  sb many;
-
-  if (((ssize_t) count) < 0)
+  if (expander == NULL || strstr (one.ptr, expander) == NULL)
     {
-      as_bad (_("negative count for %s - ignored"), start);
-      count = 0;
+      sb_build (&many, count * one.len);
+      while (count-- > 0)
+       sb_add_sb (&many, &one);
     }
-
-  sb_new (&one);
-  if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
+  else
     {
-      as_bad (_("%s without %s"), start, end);
-      return;
-    }
+      sb_new (&many);
 
-  sb_new (&many);
-
-  if (expander != NULL && strstr (one.ptr, expander) != NULL)
-    {
       while (count -- > 0)
        {
          int len;
@@ -3189,13 +3109,10 @@ do_repeat_with_expander (size_t count,
          sb_kill (& processed);
        }
     }
-  else
-    while (count-- > 0)
-      sb_add_sb (&many, &one);
 
   sb_kill (&one);
 
-  input_scrub_include_sb (&many, input_line_pointer, 1);
+  input_scrub_include_sb (&many, input_line_pointer, expanding_repeat);
   sb_kill (&many);
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }
@@ -3246,7 +3163,7 @@ assign_symbol (char *name, int mode)
       if (listing & LISTING_SYMBOLS)
        {
          extern struct list_info_struct *listing_tail;
-         fragS *dummy_frag = XCNEW (fragS);
+         fragS *dummy_frag = notes_calloc (1, sizeof (*dummy_frag));
          dummy_frag->line = listing_tail;
          dummy_frag->fr_symbol = symbolP;
          symbol_set_frag (symbolP, dummy_frag);
@@ -3449,27 +3366,37 @@ s_space (int mult)
 
       if (exp.X_op == O_constant)
        {
-         offsetT repeat;
+         addressT repeat = exp.X_add_number;
+         addressT total;
 
-         repeat = exp.X_add_number;
-         if (mult)
-           repeat *= mult;
-         bytes = repeat;
-         if (repeat <= 0)
+         bytes = 0;
+         if ((offsetT) repeat < 0)
+           {
+             as_warn (_(".space repeat count is negative, ignored"));
+             goto getout;
+           }
+         if (repeat == 0)
            {
              if (!flag_mri)
                as_warn (_(".space repeat count is zero, ignored"));
-             else if (repeat < 0)
-               as_warn (_(".space repeat count is negative, ignored"));
              goto getout;
            }
+         if ((unsigned int) mult <= 1)
+           total = repeat;
+         else if (gas_mul_overflow (repeat, mult, &total)
+                  || (offsetT) total < 0)
+           {
+             as_warn (_(".space repeat count overflow, ignored"));
+             goto getout;
+           }
+         bytes = total;
 
          /* If we are in the absolute section, just bump the offset.  */
          if (now_seg == absolute_section)
            {
              if (val.X_op != O_constant || val.X_add_number != 0)
                as_warn (_("ignoring fill value in absolute section"));
-             abs_section_offset += repeat;
+             abs_section_offset += total;
              goto getout;
            }
 
@@ -3479,13 +3406,13 @@ s_space (int mult)
          if (mri_common_symbol != NULL)
            {
              S_SET_VALUE (mri_common_symbol,
-                          S_GET_VALUE (mri_common_symbol) + repeat);
+                          S_GET_VALUE (mri_common_symbol) + total);
              goto getout;
            }
 
          if (!need_pass_2)
            p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
-                         (offsetT) repeat, (char *) 0);
+                         (offsetT) total, (char *) 0);
        }
       else
        {
@@ -3639,6 +3566,68 @@ s_nops (int ignore ATTRIBUTE_UNUSED)
   *p = val.X_add_number;
 }
 
+/* Obtain the size of a floating point number, given a type.  */
+
+static int
+float_length (int float_type, int *pad_p)
+{
+  int length, pad = 0;
+
+  switch (float_type)
+    {
+    case 'b':
+    case 'B':
+    case 'h':
+    case 'H':
+      length = 2;
+      break;
+
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      length = 4;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      length = 8;
+      break;
+
+    case 'x':
+    case 'X':
+#ifdef X_PRECISION
+      length = X_PRECISION * sizeof (LITTLENUM_TYPE);
+      pad = X_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
+      if (!length)
+#endif
+       length = 12;
+      break;
+
+    case 'p':
+    case 'P':
+#ifdef P_PRECISION
+      length = P_PRECISION * sizeof (LITTLENUM_TYPE);
+      pad = P_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
+      if (!length)
+#endif
+       length = 12;
+      break;
+
+    default:
+      as_bad (_("unknown floating type '%c'"), float_type);
+      length = -1;
+      break;
+    }
+
+  if (pad_p)
+    *pad_p = pad;
+
+  return length;
+}
+
 static int
 parse_one_float (int float_type, char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT])
 {
@@ -3709,16 +3698,19 @@ s_float_space (int float_type)
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
-      as_bad (_("missing value"));
-      ignore_rest_of_line ();
-      if (flag_mri)
-       mri_comment_end (stop, stopc);
-      return;
+      int pad;
+
+      flen = float_length (float_type, &pad);
+      if (flen >= 0)
+       memset (temp, 0, flen += pad);
     }
+  else
+    {
+      ++input_line_pointer;
 
-  ++input_line_pointer;
+      flen = parse_one_float (float_type, temp);
+    }
 
-  flen = parse_one_float (float_type, temp);
   if (flen < 0)
     {
       if (flag_mri)
@@ -3887,12 +3879,19 @@ s_weakref (int ignore ATTRIBUTE_UNUSED)
 \f
 
 /* Verify that we are at the end of a line.  If not, issue an error and
-   skip to EOL.  */
+   skip to EOL.  This function may leave input_line_pointer one past
+   buffer_limit, so should not be called from places that may
+   dereference input_line_pointer unconditionally.  Note that when the
+   gas parser is switched to handling a string (where buffer_limit
+   should be the size of the string excluding the NUL terminator) this
+   will be one past the NUL; is_end_of_line(0) returns true.  */
 
 void
 demand_empty_rest_of_line (void)
 {
   SKIP_WHITESPACE ();
+  if (input_line_pointer > buffer_limit)
+    return;
   if (is_end_of_line[(unsigned char) *input_line_pointer])
     input_line_pointer++;
   else
@@ -3905,26 +3904,22 @@ demand_empty_rest_of_line (void)
                 *input_line_pointer);
       ignore_rest_of_line ();
     }
-
   /* Return pointing just after end-of-line.  */
-  know (is_end_of_line[(unsigned char) input_line_pointer[-1]]);
 }
 
 /* Silently advance to the end of line.  Use this after already having
-   issued an error about something bad.  */
+   issued an error about something bad.  Like demand_empty_rest_of_line,
+   this function may leave input_line_pointer one after buffer_limit;
+   Don't call it from within expression parsing code in an attempt to
+   silence further errors.  */
 
 void
 ignore_rest_of_line (void)
 {
-  while (input_line_pointer < buffer_limit
-        && !is_end_of_line[(unsigned char) *input_line_pointer])
-    input_line_pointer++;
-
-  input_line_pointer++;
-
+  while (input_line_pointer <= buffer_limit)
+    if (is_end_of_line[(unsigned char) *input_line_pointer++])
+      break;
   /* Return pointing just after end-of-line.  */
-  if (input_line_pointer <= buffer_limit)
-    know (is_end_of_line[(unsigned char) input_line_pointer[-1]]);
 }
 
 /* Sets frag for given symbol to zero_address_frag, except when the
@@ -4007,10 +4002,13 @@ pseudo_set (symbolS *symbolP)
          return;
        }
 #endif
+      /* Make sure symbol_equated_p() recognizes the symbol as an equate.  */
+      exp.X_add_symbol = make_expr_symbol (&exp);
+      exp.X_add_number = 0;
+      exp.X_op = O_symbol;
+      symbol_set_value_expression (symbolP, &exp);
       S_SET_SEGMENT (symbolP, reg_section);
-      S_SET_VALUE (symbolP, (valueT) exp.X_add_number);
       set_zero_frag (symbolP);
-      symbol_get_value_expression (symbolP)->X_op = O_register;
       break;
 
     case O_symbol:
@@ -4219,7 +4217,7 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
   int c;
   struct reloc_list *reloc;
   struct _bfd_rel { const char * name; bfd_reloc_code_real_type code; };
-  static struct _bfd_rel bfd_relocs[] =
+  static const struct _bfd_rel bfd_relocs[] =
   {
     { "NONE", BFD_RELOC_NONE },
     { "8",  BFD_RELOC_8 },
@@ -4369,62 +4367,54 @@ emit_expr_with_reloc (expressionS *exp,
   /* When gcc emits DWARF 1 debugging pseudo-ops, a line number will
      appear as a four byte positive constant in the .line section,
      followed by a 2 byte 0xffff.  Look for that case here.  */
-  {
-    static int dwarf_line = -1;
-
-    if (strcmp (segment_name (now_seg), ".line") != 0)
-      dwarf_line = -1;
-    else if (dwarf_line >= 0
-            && nbytes == 2
-            && exp->X_op == O_constant
-            && (exp->X_add_number == -1 || exp->X_add_number == 0xffff))
-      listing_source_line ((unsigned int) dwarf_line);
-    else if (nbytes == 4
-            && exp->X_op == O_constant
-            && exp->X_add_number >= 0)
-      dwarf_line = exp->X_add_number;
-    else
-      dwarf_line = -1;
-  }
+  if (strcmp (segment_name (now_seg), ".line") != 0)
+    dwarf_line = -1;
+  else if (dwarf_line >= 0
+          && nbytes == 2
+          && exp->X_op == O_constant
+          && (exp->X_add_number == -1 || exp->X_add_number == 0xffff))
+    listing_source_line ((unsigned int) dwarf_line);
+  else if (nbytes == 4
+          && exp->X_op == O_constant
+          && exp->X_add_number >= 0)
+    dwarf_line = exp->X_add_number;
+  else
+    dwarf_line = -1;
 
   /* When gcc emits DWARF 1 debugging pseudo-ops, a file name will
      appear as a 2 byte TAG_compile_unit (0x11) followed by a 2 byte
      AT_sibling (0x12) followed by a four byte address of the sibling
      followed by a 2 byte AT_name (0x38) followed by the name of the
      file.  We look for that case here.  */
-  {
-    static int dwarf_file = 0;
-
-    if (strcmp (segment_name (now_seg), ".debug") != 0)
-      dwarf_file = 0;
-    else if (dwarf_file == 0
-            && nbytes == 2
-            && exp->X_op == O_constant
-            && exp->X_add_number == 0x11)
-      dwarf_file = 1;
-    else if (dwarf_file == 1
-            && nbytes == 2
-            && exp->X_op == O_constant
-            && exp->X_add_number == 0x12)
-      dwarf_file = 2;
-    else if (dwarf_file == 2
-            && nbytes == 4)
-      dwarf_file = 3;
-    else if (dwarf_file == 3
-            && nbytes == 2
-            && exp->X_op == O_constant
-            && exp->X_add_number == 0x38)
-      dwarf_file = 4;
-    else
-      dwarf_file = 0;
-
-    /* The variable dwarf_file_string tells stringer that the string
-       may be the name of the source file.  */
-    if (dwarf_file == 4)
-      dwarf_file_string = 1;
-    else
-      dwarf_file_string = 0;
-  }
+  if (strcmp (segment_name (now_seg), ".debug") != 0)
+    dwarf_file = 0;
+  else if (dwarf_file == 0
+          && nbytes == 2
+          && exp->X_op == O_constant
+          && exp->X_add_number == 0x11)
+    dwarf_file = 1;
+  else if (dwarf_file == 1
+          && nbytes == 2
+          && exp->X_op == O_constant
+          && exp->X_add_number == 0x12)
+    dwarf_file = 2;
+  else if (dwarf_file == 2
+          && nbytes == 4)
+    dwarf_file = 3;
+  else if (dwarf_file == 3
+          && nbytes == 2
+          && exp->X_op == O_constant
+          && exp->X_add_number == 0x38)
+    dwarf_file = 4;
+  else
+    dwarf_file = 0;
+
+  /* The variable dwarf_file_string tells stringer that the string
+     may be the name of the source file.  */
+  if (dwarf_file == 4)
+    dwarf_file_string = 1;
+  else
+    dwarf_file_string = 0;
 #endif
 #endif
 
@@ -4569,14 +4559,9 @@ emit_expr_with_reloc (expressionS *exp,
       use = get & unmask;
       if ((get & mask) != 0 && (-get & mask) != 0)
        {
-         char get_buf[128];
-         char use_buf[128];
-
-         /* These buffers help to ease the translation of the warning message.  */
-         sprintf_vma (get_buf, get);
-         sprintf_vma (use_buf, use);
          /* Leading bits contain both 0s & 1s.  */
-         as_warn (_("value 0x%s truncated to 0x%s"), get_buf, use_buf);
+         as_warn (_("value 0x%" PRIx64 " truncated to 0x%" PRIx64),
+                  (uint64_t) get, (uint64_t) use);
        }
       /* Put bytes in right order.  */
       md_number_to_chars (p, use, (int) nbytes);
@@ -4847,56 +4832,11 @@ parse_repeat_cons (expressionS *exp, unsigned int nbytes)
 static int
 hex_float (int float_type, char *bytes)
 {
-  int length, pad = 0;
+  int pad, length = float_length (float_type, &pad);
   int i;
 
-  switch (float_type)
-    {
-    case 'b':
-    case 'B':
-    case 'h':
-    case 'H':
-      length = 2;
-      break;
-
-    case 'f':
-    case 'F':
-    case 's':
-    case 'S':
-      length = 4;
-      break;
-
-    case 'd':
-    case 'D':
-    case 'r':
-    case 'R':
-      length = 8;
-      break;
-
-    case 'x':
-    case 'X':
-#ifdef X_PRECISION
-      length = X_PRECISION * sizeof (LITTLENUM_TYPE);
-      pad = X_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
-      if (!length)
-#endif
-       length = 12;
-      break;
-
-    case 'p':
-    case 'P':
-#ifdef P_PRECISION
-      length = P_PRECISION * sizeof (LITTLENUM_TYPE);
-      pad = P_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
-      if (!length)
-#endif
-       length = 12;
-      break;
-
-    default:
-      as_bad (_("unknown floating type type '%c'"), float_type);
-      return -1;
-    }
+  if (length < 0)
+    return length;
 
   /* It would be nice if we could go through expression to parse the
      hex constant, but if we get a bignum it's a pain to sort it into
@@ -5622,7 +5562,7 @@ next_char_of_string (void)
        case '8':
        case '9':
          {
-           long number;
+           unsigned number;
            int i;
 
            for (i = 0, number = 0;
@@ -5640,7 +5580,7 @@ next_char_of_string (void)
        case 'x':
        case 'X':
          {
-           long number;
+           unsigned number;
 
            number = 0;
            c = *input_line_pointer++;
@@ -5840,6 +5780,30 @@ equals (char *sym_name, int reassign)
     }
 }
 
+/* Open FILENAME, first trying the unadorned file name, then if that
+   fails and the file name is not an absolute path, attempt to open
+   the file in current -I include paths.  PATH is a preallocated
+   buffer which will be set to the file opened, or FILENAME if no file
+   is found.  */
+
+FILE *
+search_and_open (const char *filename, char *path)
+{
+  FILE *f = fopen (filename, FOPEN_RB);
+  if (f == NULL && !IS_ABSOLUTE_PATH (filename))
+    {
+      for (size_t i = 0; i < include_dir_count; i++)
+       {
+         sprintf (path, "%s/%s", include_dirs[i], filename);
+         f = fopen (path, FOPEN_RB);
+         if (f != NULL)
+           return f;
+       }
+    }
+  strcpy (path, filename);
+  return f;
+}
+
 /* .incbin -- include a file verbatim at the current location.  */
 
 void
@@ -5891,30 +5855,12 @@ s_incbin (int x ATTRIBUTE_UNUSED)
 
   demand_empty_rest_of_line ();
 
-  /* Try opening absolute path first, then try include dirs.  */
-  binfile = fopen (filename, FOPEN_RB);
-  if (binfile == NULL)
-    {
-      int i;
-
-      path = XNEWVEC (char, (unsigned long) len + include_dir_maxlen + 5);
-
-      for (i = 0; i < include_dir_count; i++)
-       {
-         sprintf (path, "%s/%s", include_dirs[i], filename);
+  path = XNEWVEC (char, len + include_dir_maxlen + 2);
+  binfile = search_and_open (filename, path);
 
-         binfile = fopen (path, FOPEN_RB);
-         if (binfile != NULL)
-           break;
-       }
-
-      if (binfile == NULL)
-       as_bad (_("file not found: %s"), filename);
-    }
+  if (binfile == NULL)
+    as_bad (_("file not found: %s"), filename);
   else
-    path = xstrdup (filename);
-
-  if (binfile)
     {
       long   file_len;
       struct stat filestat;
@@ -6008,50 +5954,33 @@ s_include (int arg ATTRIBUTE_UNUSED)
     }
 
   demand_empty_rest_of_line ();
-  path = XNEWVEC (char, (unsigned long) i
-                 + include_dir_maxlen + 5 /* slop */ );
 
-  for (i = 0; i < include_dir_count; i++)
-    {
-      strcpy (path, include_dirs[i]);
-      strcat (path, "/");
-      strcat (path, filename);
-      if (0 != (try_file = fopen (path, FOPEN_RT)))
-       {
-         fclose (try_file);
-         goto gotit;
-       }
-    }
+  path = notes_alloc (i + include_dir_maxlen + 2);
+  try_file = search_and_open (filename, path);
+  if (try_file)
+    fclose (try_file);
 
-  free (path);
-  path = filename;
- gotit:
-  /* malloc Storage leak when file is found on path.  FIXME-SOMEDAY.  */
   register_dependency (path);
   input_scrub_insert_file (path);
 }
 
 void
-add_include_dir (char *path)
+init_include_dir (void)
 {
-  int i;
-
-  if (include_dir_count == 0)
-    {
-      include_dirs = XNEWVEC (const char *, 2);
-      include_dirs[0] = ".";   /* Current dir.  */
-      include_dir_count = 2;
-    }
-  else
-    {
-      include_dir_count++;
-      include_dirs = XRESIZEVEC (const char *, include_dirs,
-                                include_dir_count);
-    }
+  include_dirs = XNEWVEC (const char *, 1);
+  include_dirs[0] = ".";       /* Current dir.  */
+  include_dir_count = 1;
+  include_dir_maxlen = 1;
+}
 
+void
+add_include_dir (char *path)
+{
+  include_dir_count++;
+  include_dirs = XRESIZEVEC (const char *, include_dirs, include_dir_count);
   include_dirs[include_dir_count - 1] = path;  /* New one.  */
 
-  i = strlen (path);
+  size_t i = strlen (path);
   if (i > include_dir_maxlen)
     include_dir_maxlen = i;
 }
@@ -6088,6 +6017,9 @@ generate_lineno_debug (void)
         support that is required (calling dwarf2_emit_insn), we
         let dwarf2dbg.c call as_where on its own.  */
       break;
+    case DEBUG_CODEVIEW:
+      codeview_generate_asm_lineno ();
+      break;
     }
 }
 
@@ -6106,12 +6038,6 @@ s_func (int end_p)
 static void
 do_s_func (int end_p, const char *default_prefix)
 {
-  /* Record the current function so that we can issue an error message for
-     misplaced .func,.endfunc, and also so that .endfunc needs no
-     arguments.  */
-  static char *current_name;
-  static char *current_label;
-
   if (end_p)
     {
       if (current_name == NULL)
@@ -6124,6 +6050,8 @@ do_s_func (int end_p, const char *default_prefix)
       if (debug_type == DEBUG_STABS)
        stabs_generate_asm_endfunc (current_name, current_label);
 
+      free (current_name);
+      free (current_label);
       current_name = current_label = NULL;
     }
   else /* ! end_p */
@@ -6160,7 +6088,7 @@ do_s_func (int end_p, const char *default_prefix)
                    as_fatal ("%s", xstrerror (errno));
                }
              else
-               label = name;
+               label = xstrdup (name);
            }
        }
       else
@@ -6285,7 +6213,7 @@ input_scrub_insert_line (const char *line)
   size_t len = strlen (line);
   sb_build (&newline, len);
   sb_add_buffer (&newline, line, len);
-  input_scrub_include_sb (&newline, input_line_pointer, 0);
+  input_scrub_include_sb (&newline, input_line_pointer, expanding_none);
   sb_kill (&newline);
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }
@@ -6356,7 +6284,7 @@ find_end_of_line (char *s, int mri_string)
   return _find_end_of_line (s, mri_string, 0, 0);
 }
 
-static char *saved_ilp = NULL;
+static char *saved_ilp;
 static char *saved_limit;
 
 /* Use BUF as a temporary input pointer for calling other functions in this