gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gas / read.c
index bd3fa58bbec5e5dc2e4945c82e89c9d1e0362099..8f93c2ba2b461a22440889e67875fb40a34275f4 100644 (file)
@@ -1,7 +1,5 @@
 /* read.c - read a source file -
 /* read.c - read a source file -
-   Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010  Free Software Foundation, Inc.
+   Copyright (C) 1986-2020 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 
    This file is part of GAS, the GNU Assembler.
 
@@ -21,7 +19,7 @@
    02110-1301, USA.  */
 
 /* If your chars aren't 8 bits, you will change this a bit (eg. to 0xFF).
    02110-1301, USA.  */
 
 /* 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.
+   But then, GNU isn't supposed to run on your machine anyway.
    (RMS is so shortsighted sometimes.)  */
 #define MASK_CHAR ((int)(unsigned char) -1)
 
    (RMS is so shortsighted sometimes.)  */
 #define MASK_CHAR ((int)(unsigned char) -1)
 
 #include "obstack.h"
 #include "ecoff.h"
 #include "dw2gencfi.h"
 #include "obstack.h"
 #include "ecoff.h"
 #include "dw2gencfi.h"
+#include "wchar.h"
 
 #ifndef TC_START_LABEL
 
 #ifndef TC_START_LABEL
-#define TC_START_LABEL(x,y,z) (x == ':')
+#define TC_START_LABEL(STR, NUL_CHAR, NEXT_CHAR) (NEXT_CHAR == ':')
 #endif
 
 /* Set by the object-format or the target.  */
 #endif
 
 /* Set by the object-format or the target.  */
@@ -63,6 +62,7 @@
 #endif
 
 char *input_line_pointer;      /*->next char of source file to parse.  */
 #endif
 
 char *input_line_pointer;      /*->next char of source file to parse.  */
+bfd_boolean input_from_string = FALSE;
 
 #if BITS_PER_CHAR != 8
 /*  The following table is indexed by[(char)] and will break if
 
 #if BITS_PER_CHAR != 8
 /*  The following table is indexed by[(char)] and will break if
@@ -167,7 +167,7 @@ int target_big_endian = TARGET_BYTES_BIG_ENDIAN;
 /* Variables for handling include file directory table.  */
 
 /* Table of pointers to directories to search for .include's.  */
 /* Variables for handling include file directory table.  */
 
 /* Table of pointers to directories to search for .include's.  */
-char **include_dirs;
+const char **include_dirs;
 
 /* How many are in the table.  */
 int include_dir_count;
 
 /* How many are in the table.  */
 int include_dir_count;
@@ -209,19 +209,44 @@ static int dwarf_file_string;
 #endif
 #endif
 
 #endif
 #endif
 
+/* If the target defines the md_frag_max_var hook then we know
+   enough to implement the .bundle_align_mode features.  */
+#ifdef md_frag_max_var
+# define HANDLE_BUNDLE
+#endif
+
+#ifdef HANDLE_BUNDLE
+/* .bundle_align_mode sets this.  Normally it's zero.  When nonzero,
+   it's the exponent of the bundle size, and aligned instruction bundle
+   mode is in effect.  */
+static unsigned int bundle_align_p2;
+
+/* These are set by .bundle_lock and .bundle_unlock.  .bundle_lock sets
+   bundle_lock_frag to frag_now and then starts a new frag with
+   frag_align_code.  At the same time, bundle_lock_frain gets frchain_now,
+   so that .bundle_unlock can verify that we didn't change segments.
+   .bundle_unlock resets both to NULL.  If we detect a bundling violation,
+   then we reset bundle_lock_frchain to NULL as an indicator that we've
+   already diagnosed the error with as_bad and don't need a cascade of
+   redundant errors, but bundle_lock_frag remains set to indicate that
+   we are expecting to see .bundle_unlock.  */
+static fragS *bundle_lock_frag;
+static frchainS *bundle_lock_frchain;
+
+/* This is incremented by .bundle_lock and decremented by .bundle_unlock,
+   to allow nesting.  */
+static unsigned int bundle_lock_depth;
+#endif
+
 static void do_s_func (int end_p, const char *default_prefix);
 static void do_s_func (int end_p, const char *default_prefix);
-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 void s_align (int, int);
 static void s_altmacro (int);
 static void s_bad_end (int);
-#ifdef OBJ_ELF
-static void s_gnu_attribute (int);
-#endif
 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 s_reloc (int);
 static int hex_float (int, char *);
 static segT get_known_segmented_expression (expressionS * expP);
 static void pobegin (void);
-static int get_non_macro_line_sb (sb *);
+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);
 \f
 static void generate_file_debug (void);
 static char *_find_end_of_line (char *, int, int, int);
 \f
@@ -238,8 +263,11 @@ read_begin (void)
   obstack_begin (&notes, chunksize);
   obstack_begin (&cond_obstack, chunksize);
 
   obstack_begin (&notes, chunksize);
   obstack_begin (&cond_obstack, chunksize);
 
+#ifndef tc_line_separator_chars
+#define tc_line_separator_chars line_separator_chars
+#endif
   /* Use machine dependent syntax.  */
   /* Use machine dependent syntax.  */
-  for (p = line_separator_chars; *p; p++)
+  for (p = tc_line_separator_chars; *p; p++)
     is_end_of_line[(unsigned char) *p] = 2;
   /* Use more.  FIXME-SOMEDAY.  */
 
     is_end_of_line[(unsigned char) *p] = 2;
   /* Use more.  FIXME-SOMEDAY.  */
 
@@ -277,6 +305,11 @@ static const pseudo_typeS potable[] = {
   {"balignw", s_align_bytes, -2},
   {"balignl", s_align_bytes, -4},
 /* block  */
   {"balignw", s_align_bytes, -2},
   {"balignl", s_align_bytes, -4},
 /* block  */
+#ifdef HANDLE_BUNDLE
+  {"bundle_align_mode", s_bundle_align_mode, 0},
+  {"bundle_lock", s_bundle_lock, 0},
+  {"bundle_unlock", s_bundle_unlock, 0},
+#endif
   {"byte", cons, 1},
   {"comm", s_comm, 0},
   {"common", s_mri_common, 0},
   {"byte", cons, 1},
   {"comm", s_comm, 0},
   {"common", s_mri_common, 0},
@@ -343,9 +376,6 @@ static const pseudo_typeS potable[] = {
   {"func", s_func, 0},
   {"global", s_globl, 0},
   {"globl", s_globl, 0},
   {"func", s_func, 0},
   {"global", s_globl, 0},
   {"globl", s_globl, 0},
-#ifdef OBJ_ELF
-  {"gnu_attribute", s_gnu_attribute, 0},
-#endif
   {"hword", cons, 2},
   {"if", s_if, (int) O_ne},
   {"ifb", s_ifb, 1},
   {"hword", cons, 2},
   {"if", s_if, (int) O_ne},
   {"ifb", s_ifb, 1},
@@ -387,6 +417,7 @@ static const pseudo_typeS potable[] = {
   {"noformat", s_ignore, 0},
   {"nolist", listing_list, 0}, /* Turn listing off.  */
   {"nopage", listing_nopage, 0},
   {"noformat", s_ignore, 0},
   {"nolist", listing_list, 0}, /* Turn listing off.  */
   {"nopage", listing_nopage, 0},
+  {"nops", s_nops, 0},
   {"octa", cons, 16},
   {"offset", s_struct, 0},
   {"org", s_org, 0},
   {"octa", cons, 16},
   {"offset", s_struct, 0},
   {"org", s_org, 0},
@@ -457,6 +488,7 @@ static offsetT
 get_absolute_expr (expressionS *exp)
 {
   expression_and_evaluate (exp);
 get_absolute_expr (expressionS *exp)
 {
   expression_and_evaluate (exp);
+
   if (exp->X_op != O_constant)
     {
       if (exp->X_op != O_absent)
   if (exp->X_op != O_constant)
     {
       if (exp->X_op != O_absent)
@@ -521,17 +553,17 @@ pobegin (void)
   pop_table_name = "standard";
   pop_insert (potable);
 
   pop_table_name = "standard";
   pop_insert (potable);
 
-#ifdef TARGET_USE_CFIPOP
+  /* Now CFI ones.  */
   pop_table_name = "cfi";
   pop_override_ok = 1;
   cfi_pop_insert ();
   pop_table_name = "cfi";
   pop_override_ok = 1;
   cfi_pop_insert ();
-#endif
 }
 \f
 }
 \f
-#define HANDLE_CONDITIONAL_ASSEMBLY()                                  \
+#define HANDLE_CONDITIONAL_ASSEMBLY(num_read)                          \
   if (ignore_input ())                                                 \
     {                                                                  \
   if (ignore_input ())                                                 \
     {                                                                  \
-      char *eol = find_end_of_line (input_line_pointer, flag_m68k_mri); \
+      char *eol = find_end_of_line (input_line_pointer - (num_read),   \
+                                   flag_m68k_mri);                     \
       input_line_pointer = (input_line_pointer <= buffer_limit         \
                            && eol >= buffer_limit)                     \
                           ? buffer_limit                               \
       input_line_pointer = (input_line_pointer <= buffer_limit         \
                            && eol >= buffer_limit)                     \
                           ? buffer_limit                               \
@@ -545,10 +577,10 @@ pobegin (void)
 static char *scrub_string;
 static char *scrub_string_end;
 
 static char *scrub_string;
 static char *scrub_string_end;
 
-static int
-scrub_from_string (char *buf, int buflen)
+static size_t
+scrub_from_string (char *buf, size_t buflen)
 {
 {
-  int copy;
+  size_t copy;
 
   copy = scrub_string_end - scrub_string;
   if (copy > buflen)
 
   copy = scrub_string_end - scrub_string;
   if (copy > buflen)
@@ -584,12 +616,205 @@ try_macro (char term, const char *line)
   return 0;
 }
 
   return 0;
 }
 
+#ifdef HANDLE_BUNDLE
+/* Start a new instruction bundle.  Returns the rs_align_code frag that
+   will be used to align the new bundle.  */
+static fragS *
+start_bundle (void)
+{
+  fragS *frag = frag_now;
+
+  frag_align_code (0, 0);
+
+  while (frag->fr_type != rs_align_code)
+    frag = frag->fr_next;
+
+  gas_assert (frag != frag_now);
+
+  return frag;
+}
+
+/* Calculate the maximum size after relaxation of the region starting
+   at the given frag and extending through frag_now (which is unfinished).  */
+static unsigned int
+pending_bundle_size (fragS *frag)
+{
+  unsigned int offset = frag->fr_fix;
+  unsigned int size = 0;
+
+  gas_assert (frag != frag_now);
+  gas_assert (frag->fr_type == rs_align_code);
+
+  while (frag != frag_now)
+    {
+      /* This should only happen in what will later become an error case.  */
+      if (frag == NULL)
+       return 0;
+
+      size += frag->fr_fix;
+      if (frag->fr_type == rs_machine_dependent)
+       size += md_frag_max_var (frag);
+
+      frag = frag->fr_next;
+    }
+
+  gas_assert (frag == frag_now);
+  size += frag_now_fix ();
+  if (frag->fr_type == rs_machine_dependent)
+    size += md_frag_max_var (frag);
+
+  gas_assert (size >= offset);
+
+  return size - offset;
+}
+
+/* Finish off the frag created to ensure bundle alignment.  */
+static void
+finish_bundle (fragS *frag, unsigned int size)
+{
+  gas_assert (bundle_align_p2 > 0);
+  gas_assert (frag->fr_type == rs_align_code);
+
+  if (size > 1)
+    {
+      /* If there is more than a single byte, then we need to set up the
+        alignment frag.  Otherwise we leave it at its initial state from
+        calling frag_align_code (0, 0), so that it does nothing.  */
+      frag->fr_offset = bundle_align_p2;
+      frag->fr_subtype = size - 1;
+    }
+
+  /* We do this every time rather than just in s_bundle_align_mode
+     so that we catch any affected section without needing hooks all
+     over for all paths that do section changes.  It's cheap enough.  */
+  if (bundle_align_p2 > OCTETS_PER_BYTE_POWER)
+    record_alignment (now_seg, bundle_align_p2 - OCTETS_PER_BYTE_POWER);
+}
+
+/* Assemble one instruction.  This takes care of the bundle features
+   around calling md_assemble.  */
+static void
+assemble_one (char *line)
+{
+  fragS *insn_start_frag = NULL;
+
+  if (bundle_lock_frchain != NULL && bundle_lock_frchain != frchain_now)
+    {
+      as_bad (_("cannot change section or subsection inside .bundle_lock"));
+      /* Clearing this serves as a marker that we have already complained.  */
+      bundle_lock_frchain = NULL;
+    }
+
+  if (bundle_lock_frchain == NULL && bundle_align_p2 > 0)
+    insn_start_frag = start_bundle ();
+
+  md_assemble (line);
+
+  if (bundle_lock_frchain != NULL)
+    {
+      /* Make sure this hasn't pushed the locked sequence
+        past the bundle size.  */
+      unsigned int bundle_size = pending_bundle_size (bundle_lock_frag);
+      if (bundle_size > 1U << bundle_align_p2)
+       as_bad (_ (".bundle_lock sequence at %u bytes, "
+                  "but .bundle_align_mode limit is %u bytes"),
+               bundle_size, 1U << bundle_align_p2);
+    }
+  else if (bundle_align_p2 > 0)
+    {
+      unsigned int insn_size = pending_bundle_size (insn_start_frag);
+
+      if (insn_size > 1U << bundle_align_p2)
+       as_bad (_("single instruction is %u bytes long, "
+                 "but .bundle_align_mode limit is %u bytes"),
+               insn_size, 1U << bundle_align_p2);
+
+      finish_bundle (insn_start_frag, insn_size);
+    }
+}
+
+#else  /* !HANDLE_BUNDLE */
+
+# define assemble_one(line) md_assemble(line)
+
+#endif  /* HANDLE_BUNDLE */
+
+static bfd_boolean
+in_bss (void)
+{
+  flagword flags = bfd_section_flags (now_seg);
+
+  return (flags & SEC_ALLOC) && !(flags & (SEC_LOAD | SEC_HAS_CONTENTS));
+}
+
+/* Guts of .align directive:
+   N is the power of two to which to align.  A value of zero is accepted but
+    ignored: the default alignment of the section will be at least this.
+   FILL may be NULL, or it may point to the bytes of the fill pattern.
+   LEN is the length of whatever FILL points to, if anything.  If LEN is zero
+    but FILL is not NULL then LEN is treated as if it were one.
+   MAX is the maximum number of characters to skip when doing the alignment,
+    or 0 if there is no maximum.  */
+
+void
+do_align (unsigned int n, char *fill, unsigned int len, unsigned int max)
+{
+  if (now_seg == absolute_section || in_bss ())
+    {
+      if (fill != NULL)
+       while (len-- > 0)
+         if (*fill++ != '\0')
+           {
+             if (now_seg == absolute_section)
+               as_warn (_("ignoring fill value in absolute section"));
+             else
+               as_warn (_("ignoring fill value in section `%s'"),
+                        segment_name (now_seg));
+             break;
+           }
+      fill = NULL;
+      len = 0;
+    }
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+#ifdef md_do_align
+  md_do_align (n, fill, len, max, just_record_alignment);
+#endif
+
+  /* Only make a frag if we HAVE to...  */
+  if ((n > OCTETS_PER_BYTE_POWER) && !need_pass_2)
+    {
+      if (fill == NULL)
+       {
+         if (subseg_text_p (now_seg))
+           frag_align_code (n, max);
+         else
+           frag_align (n, 0, max);
+       }
+      else if (len <= 1)
+       frag_align (n, *fill, max);
+      else
+       frag_align_pattern (n, fill, len, max);
+    }
+
+#ifdef md_do_align
+ just_record_alignment: ATTRIBUTE_UNUSED_LABEL
+#endif
+
+  if (n > OCTETS_PER_BYTE_POWER)
+    record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER);
+}
+
 /* We read the file, putting things into a web that represents what we
    have been reading.  */
 void
 /* We read the file, putting things into a web that represents what we
    have been reading.  */
 void
-read_a_source_file (char *name)
+read_a_source_file (const char *name)
 {
 {
-  char c;
+  char nul_char;
+  char next_char;
   char *s;             /* String of symbol, '\0' appended.  */
   int temp;
   pseudo_typeS *pop;
   char *s;             /* String of symbol, '\0' appended.  */
   int temp;
   pseudo_typeS *pop;
@@ -629,6 +854,7 @@ read_a_source_file (char *name)
          was_new_line = is_end_of_line[(unsigned char) input_line_pointer[-1]];
          if (was_new_line)
            {
          was_new_line = is_end_of_line[(unsigned char) input_line_pointer[-1]];
          if (was_new_line)
            {
+             symbol_set_value_now (&dot_symbol);
 #ifdef md_start_line_hook
              md_start_line_hook ();
 #endif
 #ifdef md_start_line_hook
              md_start_line_hook ();
 #endif
@@ -655,7 +881,7 @@ read_a_source_file (char *name)
                      /* Copy it for safe keeping.  Also give an indication of
                         how much macro nesting is involved at this point.  */
                      len = s - input_line_pointer;
                      /* Copy it for safe keeping.  Also give an indication of
                         how much macro nesting is involved at this point.  */
                      len = s - input_line_pointer;
-                     copy = (char *) xmalloc (len + macro_nest + 2);
+                     copy = XNEWVEC (char, len + macro_nest + 2);
                      memset (copy, '>', macro_nest);
                      copy[macro_nest] = ' ';
                      memcpy (copy + macro_nest + 1, input_line_pointer, len);
                      memset (copy, '>', macro_nest);
                      copy[macro_nest] = ' ';
                      memcpy (copy + macro_nest + 1, input_line_pointer, len);
@@ -675,16 +901,18 @@ read_a_source_file (char *name)
 
              if (LABELS_WITHOUT_COLONS || flag_m68k_mri)
                {
 
              if (LABELS_WITHOUT_COLONS || flag_m68k_mri)
                {
+                 next_char = * input_line_pointer;
                  /* Text at the start of a line must be a label, we
                     run down and stick a colon in.  */
                  /* Text at the start of a line must be a label, we
                     run down and stick a colon in.  */
-                 if (is_name_beginner (*input_line_pointer))
+                 if (is_name_beginner (next_char) || next_char == '"')
                    {
                    {
-                     char *line_start = input_line_pointer;
+                     char *line_start;
                      int mri_line_macro;
 
                      int mri_line_macro;
 
-                     HANDLE_CONDITIONAL_ASSEMBLY ();
+                     HANDLE_CONDITIONAL_ASSEMBLY (0);
 
 
-                     c = get_symbol_end ();
+                     nul_char = get_symbol_name (& line_start);
+                     next_char = (nul_char == '"' ? input_line_pointer[1] : nul_char);
 
                      /* In MRI mode, the EQU and MACRO pseudoops must
                         be handled specially.  */
 
                      /* In MRI mode, the EQU and MACRO pseudoops must
                         be handled specially.  */
@@ -718,8 +946,7 @@ read_a_source_file (char *name)
                         symbol in the symbol table.  */
                      if (!mri_line_macro
 #ifdef TC_START_LABEL_WITHOUT_COLON
                         symbol in the symbol table.  */
                      if (!mri_line_macro
 #ifdef TC_START_LABEL_WITHOUT_COLON
-                         && TC_START_LABEL_WITHOUT_COLON(c,
-                                                         input_line_pointer)
+                         && TC_START_LABEL_WITHOUT_COLON (nul_char, next_char)
 #endif
                          )
                        line_label = colon (line_start);
 #endif
                          )
                        line_label = colon (line_start);
@@ -729,8 +956,8 @@ read_a_source_file (char *name)
                                                    (valueT) 0,
                                                    &zero_address_frag);
 
                                                    (valueT) 0,
                                                    &zero_address_frag);
 
-                     *input_line_pointer = c;
-                     if (c == ':')
+                     next_char = restore_line_pointer (nul_char);
+                     if (next_char == ':')
                        input_line_pointer++;
                    }
                }
                        input_line_pointer++;
                    }
                }
@@ -745,30 +972,32 @@ read_a_source_file (char *name)
             Each test is independent of all other tests at the (top)
             level.  */
          do
             Each test is independent of all other tests at the (top)
             level.  */
          do
-           c = *input_line_pointer++;
-         while (c == '\t' || c == ' ' || c == '\f');
+           nul_char = next_char = *input_line_pointer++;
+         while (next_char == '\t' || next_char == ' ' || next_char == '\f');
 
          /* C is the 1st significant character.
             Input_line_pointer points after that character.  */
 
          /* C is the 1st significant character.
             Input_line_pointer points after that character.  */
-         if (is_name_beginner (c))
+         if (is_name_beginner (next_char) || next_char == '"')
            {
            {
+             char *rest;
+
              /* Want user-defined label or pseudo/opcode.  */
              /* Want user-defined label or pseudo/opcode.  */
-             HANDLE_CONDITIONAL_ASSEMBLY ();
+             HANDLE_CONDITIONAL_ASSEMBLY (1);
 
 
-             s = --input_line_pointer;
-             c = get_symbol_end ();    /* name's delimiter.  */
+             --input_line_pointer;
+             nul_char = get_symbol_name (& s); /* name's delimiter.  */
+             next_char = (nul_char == '"' ? input_line_pointer[1] : nul_char);
+             rest = input_line_pointer + (nul_char == '"' ? 2 : 1);
 
 
-             /* C is character after symbol.
-                That character's place in the input line is now '\0'.
+             /* NEXT_CHAR is character after symbol.
+                The end of symbol in the input line is now '\0'.
                 S points to the beginning of the symbol.
                   [In case of pseudo-op, s->'.'.]
                 S points to the beginning of the symbol.
                   [In case of pseudo-op, s->'.'.]
-                Input_line_pointer->'\0' where c was.  */
-             if (TC_START_LABEL (c, s, input_line_pointer))
+                Input_line_pointer->'\0' where NUL_CHAR was.  */
+             if (TC_START_LABEL (s, nul_char, next_char))
                {
                  if (flag_m68k_mri)
                    {
                {
                  if (flag_m68k_mri)
                    {
-                     char *rest = input_line_pointer + 1;
-
                      /* In MRI mode, \tsym: set 0 is permitted.  */
                      if (*rest == ':')
                        ++rest;
                      /* In MRI mode, \tsym: set 0 is permitted.  */
                      if (*rest == ':')
                        ++rest;
@@ -787,29 +1016,29 @@ read_a_source_file (char *name)
                    }
 
                  line_label = colon (s);       /* User-defined label.  */
                    }
 
                  line_label = colon (s);       /* User-defined label.  */
-                 /* Put ':' back for error messages' sake.  */
-                 *input_line_pointer++ = ':';
+                 restore_line_pointer (nul_char);
+                 ++ input_line_pointer;
 #ifdef tc_check_label
                  tc_check_label (line_label);
 #endif
                  /* Input_line_pointer->after ':'.  */
                  SKIP_WHITESPACE ();
                }
 #ifdef tc_check_label
                  tc_check_label (line_label);
 #endif
                  /* Input_line_pointer->after ':'.  */
                  SKIP_WHITESPACE ();
                }
-              else if ((c == '=' && input_line_pointer[1] == '=')
-                      || ((c == ' ' || c == '\t')
-                          && input_line_pointer[1] == '='
-                          && input_line_pointer[2] == '='))
+             else if ((next_char == '=' && *rest == '=')
+                      || ((next_char == ' ' || next_char == '\t')
+                          && rest[0] == '='
+                          && rest[1] == '='))
                {
                  equals (s, -1);
                  demand_empty_rest_of_line ();
                }
                {
                  equals (s, -1);
                  demand_empty_rest_of_line ();
                }
-              else if ((c == '='
-                       || ((c == ' ' || c == '\t')
-                            && input_line_pointer[1] == '='))
+             else if ((next_char == '='
+                      || ((next_char == ' ' || next_char == '\t')
+                           && *rest == '='))
 #ifdef TC_EQUAL_IN_INSN
 #ifdef TC_EQUAL_IN_INSN
-                           && !TC_EQUAL_IN_INSN (c, s)
+                          && !TC_EQUAL_IN_INSN (next_char, s)
 #endif
 #endif
-                           )
+                          )
                {
                  equals (s, 1);
                  demand_empty_rest_of_line ();
                {
                  equals (s, 1);
                  demand_empty_rest_of_line ();
@@ -823,7 +1052,8 @@ read_a_source_file (char *name)
                  {
                    char *s2 = s;
 
                  {
                    char *s2 = s;
 
-                   strncpy (original_case_string, s2, sizeof (original_case_string));
+                   strncpy (original_case_string, s2,
+                            sizeof (original_case_string) - 1);
                    original_case_string[sizeof (original_case_string) - 1] = 0;
 
                    while (*s2)
                    original_case_string[sizeof (original_case_string) - 1] = 0;
 
                    while (*s2)
@@ -847,7 +1077,7 @@ read_a_source_file (char *name)
                    {
                      /* PSEUDO - OP.
 
                    {
                      /* PSEUDO - OP.
 
-                        WARNING: c has next char, which may be end-of-line.
+                        WARNING: next_char may be end-of-line.
                         We lookup the pseudo-op table with s+1 because we
                         already know that the pseudo-op begins with a '.'.  */
 
                         We lookup the pseudo-op table with s+1 because we
                         already know that the pseudo-op begins with a '.'.  */
 
@@ -892,25 +1122,25 @@ read_a_source_file (char *name)
                        {
                          char *end = input_line_pointer;
 
                        {
                          char *end = input_line_pointer;
 
-                         *input_line_pointer = c;
+                         (void) restore_line_pointer (nul_char);
                          s_ignore (0);
                          s_ignore (0);
-                         c = *--input_line_pointer;
+                         nul_char = next_char = *--input_line_pointer;
                          *input_line_pointer = '\0';
                          *input_line_pointer = '\0';
-                         if (! macro_defined || ! try_macro (c, s))
+                         if (! macro_defined || ! try_macro (next_char, s))
                            {
                              *end = '\0';
                              as_bad (_("unknown pseudo-op: `%s'"), s);
                            {
                              *end = '\0';
                              as_bad (_("unknown pseudo-op: `%s'"), s);
-                             *input_line_pointer++ = c;
+                             *input_line_pointer++ = nul_char;
                            }
                          continue;
                        }
 
                      /* Put it back for error messages etc.  */
                            }
                          continue;
                        }
 
                      /* Put it back for error messages etc.  */
-                     *input_line_pointer = c;
+                     next_char = restore_line_pointer (nul_char);
                      /* The following skip of whitespace is compulsory.
                         A well shaped space is sometimes all that separates
                         keyword from operands.  */
                      /* The following skip of whitespace is compulsory.
                         A well shaped space is sometimes all that separates
                         keyword from operands.  */
-                     if (c == ' ' || c == '\t')
+                     if (next_char == ' ' || next_char == '\t')
                        input_line_pointer++;
 
                      /* Input_line is restored.
                        input_line_pointer++;
 
                      /* Input_line is restored.
@@ -924,16 +1154,16 @@ read_a_source_file (char *name)
                    }
                  else
                    {
                    }
                  else
                    {
-                     /* WARNING: c has char, which may be end-of-line.  */
-                     /* Also: input_line_pointer->`\0` where c was.  */
-                     *input_line_pointer = c;
+                     /* WARNING: next_char may be end-of-line.  */
+                     /* Also: input_line_pointer->`\0` where nul_char was.  */
+                     (void) restore_line_pointer (nul_char);
                      input_line_pointer = _find_end_of_line (input_line_pointer, flag_m68k_mri, 1, 0);
                      input_line_pointer = _find_end_of_line (input_line_pointer, flag_m68k_mri, 1, 0);
-                     c = *input_line_pointer;
+                     next_char = nul_char = *input_line_pointer;
                      *input_line_pointer = '\0';
 
                      generate_lineno_debug ();
 
                      *input_line_pointer = '\0';
 
                      generate_lineno_debug ();
 
-                     if (macro_defined && try_macro (c, s))
+                     if (macro_defined && try_macro (next_char, s))
                        continue;
 
                      if (mri_pending_align)
                        continue;
 
                      if (mri_pending_align)
@@ -947,9 +1177,14 @@ read_a_source_file (char *name)
                            }
                        }
 
                            }
                        }
 
-                     md_assemble (s);  /* Assemble 1 instruction.  */
+                     assemble_one (s); /* Assemble 1 instruction.  */
 
 
-                     *input_line_pointer++ = c;
+                     /* PR 19630: The backend may have set ilp to NULL
+                        if it encountered a catastrophic failure.  */
+                     if (input_line_pointer == NULL)
+                       as_fatal (_("unable to continue with assembly."));
+                     *input_line_pointer++ = nul_char;
 
                      /* We resume loop AFTER the end-of-line from
                         this instruction.  */
 
                      /* We resume loop AFTER the end-of-line from
                         this instruction.  */
@@ -959,17 +1194,20 @@ read_a_source_file (char *name)
            }
 
          /* Empty statement?  */
            }
 
          /* Empty statement?  */
-         if (is_end_of_line[(unsigned char) c])
+         if (is_end_of_line[(unsigned char) next_char])
            continue;
 
            continue;
 
-         if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) && ISDIGIT (c))
+         if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) && ISDIGIT (next_char))
            {
              /* local label  ("4:")  */
              char *backup = input_line_pointer;
 
            {
              /* local label  ("4:")  */
              char *backup = input_line_pointer;
 
-             HANDLE_CONDITIONAL_ASSEMBLY ();
+             HANDLE_CONDITIONAL_ASSEMBLY (1);
+
+             temp = next_char - '0';
 
 
-             temp = c - '0';
+             if (nul_char == '"')
+               ++ input_line_pointer;
 
              /* Read the whole number.  */
              while (ISDIGIT (*input_line_pointer))
 
              /* Read the whole number.  */
              while (ISDIGIT (*input_line_pointer))
@@ -1003,9 +1241,9 @@ read_a_source_file (char *name)
                }
 
              input_line_pointer = backup;
                }
 
              input_line_pointer = backup;
-           }                   /* local label  ("4:") */
+           }
 
 
-         if (c && strchr (line_comment_chars, c))
+         if (next_char && strchr (line_comment_chars, next_char))
            {                   /* Its a comment.  Better say APP or NO_APP.  */
              sb sbuf;
              char *ends;
            {                   /* Its a comment.  Better say APP or NO_APP.  */
              sb sbuf;
              char *ends;
@@ -1024,7 +1262,6 @@ read_a_source_file (char *name)
              bump_line_counters ();
              s += 4;
 
              bump_line_counters ();
              s += 4;
 
-             sb_new (&sbuf);
              ends = strstr (s, "#NO_APP\n");
 
              if (!ends)
              ends = strstr (s, "#NO_APP\n");
 
              if (!ends)
@@ -1037,7 +1274,7 @@ read_a_source_file (char *name)
                     that goes with this #APP  There is one.  The specs
                     guarantee it...  */
                  tmp_len = buffer_limit - s;
                     that goes with this #APP  There is one.  The specs
                     guarantee it...  */
                  tmp_len = buffer_limit - s;
-                 tmp_buf = (char *) xmalloc (tmp_len + 1);
+                 tmp_buf = XNEWVEC (char, tmp_len + 1);
                  memcpy (tmp_buf, s, tmp_len);
                  do
                    {
                  memcpy (tmp_buf, s, tmp_len);
                  do
                    {
@@ -1053,7 +1290,7 @@ read_a_source_file (char *name)
                      else
                        num = buffer_limit - buffer;
 
                      else
                        num = buffer_limit - buffer;
 
-                     tmp_buf = (char *) xrealloc (tmp_buf, tmp_len + num);
+                     tmp_buf = XRESIZEVEC (char, tmp_buf, tmp_len + num);
                      memcpy (tmp_buf + tmp_len, buffer, num);
                      tmp_len += num;
                    }
                      memcpy (tmp_buf + tmp_len, buffer, num);
                      tmp_len += num;
                    }
@@ -1074,12 +1311,12 @@ read_a_source_file (char *name)
              scrub_string_end = ends;
 
              new_length = ends - s;
              scrub_string_end = ends;
 
              new_length = ends - s;
-             new_buf = (char *) xmalloc (new_length);
+             new_buf = XNEWVEC (char, new_length);
              new_tmp = new_buf;
              for (;;)
                {
              new_tmp = new_buf;
              for (;;)
                {
-                 int space;
-                 int size;
+                 size_t space;
+                 size_t size;
 
                  space = (new_buf + new_length) - new_tmp;
                  size = do_scrub_chars (scrub_from_string, new_tmp, space);
 
                  space = (new_buf + new_length) - new_tmp;
                  size = do_scrub_chars (scrub_from_string, new_tmp, space);
@@ -1090,13 +1327,12 @@ read_a_source_file (char *name)
                      break;
                    }
 
                      break;
                    }
 
-                 new_buf = (char *) xrealloc (new_buf, new_length + 100);
+                 new_buf = XRESIZEVEC (char, new_buf, new_length + 100);
                  new_tmp = new_buf + new_length;
                  new_length += 100;
                }
 
                  new_tmp = new_buf + new_length;
                  new_length += 100;
                }
 
-             if (tmp_buf)
-               free (tmp_buf);
+             free (tmp_buf);
 
              /* We've "scrubbed" input to the preferred format.  In the
                 process we may have consumed the whole of the remaining
 
              /* We've "scrubbed" input to the preferred format.  In the
                 process we may have consumed the whole of the remaining
@@ -1105,7 +1341,9 @@ read_a_source_file (char *name)
                 actual macro expansion (possibly nested) and other
                 input expansion work.  Beware that in messages, line
                 numbers and possibly file names will be incorrect.  */
                 actual macro expansion (possibly nested) and other
                 input expansion work.  Beware that in messages, line
                 numbers and possibly file names will be incorrect.  */
-             sb_add_string (&sbuf, new_buf);
+             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);
              sb_kill (&sbuf);
              buffer_limit = input_scrub_next_buffer (&input_line_pointer);
              input_scrub_include_sb (&sbuf, input_line_pointer, 0);
              sb_kill (&sbuf);
              buffer_limit = input_scrub_next_buffer (&input_line_pointer);
@@ -1113,23 +1351,31 @@ read_a_source_file (char *name)
              continue;
            }
 
              continue;
            }
 
-         HANDLE_CONDITIONAL_ASSEMBLY ();
+         HANDLE_CONDITIONAL_ASSEMBLY (1);
 
 #ifdef tc_unrecognized_line
 
 #ifdef tc_unrecognized_line
-         if (tc_unrecognized_line (c))
+         if (tc_unrecognized_line (next_char))
            continue;
 #endif
          input_line_pointer--;
          /* Report unknown char as error.  */
          demand_empty_rest_of_line ();
        }
            continue;
 #endif
          input_line_pointer--;
          /* Report unknown char as error.  */
          demand_empty_rest_of_line ();
        }
-
-#ifdef md_after_pass_hook
-      md_after_pass_hook ();
-#endif
     }
 
  quit:
     }
 
  quit:
+  symbol_set_value_now (&dot_symbol);
+
+#ifdef HANDLE_BUNDLE
+  if (bundle_lock_frag != NULL)
+    {
+      as_bad_where (bundle_lock_frag->fr_file, bundle_lock_frag->fr_line,
+                   _(".bundle_lock with no matching .bundle_unlock"));
+      bundle_lock_frag = NULL;
+      bundle_lock_frchain = NULL;
+      bundle_lock_depth = 0;
+    }
+#endif
 
 #ifdef md_cleanup
   md_cleanup ();
 
 #ifdef md_cleanup
   md_cleanup ();
@@ -1146,10 +1392,10 @@ read_a_source_file (char *name)
 }
 
 /* Convert O_constant expression EXP into the equivalent O_big representation.
 }
 
 /* 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.  */
+   Take the sign of the number from SIGN rather than X_add_number.  */
 
 static void
 
 static void
-convert_to_bignum (expressionS *exp)
+convert_to_bignum (expressionS *exp, int sign)
 {
   valueT value;
   unsigned int i;
 {
   valueT value;
   unsigned int i;
@@ -1162,8 +1408,8 @@ convert_to_bignum (expressionS *exp)
     }
   /* Add a sequence of sign bits if the top bit of X_add_number is not
      the sign of the original value.  */
     }
   /* 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;
+  if ((exp->X_add_number < 0) == !sign)
+    generic_bignum[i++] = sign ? LITTLENUM_MASK : 0;
   exp->X_op = O_big;
   exp->X_add_number = i;
 }
   exp->X_op = O_big;
   exp->X_add_number = i;
 }
@@ -1224,58 +1470,6 @@ s_abort (int ignore ATTRIBUTE_UNUSED)
   as_fatal (_(".abort detected.  Abandoning ship."));
 }
 
   as_fatal (_(".abort detected.  Abandoning ship."));
 }
 
-/* Guts of .align directive.  N is the power of two to which to align.
-   FILL may be NULL, or it may point to the bytes of the fill pattern.
-   LEN is the length of whatever FILL points to, if anything.  MAX is
-   the maximum number of characters to skip when doing the alignment,
-   or 0 if there is no maximum.  */
-
-static void
-do_align (int n, char *fill, int len, int max)
-{
-  if (now_seg == absolute_section)
-    {
-      if (fill != NULL)
-       while (len-- > 0)
-         if (*fill++ != '\0')
-           {
-             as_warn (_("ignoring fill value in absolute section"));
-             break;
-           }
-      fill = NULL;
-      len = 0;
-    }
-
-#ifdef md_flush_pending_output
-  md_flush_pending_output ();
-#endif
-#ifdef md_do_align
-  md_do_align (n, fill, len, max, just_record_alignment);
-#endif
-
-  /* Only make a frag if we HAVE to...  */
-  if (n != 0 && !need_pass_2)
-    {
-      if (fill == NULL)
-       {
-         if (subseg_text_p (now_seg))
-           frag_align_code (n, max);
-         else
-           frag_align (n, 0, max);
-       }
-      else if (len <= 1)
-       frag_align (n, *fill, max);
-      else
-       frag_align_pattern (n, fill, len, max);
-    }
-
-#ifdef md_do_align
- just_record_alignment: ATTRIBUTE_UNUSED_LABEL
-#endif
-
-  record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER);
-}
-
 /* Handle the .align pseudo-op.  A positive ARG is a default alignment
    (in bytes).  A negative ARG is the negative of the length of the
    fill pattern.  BYTES_P is non-zero if the alignment value should be
 /* Handle the .align pseudo-op.  A positive ARG is a default alignment
    (in bytes).  A negative ARG is the negative of the length of the
    fill pattern.  BYTES_P is non-zero if the alignment value should be
@@ -1285,14 +1479,14 @@ do_align (int n, char *fill, int len, int max)
 #endif
 
 static void
 #endif
 
 static void
-s_align (int arg, int bytes_p)
+s_align (signed int arg, int bytes_p)
 {
   unsigned int align_limit = TC_ALIGN_LIMIT;
   unsigned int align;
   char *stop = NULL;
   char stopc = 0;
   offsetT fill = 0;
 {
   unsigned int align_limit = TC_ALIGN_LIMIT;
   unsigned int align;
   char *stop = NULL;
   char stopc = 0;
   offsetT fill = 0;
-  int max;
+  unsigned int max;
   int fill_p;
 
   if (flag_mri)
   int fill_p;
 
   if (flag_mri)
@@ -1309,6 +1503,11 @@ s_align (int arg, int bytes_p)
     {
       align = get_absolute_expression ();
       SKIP_WHITESPACE ();
     {
       align = get_absolute_expression ();
       SKIP_WHITESPACE ();
+
+#ifdef TC_ALIGN_ZERO_IS_DEFAULT
+      if (arg > 0 && align == 0)
+       align = arg;
+#endif
     }
 
   if (bytes_p)
     }
 
   if (bytes_p)
@@ -1367,15 +1566,16 @@ s_align (int arg, int bytes_p)
     }
   else
     {
     }
   else
     {
-      int fill_len;
+      unsigned int fill_len;
 
       if (arg >= 0)
        fill_len = 1;
       else
        fill_len = -arg;
 
       if (arg >= 0)
        fill_len = 1;
       else
        fill_len = -arg;
+
       if (fill_len <= 1)
        {
       if (fill_len <= 1)
        {
-         char fill_char;
+         char fill_char = 0;
 
          fill_char = fill;
          do_align (align, &fill_char, fill_len, max);
 
          fill_char = fill;
          do_align (align, &fill_char, fill_len, max);
@@ -1385,7 +1585,12 @@ s_align (int arg, int bytes_p)
          char ab[16];
 
          if ((size_t) fill_len > sizeof ab)
          char ab[16];
 
          if ((size_t) fill_len > sizeof ab)
-           abort ();
+           {
+             as_warn (_("fill pattern too long, truncating to %u"),
+                      (unsigned) sizeof ab);
+             fill_len = sizeof ab;
+           }
+
          md_number_to_chars (ab, fill, fill_len);
          do_align (align, ab, fill_len, max);
        }
          md_number_to_chars (ab, fill, fill_len);
          do_align (align, ab, fill_len, max);
        }
@@ -1417,20 +1622,113 @@ s_align_ptwo (int arg)
 
 /* Switch in and out of alternate macro mode.  */
 
 
 /* Switch in and out of alternate macro mode.  */
 
-void
+static void
 s_altmacro (int on)
 {
   demand_empty_rest_of_line ();
   macro_set_alternate (on);
 }
 
 s_altmacro (int on)
 {
   demand_empty_rest_of_line ();
   macro_set_alternate (on);
 }
 
+/* Read a symbol name from input_line_pointer.
+
+   Stores the symbol name in a buffer and returns a pointer to this buffer.
+   The buffer is xalloc'ed.  It is the caller's responsibility to free
+   this buffer.
+
+   The name is not left in the i_l_p buffer as it may need processing
+   to handle escape characters.
+
+   Advances i_l_p to the next non-whitespace character.
+
+   If a symbol name could not be read, the routine issues an error
+   messages, skips to the end of the line and returns NULL.  */
+
+char *
+read_symbol_name (void)
+{
+  char * name;
+  char * start;
+  char c;
+
+  c = *input_line_pointer++;
+
+  if (c == '"')
+    {
+#define SYM_NAME_CHUNK_LEN 128
+      ptrdiff_t len = SYM_NAME_CHUNK_LEN;
+      char * name_end;
+      unsigned int C;
+
+      start = name = XNEWVEC (char, len + 1);
+
+      name_end = name + SYM_NAME_CHUNK_LEN;
+
+      while (is_a_char (C = next_char_of_string ()))
+       {
+         if (name >= name_end)
+           {
+             ptrdiff_t sofar;
+
+             sofar = name - start;
+             len += SYM_NAME_CHUNK_LEN;
+             start = XRESIZEVEC (char, start, len + 1);
+             name_end = start + len;
+             name = start + sofar;
+           }
+
+         *name++ = (char) C;
+       }
+      *name = 0;
+
+      /* 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)
+       as_warn (_("symbol name not recognised in the current locale"));
+    }
+  else if (is_name_beginner (c) || (input_from_string && c == FAKE_LABEL_CHAR))
+    {
+      ptrdiff_t len;
+
+      name = input_line_pointer - 1;
+
+      /* We accept FAKE_LABEL_CHAR in a name in case this is
+        being called with a constructed string.  */
+      while (is_part_of_name (c = *input_line_pointer++)
+            || (input_from_string && c == FAKE_LABEL_CHAR))
+       ;
+
+      len = (input_line_pointer - name) - 1;
+      start = XNEWVEC (char, len + 1);
+
+      memcpy (start, name, len);
+      start[len] = 0;
+
+      /* Skip a name ender char if one is present.  */
+      if (! is_name_ender (c))
+       --input_line_pointer;
+    }
+  else
+    name = start = NULL;
+
+  if (name == start)
+    {
+      as_bad (_("expected symbol name"));
+      ignore_rest_of_line ();
+      return NULL;
+    }
+
+  SKIP_WHITESPACE ();
+
+  return start;
+}
+
+
 symbolS *
 s_comm_internal (int param,
                 symbolS *(*comm_parse_extra) (int, symbolS *, addressT))
 {
   char *name;
 symbolS *
 s_comm_internal (int param,
                 symbolS *(*comm_parse_extra) (int, symbolS *, addressT))
 {
   char *name;
-  char c;
-  char *p;
   offsetT temp, size;
   symbolS *symbolP = NULL;
   char *stop = NULL;
   offsetT temp, size;
   symbolS *symbolP = NULL;
   char *stop = NULL;
@@ -1440,20 +1738,8 @@ s_comm_internal (int param,
   if (flag_mri)
     stop = mri_comment_field (&stopc);
 
   if (flag_mri)
     stop = mri_comment_field (&stopc);
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
-  /* Just after name is now '\0'.  */
-  p = input_line_pointer;
-  *p = c;
-
-  if (name == p)
-    {
-      as_bad (_("expected symbol name"));
-      ignore_rest_of_line ();
-      goto out;
-    }
-
-  SKIP_WHITESPACE ();
+  if ((name = read_symbol_name ()) == NULL)
+    goto out;
 
   /* Accept an optional comma after the name.  The comma used to be
      required, but Irix 5 cc does not generate it for .lcomm.  */
 
   /* Accept an optional comma after the name.  The comma used to be
      required, but Irix 5 cc does not generate it for .lcomm.  */
@@ -1462,7 +1748,7 @@ s_comm_internal (int param,
 
   temp = get_absolute_expr (&exp);
   size = temp;
 
   temp = get_absolute_expr (&exp);
   size = temp;
-  size &= ((offsetT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1;
+  size &= ((addressT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1;
   if (exp.X_op == O_absent)
     {
       as_bad (_("missing size expression"));
   if (exp.X_op == O_absent)
     {
       as_bad (_("missing size expression"));
@@ -1476,7 +1762,6 @@ s_comm_internal (int param,
       goto out;
     }
 
       goto out;
     }
 
-  *p = 0;
   symbolP = symbol_find_or_make (name);
   if ((S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
       && !S_IS_COMMON (symbolP))
   symbolP = symbol_find_or_make (name);
   if ((S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
       && !S_IS_COMMON (symbolP))
@@ -1485,7 +1770,6 @@ s_comm_internal (int param,
        {
          symbolP = NULL;
          as_bad (_("symbol `%s' is already defined"), name);
        {
          symbolP = NULL;
          as_bad (_("symbol `%s' is already defined"), name);
-         *p = c;
          ignore_rest_of_line ();
          goto out;
        }
          ignore_rest_of_line ();
          goto out;
        }
@@ -1503,7 +1787,6 @@ s_comm_internal (int param,
     as_warn (_("size of \"%s\" is already %ld; not changing to %ld"),
             name, (long) size, (long) temp);
 
     as_warn (_("size of \"%s\" is already %ld; not changing to %ld"),
             name, (long) size, (long) temp);
 
-  *p = c;
   if (comm_parse_extra != NULL)
     symbolP = (*comm_parse_extra) (param, symbolP, size);
   else
   if (comm_parse_extra != NULL)
     symbolP = (*comm_parse_extra) (param, symbolP, size);
   else
@@ -1511,19 +1794,13 @@ s_comm_internal (int param,
       S_SET_VALUE (symbolP, (valueT) size);
       S_SET_EXTERNAL (symbolP);
       S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
       S_SET_VALUE (symbolP, (valueT) size);
       S_SET_EXTERNAL (symbolP);
       S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
-#ifdef OBJ_VMS
-      {
-       extern int flag_one;
-       if (size == 0 || !flag_one)
-         S_GET_OTHER (symbolP) = const_flag;
-      }
-#endif
     }
 
   demand_empty_rest_of_line ();
  out:
   if (flag_mri)
     mri_comment_end (stop, stopc);
     }
 
   demand_empty_rest_of_line ();
  out:
   if (flag_mri)
     mri_comment_end (stop, stopc);
+  free (name);
   return symbolP;
 }
 
   return symbolP;
 }
 
@@ -1560,7 +1837,7 @@ s_mri_common (int small ATTRIBUTE_UNUSED)
 
   name = input_line_pointer;
   if (!ISDIGIT (*name))
 
   name = input_line_pointer;
   if (!ISDIGIT (*name))
-    c = get_symbol_end ();
+    c = get_symbol_name (& name);
   else
     {
       do
   else
     {
       do
@@ -1574,18 +1851,16 @@ s_mri_common (int small ATTRIBUTE_UNUSED)
 
       if (line_label != NULL)
        {
 
       if (line_label != NULL)
        {
-         alc = (char *) xmalloc (strlen (S_GET_NAME (line_label))
-                                 + (input_line_pointer - name)
-                                 + 1);
+         alc = XNEWVEC (char, strlen (S_GET_NAME (line_label))
+                        + (input_line_pointer - name) + 1);
          sprintf (alc, "%s%s", name, S_GET_NAME (line_label));
          name = alc;
        }
     }
 
   sym = symbol_find_or_make (name);
          sprintf (alc, "%s%s", name, S_GET_NAME (line_label));
          name = alc;
        }
     }
 
   sym = symbol_find_or_make (name);
-  *input_line_pointer = c;
-  if (alc != NULL)
-    free (alc);
+  c = restore_line_pointer (c);
+  free (alc);
 
   if (*input_line_pointer != ',')
     align = 0;
 
   if (*input_line_pointer != ',')
     align = 0;
@@ -1656,9 +1931,6 @@ s_data (int ignore ATTRIBUTE_UNUSED)
 
   subseg_set (section, (subsegT) temp);
 
 
   subseg_set (section, (subsegT) temp);
 
-#ifdef OBJ_VMS
-  const_flag = 0;
-#endif
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
@@ -1747,7 +2019,7 @@ s_app_line (int appline)
        Besides, it's silly.  GCC however will generate a line number of
        zero when it is pre-processing builtins for assembler-with-cpp files:
 
        Besides, it's silly.  GCC however will generate a line number of
        zero when it is pre-processing builtins for assembler-with-cpp files:
 
-          # 0 "<built-in>"
+         # 0 "<built-in>"
 
        We do not want to barf on this, especially since such files are used
        in the GCC and GDB testsuites.  So we check for negative line numbers
 
        We do not want to barf on this, especially since such files are used
        in the GCC and GDB testsuites.  So we check for negative line numbers
@@ -1776,7 +2048,7 @@ s_app_line (int appline)
                    /* From GCC's cpp documentation:
                       1: start of a new file.
                       2: returning to a file after having included
                    /* From GCC's cpp documentation:
                       1: start of a new file.
                       2: returning to a file after having included
-                         another file.
+                         another file.
                       3: following text comes from a system header file.
                       4: following text should be treated as extern "C".
 
                       3: following text comes from a system header file.
                       4: following text should be treated as extern "C".
 
@@ -1864,7 +2136,7 @@ s_errwarn (int err)
      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.  */
      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
+  const char *msg
     = (err ? _(".error directive invoked in source file")
        : _(".warning directive invoked in source file"));
 
     = (err ? _(".error directive invoked in source file")
        : _(".warning directive invoked in source file"));
 
@@ -1930,7 +2202,7 @@ s_fill (int ignore ATTRIBUTE_UNUSED)
   md_cons_align (1);
 #endif
 
   md_cons_align (1);
 #endif
 
-  get_known_segmented_expression (&rep_exp);
+  expression (&rep_exp);
   if (*input_line_pointer == ',')
     {
       input_line_pointer++;
   if (*input_line_pointer == ',')
     {
       input_line_pointer++;
@@ -1963,6 +2235,20 @@ s_fill (int ignore ATTRIBUTE_UNUSED)
 
   if (size && !need_pass_2)
     {
 
   if (size && !need_pass_2)
     {
+      if (now_seg == absolute_section)
+       {
+         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;
+       }
+      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));
+
       if (rep_exp.X_op == O_constant)
        {
          p = frag_var (rs_fill, (int) size, (int) size,
       if (rep_exp.X_op == O_constant)
        {
          p = frag_var (rs_fill, (int) size, (int) size,
@@ -2030,12 +2316,12 @@ s_globl (int ignore ATTRIBUTE_UNUSED)
 
   do
     {
 
   do
     {
-      name = input_line_pointer;
-      c = get_symbol_end ();
+      if ((name = read_symbol_name ()) == NULL)
+       return;
+
       symbolP = symbol_find_or_make (name);
       S_SET_EXTERNAL (symbolP);
 
       symbolP = symbol_find_or_make (name);
       S_SET_EXTERNAL (symbolP);
 
-      *input_line_pointer = c;
       SKIP_WHITESPACE ();
       c = *input_line_pointer;
       if (c == ',')
       SKIP_WHITESPACE ();
       c = *input_line_pointer;
       if (c == ',')
@@ -2045,6 +2331,8 @@ s_globl (int ignore ATTRIBUTE_UNUSED)
          if (is_end_of_line[(unsigned char) *input_line_pointer])
            c = '\n';
        }
          if (is_end_of_line[(unsigned char) *input_line_pointer])
            c = '\n';
        }
+
+      free (name);
     }
   while (c == ',');
 
     }
   while (c == ',');
 
@@ -2054,154 +2342,22 @@ s_globl (int ignore ATTRIBUTE_UNUSED)
     mri_comment_end (stop, stopc);
 }
 
     mri_comment_end (stop, stopc);
 }
 
-#ifdef OBJ_ELF
-#define skip_whitespace(str)  do { if (*(str) == ' ') ++(str); } while (0)
-
-static inline int
-skip_past_char (char ** str, char c)
-{
-  if (**str == c)
-    {
-      (*str)++;
-      return 0;
-    }
-  else
-    return -1;
-}
-#define skip_past_comma(str) skip_past_char (str, ',')
-
-/* Parse an attribute directive for VENDOR.
-   Returns the attribute number read, or zero on error.  */
-int
-s_vendor_attribute (int vendor)
-{
-  expressionS exp;
-  int type;
-  int tag;
-  unsigned int i = 0;
-  char *s = NULL;
-
-  /* Read the first number or name.  */
-  skip_whitespace (input_line_pointer);
-  s = input_line_pointer;
-  if (ISDIGIT (*input_line_pointer))
-    {
-      expression (& exp);
-      if (exp.X_op != O_constant)
-       goto bad;
-      tag = exp.X_add_number;
-    }
-  else
-    {
-      char *name;
-
-      /* A name may contain '_', but no other punctuation.  */
-      for (; ISALNUM (*input_line_pointer) || *input_line_pointer == '_';
-          ++input_line_pointer)
-       i++;
-      if (i == 0)
-       goto bad;
-
-      name = (char *) alloca (i + 1);
-      memcpy (name, s, i);
-      name[i] = '\0';
-
-#ifndef CONVERT_SYMBOLIC_ATTRIBUTE
-#define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1
-#endif
-
-      tag = CONVERT_SYMBOLIC_ATTRIBUTE (name);
-      if (tag == -1)
-       {
-         as_bad (_("Attribute name not recognised: %s"), name);
-         ignore_rest_of_line ();
-         return 0;
-       }
-    }
-
-  type = _bfd_elf_obj_attrs_arg_type (stdoutput, vendor, tag);
-
-  if (skip_past_comma (&input_line_pointer) == -1)
-    goto bad;
-  if (type & 1)
-    {
-      expression (& exp);
-      if (exp.X_op != O_constant)
-       {
-         as_bad (_("expected numeric constant"));
-         ignore_rest_of_line ();
-         return 0;
-       }
-      i = exp.X_add_number;
-    }
-  if ((type & 3) == 3
-      && skip_past_comma (&input_line_pointer) == -1)
-    {
-      as_bad (_("expected comma"));
-      ignore_rest_of_line ();
-      return 0;
-    }
-  if (type & 2)
-    {
-      int len;
-
-      skip_whitespace (input_line_pointer);
-      if (*input_line_pointer != '"')
-       goto bad_string;
-      s = demand_copy_C_string (&len);
-    }
-
-  switch (type & 3)
-    {
-    case 3:
-      bfd_elf_add_obj_attr_int_string (stdoutput, vendor, tag, i, s);
-      break;
-    case 2:
-      bfd_elf_add_obj_attr_string (stdoutput, vendor, tag, s);
-      break;
-    case 1:
-      bfd_elf_add_obj_attr_int (stdoutput, vendor, tag, i);
-      break;
-    default:
-      abort ();
-    }
-
-  demand_empty_rest_of_line ();
-  return tag;
-bad_string:
-  as_bad (_("bad string constant"));
-  ignore_rest_of_line ();
-  return 0;
-bad:
-  as_bad (_("expected <tag> , <value>"));
-  ignore_rest_of_line ();
-  return 0;
-}
-
-/* Parse a .gnu_attribute directive.  */
-
-static void
-s_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
-{
-  s_vendor_attribute (OBJ_ATTR_GNU);
-}
-#endif /* OBJ_ELF */
-
 /* Handle the MRI IRP and IRPC pseudo-ops.  */
 
 void
 s_irp (int irpc)
 {
 /* Handle the MRI IRP and IRPC pseudo-ops.  */
 
 void
 s_irp (int irpc)
 {
-  char *file, *eol;
+  char * eol;
+  const char * file;
   unsigned int line;
   sb s;
   const char *err;
   sb out;
 
   unsigned int line;
   sb s;
   const char *err;
   sb out;
 
-  as_where (&file, &line);
+  file = as_where (&line);
 
 
-  sb_new (&s);
   eol = find_end_of_line (input_line_pointer, 0);
   eol = find_end_of_line (input_line_pointer, 0);
+  sb_build (&s, eol - input_line_pointer);
   sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer);
   input_line_pointer = eol;
 
   sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer);
   input_line_pointer = eol;
 
@@ -2237,8 +2393,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED)
       char *s;
       char c;
 
       char *s;
       char c;
 
-      s = input_line_pointer;
-      c = get_symbol_end ();
+      c = get_symbol_name (& s);
       if (strcasecmp (s, "discard") == 0)
        type = LINKONCE_DISCARD;
       else if (strcasecmp (s, "one_only") == 0)
       if (strcasecmp (s, "discard") == 0)
        type = LINKONCE_DISCARD;
       else if (strcasecmp (s, "one_only") == 0)
@@ -2250,7 +2405,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED)
       else
        as_warn (_("unrecognized .linkonce type `%s'"), s);
 
       else
        as_warn (_("unrecognized .linkonce type `%s'"), s);
 
-      *input_line_pointer = c;
+      (void) restore_line_pointer (c);
     }
 
 #ifdef obj_handle_link_once
     }
 
 #ifdef obj_handle_link_once
@@ -2262,7 +2417,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED)
     if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0)
       as_warn (_(".linkonce is not supported for this object file format"));
 
     if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0)
       as_warn (_(".linkonce is not supported for this object file format"));
 
-    flags = bfd_get_section_flags (stdoutput, now_seg);
+    flags = bfd_section_flags (now_seg);
     flags |= SEC_LINK_ONCE;
     switch (type)
       {
     flags |= SEC_LINK_ONCE;
     switch (type)
       {
@@ -2281,7 +2436,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED)
        flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
        break;
       }
        flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
        break;
       }
-    if (!bfd_set_section_flags (stdoutput, now_seg, flags))
+    if (!bfd_set_section_flags (now_seg, flags))
       as_bad (_("bfd_set_section_flags: %s"),
              bfd_errmsg (bfd_get_error ()));
   }
       as_bad (_("bfd_set_section_flags: %s"),
              bfd_errmsg (bfd_get_error ()));
   }
@@ -2291,7 +2446,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED)
 }
 
 void
 }
 
 void
-bss_alloc (symbolS *symbolP, addressT size, int align)
+bss_alloc (symbolS *symbolP, addressT size, unsigned int align)
 {
   char *pfrag;
   segT current_seg = now_seg;
 {
   char *pfrag;
   segT current_seg = now_seg;
@@ -2307,7 +2462,7 @@ bss_alloc (symbolS *symbolP, addressT size, int align)
        {
          bss_seg = subseg_new (".sbss", 1);
          seg_info (bss_seg)->bss = 1;
        {
          bss_seg = subseg_new (".sbss", 1);
          seg_info (bss_seg)->bss = 1;
-         if (!bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC))
+         if (!bfd_set_section_flags (bss_seg, SEC_ALLOC | SEC_SMALL_DATA))
            as_warn (_("error setting flags for \".sbss\": %s"),
                     bfd_errmsg (bfd_get_error ()));
        }
            as_warn (_("error setting flags for \".sbss\": %s"),
                     bfd_errmsg (bfd_get_error ()));
        }
@@ -2315,7 +2470,7 @@ bss_alloc (symbolS *symbolP, addressT size, int align)
 #endif
   subseg_set (bss_seg, 1);
 
 #endif
   subseg_set (bss_seg, 1);
 
-  if (align)
+  if (align > OCTETS_PER_BYTE_POWER)
     {
       record_alignment (bss_seg, align);
       frag_align (align, 0, 0);
     {
       record_alignment (bss_seg, align);
       frag_align (align, 0, 0);
@@ -2431,33 +2586,17 @@ void
 s_lsym (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
 s_lsym (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
-  char c;
-  char *p;
   expressionS exp;
   symbolS *symbolP;
 
   /* We permit ANY defined expression: BSD4.2 demands constants.  */
   expressionS exp;
   symbolS *symbolP;
 
   /* We permit ANY defined expression: BSD4.2 demands constants.  */
-  name = input_line_pointer;
-  c = get_symbol_end ();
-  p = input_line_pointer;
-  *p = c;
-
-  if (name == p)
-    {
-      as_bad (_("expected symbol name"));
-      ignore_rest_of_line ();
-      return;
-    }
-
-  SKIP_WHITESPACE ();
+  if ((name = read_symbol_name ()) == NULL)
+    return;
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      *p = 0;
       as_bad (_("expected comma after \"%s\""), name);
       as_bad (_("expected comma after \"%s\""), name);
-      *p = c;
-      ignore_rest_of_line ();
-      return;
+      goto err_out;
     }
 
   input_line_pointer++;
     }
 
   input_line_pointer++;
@@ -2467,11 +2606,9 @@ s_lsym (int ignore ATTRIBUTE_UNUSED)
       && exp.X_op != O_register)
     {
       as_bad (_("bad expression"));
       && exp.X_op != O_register)
     {
       as_bad (_("bad expression"));
-      ignore_rest_of_line ();
-      return;
+      goto err_out;
     }
 
     }
 
-  *p = 0;
   symbolP = symbol_find_or_make (name);
 
   if (S_GET_SEGMENT (symbolP) == undefined_section)
   symbolP = symbol_find_or_make (name);
 
   if (S_GET_SEGMENT (symbolP) == undefined_section)
@@ -2489,8 +2626,14 @@ s_lsym (int ignore ATTRIBUTE_UNUSED)
       as_bad (_("symbol `%s' is already defined"), name);
     }
 
       as_bad (_("symbol `%s' is already defined"), name);
     }
 
-  *p = c;
   demand_empty_rest_of_line ();
   demand_empty_rest_of_line ();
+  free (name);
+  return;
+
+ err_out:
+  ignore_rest_of_line ();
+  free (name);
+  return;
 }
 
 /* Read a line into an sb.  Returns the character that ended the line
 }
 
 /* Read a line into an sb.  Returns the character that ended the line
@@ -2523,13 +2666,13 @@ get_line_sb (sb *line, int in_macro)
   return *input_line_pointer++;
 }
 
   return *input_line_pointer++;
 }
 
-static int
+static size_t
 get_non_macro_line_sb (sb *line)
 {
   return get_line_sb (line, 0);
 }
 
 get_non_macro_line_sb (sb *line)
 {
   return get_line_sb (line, 0);
 }
 
-static int
+static size_t
 get_macro_line_sb (sb *line)
 {
   return get_line_sb (line, 1);
 get_macro_line_sb (sb *line)
 {
   return get_line_sb (line, 1);
@@ -2540,25 +2683,29 @@ get_macro_line_sb (sb *line)
 void
 s_macro (int ignore ATTRIBUTE_UNUSED)
 {
 void
 s_macro (int ignore ATTRIBUTE_UNUSED)
 {
-  char *file, *eol;
+  char *eol;
+  const char * file;
   unsigned int line;
   sb s;
   const char *err;
   const char *name;
 
   unsigned int line;
   sb s;
   const char *err;
   const char *name;
 
-  as_where (&file, &line);
+  file = as_where (&line);
 
 
-  sb_new (&s);
   eol = find_end_of_line (input_line_pointer, 0);
   eol = find_end_of_line (input_line_pointer, 0);
+  sb_build (&s, eol - input_line_pointer);
   sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer);
   input_line_pointer = eol;
 
   if (line_label != NULL)
     {
       sb label;
   sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer);
   input_line_pointer = eol;
 
   if (line_label != NULL)
     {
       sb label;
+      size_t len;
 
 
-      sb_new (&label);
-      sb_add_string (&label, S_GET_NAME (line_label));
+      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);
       sb_kill (&label);
     }
       err = define_macro (0, &s, &label, get_macro_line_sb, file, line, &name);
       sb_kill (&label);
     }
@@ -2652,7 +2799,9 @@ s_mri (int ignore ATTRIBUTE_UNUSED)
 static void
 do_org (segT segment, expressionS *exp, int fill)
 {
 static void
 do_org (segT segment, expressionS *exp, int fill)
 {
-  if (segment != now_seg && segment != absolute_section)
+  if (segment != now_seg
+      && segment != absolute_section
+      && segment != expr_section)
     as_bad (_("invalid segment \"%s\""), segment_name (segment));
 
   if (now_seg == absolute_section)
     as_bad (_("invalid segment \"%s\""), segment_name (segment));
 
   if (now_seg == absolute_section)
@@ -2672,6 +2821,10 @@ do_org (segT segment, expressionS *exp, int fill)
       symbolS *sym = exp->X_add_symbol;
       offsetT off = exp->X_add_number * OCTETS_PER_BYTE;
 
       symbolS *sym = exp->X_add_symbol;
       offsetT off = exp->X_add_number * OCTETS_PER_BYTE;
 
+      if (fill && in_bss ())
+       as_warn (_("ignoring fill value in section `%s'"),
+                segment_name (now_seg));
+
       if (exp->X_op != O_constant && exp->X_op != O_symbol)
        {
          /* Handle complex expressions.  */
       if (exp->X_op != O_constant && exp->X_op != O_symbol)
        {
          /* Handle complex expressions.  */
@@ -2751,7 +2904,7 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED)
 
   name = input_line_pointer;
   if (!ISDIGIT (*name))
 
   name = input_line_pointer;
   if (!ISDIGIT (*name))
-    c = get_symbol_end ();
+    c = get_symbol_name (& name);
   else
     {
       do
   else
     {
       do
@@ -2766,13 +2919,13 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED)
 
   name = xstrdup (name);
 
 
   name = xstrdup (name);
 
-  *input_line_pointer = c;
+  c = restore_line_pointer (c);
 
   seg = subseg_new (name, 0);
 
 
   seg = subseg_new (name, 0);
 
-  if (*input_line_pointer == ',')
+  if (c == ',')
     {
     {
-      int align;
+      unsigned int align;
 
       ++input_line_pointer;
       align = get_absolute_expression ();
 
       ++input_line_pointer;
       align = get_absolute_expression ();
@@ -2802,9 +2955,9 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED)
          flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM;
        if (flags != SEC_NO_FLAGS)
          {
          flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM;
        if (flags != SEC_NO_FLAGS)
          {
-           if (!bfd_set_section_flags (stdoutput, seg, flags))
+           if (!bfd_set_section_flags (seg, flags))
              as_warn (_("error setting flags for \"%s\": %s"),
              as_warn (_("error setting flags for \"%s\": %s"),
-                      bfd_section_name (stdoutput, seg),
+                      bfd_section_name (seg),
                       bfd_errmsg (bfd_get_error ()));
          }
       }
                       bfd_errmsg (bfd_get_error ()));
          }
       }
@@ -2817,84 +2970,10 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 
 #else /* ! TC_M68K */
   demand_empty_rest_of_line ();
 
 #else /* ! TC_M68K */
-#ifdef TC_I960
-
-  char *name;
-  char c;
-  segT seg;
-
-  SKIP_WHITESPACE ();
-
-  name = input_line_pointer;
-  c = get_symbol_end ();
-
-  name = xstrdup (name);
-
-  *input_line_pointer = c;
-
-  seg = subseg_new (name, 0);
-
-  if (*input_line_pointer != ',')
-    *type = 'C';
-  else
-    {
-      char *sectype;
-
-      ++input_line_pointer;
-      SKIP_WHITESPACE ();
-      sectype = input_line_pointer;
-      c = get_symbol_end ();
-      if (*sectype == '\0')
-       *type = 'C';
-      else if (strcasecmp (sectype, "text") == 0)
-       *type = 'C';
-      else if (strcasecmp (sectype, "data") == 0)
-       *type = 'D';
-      else if (strcasecmp (sectype, "romdata") == 0)
-       *type = 'R';
-      else
-       as_warn (_("unrecognized section type `%s'"), sectype);
-      *input_line_pointer = c;
-    }
-
-  if (*input_line_pointer == ',')
-    {
-      char *seccmd;
-
-      ++input_line_pointer;
-      SKIP_WHITESPACE ();
-      seccmd = input_line_pointer;
-      c = get_symbol_end ();
-      if (strcasecmp (seccmd, "absolute") == 0)
-       {
-         as_bad (_("absolute sections are not supported"));
-         *input_line_pointer = c;
-         ignore_rest_of_line ();
-         return;
-       }
-      else if (strcasecmp (seccmd, "align") == 0)
-       {
-         int align;
-
-         *input_line_pointer = c;
-         align = get_absolute_expression ();
-         record_alignment (seg, align);
-       }
-      else
-       {
-         as_warn (_("unrecognized section command `%s'"), seccmd);
-         *input_line_pointer = c;
-       }
-    }
-
-  demand_empty_rest_of_line ();
-
-#else /* ! TC_I960 */
   /* The MRI assembler seems to use different forms of .sect for
      different targets.  */
   as_bad ("MRI mode not supported for this target");
   ignore_rest_of_line ();
   /* The MRI assembler seems to use different forms of .sect for
      different targets.  */
   as_bad ("MRI mode not supported for this target");
   ignore_rest_of_line ();
-#endif /* ! TC_I960 */
 #endif /* ! TC_M68K */
 }
 
 #endif /* ! TC_M68K */
 }
 
@@ -2929,11 +3008,10 @@ s_purgem (int ignore ATTRIBUTE_UNUSED)
       char c;
 
       SKIP_WHITESPACE ();
       char c;
 
       SKIP_WHITESPACE ();
-      name = input_line_pointer;
-      c = get_symbol_end ();
+      c = get_symbol_name (& name);
       delete_macro (name);
       *input_line_pointer = c;
       delete_macro (name);
       *input_line_pointer = c;
-      SKIP_WHITESPACE ();
+      SKIP_WHITESPACE_AFTER_NAME ();
     }
   while (*input_line_pointer++ == ',');
 
     }
   while (*input_line_pointer++ == ',');
 
@@ -2946,7 +3024,7 @@ s_purgem (int ignore ATTRIBUTE_UNUSED)
 static void
 s_bad_end (int endr)
 {
 static void
 s_bad_end (int endr)
 {
-  as_warn (_(".end%c encountered without preceeding %s"),
+  as_warn (_(".end%c encountered without preceding %s"),
           endr ? 'r' : 'm',
           endr ? ".rept, .irp, or .irpc" : ".macro");
   demand_empty_rest_of_line ();
           endr ? 'r' : 'm',
           endr ? ".rept, .irp, or .irpc" : ".macro");
   demand_empty_rest_of_line ();
@@ -2957,9 +3035,9 @@ s_bad_end (int endr)
 void
 s_rept (int ignore ATTRIBUTE_UNUSED)
 {
 void
 s_rept (int ignore ATTRIBUTE_UNUSED)
 {
-  int count;
+  size_t count;
 
 
-  count = get_absolute_expression ();
+  count = (size_t) get_absolute_expression ();
 
   do_repeat (count, "REPT", "ENDR");
 }
 
   do_repeat (count, "REPT", "ENDR");
 }
@@ -2968,11 +3046,17 @@ s_rept (int ignore ATTRIBUTE_UNUSED)
    different directives to be used as the start/end keys.  */
 
 void
    different directives to be used as the start/end keys.  */
 
 void
-do_repeat (int count, const char *start, const char *end)
+do_repeat (size_t count, const char *start, const char *end)
 {
   sb one;
   sb many;
 
 {
   sb one;
   sb many;
 
+  if (((ssize_t) count) < 0)
+    {
+      as_bad (_("negative count for %s - ignored"), start);
+      count = 0;
+    }
+
   sb_new (&one);
   if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
     {
   sb_new (&one);
   if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
     {
@@ -2980,7 +3064,7 @@ do_repeat (int count, const char *start, const char *end)
       return;
     }
 
       return;
     }
 
-  sb_new (&many);
+  sb_build (&many, count * one.len);
   while (count-- > 0)
     sb_add_sb (&many, &one);
 
   while (count-- > 0)
     sb_add_sb (&many, &one);
 
@@ -2992,10 +3076,10 @@ do_repeat (int count, const char *start, const char *end)
 }
 
 /* Like do_repeat except that any text matching EXPANDER in the
 }
 
 /* Like do_repeat except that any text matching EXPANDER in the
-   block is replaced by the itteration count.  */
+   block is replaced by the iteration count.  */
 
 void
 
 void
-do_repeat_with_expander (int count,
+do_repeat_with_expander (size_t count,
                         const char * start,
                         const char * end,
                         const char * expander)
                         const char * start,
                         const char * end,
                         const char * expander)
@@ -3003,6 +3087,12 @@ do_repeat_with_expander (int count,
   sb one;
   sb many;
 
   sb one;
   sb many;
 
+  if (((ssize_t) count) < 0)
+    {
+      as_bad (_("negative count for %s - ignored"), start);
+      count = 0;
+    }
+
   sb_new (&one);
   if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
     {
   sb_new (&one);
   if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
     {
@@ -3020,12 +3110,13 @@ do_repeat_with_expander (int count,
          char * sub;
          sb processed;
 
          char * sub;
          sb processed;
 
-         sb_new (& processed);
+         sb_build (& processed, one.len);
          sb_add_sb (& processed, & one);
          sub = strstr (processed.ptr, expander);
          sb_add_sb (& processed, & one);
          sub = strstr (processed.ptr, expander);
-         len = sprintf (sub, "%d", count);
+         len = sprintf (sub, "%lu", (unsigned long) count);
          gas_assert (len < 8);
          gas_assert (len < 8);
-         strcpy (sub + len, sub + 8);
+         memmove (sub + len, sub + 8,
+                  processed.ptr + processed.len - (sub + 8));
          processed.len -= (8 - len);
          sb_add_sb (& many, & processed);
          sb_kill (& processed);
          processed.len -= (8 - len);
          sb_add_sb (& many, & processed);
          sb_kill (& processed);
@@ -3088,13 +3179,13 @@ assign_symbol (char *name, int mode)
       if (listing & LISTING_SYMBOLS)
        {
          extern struct list_info_struct *listing_tail;
       if (listing & LISTING_SYMBOLS)
        {
          extern struct list_info_struct *listing_tail;
-         fragS *dummy_frag = (fragS *) xcalloc (1, sizeof (fragS));
+         fragS *dummy_frag = XCNEW (fragS);
          dummy_frag->line = listing_tail;
          dummy_frag->fr_symbol = symbolP;
          symbol_set_frag (symbolP, dummy_frag);
        }
 #endif
          dummy_frag->line = listing_tail;
          dummy_frag->fr_symbol = symbolP;
          symbol_set_frag (symbolP, dummy_frag);
        }
 #endif
-#ifdef OBJ_COFF
+#if defined (OBJ_COFF) && !defined (TE_PE)
       /* "set" symbols are local unless otherwise specified.  */
       SF_SET_LOCAL (symbolP);
 #endif
       /* "set" symbols are local unless otherwise specified.  */
       SF_SET_LOCAL (symbolP);
 #endif
@@ -3102,12 +3193,13 @@ assign_symbol (char *name, int mode)
 
   if (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
     {
 
   if (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
     {
-      /* Permit register names to be redefined.  */
       if ((mode != 0 || !S_IS_VOLATILE (symbolP))
       if ((mode != 0 || !S_IS_VOLATILE (symbolP))
-         && S_GET_SEGMENT (symbolP) != reg_section)
+         && !S_CAN_BE_REDEFINED (symbolP))
        {
          as_bad (_("symbol `%s' is already defined"), name);
        {
          as_bad (_("symbol `%s' is already defined"), name);
-         symbolP = symbol_clone (symbolP, 0);
+         ignore_rest_of_line ();
+         input_line_pointer--;
+         return;
        }
       /* If the symbol is volatile, copy the symbol and replace the
         original with the copy, so that previous uses of the symbol will
        }
       /* If the symbol is volatile, copy the symbol and replace the
         original with the copy, so that previous uses of the symbol will
@@ -3133,42 +3225,25 @@ void
 s_set (int equiv)
 {
   char *name;
 s_set (int equiv)
 {
   char *name;
-  char delim;
-  char *end_name;
 
   /* Especial apologies for the random logic:
      this just grew, and could be parsed much more simply!
      Dean in haste.  */
 
   /* Especial apologies for the random logic:
      this just grew, and could be parsed much more simply!
      Dean in haste.  */
-  name = input_line_pointer;
-  delim = get_symbol_end ();
-  end_name = input_line_pointer;
-  *end_name = delim;
-
-  if (name == end_name)
-    {
-      as_bad (_("expected symbol name"));
-      ignore_rest_of_line ();
-      return;
-    }
-
-  SKIP_WHITESPACE ();
+  if ((name = read_symbol_name ()) == NULL)
+    return;
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      *end_name = 0;
       as_bad (_("expected comma after \"%s\""), name);
       as_bad (_("expected comma after \"%s\""), name);
-      *end_name = delim;
       ignore_rest_of_line ();
       ignore_rest_of_line ();
+      free (name);
       return;
     }
 
   input_line_pointer++;
       return;
     }
 
   input_line_pointer++;
-  *end_name = 0;
-
   assign_symbol (name, equiv);
   assign_symbol (name, equiv);
-  *end_name = delim;
-
   demand_empty_rest_of_line ();
   demand_empty_rest_of_line ();
+  free (name);
 }
 
 void
 }
 
 void
@@ -3248,10 +3323,11 @@ s_space (int mult)
       val.X_add_number = 0;
     }
 
       val.X_add_number = 0;
     }
 
-  if (val.X_op != O_constant
-      || val.X_add_number < - 0x80
-      || val.X_add_number > 0xff
-      || (mult != 0 && mult != 1 && val.X_add_number != 0))
+  if ((val.X_op != O_constant
+       || val.X_add_number < - 0x80
+       || val.X_add_number > 0xff
+       || (mult != 0 && mult != 1 && val.X_add_number != 0))
+      && (now_seg != absolute_section && !in_bss ()))
     {
       resolve_expression (&exp);
       if (exp.X_op != O_constant)
     {
       resolve_expression (&exp);
       if (exp.X_op != O_constant)
@@ -3260,11 +3336,20 @@ s_space (int mult)
        {
          offsetT i;
 
        {
          offsetT i;
 
-         if (mult == 0)
-           mult = 1;
-         bytes = mult * exp.X_add_number;
-         for (i = 0; i < exp.X_add_number; i++)
-           emit_expr (&val, mult);
+         /* PR 20901: Check for excessive values.
+            FIXME: 1<<10 is an arbitrary limit.  Maybe use maxpagesize instead ?  */
+         if (exp.X_add_number < 0 || exp.X_add_number > (1 << 10))
+           as_bad (_("size value for space directive too large: %lx"),
+                   (long) exp.X_add_number);
+         else
+           {
+             if (mult == 0)
+               mult = 1;
+             bytes = mult * exp.X_add_number;
+
+             for (i = 0; i < exp.X_add_number; i++)
+               emit_expr (&val, mult);
+           }
        }
     }
   else
        }
     }
   else
@@ -3292,6 +3377,8 @@ s_space (int mult)
          /* If we are in the absolute section, just bump the offset.  */
          if (now_seg == absolute_section)
            {
          /* 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;
              goto getout;
            }
              abs_section_offset += repeat;
              goto getout;
            }
@@ -3329,7 +3416,10 @@ s_space (int mult)
                          make_expr_symbol (&exp), (offsetT) 0, (char *) 0);
        }
 
                          make_expr_symbol (&exp), (offsetT) 0, (char *) 0);
        }
 
-      if (p)
+      if ((val.X_op != O_constant || val.X_add_number != 0) && in_bss ())
+       as_warn (_("ignoring fill value in section `%s'"),
+                segment_name (now_seg));
+      else if (p)
        *p = val.X_add_number;
     }
 
        *p = val.X_add_number;
     }
 
@@ -3347,6 +3437,58 @@ s_space (int mult)
     mri_comment_end (stop, stopc);
 }
 
     mri_comment_end (stop, stopc);
 }
 
+void
+s_nops (int ignore ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+  expressionS val;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+#ifdef md_cons_align
+  md_cons_align (1);
+#endif
+
+  expression (&exp);
+
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      expression (&val);
+    }
+  else
+    {
+      val.X_op = O_constant;
+      val.X_add_number = 0;
+    }
+
+  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;
+       }
+    }
+  else
+    as_bad (_("unsupported variable nop control in .nops directive"));
+
+  demand_empty_rest_of_line ();
+}
+
 /* This is like s_space, but the value is a floating point number with
    the given precision.  This is for the MRI dcb.s pseudo-op and
    friends.  */
 /* This is like s_space, but the value is a floating point number with
    the given precision.  This is for the MRI dcb.s pseudo-op and
    friends.  */
@@ -3404,7 +3546,7 @@ s_float_space (int float_type)
     }
   else
     {
     }
   else
     {
-      char *err;
+      const char *err;
 
       err = md_atof (float_type, temp, &flen);
       know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
 
       err = md_atof (float_type, temp, &flen);
       know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
@@ -3464,9 +3606,6 @@ s_text (int ignore ATTRIBUTE_UNUSED)
   temp = get_absolute_expression ();
   subseg_set (text_section, (subsegT) temp);
   demand_empty_rest_of_line ();
   temp = get_absolute_expression ();
   subseg_set (text_section, (subsegT) temp);
   demand_empty_rest_of_line ();
-#ifdef OBJ_VMS
-  const_flag &= ~IN_DEFAULT_SECTION;
-#endif
 }
 
 /* .weakref x, y sets x as an alias to y that, as long as y is not
 }
 
 /* .weakref x, y sets x as an alias to y that, as long as y is not
@@ -3475,23 +3614,12 @@ void
 s_weakref (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
 s_weakref (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
-  char delim;
-  char *end_name;
   symbolS *symbolP;
   symbolS *symbolP2;
   expressionS exp;
 
   symbolS *symbolP;
   symbolS *symbolP2;
   expressionS exp;
 
-  name = input_line_pointer;
-  delim = get_symbol_end ();
-  end_name = input_line_pointer;
-
-  if (name == end_name)
-    {
-      as_bad (_("expected symbol name"));
-      *end_name = delim;
-      ignore_rest_of_line ();
-      return;
-    }
+  if ((name = read_symbol_name ()) == NULL)
+    return;
 
   symbolP = symbol_find_or_make (name);
 
 
   symbolP = symbol_find_or_make (name);
 
@@ -3500,41 +3628,27 @@ s_weakref (int ignore ATTRIBUTE_UNUSED)
       if (!S_IS_VOLATILE (symbolP))
        {
          as_bad (_("symbol `%s' is already defined"), name);
       if (!S_IS_VOLATILE (symbolP))
        {
          as_bad (_("symbol `%s' is already defined"), name);
-         *end_name = delim;
-         ignore_rest_of_line ();
-         return;
+         goto err_out;
        }
       symbolP = symbol_clone (symbolP, 1);
       S_CLEAR_VOLATILE (symbolP);
     }
 
        }
       symbolP = symbol_clone (symbolP, 1);
       S_CLEAR_VOLATILE (symbolP);
     }
 
-  *end_name = delim;
-
   SKIP_WHITESPACE ();
 
   if (*input_line_pointer != ',')
     {
   SKIP_WHITESPACE ();
 
   if (*input_line_pointer != ',')
     {
-      *end_name = 0;
       as_bad (_("expected comma after \"%s\""), name);
       as_bad (_("expected comma after \"%s\""), name);
-      *end_name = delim;
-      ignore_rest_of_line ();
-      return;
+      goto err_out;
     }
 
   input_line_pointer++;
 
   SKIP_WHITESPACE ();
     }
 
   input_line_pointer++;
 
   SKIP_WHITESPACE ();
+  free (name);
 
 
-  name = input_line_pointer;
-  delim = get_symbol_end ();
-  end_name = input_line_pointer;
-
-  if (name == end_name)
-    {
-      as_bad (_("expected symbol name"));
-      ignore_rest_of_line ();
-      return;
-    }
+  if ((name = read_symbol_name ()) == NULL)
+    return;
 
   if ((symbolP2 = symbol_find_noref (name, 1)) == NULL
       && (symbolP2 = md_undefined_symbol (name)) == NULL)
 
   if ((symbolP2 = symbol_find_noref (name, 1)) == NULL
       && (symbolP2 = md_undefined_symbol (name)) == NULL)
@@ -3565,6 +3679,7 @@ s_weakref (int ignore ATTRIBUTE_UNUSED)
          while (symp != symbolP)
            {
              char *old_loop = loop;
          while (symp != symbolP)
            {
              char *old_loop = loop;
+
              symp = symbol_get_value_expression (symp)->X_add_symbol;
              loop = concat (loop, " => ", S_GET_NAME (symp),
                             (const char *) NULL);
              symp = symbol_get_value_expression (symp)->X_add_symbol;
              loop = concat (loop, " => ", S_GET_NAME (symp),
                             (const char *) NULL);
@@ -3575,8 +3690,7 @@ s_weakref (int ignore ATTRIBUTE_UNUSED)
                  S_GET_NAME (symbolP), loop);
 
          free (loop);
                  S_GET_NAME (symbolP), loop);
 
          free (loop);
-
-         *end_name = delim;
+         free (name);
          ignore_rest_of_line ();
          return;
        }
          ignore_rest_of_line ();
          return;
        }
@@ -3587,8 +3701,6 @@ s_weakref (int ignore ATTRIBUTE_UNUSED)
       /* symbolP2 = symp; */
     }
 
       /* symbolP2 = symp; */
     }
 
-  *end_name = delim;
-
   memset (&exp, 0, sizeof (exp));
   exp.X_op = O_symbol;
   exp.X_add_symbol = symbolP2;
   memset (&exp, 0, sizeof (exp));
   exp.X_op = O_symbol;
   exp.X_add_symbol = symbolP2;
@@ -3599,6 +3711,13 @@ s_weakref (int ignore ATTRIBUTE_UNUSED)
   S_SET_WEAKREFR (symbolP);
 
   demand_empty_rest_of_line ();
   S_SET_WEAKREFR (symbolP);
 
   demand_empty_rest_of_line ();
+  free (name);
+  return;
+
+ err_out:
+  ignore_rest_of_line ();
+  free (name);
+  return;
 }
 \f
 
 }
 \f
 
@@ -3621,7 +3740,7 @@ demand_empty_rest_of_line (void)
                 *input_line_pointer);
       ignore_rest_of_line ();
     }
                 *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]]);
 }
   /* Return pointing just after end-of-line.  */
   know (is_end_of_line[(unsigned char) input_line_pointer[-1]]);
 }
@@ -3639,7 +3758,8 @@ ignore_rest_of_line (void)
   input_line_pointer++;
 
   /* Return pointing just after end-of-line.  */
   input_line_pointer++;
 
   /* Return pointing just after end-of-line.  */
-  know (is_end_of_line[(unsigned char) input_line_pointer[-1]]);
+  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
 }
 
 /* Sets frag for given symbol to zero_address_frag, except when the
@@ -3745,7 +3865,7 @@ pseudo_set (symbolS *symbolP)
          symbolS *s = exp.X_add_symbol;
 
          if (S_IS_COMMON (s))
          symbolS *s = exp.X_add_symbol;
 
          if (S_IS_COMMON (s))
-           as_bad (_("`%s' can't be equated to common symbol '%s'"),
+           as_bad (_("`%s' can't be equated to common symbol `%s'"),
                    S_GET_NAME (symbolP), S_GET_NAME (s));
 
          S_SET_SEGMENT (symbolP, seg);
                    S_GET_NAME (symbolP), S_GET_NAME (s));
 
          S_SET_SEGMENT (symbolP, seg);
@@ -3787,7 +3907,6 @@ pseudo_set (symbolS *symbolP)
 /* Some targets need to parse the expression in various fancy ways.
    You can define TC_PARSE_CONS_EXPRESSION to do whatever you like
    (for example, the HPPA does this).  Otherwise, you can define
 /* Some targets need to parse the expression in various fancy ways.
    You can define TC_PARSE_CONS_EXPRESSION to do whatever you like
    (for example, the HPPA does this).  Otherwise, you can define
-   BITFIELD_CONS_EXPRESSIONS to permit bitfields to be specified, or
    REPEAT_CONS_EXPRESSIONS to permit repeat counts.  If none of these
    are defined, which is the normal case, then only simple expressions
    are permitted.  */
    REPEAT_CONS_EXPRESSIONS to permit repeat counts.  If none of these
    are defined, which is the normal case, then only simple expressions
    are permitted.  */
@@ -3798,20 +3917,17 @@ parse_mri_cons (expressionS *exp, unsigned int nbytes);
 #endif
 
 #ifndef TC_PARSE_CONS_EXPRESSION
 #endif
 
 #ifndef TC_PARSE_CONS_EXPRESSION
-#ifdef BITFIELD_CONS_EXPRESSIONS
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES)
-static void
-parse_bitfield_cons (expressionS *exp, unsigned int nbytes);
-#endif
 #ifdef REPEAT_CONS_EXPRESSIONS
 #ifdef REPEAT_CONS_EXPRESSIONS
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES)
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+  (parse_repeat_cons (EXP, NBYTES), TC_PARSE_CONS_RETURN_NONE)
 static void
 parse_repeat_cons (expressionS *exp, unsigned int nbytes);
 #endif
 
 /* If we haven't gotten one yet, just call expression.  */
 #ifndef TC_PARSE_CONS_EXPRESSION
 static void
 parse_repeat_cons (expressionS *exp, unsigned int nbytes);
 #endif
 
 /* If we haven't gotten one yet, just call expression.  */
 #ifndef TC_PARSE_CONS_EXPRESSION
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) expression (EXP)
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+  (expression (EXP), TC_PARSE_CONS_RETURN_NONE)
 #endif
 #endif
 
 #endif
 #endif
 
@@ -3819,7 +3935,7 @@ void
 do_parse_cons_expression (expressionS *exp,
                          int nbytes ATTRIBUTE_UNUSED)
 {
 do_parse_cons_expression (expressionS *exp,
                          int nbytes ATTRIBUTE_UNUSED)
 {
-  TC_PARSE_CONS_EXPRESSION (exp, nbytes);
+  (void) TC_PARSE_CONS_EXPRESSION (exp, nbytes);
 }
 
 
 }
 
 
@@ -3862,19 +3978,29 @@ cons_worker (int nbytes,        /* 1=.byte, 2=.word, 4=.long.  */
   c = 0;
   do
     {
   c = 0;
   do
     {
+      TC_PARSE_CONS_RETURN_TYPE ret = TC_PARSE_CONS_RETURN_NONE;
+#ifdef TC_CONS_FIX_CHECK
+      fixS **cur_fix = &frchain_now->fix_tail;
+
+      if (*cur_fix != NULL)
+       cur_fix = &(*cur_fix)->fx_next;
+#endif
+
 #ifdef TC_M68K
       if (flag_m68k_mri)
        parse_mri_cons (&exp, (unsigned int) nbytes);
       else
 #endif
 #ifdef TC_M68K
       if (flag_m68k_mri)
        parse_mri_cons (&exp, (unsigned int) nbytes);
       else
 #endif
-        {
+       {
+#if 0
          if (*input_line_pointer == '"')
            {
              as_bad (_("unexpected `\"' in expression"));
              ignore_rest_of_line ();
              return;
            }
          if (*input_line_pointer == '"')
            {
              as_bad (_("unexpected `\"' in expression"));
              ignore_rest_of_line ();
              return;
            }
-         TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes);
+#endif
+         ret = TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes);
        }
 
       if (rva)
        }
 
       if (rva)
@@ -3884,7 +4010,10 @@ cons_worker (int nbytes, /* 1=.byte, 2=.word, 4=.long.  */
          else
            as_fatal (_("rva without symbol"));
        }
          else
            as_fatal (_("rva without symbol"));
        }
-      emit_expr (&exp, (unsigned int) nbytes);
+      emit_expr_with_reloc (&exp, (unsigned int) nbytes, ret);
+#ifdef TC_CONS_FIX_CHECK
+      TC_CONS_FIX_CHECK (&exp, nbytes, *cur_fix);
+#endif
       ++c;
     }
   while (*input_line_pointer++ == ',');
       ++c;
     }
   while (*input_line_pointer++ == ',');
@@ -3917,7 +4046,7 @@ s_rva (int size)
 
 /* .reloc offset, reloc_name, symbol+addend.  */
 
 
 /* .reloc offset, reloc_name, symbol+addend.  */
 
-void
+static void
 s_reloc (int ignore ATTRIBUTE_UNUSED)
 {
   char *stop = NULL;
 s_reloc (int ignore ATTRIBUTE_UNUSED)
 {
   char *stop = NULL;
@@ -3926,8 +4055,17 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
   char *r_name;
   int c;
   struct reloc_list *reloc;
   char *r_name;
   int c;
   struct reloc_list *reloc;
+  struct _bfd_rel { const char * name; bfd_reloc_code_real_type code; };
+  static struct _bfd_rel bfd_relocs[] =
+  {
+    { "NONE", BFD_RELOC_NONE },
+    { "8",  BFD_RELOC_8 },
+    { "16", BFD_RELOC_16 },
+    { "32", BFD_RELOC_32 },
+    { "64", BFD_RELOC_64 }
+  };
 
 
-  reloc = (struct reloc_list *) xmalloc (sizeof (*reloc));
+  reloc = XNEW (struct reloc_list);
 
   if (flag_mri)
     stop = mri_comment_field (&stopc);
 
   if (flag_mri)
     stop = mri_comment_field (&stopc);
@@ -3944,14 +4082,14 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
     case O_constant:
       exp.X_add_symbol = section_symbol (now_seg);
       exp.X_op = O_symbol;
     case O_constant:
       exp.X_add_symbol = section_symbol (now_seg);
       exp.X_op = O_symbol;
-      /* Fall thru */
+      /* Fallthru */
     case O_symbol:
       if (exp.X_add_number == 0)
        {
          reloc->u.a.offset_sym = exp.X_add_symbol;
          break;
        }
     case O_symbol:
       if (exp.X_add_number == 0)
        {
          reloc->u.a.offset_sym = exp.X_add_symbol;
          break;
        }
-      /* Fall thru */
+      /* Fallthru */
     default:
       reloc->u.a.offset_sym = make_expr_symbol (&exp);
       break;
     default:
       reloc->u.a.offset_sym = make_expr_symbol (&exp);
       break;
@@ -3966,9 +4104,21 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
 
   ++input_line_pointer;
   SKIP_WHITESPACE ();
 
   ++input_line_pointer;
   SKIP_WHITESPACE ();
-  r_name = input_line_pointer;
-  c = get_symbol_end ();
-  reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, r_name);
+  c = get_symbol_name (& r_name);
+  if (strncasecmp (r_name, "BFD_RELOC_", 10) == 0)
+    {
+      unsigned int i;
+
+      for (reloc->u.a.howto = NULL, i = 0; i < ARRAY_SIZE (bfd_relocs); i++)
+       if (strcasecmp (r_name + 10, bfd_relocs[i].name) == 0)
+         {
+           reloc->u.a.howto = bfd_reloc_type_lookup (stdoutput,
+                                                     bfd_relocs[i].code);
+           break;
+         }
+    }
+  else
+    reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, r_name);
   *input_line_pointer = c;
   if (reloc->u.a.howto == NULL)
     {
   *input_line_pointer = c;
   if (reloc->u.a.howto == NULL)
     {
@@ -3977,7 +4127,7 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
     }
 
   exp.X_op = O_absent;
     }
 
   exp.X_op = O_absent;
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
   if (*input_line_pointer == ',')
     {
       ++input_line_pointer;
   if (*input_line_pointer == ',')
     {
       ++input_line_pointer;
@@ -4013,7 +4163,7 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
       break;
     }
 
       break;
     }
 
-  as_where (&reloc->file, &reloc->line);
+  reloc->file = as_where (&reloc->line);
   reloc->next = reloc_list;
   reloc_list = reloc;
 
   reloc->next = reloc_list;
   reloc_list = reloc;
 
@@ -4027,6 +4177,14 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
 
 void
 emit_expr (expressionS *exp, unsigned int nbytes)
 
 void
 emit_expr (expressionS *exp, unsigned int nbytes)
+{
+  emit_expr_with_reloc (exp, nbytes, TC_PARSE_CONS_RETURN_NONE);
+}
+
+void
+emit_expr_with_reloc (expressionS *exp,
+                     unsigned int nbytes,
+                     TC_PARSE_CONS_RETURN_TYPE reloc)
 {
   operatorT op;
   char *p;
 {
   operatorT op;
   char *p;
@@ -4036,10 +4194,9 @@ emit_expr (expressionS *exp, unsigned int nbytes)
   if (need_pass_2)
     return;
 
   if (need_pass_2)
     return;
 
-  /* Grow the current frag now so that dot_value does not get invalidated
-     if the frag were to fill up in the frag_more() call below.  */
   frag_grow (nbytes);
   dot_value = frag_now_fix ();
   frag_grow (nbytes);
   dot_value = frag_now_fix ();
+  dot_frag = frag_now;
 
 #ifndef NO_LISTING
 #ifdef OBJ_ELF
 
 #ifndef NO_LISTING
 #ifdef OBJ_ELF
@@ -4110,15 +4267,6 @@ emit_expr (expressionS *exp, unsigned int nbytes)
 
   op = exp->X_op;
 
 
   op = exp->X_op;
 
-  /* Allow `.word 0' in the absolute section.  */
-  if (now_seg == absolute_section)
-    {
-      if (op != O_constant || exp->X_add_number != 0)
-       as_bad (_("attempt to store value in absolute section"));
-      abs_section_offset += nbytes;
-      return;
-    }
-
   /* Handle a negative bignum.  */
   if (op == O_uminus
       && exp->X_add_number == 0
   /* Handle a negative bignum.  */
   if (op == O_uminus
       && exp->X_add_number == 0
@@ -4168,8 +4316,28 @@ emit_expr (expressionS *exp, unsigned int nbytes)
       op = O_constant;
     }
 
       op = O_constant;
     }
 
+  /* Allow `.word 0' in the absolute section.  */
+  if (now_seg == absolute_section)
+    {
+      if (op != O_constant || exp->X_add_number != 0)
+       as_bad (_("attempt to store value in absolute section"));
+      abs_section_offset += nbytes;
+      return;
+    }
+
+  /* Allow `.word 0' in BSS style sections.  */
+  if ((op != O_constant || exp->X_add_number != 0) && in_bss ())
+    as_bad (_("attempt to store non-zero value in section `%s'"),
+           segment_name (now_seg));
+
   p = frag_more ((int) nbytes);
 
   p = frag_more ((int) nbytes);
 
+  if (reloc != TC_PARSE_CONS_RETURN_NONE)
+    {
+      emit_expr_fix (exp, nbytes, frag_now, p, reloc);
+      return;
+    }
+
 #ifndef WORKING_DOT_WORD
   /* If we have the difference of two symbols in a word, save it on
      the broken_words list.  See the code in write.c.  */
 #ifndef WORKING_DOT_WORD
   /* If we have the difference of two symbols in a word, save it on
      the broken_words list.  See the code in write.c.  */
@@ -4177,7 +4345,7 @@ emit_expr (expressionS *exp, unsigned int nbytes)
     {
       struct broken_word *x;
 
     {
       struct broken_word *x;
 
-      x = (struct broken_word *) xmalloc (sizeof (struct broken_word));
+      x = XNEW (struct broken_word);
       x->next_broken_word = broken_words;
       broken_words = x;
       x->seg = now_seg;
       x->next_broken_word = broken_words;
       broken_words = x;
       x->seg = now_seg;
@@ -4200,7 +4368,7 @@ emit_expr (expressionS *exp, unsigned int nbytes)
   if (op == O_constant && nbytes > sizeof (valueT))
     {
       extra_digit = exp->X_unsigned ? 0 : -1;
   if (op == O_constant && nbytes > sizeof (valueT))
     {
       extra_digit = exp->X_unsigned ? 0 : -1;
-      convert_to_bignum (exp);
+      convert_to_bignum (exp, !exp->X_unsigned);
       op = O_big;
     }
 
       op = O_big;
     }
 
@@ -4241,7 +4409,8 @@ emit_expr (expressionS *exp, unsigned int nbytes)
       if ((get & mask) != 0
          && ((get & mask) != mask
              || (get & hibit) == 0))
       if ((get & mask) != 0
          && ((get & mask) != mask
              || (get & hibit) == 0))
-       {               /* Leading bits contain both 0s & 1s.  */
+       {
+         /* Leading bits contain both 0s & 1s.  */
 #if defined (BFD64) && BFD_HOST_64BIT_LONG_LONG
 #ifndef __MSVCRT__
          as_warn (_("value 0x%llx truncated to 0x%llx"),
 #if defined (BFD64) && BFD_HOST_64BIT_LONG_LONG
 #ifndef __MSVCRT__
          as_warn (_("value 0x%llx truncated to 0x%llx"),
@@ -4267,18 +4436,39 @@ emit_expr (expressionS *exp, unsigned int nbytes)
       if (nbytes < size)
        {
          int i = nbytes / CHARS_PER_LITTLENUM;
       if (nbytes < size)
        {
          int i = nbytes / CHARS_PER_LITTLENUM;
+
          if (i != 0)
            {
              LITTLENUM_TYPE sign = 0;
              if ((generic_bignum[--i]
                   & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) != 0)
                sign = ~(LITTLENUM_TYPE) 0;
          if (i != 0)
            {
              LITTLENUM_TYPE sign = 0;
              if ((generic_bignum[--i]
                   & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) != 0)
                sign = ~(LITTLENUM_TYPE) 0;
+
              while (++i < exp->X_add_number)
                if (generic_bignum[i] != sign)
                  break;
            }
              while (++i < exp->X_add_number)
                if (generic_bignum[i] != sign)
                  break;
            }
+         else if (nbytes == 1)
+           {
+             /* We have nbytes == 1 and CHARS_PER_LITTLENUM == 2 (probably).
+                Check that bits 8.. of generic_bignum[0] match bit 7
+                and that they match all of generic_bignum[1..exp->X_add_number].  */
+             LITTLENUM_TYPE sign = (generic_bignum[0] & (1 << 7)) ? -1 : 0;
+             LITTLENUM_TYPE himask = LITTLENUM_MASK & ~ 0xFF;
+
+             if ((generic_bignum[0] & himask) == (sign & himask))
+               {
+                 while (++i < exp->X_add_number)
+                   if (generic_bignum[i] != sign)
+                     break;
+               }
+           }
+
          if (i < exp->X_add_number)
          if (i < exp->X_add_number)
-           as_warn (_("bignum truncated to %d bytes"), nbytes);
+           as_warn (ngettext ("bignum truncated to %d byte",
+                              "bignum truncated to %d bytes",
+                              nbytes),
+                    nbytes);
          size = nbytes;
        }
 
          size = nbytes;
        }
 
@@ -4328,23 +4518,43 @@ emit_expr (expressionS *exp, unsigned int nbytes)
        }
     }
   else
        }
     }
   else
-    emit_expr_fix (exp, nbytes, frag_now, p);
+    emit_expr_fix (exp, nbytes, frag_now, p, TC_PARSE_CONS_RETURN_NONE);
 }
 
 void
 }
 
 void
-emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p)
+emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p,
+              TC_PARSE_CONS_RETURN_TYPE r ATTRIBUTE_UNUSED)
 {
 {
-  memset (p, 0, nbytes);
+  int offset = 0;
+  unsigned int size = nbytes;
+
+  memset (p, 0, size);
 
   /* Generate a fixS to record the symbol value.  */
 
 #ifdef TC_CONS_FIX_NEW
 
   /* Generate a fixS to record the symbol value.  */
 
 #ifdef TC_CONS_FIX_NEW
-  TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp);
+  TC_CONS_FIX_NEW (frag, p - frag->fr_literal + offset, size, exp, r);
 #else
 #else
-  {
-    bfd_reloc_code_real_type r;
+  if (r != TC_PARSE_CONS_RETURN_NONE)
+    {
+      reloc_howto_type *reloc_howto;
+
+      reloc_howto = bfd_reloc_type_lookup (stdoutput, r);
+      size = bfd_get_reloc_size (reloc_howto);
 
 
-    switch (nbytes)
+      if (size > nbytes)
+       {
+         as_bad (ngettext ("%s relocations do not fit in %u byte",
+                           "%s relocations do not fit in %u bytes",
+                           nbytes),
+                 reloc_howto->name, nbytes);
+         return;
+       }
+      else if (target_big_endian)
+       offset = nbytes - size;
+    }
+  else
+    switch (size)
       {
       case 1:
        r = BFD_RELOC_8;
       {
       case 1:
        r = BFD_RELOC_8;
@@ -4362,156 +4572,25 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p)
        r = BFD_RELOC_64;
        break;
       default:
        r = BFD_RELOC_64;
        break;
       default:
-       as_bad (_("unsupported BFD relocation size %u"), nbytes);
-       r = BFD_RELOC_32;
-       break;
+       as_bad (_("unsupported BFD relocation size %u"), size);
+       return;
       }
       }
-    fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp,
-                0, r);
-  }
+  fix_new_exp (frag, p - frag->fr_literal + offset, size,
+              exp, 0, r);
 #endif
 }
 \f
 #endif
 }
 \f
-#ifdef BITFIELD_CONS_EXPRESSIONS
-
-/* i960 assemblers, (eg, asm960), allow bitfields after ".byte" as
-   w:x,y:z, where w and y are bitwidths and x and y are values.  They
-   then pack them all together. We do a little better in that we allow
-   them in words, longs, etc. and we'll pack them in target byte order
-   for you.
-
-   The rules are: pack least significant bit first, if a field doesn't
-   entirely fit, put it in the next unit.  Overflowing the bitfield is
-   explicitly *not* even a warning.  The bitwidth should be considered
-   a "mask".
-
-   To use this function the tc-XXX.h file should define
-   BITFIELD_CONS_EXPRESSIONS.  */
-
-static void
-parse_bitfield_cons (exp, nbytes)
-     expressionS *exp;
-     unsigned int nbytes;
-{
-  unsigned int bits_available = BITS_PER_CHAR * nbytes;
-  char *hold = input_line_pointer;
-
-  (void) expression (exp);
-
-  if (*input_line_pointer == ':')
-    {
-      /* Bitfields.  */
-      long value = 0;
-
-      for (;;)
-       {
-         unsigned long width;
-
-         if (*input_line_pointer != ':')
-           {
-             input_line_pointer = hold;
-             break;
-           }                   /* Next piece is not a bitfield.  */
-
-         /* In the general case, we can't allow
-            full expressions with symbol
-            differences and such.  The relocation
-            entries for symbols not defined in this
-            assembly would require arbitrary field
-            widths, positions, and masks which most
-            of our current object formats don't
-            support.
-
-            In the specific case where a symbol
-            *is* defined in this assembly, we
-            *could* build fixups and track it, but
-            this could lead to confusion for the
-            backends.  I'm lazy. I'll take any
-            SEG_ABSOLUTE. I think that means that
-            you can use a previous .set or
-            .equ type symbol.  xoxorich.  */
-
-         if (exp->X_op == O_absent)
-           {
-             as_warn (_("using a bit field width of zero"));
-             exp->X_add_number = 0;
-             exp->X_op = O_constant;
-           }                   /* Implied zero width bitfield.  */
-
-         if (exp->X_op != O_constant)
-           {
-             *input_line_pointer = '\0';
-             as_bad (_("field width \"%s\" too complex for a bitfield"), hold);
-             *input_line_pointer = ':';
-             demand_empty_rest_of_line ();
-             return;
-           }                   /* Too complex.  */
-
-         if ((width = exp->X_add_number) > (BITS_PER_CHAR * nbytes))
-           {
-             as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"),
-                      width, nbytes, (BITS_PER_CHAR * nbytes));
-             width = BITS_PER_CHAR * nbytes;
-           }                   /* Too big.  */
-
-         if (width > bits_available)
-           {
-             /* FIXME-SOMEDAY: backing up and reparsing is wasteful.  */
-             input_line_pointer = hold;
-             exp->X_add_number = value;
-             break;
-           }                   /* Won't fit.  */
-
-         /* Skip ':'.  */
-         hold = ++input_line_pointer;
-
-         (void) expression (exp);
-         if (exp->X_op != O_constant)
-           {
-             char cache = *input_line_pointer;
-
-             *input_line_pointer = '\0';
-             as_bad (_("field value \"%s\" too complex for a bitfield"), hold);
-             *input_line_pointer = cache;
-             demand_empty_rest_of_line ();
-             return;
-           }                   /* Too complex.  */
-
-         value |= ((~(-1 << width) & exp->X_add_number)
-                   << ((BITS_PER_CHAR * nbytes) - bits_available));
-
-         if ((bits_available -= width) == 0
-             || is_it_end_of_statement ()
-             || *input_line_pointer != ',')
-           {
-             break;
-           }                   /* All the bitfields we're gonna get.  */
-
-         hold = ++input_line_pointer;
-         (void) expression (exp);
-       }
-
-      exp->X_add_number = value;
-      exp->X_op = O_constant;
-      exp->X_unsigned = 1;
-    }
-}
-
-#endif /* BITFIELD_CONS_EXPRESSIONS */
-\f
 /* Handle an MRI style string expression.  */
 
 #ifdef TC_M68K
 static void
 /* Handle an MRI style string expression.  */
 
 #ifdef TC_M68K
 static void
-parse_mri_cons (exp, nbytes)
-     expressionS *exp;
-     unsigned int nbytes;
+parse_mri_cons (expressionS *exp, unsigned int nbytes)
 {
   if (*input_line_pointer != '\''
       && (input_line_pointer[1] != '\''
          || (*input_line_pointer != 'A'
              && *input_line_pointer != 'E')))
 {
   if (*input_line_pointer != '\''
       && (input_line_pointer[1] != '\''
          || (*input_line_pointer != 'A'
              && *input_line_pointer != 'E')))
-    TC_PARSE_CONS_EXPRESSION (exp, nbytes);
+    (void) TC_PARSE_CONS_EXPRESSION (exp, nbytes);
   else
     {
       unsigned int scan;
   else
     {
       unsigned int scan;
@@ -4577,9 +4656,7 @@ parse_mri_cons (exp, nbytes)
    To use this for a target, define REPEAT_CONS_EXPRESSIONS.  */
 
 static void
    To use this for a target, define REPEAT_CONS_EXPRESSIONS.  */
 
 static void
-parse_repeat_cons (exp, nbytes)
-     expressionS *exp;
-     unsigned int nbytes;
+parse_repeat_cons (expressionS *exp, unsigned int nbytes)
 {
   expressionS count;
   int i;
 {
   expressionS count;
   int i;
@@ -4721,7 +4798,7 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line.  */
 {
   char *p;
   int length;                  /* Number of chars in an object.  */
 {
   char *p;
   int length;                  /* Number of chars in an object.  */
-  char *err;           /* Error from scanning floating literal.  */
+  const char *err;             /* Error from scanning floating literal.  */
   char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
 
   if (is_it_end_of_statement ())
   char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
 
   if (is_it_end_of_statement ())
@@ -4730,6 +4807,21 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line.  */
       return;
     }
 
       return;
     }
 
+  if (now_seg == absolute_section)
+    {
+      as_bad (_("attempt to store float in absolute section"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  if (in_bss ())
+    {
+      as_bad (_("attempt to store float in section `%s'"),
+             segment_name (now_seg));
+      ignore_rest_of_line ();
+      return;
+    }
+
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
 #endif
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
 #endif
@@ -4813,9 +4905,25 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line.  */
   demand_empty_rest_of_line ();
 }
 \f
   demand_empty_rest_of_line ();
 }
 \f
-/* Return the size of a LEB128 value.  */
+/* LEB128 Encoding.
 
 
-static inline int
+   Note - we are using the DWARF standard's definition of LEB128 encoding
+   where each 7-bit value is a stored in a byte, *not* an octet.  This
+   means that on targets where a byte contains multiple octets there is
+   a *huge waste of space*.  (This also means that we do not have to
+   have special versions of these functions for when OCTETS_PER_BYTE_POWER
+   is non-zero).
+
+   If the 7-bit values were to be packed into N-bit bytes (where N > 8)
+   we would then have to consider whether multiple, successive LEB128
+   values should be packed into the bytes without padding (bad idea) or
+   whether each LEB128 number is padded out to a whole number of bytes.
+   Plus you have to decide on the endianness of packing octets into a
+   byte.  */
+
+/* Return the size of a LEB128 value in bytes.  */
+
+static inline unsigned int
 sizeof_sleb128 (offsetT value)
 {
   int size = 0;
 sizeof_sleb128 (offsetT value)
 {
   int size = 0;
@@ -4836,7 +4944,7 @@ sizeof_sleb128 (offsetT value)
   return size;
 }
 
   return size;
 }
 
-static inline int
+static inline unsigned int
 sizeof_uleb128 (valueT value)
 {
   int size = 0;
 sizeof_uleb128 (valueT value)
 {
   int size = 0;
@@ -4851,7 +4959,7 @@ sizeof_uleb128 (valueT value)
   return size;
 }
 
   return size;
 }
 
-int
+unsigned int
 sizeof_leb128 (valueT value, int sign)
 {
   if (sign)
 sizeof_leb128 (valueT value, int sign)
 {
   if (sign)
@@ -4860,9 +4968,9 @@ sizeof_leb128 (valueT value, int sign)
     return sizeof_uleb128 (value);
 }
 
     return sizeof_uleb128 (value);
 }
 
-/* Output a LEB128 value.  */
+/* Output a LEB128 value.  Returns the number of bytes used.  */
 
 
-static inline int
+static inline unsigned int
 output_sleb128 (char *p, offsetT value)
 {
   char *orig = p;
 output_sleb128 (char *p, offsetT value)
 {
   char *orig = p;
@@ -4889,7 +4997,7 @@ output_sleb128 (char *p, offsetT value)
   return p - orig;
 }
 
   return p - orig;
 }
 
-static inline int
+static inline unsigned int
 output_uleb128 (char *p, valueT value)
 {
   char *orig = p;
 output_uleb128 (char *p, valueT value)
 {
   char *orig = p;
@@ -4897,6 +5005,7 @@ output_uleb128 (char *p, valueT value)
   do
     {
       unsigned byte = (value & 0x7f);
   do
     {
       unsigned byte = (value & 0x7f);
+
       value >>= 7;
       if (value != 0)
        /* More bytes to follow.  */
       value >>= 7;
       if (value != 0)
        /* More bytes to follow.  */
@@ -4909,7 +5018,7 @@ output_uleb128 (char *p, valueT value)
   return p - orig;
 }
 
   return p - orig;
 }
 
-int
+unsigned int
 output_leb128 (char *p, valueT value, int sign)
 {
   if (sign)
 output_leb128 (char *p, valueT value, int sign)
 {
   if (sign)
@@ -4920,10 +5029,11 @@ output_leb128 (char *p, valueT value, int sign)
 
 /* Do the same for bignums.  We combine sizeof with output here in that
    we don't output for NULL values of P.  It isn't really as critical as
 
 /* Do the same for bignums.  We combine sizeof with output here in that
    we don't output for NULL values of P.  It isn't really as critical as
-   for "normal" values that this be streamlined.  */
+   for "normal" values that this be streamlined.  Returns the number of
+   bytes used.  */
 
 
-static inline int
-output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
+static inline unsigned int
+output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size)
 {
   char *orig = p;
   valueT val = 0;
 {
   char *orig = p;
   valueT val = 0;
@@ -4968,7 +5078,7 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
     {
       /* Sign-extend VAL.  */
       if (val & (1 << (loaded - 1)))
     {
       /* Sign-extend VAL.  */
       if (val & (1 << (loaded - 1)))
-       val |= ~0 << loaded;
+       val |= ~0U << loaded;
       if (orig)
        *p = val & 0x7f;
       p++;
       if (orig)
        *p = val & 0x7f;
       p++;
@@ -4977,8 +5087,8 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
   return p - orig;
 }
 
   return p - orig;
 }
 
-static inline int
-output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
+static inline unsigned int
+output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size)
 {
   char *orig = p;
   valueT val = 0;
 {
   char *orig = p;
   valueT val = 0;
@@ -5016,8 +5126,8 @@ output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
   return p - orig;
 }
 
   return p - orig;
 }
 
-static int
-output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, int size, int sign)
+static unsigned int
+output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size, int sign)
 {
   if (sign)
     return output_big_sleb128 (p, bignum, size);
 {
   if (sign)
     return output_big_sleb128 (p, bignum, size);
@@ -5026,7 +5136,7 @@ output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, int size, int sign)
 }
 
 /* Generate the appropriate fragments for a given expression to emit a
 }
 
 /* Generate the appropriate fragments for a given expression to emit a
-   leb128 value.  */
+   leb128 value.  SIGN is 1 for sleb, 0 for uleb.  */
 
 static void
 emit_leb128_expr (expressionS *exp, int sign)
 
 static void
 emit_leb128_expr (expressionS *exp, int sign)
@@ -5053,15 +5163,27 @@ emit_leb128_expr (expressionS *exp, int sign)
     }
   else if (op == O_constant
           && sign
     }
   else if (op == O_constant
           && sign
-          && (exp->X_add_number < 0) != !exp->X_unsigned)
+          && (exp->X_add_number < 0) == !exp->X_extrabit)
     {
       /* 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.  */
     {
       /* 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);
+      convert_to_bignum (exp, exp->X_extrabit);
       op = O_big;
     }
 
       op = O_big;
     }
 
+  if (now_seg == absolute_section)
+    {
+      if (op != O_constant || exp->X_add_number != 0)
+       as_bad (_("attempt to store value in absolute section"));
+      abs_section_offset++;
+      return;
+    }
+
+  if ((op != O_constant || exp->X_add_number != 0) && in_bss ())
+    as_bad (_("attempt to store non-zero value in section `%s'"),
+           segment_name (now_seg));
+
   /* 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.  */
   nbytes = (unsigned int) -1;
   /* 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.  */
   nbytes = (unsigned int) -1;
@@ -5078,23 +5200,33 @@ emit_leb128_expr (expressionS *exp, int sign)
       /* If we've got a constant, emit the thing directly right now.  */
 
       valueT value = exp->X_add_number;
       /* If we've got a constant, emit the thing directly right now.  */
 
       valueT value = exp->X_add_number;
-      int size;
+      unsigned int size;
       char *p;
 
       size = sizeof_leb128 (value, sign);
       p = frag_more (size);
       char *p;
 
       size = sizeof_leb128 (value, sign);
       p = frag_more (size);
-      output_leb128 (p, value, sign);
+      if (output_leb128 (p, value, sign) > size)
+       abort ();
     }
   else if (op == O_big)
     {
       /* O_big is a different sort of constant.  */
     }
   else if (op == O_big)
     {
       /* O_big is a different sort of constant.  */
-
-      int size;
+      int nbr_digits = exp->X_add_number;
+      unsigned int size;
       char *p;
 
       char *p;
 
-      size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign);
+      /* If the leading littenum is 0xffff, prepend a 0 to avoid confusion with
+        a signed number.  Unary operators like - or ~ always extend the
+        bignum to its largest size.  */
+      if (exp->X_unsigned
+         && nbr_digits < SIZE_OF_LARGE_NUMBER
+         && generic_bignum[nbr_digits - 1] == LITTLENUM_MASK)
+       generic_bignum[nbr_digits++] = 0;
+
+      size = output_big_leb128 (NULL, generic_bignum, nbr_digits, sign);
       p = frag_more (size);
       p = frag_more (size);
-      output_big_leb128 (p, generic_bignum, exp->X_add_number, sign);
+      if (output_big_leb128 (p, generic_bignum, nbr_digits, sign) > size)
+       abort ();
     }
   else
     {
     }
   else
     {
@@ -5131,6 +5263,10 @@ s_leb128 (int sign)
 static void
 stringer_append_char (int c, int bitsize)
 {
 static void
 stringer_append_char (int c, int bitsize)
 {
+  if (c && in_bss ())
+    as_bad (_("attempt to store non-empty string in section `%s'"),
+           segment_name (now_seg));
+
   if (!target_big_endian)
     FRAG_APPEND_1_CHAR (c);
 
   if (!target_big_endian)
     FRAG_APPEND_1_CHAR (c);
 
@@ -5186,6 +5322,15 @@ stringer (int bits_appendzero)
   md_cons_align (1);
 #endif
 
   md_cons_align (1);
 #endif
 
+  /* If we have been switched into the abs_section then we
+     will not have an obstack onto which we can hang strings.  */
+  if (now_seg == absolute_section)
+    {
+      as_bad (_("strings must be placed into a section"));
+      ignore_rest_of_line ();
+      return;
+    }
+
   /* The following awkward logic is to parse ZERO or more strings,
      comma separated. Recall a string expression includes spaces
      before the opening '\"' and spaces after the closing '\"'.
   /* The following awkward logic is to parse ZERO or more strings,
      comma separated. Recall a string expression includes spaces
      before the opening '\"' and spaces after the closing '\"'.
@@ -5200,14 +5345,6 @@ stringer (int bits_appendzero)
     {
       c = ',';                 /* Do loop.  */
     }
     {
       c = ',';                 /* Do loop.  */
     }
-  /* If we have been switched into the abs_section then we
-     will not have an obstack onto which we can hang strings.  */
-  if (now_seg == absolute_section)
-    {
-      as_bad (_("strings must be placed into a section"));
-      c = 0;
-      ignore_rest_of_line ();
-    }
 
   while (c == ',' || c == '<' || c == '"')
     {
 
   while (c == ',' || c == '<' || c == '"')
     {
@@ -5226,8 +5363,6 @@ stringer (int bits_appendzero)
          if (append_zero)
            stringer_append_char (0, bitsize);
 
          if (append_zero)
            stringer_append_char (0, bitsize);
 
-         know (input_line_pointer[-1] == '\"');
-
 #if !defined(NO_LISTING) && defined (OBJ_ELF)
          /* In ELF, when gcc is emitting DWARF 1 debugging output, it
             will emit .string with a filename in the .debug section
 #if !defined(NO_LISTING) && defined (OBJ_ELF)
          /* In ELF, when gcc is emitting DWARF 1 debugging output, it
             will emit .string with a filename in the .debug section
@@ -5252,8 +5387,11 @@ stringer (int bits_appendzero)
          c = get_single_number ();
          stringer_append_char (c, bitsize);
          if (*input_line_pointer != '>')
          c = get_single_number ();
          stringer_append_char (c, bitsize);
          if (*input_line_pointer != '>')
-           as_bad (_("expected <nn>"));
-
+           {
+             as_bad (_("expected <nn>"));
+             ignore_rest_of_line ();
+             return;
+           }
          input_line_pointer++;
          break;
        case ',':
          input_line_pointer++;
          break;
        case ',':
@@ -5280,6 +5418,12 @@ next_char_of_string (void)
   c = *input_line_pointer++ & CHAR_MASK;
   switch (c)
     {
   c = *input_line_pointer++ & CHAR_MASK;
   switch (c)
     {
+    case 0:
+      /* PR 20902: Do not advance past the end of the buffer.  */
+      -- input_line_pointer;
+      c = NOT_A_CHAR;
+      break;
+
     case '\"':
       c = NOT_A_CHAR;
       break;
     case '\"':
       c = NOT_A_CHAR;
       break;
@@ -5289,9 +5433,10 @@ next_char_of_string (void)
       bump_line_counters ();
       break;
 
       bump_line_counters ();
       break;
 
-#ifndef NO_STRING_ESCAPES
     case '\\':
     case '\\':
-      switch (c = *input_line_pointer++)
+      if (!TC_STRING_ESCAPES)
+       break;
+      switch (c = *input_line_pointer++ & CHAR_MASK)
        {
        case 'b':
          c = '\b';
        {
        case 'b':
          c = '\b';
@@ -5342,7 +5487,7 @@ next_char_of_string (void)
                number = number * 8 + c - '0';
              }
 
                number = number * 8 + c - '0';
              }
 
-           c = number & 0xff;
+           c = number & CHAR_MASK;
          }
          --input_line_pointer;
          break;
          }
          --input_line_pointer;
          break;
@@ -5364,7 +5509,7 @@ next_char_of_string (void)
                  number = number * 16 + c - 'a' + 10;
                c = *input_line_pointer++;
              }
                  number = number * 16 + c - 'a' + 10;
                c = *input_line_pointer++;
              }
-           c = number & 0xff;
+           c = number & CHAR_MASK;
            --input_line_pointer;
          }
          break;
            --input_line_pointer;
          }
          break;
@@ -5376,6 +5521,12 @@ next_char_of_string (void)
          bump_line_counters ();
          break;
 
          bump_line_counters ();
          break;
 
+       case 0:
+         /* Do not advance past the end of the buffer.  */
+         -- input_line_pointer;
+         c = NOT_A_CHAR;
+         break;
+
        default:
 
 #ifdef ONLY_STANDARD_ESCAPES
        default:
 
 #ifdef ONLY_STANDARD_ESCAPES
@@ -5386,7 +5537,6 @@ next_char_of_string (void)
          break;
        }
       break;
          break;
        }
       break;
-#endif /* ! defined (NO_STRING_ESCAPES) */
 
     default:
       break;
 
     default:
       break;
@@ -5415,9 +5565,9 @@ get_segmented_expression (expressionS *expP)
 static segT
 get_known_segmented_expression (expressionS *expP)
 {
 static segT
 get_known_segmented_expression (expressionS *expP)
 {
-  segT retval;
+  segT retval = get_segmented_expression (expP);
 
 
-  if ((retval = get_segmented_expression (expP)) == undefined_section)
+  if (retval == undefined_section)
     {
       /* There is no easy way to extract the undefined symbol from the
         expression.  */
     {
       /* There is no easy way to extract the undefined symbol from the
         expression.  */
@@ -5431,8 +5581,7 @@ get_known_segmented_expression (expressionS *expP)
       expP->X_op = O_constant;
       expP->X_add_number = 0;
     }
       expP->X_op = O_constant;
       expP->X_add_number = 0;
     }
-  know (retval == absolute_section || SEG_NORMAL (retval));
-  return (retval);
+  return retval;
 }
 
 char                           /* Return terminator.  */
 }
 
 char                           /* Return terminator.  */
@@ -5603,7 +5752,7 @@ s_incbin (int x ATTRIBUTE_UNUSED)
     {
       int i;
 
     {
       int i;
 
-      path = (char *) xmalloc ((unsigned long) len + include_dir_maxlen + 5);
+      path = XNEWVEC (char, (unsigned long) len + include_dir_maxlen + 5);
 
       for (i = 0; i < include_dir_count; i++)
        {
 
       for (i = 0; i < include_dir_count; i++)
        {
@@ -5659,11 +5808,10 @@ s_incbin (int x ATTRIBUTE_UNUSED)
        as_warn (_("truncated file `%s', %ld of %ld bytes read"),
                 path, bytes, count);
     }
        as_warn (_("truncated file `%s', %ld of %ld bytes read"),
                 path, bytes, count);
     }
-done:
+ done:
   if (binfile != NULL)
     fclose (binfile);
   if (binfile != NULL)
     fclose (binfile);
-  if (path)
-    free (path);
+  free (path);
 }
 
 /* .include -- include a file at this point.  */
 }
 
 /* .include -- include a file at this point.  */
@@ -5706,8 +5854,8 @@ s_include (int arg ATTRIBUTE_UNUSED)
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
-  path = (char *) xmalloc ((unsigned long) i
-                           + include_dir_maxlen + 5 /* slop */ );
+  path = XNEWVEC (char, (unsigned long) i
+                 + include_dir_maxlen + 5 /* slop */ );
 
   for (i = 0; i < include_dir_count; i++)
     {
 
   for (i = 0; i < include_dir_count; i++)
     {
@@ -5723,7 +5871,7 @@ s_include (int arg ATTRIBUTE_UNUSED)
 
   free (path);
   path = filename;
 
   free (path);
   path = filename;
-gotit:
+ gotit:
   /* malloc Storage leak when file is found on path.  FIXME-SOMEDAY.  */
   register_dependency (path);
   input_scrub_insert_file (path);
   /* malloc Storage leak when file is found on path.  FIXME-SOMEDAY.  */
   register_dependency (path);
   input_scrub_insert_file (path);
@@ -5736,16 +5884,15 @@ add_include_dir (char *path)
 
   if (include_dir_count == 0)
     {
 
   if (include_dir_count == 0)
     {
-      include_dirs = (char **) xmalloc (2 * sizeof (*include_dirs));
+      include_dirs = XNEWVEC (const char *, 2);
       include_dirs[0] = ".";   /* Current dir.  */
       include_dir_count = 2;
     }
   else
     {
       include_dir_count++;
       include_dirs[0] = ".";   /* Current dir.  */
       include_dir_count = 2;
     }
   else
     {
       include_dir_count++;
-      include_dirs =
-       (char **) realloc (include_dirs,
-                          include_dir_count * sizeof (*include_dirs));
+      include_dirs = XRESIZEVEC (const char *, include_dirs,
+                                include_dir_count);
     }
 
   include_dirs[include_dir_count - 1] = path;  /* New one.  */
     }
 
   include_dirs[include_dir_count - 1] = path;  /* New one.  */
@@ -5837,11 +5984,10 @@ do_s_func (int end_p, const char *default_prefix)
          return;
        }
 
          return;
        }
 
-      name = input_line_pointer;
-      delim1 = get_symbol_end ();
+      delim1 = get_symbol_name (& name);
       name = xstrdup (name);
       *input_line_pointer = delim1;
       name = xstrdup (name);
       *input_line_pointer = delim1;
-      SKIP_WHITESPACE ();
+      SKIP_WHITESPACE_AFTER_NAME ();
       if (*input_line_pointer != ',')
        {
          if (default_prefix)
       if (*input_line_pointer != ',')
        {
          if (default_prefix)
@@ -5867,10 +6013,9 @@ do_s_func (int end_p, const char *default_prefix)
        {
          ++input_line_pointer;
          SKIP_WHITESPACE ();
        {
          ++input_line_pointer;
          SKIP_WHITESPACE ();
-         label = input_line_pointer;
-         delim2 = get_symbol_end ();
+         delim2 = get_symbol_name (& label);
          label = xstrdup (label);
          label = xstrdup (label);
-         *input_line_pointer = delim2;
+         restore_line_pointer (delim2);
        }
 
       if (debug_type == DEBUG_STABS)
        }
 
       if (debug_type == DEBUG_STABS)
@@ -5883,6 +6028,81 @@ do_s_func (int end_p, const char *default_prefix)
   demand_empty_rest_of_line ();
 }
 \f
   demand_empty_rest_of_line ();
 }
 \f
+#ifdef HANDLE_BUNDLE
+
+void
+s_bundle_align_mode (int arg ATTRIBUTE_UNUSED)
+{
+  unsigned int align = get_absolute_expression ();
+  SKIP_WHITESPACE ();
+  demand_empty_rest_of_line ();
+
+  if (align > (unsigned int) TC_ALIGN_LIMIT)
+    as_fatal (_(".bundle_align_mode alignment too large (maximum %u)"),
+             (unsigned int) TC_ALIGN_LIMIT);
+
+  if (bundle_lock_frag != NULL)
+    {
+      as_bad (_("cannot change .bundle_align_mode inside .bundle_lock"));
+      return;
+    }
+
+  bundle_align_p2 = align;
+}
+
+void
+s_bundle_lock (int arg ATTRIBUTE_UNUSED)
+{
+  demand_empty_rest_of_line ();
+
+  if (bundle_align_p2 == 0)
+    {
+      as_bad (_(".bundle_lock is meaningless without .bundle_align_mode"));
+      return;
+    }
+
+  if (bundle_lock_depth == 0)
+    {
+      bundle_lock_frchain = frchain_now;
+      bundle_lock_frag = start_bundle ();
+    }
+  ++bundle_lock_depth;
+}
+
+void
+s_bundle_unlock (int arg ATTRIBUTE_UNUSED)
+{
+  unsigned int size;
+
+  demand_empty_rest_of_line ();
+
+  if (bundle_lock_frag == NULL)
+    {
+      as_bad (_(".bundle_unlock without preceding .bundle_lock"));
+      return;
+    }
+
+  gas_assert (bundle_align_p2 > 0);
+
+  gas_assert (bundle_lock_depth > 0);
+  if (--bundle_lock_depth > 0)
+    return;
+
+  size = pending_bundle_size (bundle_lock_frag);
+
+  if (size > 1U << bundle_align_p2)
+    as_bad (_(".bundle_lock sequence is %u bytes, "
+             "but bundle size is only %u bytes"),
+           size, 1u << bundle_align_p2);
+  else
+    finish_bundle (bundle_lock_frag, size);
+
+  bundle_lock_frag = NULL;
+  bundle_lock_frchain = NULL;
+}
+
+#endif  /* HANDLE_BUNDLE */
+\f
 void
 s_ignore (int arg ATTRIBUTE_UNUSED)
 {
 void
 s_ignore (int arg ATTRIBUTE_UNUSED)
 {
@@ -5908,8 +6128,9 @@ void
 input_scrub_insert_line (const char *line)
 {
   sb newline;
 input_scrub_insert_line (const char *line)
 {
   sb newline;
-  sb_new (&newline);
-  sb_add_string (&newline, 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);
   sb_kill (&newline);
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
   input_scrub_include_sb (&newline, input_line_pointer, 0);
   sb_kill (&newline);
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
@@ -5970,7 +6191,7 @@ _find_end_of_line (char *s, int mri_string, int insn ATTRIBUTE_UNUSED,
     }
   if (inquote)
     as_warn (_("missing closing `%c'"), inquote);
     }
   if (inquote)
     as_warn (_("missing closing `%c'"), inquote);
-  if (inescape)
+  if (inescape && !ignore_input ())
     as_warn (_("stray `\\'"));
   return s;
 }
     as_warn (_("stray `\\'"));
   return s;
 }
@@ -5980,3 +6201,46 @@ find_end_of_line (char *s, int mri_string)
 {
   return _find_end_of_line (s, mri_string, 0, 0);
 }
 {
   return _find_end_of_line (s, mri_string, 0, 0);
 }
+
+static char *saved_ilp = NULL;
+static char *saved_limit;
+
+/* Use BUF as a temporary input pointer for calling other functions in this
+   file.  BUF must be a C string, so that its end can be found by strlen.
+   Also sets the buffer_limit variable (local to this file) so that buffer
+   overruns should not occur.  Saves the current input line pointer so that
+   it can be restored by calling restore_ilp().
+
+   Does not support recursion.  */
+
+void
+temp_ilp (char *buf)
+{
+  gas_assert (saved_ilp == NULL);
+  gas_assert (buf != NULL);
+
+  saved_ilp = input_line_pointer;
+  saved_limit = buffer_limit;
+  /* Prevent the assert in restore_ilp from triggering if
+     the input_line_pointer has not yet been initialised.  */
+  if (saved_ilp == NULL)
+    saved_limit = saved_ilp = (char *) "";
+
+  input_line_pointer = buf;
+  buffer_limit = buf + strlen (buf);
+  input_from_string = TRUE;
+}
+
+/* Restore a saved input line pointer.  */
+
+void
+restore_ilp (void)
+{
+  gas_assert (saved_ilp != NULL);
+
+  input_line_pointer = saved_ilp;
+  buffer_limit = saved_limit;
+  input_from_string = FALSE;
+
+  saved_ilp = NULL;
+}
This page took 0.068417 seconds and 4 git commands to generate.