]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/read.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.git] / gas / read.c
index f63bae405c4ce5a1e162b6543d10c37e074b5c74..fd2aa66f7b66f94075bf563cca5224ab87312492 100644 (file)
@@ -1,5 +1,5 @@
 /* read.c - read a source file -
-   Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 1997
+   Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 97, 1998
    Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
@@ -63,8 +63,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 char *input_line_pointer;      /*->next char of source file to parse. */
 
-int generate_asm_lineno = 0;   /* flag to generate line stab for .s file */
-
 #if BITS_PER_CHAR != 8
 /*  The following table is indexed by[(char)] and will break if
     a char does not have exactly 256 states (hopefully 0:255!)!  */
@@ -96,6 +94,11 @@ die horribly;
 #define LEX_DOLLAR 3
 #endif
 
+#ifndef LEX_TILDE
+/* The Delta 68k assembler permits ~ at start of label names.  */
+#define LEX_TILDE 0
+#endif
+
 /* used by is_... macros. our ctype[] */
 char lex_type[256] =
 {
@@ -106,7 +109,7 @@ char lex_type[256] =
   LEX_AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 3, /* PQRSTUVWXYZ[\]^_ */
   0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,      /* `abcdefghijklmno */
-  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 0, /* pqrstuvwxyz{|}~. */
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, LEX_TILDE, 0, /* pqrstuvwxyz{|}~. */
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -121,61 +124,53 @@ char lex_type[256] =
  * In: a character.
  * Out: 1 if this character ends a line.
  */
-#define _ (0)
+#define Z_ (0)
 char is_end_of_line[256] =
 {
 #ifdef CR_EOL
-  _, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _,    /* @abcdefghijklmno */
+  99, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, 99, Z_, Z_, 99, Z_, Z_,      /* @abcdefghijklmno */
 #else
-  _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _,     /* @abcdefghijklmno */
+  99, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, 99, Z_, Z_, Z_, Z_, Z_,      /* @abcdefghijklmno */
 #endif
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
 #ifdef TC_HPPA
-  _,99, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* _!"#$%&'()*+,-./ */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* 0123456789:;<=>? */
+  Z_,99, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,       /* _!"#$%&'()*+,-./ */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* 0123456789:;<=>? */
 #else
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _,     /* 0123456789:;<=>? */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, 99, Z_, Z_, Z_, Z_,      /* 0123456789:;<=>? */
 #endif
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
-  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
+  Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_,      /* */
 };
-#undef _
+#undef Z_
 
 /* Functions private to this file. */
 
 static char *buffer;   /* 1st char of each buffer of lines is here. */
 static char *buffer_limit;     /*->1 + last char in buffer. */
 
-#ifdef TARGET_BYTES_BIG_ENDIAN
-/* Hack to deal with tc-*.h defining TARGET_BYTES_BIG_ENDIAN to empty
-   instead of to 0 or 1.  */
-#if 5 - TARGET_BYTES_BIG_ENDIAN - 5 == 10
-#undef  TARGET_BYTES_BIG_ENDIAN
-#define TARGET_BYTES_BIG_ENDIAN 1
-#endif
+/* TARGET_BYTES_BIG_ENDIAN is required to be defined to either 0 or 1 in the
+   tc-<CPU>.h file.  See the "Porting GAS" section of the internals manual. */
 int target_big_endian = TARGET_BYTES_BIG_ENDIAN;
-#else
-int target_big_endian /* = 0 */;
-#endif
 
 static char *old_buffer;       /* JF a hack */
 static char *old_input;
 static char *old_limit;
 
-/* Variables for handling include file directory list. */
+/* Variables for handling include file directory table. */
 
-char **include_dirs;   /* List of pointers to directories to
+char **include_dirs;   /* Table of pointers to directories to
                           search for .include's */
-int include_dir_count; /* How many are in the list */
-int include_dir_maxlen = 1;/* Length of longest in list */
+int include_dir_count; /* How many are in the table */
+int include_dir_maxlen = 1;/* Length of longest in table */
 
 #ifndef WORKING_DOT_WORD
 struct broken_word *broken_words;
@@ -202,8 +197,19 @@ symbolS *mri_common_symbol;
    may be needed.  */
 static int mri_pending_align;
 
+#ifndef NO_LISTING
+#ifdef OBJ_ELF
+/* This variable is set to be non-zero if the next string we see might
+   be the name of the source file in DWARF debugging information.  See
+   the comment in emit_expr for the format we look for.  */
+static int dwarf_file_string;
+#endif
+#endif
+
+static void cons_worker PARAMS ((int, int));
 static int scrub_from_string PARAMS ((char **));
-static void do_align PARAMS ((int, char *, int));
+static void do_align PARAMS ((int, char *, int, int));
+static void s_align PARAMS ((int, int));
 static int hex_float PARAMS ((int, char *));
 static void do_org PARAMS ((segT, expressionS *, int));
 char *demand_copy_string PARAMS ((int *lenP));
@@ -211,6 +217,8 @@ static segT get_segmented_expression PARAMS ((expressionS *expP));
 static segT get_known_segmented_expression PARAMS ((expressionS * expP));
 static void pobegin PARAMS ((void));
 static int get_line_sb PARAMS ((sb *));
+static void generate_file_debug PARAMS ((void));
+static void generate_lineno_debug PARAMS ((void));
 \f
 
 void
@@ -288,9 +296,11 @@ static const pseudo_typeS potable[] =
   {"elsec", s_else, 0},
   {"end", s_end, 0},
   {"endc", s_endif, 0},
+  {"endfunc", s_func, 1},
   {"endif", s_endif, 0},
 /* endef */
   {"equ", s_set, 0},
+  {"equiv", s_set, 1},
   {"err", s_err, 0},
   {"exitm", s_mexit, 0},
 /* extend */
@@ -302,6 +312,7 @@ static const pseudo_typeS potable[] =
   {"fill", s_fill, 0},
   {"float", float_cons, 'f'},
   {"format", s_ignore, 0},
+  {"func", s_func, 0},
   {"global", s_globl, 0},
   {"globl", s_globl, 0},
   {"hword", cons, 2},
@@ -364,6 +375,7 @@ static const pseudo_typeS potable[] =
 /* size */
   {"space", s_space, 0},
   {"skip", s_space, 0},
+  {"sleb128", s_leb128, 1},
   {"spc", s_ignore, 0},
   {"stabd", s_stab, 'd'},
   {"stabn", s_stab, 'n'},
@@ -386,6 +398,7 @@ static const pseudo_typeS potable[] =
   {"title", listing_title, 0}, /* Listing title */
   {"ttl", listing_title, 0},
 /* type */
+  {"uleb128", s_leb128, 0},
 /* use */
 /* val */
   {"xcom", s_comm, 0},
@@ -410,7 +423,7 @@ pop_insert (table)
     {
       errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
       if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists")))
-       as_fatal ("error constructing %s pseudo-op table: %s", pop_table_name,
+       as_fatal (_("error constructing %s pseudo-op table: %s"), pop_table_name,
                  errtxt);
     }
 }
@@ -487,7 +500,13 @@ read_a_source_file (name)
   buffer = input_scrub_new_file (name);
 
   listing_file (name);
-  listing_newline ("");
+  listing_newline (NULL);
+  register_dependency (name);
+
+  /* Generate debugging information before we've read anything in to denote
+     this file as the "main" source file and not a subordinate one
+     (e.g. N_SO vs N_SOL in stabs).  */
+  generate_file_debug ();
 
   while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0)
     {                          /* We have another line to parse. */
@@ -529,6 +548,7 @@ read_a_source_file (name)
                      char c;
                      int mri_line_macro;
 
+                     LISTING_NEWLINE ();
                      HANDLE_CONDITIONAL_ASSEMBLY ();
 
                      c = get_symbol_end ();
@@ -549,7 +569,8 @@ read_a_source_file (name)
                              && (rest[3] == ' ' || rest[3] == '\t'))
                            {
                              input_line_pointer = rest + 3;
-                             equals (line_start);
+                             equals (line_start,
+                                     strncasecmp (rest, "SET", 3) == 0);
                              continue;
                            }
                          if (strncasecmp (rest, "MACRO", 5) == 0
@@ -599,7 +620,39 @@ read_a_source_file (name)
              c = *input_line_pointer++;
            }
          know (c != ' ');      /* No further leading whitespace. */
-         LISTING_NEWLINE ();
+
+#ifndef NO_LISTING
+         /* If listing is on, and we are expanding a macro, then give
+            the listing code the contents of the expanded line.  */
+         if (listing)
+           {
+             if ((listing & LISTING_MACEXP) && macro_nest > 0)
+               {
+                 char *copy;
+                 int len;
+
+                 /* Find the end of the current expanded macro line.  */
+                 for (s = input_line_pointer-1; *s ; ++s)
+                   if (is_end_of_line[(unsigned char) *s])
+                     break;
+
+                 /* Copy it for safe keeping.  Also give an indication of
+                    how much macro nesting is involved at this point.  */
+                 len = s - (input_line_pointer-1);
+                 copy = (char *) xmalloc (len + macro_nest + 2);
+                 memset (copy, '>', macro_nest);
+                 copy[macro_nest] = ' ';
+                 memcpy (copy + macro_nest + 1, input_line_pointer-1, len);
+                 copy[macro_nest+1+len] = '\0';
+
+                 /* Install the line with the listing facility.  */
+                 listing_newline (copy);
+               }
+             else
+               listing_newline (NULL);
+           }
+#endif
+
          /*
           * C is the 1st significant character.
           * Input_line_pointer points after that character.
@@ -635,7 +688,7 @@ read_a_source_file (name)
                          && (rest[3] == ' ' || rest[3] == '\t'))
                        {
                          input_line_pointer = rest + 3;
-                         equals (s);
+                         equals (s, 1);
                          continue;
                        }
                    }
@@ -648,13 +701,14 @@ read_a_source_file (name)
 
                }
              else if (c == '='
-                      || (input_line_pointer[1] == '='
+                      || ((c == ' ' || c == '\t')
+                          && input_line_pointer[1] == '='
 #ifdef TC_EQUAL_IN_INSN
                           && ! TC_EQUAL_IN_INSN (c, input_line_pointer)
 #endif
                           ))
                {
-                 equals (s);
+                 equals (s, 1);
                  demand_empty_rest_of_line ();
                }
              else
@@ -667,7 +721,7 @@ read_a_source_file (name)
                    char *s2 = s;
                    while (*s2)
                      {
-                       if (isupper (*s2))
+                       if (isupper ((unsigned char) *s2))
                          *s2 = tolower (*s2);
                        s2++;
                      }
@@ -718,16 +772,23 @@ read_a_source_file (name)
                                    || pop->poc_handler == s_ifc
                                    || pop->poc_handler == s_ifeqs
                                    || pop->poc_handler == s_else
-                                   || pop->poc_handler == s_endif)))
+                                   || pop->poc_handler == s_endif
+                                   || pop->poc_handler == s_globl
+                                   || pop->poc_handler == s_ignore)))
                        {
-                         do_align (1, (char *) NULL, 0);
+                         do_align (1, (char *) NULL, 0, 0);
                          mri_pending_align = 0;
+                         if (line_label != NULL)
+                           {
+                             line_label->sy_frag = frag_now;
+                             S_SET_VALUE (line_label, frag_now_fix ());
+                           }
                        }
 
                      /* Print the error msg now, while we still can */
                      if (pop == NULL)
                        {
-                         as_bad ("Unknown pseudo-op:  `%s'", s);
+                         as_bad (_("Unknown pseudo-op:  `%s'"), s);
                          *input_line_pointer = c;
                          s_ignore (0);
                          continue;
@@ -773,21 +834,7 @@ read_a_source_file (name)
                      c = *input_line_pointer;
                      *input_line_pointer = '\0';
 
-#ifdef OBJ_GENERATE_ASM_LINENO
-                     if (generate_asm_lineno == 0)
-                       {
-                         if (ecoff_no_current_file ())
-                           generate_asm_lineno = 1;
-                       }
-                     if (generate_asm_lineno == 1)
-                       {
-                         unsigned int lineno;
-                         char *s;
-
-                         as_where (&s, &lineno);
-                         OBJ_GENERATE_ASM_LINENO (s, lineno);
-                       }
-#endif
+                     generate_lineno_debug ();
 
                      if (macro_defined)
                        {
@@ -810,8 +857,13 @@ read_a_source_file (name)
 
                      if (mri_pending_align)
                        {
-                         do_align (1, (char *) NULL, 0);
+                         do_align (1, (char *) NULL, 0, 0);
                          mri_pending_align = 0;
+                         if (line_label != NULL)
+                           {
+                             line_label->sy_frag = frag_now;
+                             S_SET_VALUE (line_label, frag_now_fix ());
+                           }
                        }
 
                      md_assemble (s);  /* Assemble 1 instruction. */
@@ -831,7 +883,7 @@ read_a_source_file (name)
            continue;
 
          if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB)
-             && isdigit (c))
+             && isdigit ((unsigned char) c))
            {
              /* local label  ("4:") */
              char *backup = input_line_pointer;
@@ -840,7 +892,7 @@ read_a_source_file (name)
 
              temp = c - '0';
 
-             while (isdigit (*input_line_pointer))
+             while (isdigit ((unsigned char) *input_line_pointer))
                {
                  temp = (temp * 10) + *input_line_pointer - '0';
                  ++input_line_pointer;
@@ -854,7 +906,7 @@ read_a_source_file (name)
 
                  if (dollar_label_defined (temp))
                    {
-                     as_fatal ("label \"%d$\" redefined", temp);
+                     as_fatal (_("label \"%d$\" redefined"), temp);
                    }
 
                  define_dollar_label (temp);
@@ -1071,43 +1123,59 @@ void
 s_abort (ignore)
      int ignore;
 {
-  as_fatal (".abort detected.  Abandoning ship.");
+  as_fatal (_(".abort detected.  Abandoning ship."));
 }
 
-/* Guts of .align directive.  */
+/* 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 (n, fill, len)
+do_align (n, fill, len, max)
      int n;
      char *fill;
      int len;
+     int max;
 {
+  char default_fill;
+
 #ifdef md_do_align
-  md_do_align (n, fill, len, just_record_alignment);
+  md_do_align (n, fill, len, max, just_record_alignment);
 #endif
-  if (!fill)
+
+  if (fill == NULL)
     {
-      /* @@ Fix this right for BFD!  */
-      static char zero;
-      static char nop_opcode = NOP_OPCODE;
+      int maybe_text;
 
+#ifdef BFD_ASSEMBLER
+      if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
+       maybe_text = 1;
+      else
+       maybe_text = 0;
+#else
       if (now_seg != data_section && now_seg != bss_section)
-       {
-         fill = &nop_opcode;
-       }
+       maybe_text = 1;
       else
-       {
-         fill = &zero;
-       }
+       maybe_text = 0;
+#endif
+
+      if (maybe_text)
+       default_fill = NOP_OPCODE;
+      else
+       default_fill = 0;
+      fill = &default_fill;
       len = 1;
     }
 
   /* Only make a frag if we HAVE to. . . */
-  if (n && !need_pass_2)
+  if (n != 0 && !need_pass_2)
     {
       if (len <= 1)
-       frag_align (n, *fill);
+       frag_align (n, *fill, max);
       else
-       frag_align_pattern (n, fill, len);
+       frag_align_pattern (n, fill, len, max);
     }
 
 #ifdef md_do_align
@@ -1117,17 +1185,22 @@ do_align (n, fill, len)
   record_alignment (now_seg, n);
 }
 
-/* For machines where ".align 4" means align to a 4 byte boundary. */
-void 
-s_align_bytes (arg)
+/* 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
+   interpreted as the byte boundary, rather than the power of 2.  */
+
+static void
+s_align (arg, bytes_p)
      int arg;
+     int bytes_p;
 {
-  register unsigned int temp;
-  char temp_fill;
-  unsigned int i = 0;
-  unsigned long max_alignment = 1 << 15;
+  register unsigned int align;
   char *stop = NULL;
   char stopc;
+  offsetT fill = 0;
+  int max;
+  int fill_p;
 
   if (flag_mri)
     stop = mri_comment_field (&stopc);
@@ -1135,127 +1208,119 @@ s_align_bytes (arg)
   if (is_end_of_line[(unsigned char) *input_line_pointer])
     {
       if (arg < 0)
-       temp = 0;
+       align = 0;
       else
-       temp = arg;     /* Default value from pseudo-op table */
+       align = arg;    /* Default value from pseudo-op table */
     }
   else
-    temp = get_absolute_expression ();
-
-  if (temp > max_alignment)
     {
-      as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
+      align = get_absolute_expression ();
+      SKIP_WHITESPACE ();
     }
 
-  /* For the sparc, `.align (1<<n)' actually means `.align n' so we
-     have to convert it.  */
-  if (temp != 0)
+  if (bytes_p)
     {
-      for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
-       ;
+      /* Convert to a power of 2.  */
+      if (align != 0)
+       {
+         unsigned int i;
+
+         for (i = 0; (align & 1) == 0; align >>= 1, ++i)
+           ;
+         if (align != 1)
+           as_bad (_("Alignment not a power of 2"));
+         align = i;
+       }
     }
-  if (temp != 1)
-    as_bad ("Alignment not a power of 2");
 
-  temp = i;
-  if (*input_line_pointer == ',')
+  if (align > 15)
     {
-      offsetT fillval;
-      int len;
+      align = 15;
+      as_bad (_("Alignment too large: %u assumed"), align);
+    }
 
-      input_line_pointer++;
-      fillval = get_absolute_expression ();
-      if (arg >= 0)
-       len = 1;
+  if (*input_line_pointer != ',')
+    {
+      fill_p = 0;
+      max = 0;
+    }
+  else
+    {
+      ++input_line_pointer;
+      if (*input_line_pointer == ',')
+       fill_p = 0;
       else
-       len = - arg;
-      if (len <= 1)
        {
-         temp_fill = fillval;
-         do_align (temp, &temp_fill, len);
+         fill = get_absolute_expression ();
+         SKIP_WHITESPACE ();
+         fill_p = 1;
        }
+
+      if (*input_line_pointer != ',')
+       max = 0;
       else
        {
-         char ab[16];
-
-         if (len > sizeof ab)
-           abort ();
-         md_number_to_chars (ab, fillval, len);
-         do_align (temp, ab, len);
+         ++input_line_pointer;
+         max = get_absolute_expression ();
        }
     }
-  else
-    {
-      if (arg < 0)
-       as_warn ("expected fill pattern missing");
-      do_align (temp, (char *) NULL, 0);
-    }
-
-  if (flag_mri)
-    mri_comment_end (stop, stopc);
-
-  demand_empty_rest_of_line ();
-}
 
-/* For machines where ".align 4" means align to 2**4 boundary. */
-void 
-s_align_ptwo (arg)
-     int arg;
-{
-  register int temp;
-  char temp_fill;
-  long max_alignment = 15;
-  char *stop = NULL;
-  char stopc;
-
-  if (flag_mri)
-    stop = mri_comment_field (&stopc);
-
-  temp = get_absolute_expression ();
-  if (temp > max_alignment)
-    as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
-  else if (temp < 0)
+  if (! fill_p)
     {
-      as_bad ("Alignment negative. 0 assumed.");
-      temp = 0;
+      if (arg < 0)
+       as_warn (_("expected fill pattern missing"));
+      do_align (align, (char *) NULL, 0, max);
     }
-  if (*input_line_pointer == ',')
+  else
     {
-      offsetT fillval;
-      int len;
+      int fill_len;
 
-      input_line_pointer++;
-      fillval = get_absolute_expression ();
       if (arg >= 0)
-       len = 1;
+       fill_len = 1;
       else
-       len = - arg;
-      if (len <= 1)
+       fill_len = - arg;
+      if (fill_len <= 1)
        {
-         temp_fill = fillval;
-         do_align (temp, &temp_fill, len);
+         char fill_char;
+
+         fill_char = fill;
+         do_align (align, &fill_char, fill_len, max);
        }
       else
        {
          char ab[16];
 
-         if (len > sizeof ab)
+         if ((size_t) fill_len > sizeof ab)
            abort ();
-         md_number_to_chars (ab, fillval, len);
-         do_align (temp, ab, len);
+         md_number_to_chars (ab, fill, fill_len);
+         do_align (align, ab, fill_len, max);
        }
     }
-  else
-    {
-      if (arg < 0)
-       as_warn ("expected fill pattern missing");
-      do_align (temp, (char *) NULL, 0);
-    }
+
+  demand_empty_rest_of_line ();
 
   if (flag_mri)
     mri_comment_end (stop, stopc);
+}
 
-  demand_empty_rest_of_line ();
+/* Handle the .align pseudo-op on machines where ".align 4" means
+   align to a 4 byte boundary.  */
+
+void 
+s_align_bytes (arg)
+     int arg;
+{
+  s_align (arg, 1);
+}
+
+/* Handle the .align pseudo-op on machines where ".align 4" means align
+   to a 2**4 boundary.  */
+
+void 
+s_align_ptwo (arg)
+     int arg;
+{
+  s_align (arg, 0);
 }
 
 void 
@@ -1281,37 +1346,37 @@ s_comm (ignore)
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
-      as_bad ("Expected comma after symbol-name: rest of line ignored.");
+      as_bad (_("Expected comma after symbol-name: rest of line ignored."));
+      ignore_rest_of_line ();
       if (flag_mri)
        mri_comment_end (stop, stopc);
-      ignore_rest_of_line ();
       return;
     }
   input_line_pointer++;                /* skip ',' */
   if ((temp = get_absolute_expression ()) < 0)
     {
-      as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp);
+      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp);
+      ignore_rest_of_line ();
       if (flag_mri)
        mri_comment_end (stop, stopc);
-      ignore_rest_of_line ();
       return;
     }
   *p = 0;
   symbolP = symbol_find_or_make (name);
   *p = c;
-  if (S_IS_DEFINED (symbolP))
+  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
     {
-      as_bad ("Ignoring attempt to re-define symbol `%s'.",
+      as_bad (_("Ignoring attempt to re-define symbol `%s'."),
              S_GET_NAME (symbolP));
+      ignore_rest_of_line ();
       if (flag_mri)
        mri_comment_end (stop, stopc);
-      ignore_rest_of_line ();
       return;
     }
   if (S_GET_VALUE (symbolP))
     {
       if (S_GET_VALUE (symbolP) != (valueT) temp)
-       as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.",
+       as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
                S_GET_NAME (symbolP),
                (long) S_GET_VALUE (symbolP),
                (long) temp);
@@ -1330,10 +1395,10 @@ s_comm (ignore)
 #endif /* not OBJ_VMS */
   know (symbolP->sy_frag == &zero_address_frag);
 
+  demand_empty_rest_of_line ();
+
   if (flag_mri)
     mri_comment_end (stop, stopc);
-
-  demand_empty_rest_of_line ();
 }                              /* s_comm() */
 
 /* The MRI COMMON pseudo-op.  We handle this by creating a common
@@ -1398,17 +1463,12 @@ s_mri_common (small)
       align = get_absolute_expression ();
     }
 
-  if (S_IS_DEFINED (sym))
+  if (S_IS_DEFINED (sym) && ! S_IS_COMMON (sym))
     {
-#if defined (S_IS_COMMON) || defined (BFD_ASSEMBLER)
-      if (! S_IS_COMMON (sym))
-#endif
-       {
-         as_bad ("attempt to re-define symbol `%s'", S_GET_NAME (sym));
-         mri_comment_end (stop, stopc);
-         ignore_rest_of_line ();
-         return;
-       }
+      as_bad (_("attempt to re-define symbol `%s'"), S_GET_NAME (sym));
+      ignore_rest_of_line ();
+      mri_comment_end (stop, stopc);
+      return;
     }
 
   S_SET_EXTERNAL (sym);
@@ -1437,9 +1497,9 @@ s_mri_common (small)
   if (*input_line_pointer == ',')
     input_line_pointer += 2;
 
-  mri_comment_end (stop, stopc);
-
   demand_empty_rest_of_line ();
+
+  mri_comment_end (stop, stopc);
 }
 
 void
@@ -1486,7 +1546,8 @@ s_app_file (appfile)
       /* If this is a fake .appfile, a fake newline was inserted into
         the buffer.  Passing -2 to new_logical_line tells it to
         account for it.  */
-      new_logical_line (s, appfile ? -2 : -1);
+      int may_omit
+       = (! new_logical_line (s, appfile ? -2 : -1) && appfile);
 
       /* In MRI mode, the preprocessor may have inserted an extraneous
          backquote.  */
@@ -1496,14 +1557,18 @@ s_app_file (appfile)
        ++input_line_pointer;
 
       demand_empty_rest_of_line ();
+      if (! may_omit)
+       {
 #ifdef LISTING
-      if (listing)
-       listing_source_file (s);
+         if (listing)
+           listing_source_file (s);
 #endif
-    }
+         register_dependency (s);
 #ifdef obj_app_file
-  obj_app_file (s);
+         obj_app_file (s);
 #endif
+       }
+    }
 }
 
 /* Handle the .appline pseudo-op.  This is automatically generated by
@@ -1522,7 +1587,7 @@ s_app_line (ignore)
   if (l < 0)
     /* Some of the back ends can't deal with non-positive line numbers.
        Besides, it's silly.  */
-    as_warn ("Line numbers must be positive; line number %d rejected.", l+1);
+    as_warn (_("Line numbers must be positive; line number %d rejected."), l+1);
   else
     {
       new_logical_line ((char *) NULL, l);
@@ -1549,7 +1614,7 @@ s_end (ignore)
       if (! is_end_of_line[(unsigned char) *input_line_pointer]
          && *input_line_pointer != '*'
          && *input_line_pointer != '!')
-       as_warn ("start address not supported");
+       as_warn (_("start address not supported"));
     }
 }
 
@@ -1559,7 +1624,7 @@ void
 s_err (ignore)
      int ignore;
 {
-  as_bad (".err encountered");
+  as_bad (_(".err encountered"));
   demand_empty_rest_of_line ();
 }
 
@@ -1578,73 +1643,105 @@ s_fail (ignore)
 
   temp = get_absolute_expression ();
   if (temp >= 500)
-    as_warn (".fail %ld encountered", (long) temp);
+    as_warn (_(".fail %ld encountered"), (long) temp);
   else
-    as_bad (".fail %ld encountered", (long) temp);
+    as_bad (_(".fail %ld encountered"), (long) temp);
+
+  demand_empty_rest_of_line ();
 
   if (flag_mri)
     mri_comment_end (stop, stopc);
-
-  demand_empty_rest_of_line ();
 }
 
 void 
 s_fill (ignore)
      int ignore;
 {
-  long temp_repeat = 0;
-  long temp_size = 1;
-  register long temp_fill = 0;
+  expressionS rep_exp;
+  long size = 1;
+  register long fill = 0;
   char *p;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
 #endif
 
-  temp_repeat = get_absolute_expression ();
+  get_known_segmented_expression (&rep_exp);
   if (*input_line_pointer == ',')
     {
       input_line_pointer++;
-      temp_size = get_absolute_expression ();
+      size = get_absolute_expression ();
       if (*input_line_pointer == ',')
        {
          input_line_pointer++;
-         temp_fill = get_absolute_expression ();
+         fill = get_absolute_expression ();
        }
     }
+
   /* This is to be compatible with BSD 4.2 AS, not for any rational reason.  */
 #define BSD_FILL_SIZE_CROCK_8 (8)
-  if (temp_size > BSD_FILL_SIZE_CROCK_8)
+  if (size > BSD_FILL_SIZE_CROCK_8)
     {
-      as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
-      temp_size = BSD_FILL_SIZE_CROCK_8;
+      as_warn (_(".fill size clamped to %d."), BSD_FILL_SIZE_CROCK_8);
+      size = BSD_FILL_SIZE_CROCK_8;
     }
-  if (temp_size < 0)
+  if (size < 0)
     {
-      as_warn ("Size negative: .fill ignored.");
-      temp_size = 0;
+      as_warn (_("Size negative: .fill ignored."));
+      size = 0;
     }
-  else if (temp_repeat <= 0)
+  else if (rep_exp.X_op == O_constant && rep_exp.X_add_number <= 0)
     {
-      if (temp_repeat < 0)
-       as_warn ("Repeat < 0, .fill ignored");
-      temp_size = 0;
+      if (rep_exp.X_add_number < 0)
+       as_warn (_("Repeat < 0, .fill ignored"));
+      size = 0;
     }
 
-  if (temp_size && !need_pass_2)
+  if (size && !need_pass_2)
     {
-      p = frag_var (rs_fill, (int) temp_size, (int) temp_size, (relax_substateT) 0, (symbolS *) 0, temp_repeat, (char *) 0);
-      memset (p, 0, (unsigned int) temp_size);
+      if (rep_exp.X_op == O_constant)
+       {
+         p = frag_var (rs_fill, (int) size, (int) size,
+                       (relax_substateT) 0, (symbolS *) 0,
+                       (offsetT) rep_exp.X_add_number,
+                       (char *) 0);
+       }
+      else
+       {
+         /* We don't have a constant repeat count, so we can't use
+            rs_fill.  We can get the same results out of rs_space,
+            but its argument is in bytes, so we must multiply the
+            repeat count by size.  */
+
+         symbolS *rep_sym;
+         rep_sym = make_expr_symbol (&rep_exp);
+         if (size != 1)
+           {
+             expressionS size_exp;
+             size_exp.X_op = O_constant;
+             size_exp.X_add_number = size;
+
+             rep_exp.X_op = O_multiply;
+             rep_exp.X_add_symbol = rep_sym;
+             rep_exp.X_op_symbol = make_expr_symbol (&size_exp);
+             rep_exp.X_add_number = 0;
+             rep_sym = make_expr_symbol (&rep_exp);
+           }
+
+         p = frag_var (rs_space, (int) size, (int) size,
+                       (relax_substateT) 0, rep_sym, (offsetT) 0, (char *) 0);
+       }
+      memset (p, 0, (unsigned int) size);
       /* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX
        * flavoured AS.  The following bizzare behaviour is to be
        * compatible with above.  I guess they tried to take up to 8
        * bytes from a 4-byte expression and they forgot to sign
        * extend. Un*x Sux. */
 #define BSD_FILL_SIZE_CROCK_4 (4)
-      md_number_to_chars (p, (valueT) temp_fill,
-                         (temp_size > BSD_FILL_SIZE_CROCK_4
+      md_number_to_chars (p, (valueT) fill,
+                         (size > BSD_FILL_SIZE_CROCK_4
                           ? BSD_FILL_SIZE_CROCK_4
-                          : (int) temp_size));
+                          : (int) size));
       /* Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
        * but emits no error message because it seems a legal thing to do.
        * It is a degenerate case of .fill but could be emitted by a compiler.
@@ -1684,10 +1781,10 @@ s_globl (ignore)
     }
   while (c == ',');
 
+  demand_empty_rest_of_line ();
+
   if (flag_mri)
     mri_comment_end (stop, stopc);
-
-  demand_empty_rest_of_line ();
 }
 
 /* Handle the MRI IRP and IRPC pseudo-ops.  */
@@ -1752,7 +1849,7 @@ s_linkonce (ignore)
       else if (strcasecmp (s, "same_contents") == 0)
        type = LINKONCE_SAME_CONTENTS;
       else
-       as_warn ("unrecognized .linkonce type `%s'", s);
+       as_warn (_("unrecognized .linkonce type `%s'"), s);
 
       *input_line_pointer = c;
     }
@@ -1765,7 +1862,7 @@ s_linkonce (ignore)
     flagword flags;
 
     if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0)
-      as_warn (".linkonce is not supported for this object file format");
+      as_warn (_(".linkonce is not supported for this object file format"));
 
     flags = bfd_get_section_flags (stdoutput, now_seg);
     flags |= SEC_LINK_ONCE;
@@ -1787,22 +1884,25 @@ s_linkonce (ignore)
        break;
       }
     if (! bfd_set_section_flags (stdoutput, now_seg, flags))
-      as_bad ("bfd_set_section_flags: %s",
+      as_bad (_("bfd_set_section_flags: %s"),
              bfd_errmsg (bfd_get_error ()));
   }
 #else /* ! defined (BFD_ASSEMBLER) */
-  as_warn (".linkonce is not supported for this object file format");
+  as_warn (_(".linkonce is not supported for this object file format"));
 #endif /* ! defined (BFD_ASSEMBLER) */
 #endif /* ! defined (obj_handle_link_once) */
 
   demand_empty_rest_of_line ();
 }
 
-void 
-s_lcomm (needs_align)
+static void 
+s_lcomm_internal (needs_align, bytes_p)
      /* 1 if this was a ".bss" directive, which may require a 3rd argument
        (alignment); 0 if it was an ".lcomm" (2 args only)  */
      int needs_align;
+     /* 1 if the alignment value should be interpreted as the byte boundary,
+       rather than the power of 2. */
+     int bytes_p;
 {
   register char *name;
   register char c;
@@ -1831,13 +1931,13 @@ s_lcomm (needs_align)
 
   if (*input_line_pointer == '\n')
     {
-      as_bad ("Missing size expression");
+      as_bad (_("Missing size expression"));
       return;
     }
 
   if ((temp = get_absolute_expression ()) < 0)
     {
-      as_warn ("BSS length (%d.) <0! Ignored.", temp);
+      as_warn (_("BSS length (%d.) <0! Ignored."), temp);
       ignore_rest_of_line ();
       return;
     }
@@ -1853,7 +1953,7 @@ s_lcomm (needs_align)
          seg_info (bss_seg)->bss = 1;
 #ifdef BFD_ASSEMBLER
          if (! bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC))
-           as_warn ("error setting flags for \".sbss\": %s",
+           as_warn (_("error setting flags for \".sbss\": %s"),
                     bfd_errmsg (bfd_get_error ()));
 #endif
        }
@@ -1885,7 +1985,7 @@ s_lcomm (needs_align)
       SKIP_WHITESPACE ();
       if (*input_line_pointer != ',')
        {
-         as_bad ("Expected comma after size");
+         as_bad (_("Expected comma after size"));
          ignore_rest_of_line ();
          return;
        }
@@ -1893,19 +1993,33 @@ s_lcomm (needs_align)
       SKIP_WHITESPACE ();
       if (*input_line_pointer == '\n')
        {
-         as_bad ("Missing alignment");
+         as_bad (_("Missing alignment"));
          return;
        }
       align = get_absolute_expression ();
+      if (bytes_p)
+       {
+         /* Convert to a power of 2.  */
+         if (align != 0)
+           {
+             unsigned int i;
+
+             for (i = 0; (align & 1) == 0; align >>= 1, ++i)
+               ;
+             if (align != 1)
+               as_bad (_("Alignment not a power of 2"));
+             align = i;
+           }
+       }
       if (align > max_alignment)
        {
          align = max_alignment;
-         as_warn ("Alignment too large: %d. assumed.", align);
+         as_warn (_("Alignment too large: %d. assumed."), align);
        }
       else if (align < 0)
        {
          align = 0;
-         as_warn ("Alignment negative. 0 assumed.");
+         as_warn (_("Alignment negative. 0 assumed."));
        }
       record_alignment (bss_seg, align);
     }                          /* if needs align */
@@ -1939,14 +2053,14 @@ s_lcomm (needs_align)
       subseg_set (bss_seg, 1);
 
       if (align)
-       frag_align (align, 0);
+       frag_align (align, 0, 0);
                                        /* detach from old frag */
       if (S_GET_SEGMENT (symbolP) == bss_seg)
        symbolP->sy_frag->fr_symbol = NULL;
 
       symbolP->sy_frag = frag_now;
       pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
-                       temp, (char *)0);
+                       (offsetT) temp, (char *) 0);
       *pfrag = 0;
 
       S_SET_SEGMENT (symbolP, bss_seg);
@@ -1966,13 +2080,26 @@ s_lcomm (needs_align)
 #endif
     }
   else
-    as_bad ("Ignoring attempt to re-define symbol `%s'.",
+    as_bad (_("Ignoring attempt to re-define symbol `%s'."),
            S_GET_NAME (symbolP));
 
   subseg_set (current_seg, current_subseg);
 
   demand_empty_rest_of_line ();
-}                              /* s_lcomm() */
+}                              /* s_lcomm_internal() */
+
+void
+s_lcomm (needs_align)
+     int needs_align;
+{
+  s_lcomm_internal (needs_align, 0);
+}
+
+void s_lcomm_bytes (needs_align)
+     int needs_align;
+{
+  s_lcomm_internal (needs_align, 1);
+}
 
 void 
 s_lsym (ignore)
@@ -1993,7 +2120,7 @@ s_lsym (ignore)
   if (*input_line_pointer != ',')
     {
       *p = 0;
-      as_bad ("Expected comma after name \"%s\"", name);
+      as_bad (_("Expected comma after name \"%s\""), name);
       *p = c;
       ignore_rest_of_line ();
       return;
@@ -2003,7 +2130,7 @@ s_lsym (ignore)
   if (exp.X_op != O_constant
       && exp.X_op != O_register)
     {
-      as_bad ("bad expression");
+      as_bad (_("bad expression"));
       ignore_rest_of_line ();
       return;
     }
@@ -2030,7 +2157,7 @@ s_lsym (ignore)
     }
   else
     {
-      as_bad ("Symbol %s already defined", name);
+      as_bad (_("Symbol %s already defined"), name);
     }
   *p = c;
   demand_empty_rest_of_line ();
@@ -2042,6 +2169,8 @@ static int
 get_line_sb (line)
      sb *line;
 {
+  char quote1, quote2, inquote;
+
   if (input_line_pointer[-1] == '\n')
     bump_line_counters ();
 
@@ -2052,8 +2181,35 @@ get_line_sb (line)
        return 0;
     }
 
-  while (! is_end_of_line[(unsigned char) *input_line_pointer])
-    sb_add_char (line, *input_line_pointer++);
+  /* If app.c sets any other characters to LEX_IS_STRINGQUOTE, this
+     code needs to be changed.  */
+  if (! flag_m68k_mri)
+    quote1 = '"';
+  else
+    quote1 = '\0';
+
+  quote2 = '\0';
+  if (flag_m68k_mri)
+    quote2 = '\'';
+#ifdef LEX_IS_STRINGQUOTE
+  quote2 = '\'';
+#endif
+
+  inquote = '\0';
+  while (! is_end_of_line[(unsigned char) *input_line_pointer]
+        || (inquote != '\0' && *input_line_pointer != '\n'))
+    {
+      if (inquote == *input_line_pointer)
+       inquote = '\0';
+      else if (inquote == '\0')
+       {
+         if (*input_line_pointer == quote1)
+           inquote = quote1;
+         else if (*input_line_pointer == quote2)
+           inquote = quote2;
+       }
+      sb_add_char (line, *input_line_pointer++);
+    }
   while (input_line_pointer < buffer_limit
         && is_end_of_line[(unsigned char) *input_line_pointer])
     {
@@ -2109,7 +2265,7 @@ s_macro (ignore)
          || (! flag_m68k_mri
              && *name == '.'
              && hash_find (po_hash, name + 1) != NULL))
-       as_warn ("attempt to redefine pseudo-op `%s' ignored",
+       as_warn (_("attempt to redefine pseudo-op `%s' ignored"),
                 name);
     }
 
@@ -2123,6 +2279,7 @@ void
 s_mexit (ignore)
      int ignore;
 {
+  cond_exit_macro (macro_nest);
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }
 
@@ -2142,13 +2299,19 @@ s_mri (ignore)
 #ifdef TC_M68K
       flag_m68k_mri = 1;
 #endif
+      macro_mri_mode (1);
     }
   else
     {
       flag_mri = 0;
       flag_m68k_mri = 0;
+      macro_mri_mode (0);
     }
 
+  /* Operator precedence changes in m68k MRI mode, so we need to
+     update the operator rankings.  */
+  expr_set_precedence ();
+
 #ifdef MRI_MODE_CHANGE
   if (on != old_flag)
     MRI_MODE_CHANGE (on);
@@ -2166,16 +2329,16 @@ do_org (segment, exp, fill)
      int fill;
 {
   if (segment != now_seg && segment != absolute_section)
-    as_bad ("invalid segment \"%s\"; segment \"%s\" assumed",
+    as_bad (_("invalid segment \"%s\"; segment \"%s\" assumed"),
            segment_name (segment), segment_name (now_seg));
 
   if (now_seg == absolute_section)
     {
       if (fill != 0)
-       as_warn ("ignoring fill value in absolute section");
+       as_warn (_("ignoring fill value in absolute section"));
       if (exp->X_op != O_constant)
        {
-         as_bad ("only constant offsets supported in absolute section");
+         as_bad (_("only constant offsets supported in absolute section"));
          exp->X_add_number = 0;
        }
       abs_section_offset = exp->X_add_number;
@@ -2198,12 +2361,16 @@ s_org (ignore)
   expressionS exp;
   register long temp_fill;
 
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
   /* The m68k MRI assembler has a different meaning for .org.  It
      means to create an absolute section at a given address.  We can't
      support that--use a linker script instead.  */
   if (flag_m68k_mri)
     {
-      as_bad ("MRI style ORG pseudo-op not supported");
+      as_bad (_("MRI style ORG pseudo-op not supported"));
       ignore_rest_of_line ();
       return;
     }
@@ -2291,7 +2458,7 @@ s_mri_sect (type)
       if (c == 'C' || c == 'D' || c == 'M' || c == 'R')
        *type = c;
       else
-       as_bad ("unrecognized section type");
+       as_bad (_("unrecognized section type"));
       ++input_line_pointer;
 
 #ifdef BFD_ASSEMBLER
@@ -2308,7 +2475,7 @@ s_mri_sect (type)
        if (flags != SEC_NO_FLAGS)
          {
            if (! bfd_set_section_flags (stdoutput, seg, flags))
-             as_warn ("error setting flags for \"%s\": %s",
+             as_warn (_("error setting flags for \"%s\": %s"),
                       bfd_section_name (stdoutput, seg),
                       bfd_errmsg (bfd_get_error ()));
          }
@@ -2359,7 +2526,7 @@ s_mri_sect (type)
       else if (strcasecmp (sectype, "romdata") == 0)
        *type = 'R';
       else
-       as_warn ("unrecognized section type `%s'", sectype);
+       as_warn (_("unrecognized section type `%s'"), sectype);
       *input_line_pointer = c;
     }
 
@@ -2373,7 +2540,7 @@ s_mri_sect (type)
       c = get_symbol_end ();
       if (strcasecmp (seccmd, "absolute") == 0)
        {
-         as_bad ("absolute sections are not supported");
+         as_bad (_("absolute sections are not supported"));
          *input_line_pointer = c;
          ignore_rest_of_line ();
          return;
@@ -2388,7 +2555,7 @@ s_mri_sect (type)
        }
       else
        {
-         as_warn ("unrecognized section command `%s'", seccmd);
+         as_warn (_("unrecognized section command `%s'"), seccmd);
          *input_line_pointer = c;
        }
     }
@@ -2398,7 +2565,8 @@ s_mri_sect (type)
 #else /* ! TC_I960 */
   /* The MRI assembler seems to use different forms of .sect for
      different targets.  */
-  abort ();
+  as_bad ("MRI mode not supported for this target");
+  ignore_rest_of_line ();
 #endif /* ! TC_I960 */
 #endif /* ! TC_M68K */
 }
@@ -2462,7 +2630,7 @@ s_rept (ignore)
   sb_new (&one);
   if (! buffer_and_nest ("REPT", "ENDR", &one, get_line_sb))
     {
-      as_bad ("rept without endr");
+      as_bad (_("rept without endr"));
       return;
     }
 
@@ -2477,9 +2645,13 @@ s_rept (ignore)
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }
 
+/* Handle the .equ, .equiv and .set directives.  If EQUIV is 1, then
+   this is .equiv, and it is an error if the symbol is already
+   defined.  */
+
 void 
-s_set (ignore)
-     int ignore;
+s_set (equiv)
+     int equiv;
 {
   register char *name;
   register char delim;
@@ -2500,7 +2672,7 @@ s_set (ignore)
   if (*input_line_pointer != ',')
     {
       *end_name = 0;
-      as_bad ("Expected comma after name \"%s\"", name);
+      as_bad (_("Expected comma after name \"%s\""), name);
       *end_name = delim;
       ignore_rest_of_line ();
       return;
@@ -2527,7 +2699,24 @@ s_set (ignore)
   if ((symbolP = symbol_find (name)) == NULL
       && (symbolP = md_undefined_symbol (name)) == NULL)
     {
-      symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
+#ifndef NO_LISTING
+      /* When doing symbol listings, play games with dummy fragments living
+        outside the normal fragment chain to record the file and line info
+         for this symbol.  */
+      if (listing & LISTING_SYMBOLS)
+       {
+         extern struct list_info_struct *listing_tail;
+         fragS *dummy_frag = (fragS *) xmalloc (sizeof(fragS));
+         memset (dummy_frag, 0, sizeof(fragS));
+         dummy_frag->fr_type = rs_fill;
+         dummy_frag->line = listing_tail;
+         symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
+         dummy_frag->fr_symbol = symbolP;
+       }
+      else
+#endif
+        symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
+                           
 #ifdef OBJ_COFF
       /* "set" symbols are local unless otherwise specified. */
       SF_SET_LOCAL (symbolP);
@@ -2538,6 +2727,12 @@ s_set (ignore)
   symbol_table_insert (symbolP);
 
   *end_name = delim;
+
+  if (equiv
+      && S_IS_DEFINED (symbolP)
+      && S_GET_SEGMENT (symbolP) != reg_section)
+    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
+
   pseudo_set (symbolP);
   demand_empty_rest_of_line ();
 }                              /* s_set() */
@@ -2551,6 +2746,7 @@ s_space (mult)
   char *p = 0;
   char *stop = NULL;
   char stopc;
+  int bytes;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
@@ -2587,7 +2783,7 @@ s_space (mult)
        }
       else
        {
-         do_align (1, (char *) NULL, 0);
+         do_align (1, (char *) NULL, 0, 0);
          if (line_label != NULL)
            {
              line_label->sy_frag = frag_now;
@@ -2596,6 +2792,8 @@ s_space (mult)
        }
     }
 
+  bytes = mult;
+
   expression (&exp);
 
   SKIP_WHITESPACE ();
@@ -2616,13 +2814,14 @@ s_space (mult)
       || (mult != 0 && mult != 1 && val.X_add_number != 0))
     {
       if (exp.X_op != O_constant)
-       as_bad ("Unsupported variable size or fill value");
+       as_bad (_("Unsupported variable size or fill value"));
       else
        {
          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);
        }
@@ -2636,11 +2835,13 @@ s_space (mult)
          repeat = exp.X_add_number;
          if (mult)
            repeat *= mult;
+         bytes = repeat;
          if (repeat <= 0)
            {
-             if (! flag_mri || repeat < 0)
-               as_warn (".space repeat count is %s, ignored",
-                        repeat ? "negative" : "zero");
+             if (! flag_mri)
+               as_warn (_(".space repeat count is zero, ignored"));
+             else if (repeat < 0)
+               as_warn (_(".space repeat count is negative, ignored"));
              goto getout;
            }
 
@@ -2663,23 +2864,23 @@ s_space (mult)
 
          if (!need_pass_2)
            p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
-                         repeat, (char *) 0);
+                         (offsetT) repeat, (char *) 0);
        }
       else
        {
          if (now_seg == absolute_section)
            {
-             as_bad ("space allocation too complex in absolute section");
+             as_bad (_("space allocation too complex in absolute section"));
              subseg_set (text_section, 0);
            }
          if (mri_common_symbol != NULL)
            {
-             as_bad ("space allocation too complex in common section");
+             as_bad (_("space allocation too complex in common section"));
              mri_common_symbol = NULL;
            }
          if (!need_pass_2)
            p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
-                         make_expr_symbol (&exp), 0L, (char *) 0);
+                         make_expr_symbol (&exp), (offsetT) 0, (char *) 0);
        }
 
       if (p)
@@ -2687,10 +2888,17 @@ s_space (mult)
     }
 
  getout:
-  if (flag_mri)
-    mri_comment_end (stop, stopc);
+
+  /* In MRI mode, after an odd number of bytes, we must align to an
+     even word boundary, unless the next instruction is a dc.b, ds.b
+     or dcb.b.  */
+  if (flag_mri && (bytes & 1) != 0)
+    mri_pending_align = 1;
 
   demand_empty_rest_of_line ();
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
 }
 
 /* This is like s_space, but the value is a floating point number with
@@ -2715,10 +2923,10 @@ s_float_space (float_type)
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
-      as_bad ("missing value");
+      as_bad (_("missing value"));
+      ignore_rest_of_line ();
       if (flag_mri)
        mri_comment_end (stop, stopc);
-      ignore_rest_of_line ();
       return;
     }
 
@@ -2728,7 +2936,8 @@ s_float_space (float_type)
 
   /* Skip any 0{letter} that may be present.  Don't even check if the
    * letter is legal.  */
-  if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
+  if (input_line_pointer[0] == '0'
+      && isalpha ((unsigned char) input_line_pointer[1]))
     input_line_pointer += 2;
 
   /* Accept :xxxx, where the x's are hex digits, for a floating point
@@ -2738,9 +2947,9 @@ s_float_space (float_type)
       flen = hex_float (float_type, temp);
       if (flen < 0)
        {
+         ignore_rest_of_line ();
          if (flag_mri)
            mri_comment_end (stop, stopc);
-         ignore_rest_of_line ();
          return;
        }
     }
@@ -2753,10 +2962,10 @@ s_float_space (float_type)
       know (flen > 0);
       if (err)
        {
-         as_bad ("Bad floating literal: %s", err);
+         as_bad (_("Bad floating literal: %s"), err);
+         ignore_rest_of_line ();
          if (flag_mri)
            mri_comment_end (stop, stopc);
-         ignore_rest_of_line ();
          return;
        }
     }
@@ -2769,10 +2978,10 @@ s_float_space (float_type)
       memcpy (p, temp, (unsigned int) flen);
     }
 
+  demand_empty_rest_of_line ();
+
   if (flag_mri)
     mri_comment_end (stop, stopc);
-
-  demand_empty_rest_of_line ();
 }
 
 /* Handle the .struct pseudo-op, as found in MIPS assemblers.  */
@@ -2788,9 +2997,9 @@ s_struct (ignore)
     stop = mri_comment_field (&stopc);
   abs_section_offset = get_absolute_expression ();
   subseg_set (absolute_section, 0);
+  demand_empty_rest_of_line ();
   if (flag_mri)
     mri_comment_end (stop, stopc);
-  demand_empty_rest_of_line ();
 }
 
 void
@@ -2828,11 +3037,11 @@ ignore_rest_of_line ()          /* For suspect lines: gives warning. */
 {
   if (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
-      if (isprint (*input_line_pointer))
-       as_bad ("Rest of line ignored. First ignored character is `%c'.",
+      if (isprint ((unsigned char) *input_line_pointer))
+       as_bad (_("Rest of line ignored. First ignored character is `%c'."),
                *input_line_pointer);
       else
-       as_bad ("Rest of line ignored. First ignored character valued 0x%x.",
+       as_bad (_("Rest of line ignored. First ignored character valued 0x%x."),
                *input_line_pointer);
       while (input_line_pointer < buffer_limit
             && !is_end_of_line[(unsigned char) *input_line_pointer])
@@ -2871,12 +3080,16 @@ pseudo_set (symbolP)
   (void) expression (&exp);
 
   if (exp.X_op == O_illegal)
-    as_bad ("illegal expression; zero assumed");
+    as_bad (_("illegal expression; zero assumed"));
   else if (exp.X_op == O_absent)
-    as_bad ("missing expression; zero assumed");
+    as_bad (_("missing expression; zero assumed"));
   else if (exp.X_op == O_big)
-    as_bad ("%s number invalid; zero assumed",
-           exp.X_add_number > 0 ? "bignum" : "floating point");
+    {
+      if (exp.X_add_number > 0)
+       as_bad (_("bignum invalid; zero assumed"));
+      else
+       as_bad (_("floating point number invalid; zero assumed"));
+    }
   else if (exp.X_op == O_subtract
           && (S_GET_SEGMENT (exp.X_add_symbol)
               == S_GET_SEGMENT (exp.X_op_symbol))
@@ -2904,7 +3117,8 @@ pseudo_set (symbolP)
        S_CLEAR_EXTERNAL (symbolP);
 #endif /* OBJ_AOUT or OBJ_BOUT */
       S_SET_VALUE (symbolP, (valueT) exp.X_add_number);
-      symbolP->sy_frag = &zero_address_frag;
+      if (exp.X_op != O_constant)
+        symbolP->sy_frag = &zero_address_frag;
       break;
 
     case O_register:
@@ -3011,9 +3225,9 @@ cons_worker (nbytes, rva)
 
   if (is_it_end_of_statement ())
     {
+      demand_empty_rest_of_line ();
       if (flag_mri)
        mri_comment_end (stop, stopc);
-      demand_empty_rest_of_line ();
       return;
     }
 
@@ -3034,7 +3248,7 @@ cons_worker (nbytes, rva)
          if (exp.X_op == O_symbol)
            exp.X_op = O_symbol_rva;
          else
-           as_fatal ("rva without symbol");
+           as_fatal (_("rva without symbol"));
        }
       emit_expr (&exp, (unsigned int) nbytes);
       ++c;
@@ -3049,10 +3263,10 @@ cons_worker (nbytes, rva)
 
   input_line_pointer--;                /* Put terminator back into stream. */
 
+  demand_empty_rest_of_line ();
+
   if (flag_mri)
     mri_comment_end (stop, stopc);
-
-  demand_empty_rest_of_line ();
 }
 
 
@@ -3070,7 +3284,6 @@ s_rva (size)
   cons_worker (size, 1);
 }
 
-
 /* Put the contents of expression EXP into the object file using
    NBYTES bytes.  If need_pass_2 is 1, this does nothing.  */
 
@@ -3087,13 +3300,80 @@ emit_expr (exp, nbytes)
   if (need_pass_2)
     return;
 
+#ifndef NO_LISTING
+#ifdef OBJ_ELF
+  /* When gcc emits DWARF 1 debugging pseudo-ops, a line number will
+     appear as a four byte positive constant in the .line section,
+     followed by a 2 byte 0xffff.  Look for that case here.  */
+  {
+    static int dwarf_line = -1;
+
+    if (strcmp (segment_name (now_seg), ".line") != 0)
+      dwarf_line = -1;
+    else if (dwarf_line >= 0
+            && nbytes == 2
+            && exp->X_op == O_constant
+            && (exp->X_add_number == -1 || exp->X_add_number == 0xffff))
+      listing_source_line ((unsigned int) dwarf_line);
+    else if (nbytes == 4
+            && exp->X_op == O_constant
+            && exp->X_add_number >= 0)
+      dwarf_line = exp->X_add_number;
+    else
+      dwarf_line = -1;
+  }
+
+  /* When gcc emits DWARF 1 debugging pseudo-ops, a file name will
+     appear as a 2 byte TAG_compile_unit (0x11) followed by a 2 byte
+     AT_sibling (0x12) followed by a four byte address of the sibling
+     followed by a 2 byte AT_name (0x38) followed by the name of the
+     file.  We look for that case here.  */
+  {
+    static int dwarf_file = 0;
+
+    if (strcmp (segment_name (now_seg), ".debug") != 0)
+      dwarf_file = 0;
+    else if (dwarf_file == 0
+            && nbytes == 2
+            && exp->X_op == O_constant
+            && exp->X_add_number == 0x11)
+      dwarf_file = 1;
+    else if (dwarf_file == 1
+            && nbytes == 2
+            && exp->X_op == O_constant
+            && exp->X_add_number == 0x12)
+      dwarf_file = 2;
+    else if (dwarf_file == 2
+            && nbytes == 4)
+      dwarf_file = 3;
+    else if (dwarf_file == 3
+            && nbytes == 2
+            && exp->X_op == O_constant
+            && exp->X_add_number == 0x38)
+      dwarf_file = 4;
+    else
+      dwarf_file = 0;
+
+    /* The variable dwarf_file_string tells stringer that the string
+       may be the name of the source file.  */
+    if (dwarf_file == 4)
+      dwarf_file_string = 1;
+    else
+      dwarf_file_string = 0;
+  }
+#endif
+#endif
+
+  if (check_eh_frame (exp, &nbytes))
+    return;
+
   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");
+       as_bad (_("attempt to store value in absolute section"));
       abs_section_offset += nbytes;
       return;
     }
@@ -3131,19 +3411,19 @@ emit_expr (exp, nbytes)
 
   if (op == O_absent || op == O_illegal)
     {
-      as_warn ("zero assumed for missing expression");
+      as_warn (_("zero assumed for missing expression"));
       exp->X_add_number = 0;
       op = O_constant;
     }
   else if (op == O_big && exp->X_add_number <= 0)
     {
-      as_bad ("floating point number invalid; zero assumed");
+      as_bad (_("floating point number invalid; zero assumed"));
       exp->X_add_number = 0;
       op = O_constant;
     }
   else if (op == O_register)
     {
-      as_warn ("register value used as expression");
+      as_warn (_("register value used as expression"));
       op = O_constant;
     }
 
@@ -3159,6 +3439,8 @@ emit_expr (exp, nbytes)
       x = (struct broken_word *) xmalloc (sizeof (struct broken_word));
       x->next_broken_word = broken_words;
       broken_words = x;
+      x->seg = now_seg;
+      x->subseg = now_subseg;
       x->frag = frag_now;
       x->word_goes_here = p;
       x->dispfrag = 0;
@@ -3198,14 +3480,25 @@ emit_expr (exp, nbytes)
       register valueT get;
       register valueT use;
       register valueT mask;
+      valueT hibit;
       register valueT unmask;
 
       /* JF << of >= number of bits in the object is undefined.  In
         particular SPARC (Sun 4) has problems */
       if (nbytes >= sizeof (valueT))
-       mask = 0;
+       {
+         mask = 0;
+         if (nbytes > sizeof (valueT))
+           hibit = 0;
+         else
+           hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
+       }
       else
-       mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
+       {
+         /* Don't store these bits. */
+         mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes);
+         hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
+       }
 
       unmask = ~mask;          /* Do store these bits. */
 
@@ -3216,9 +3509,11 @@ emit_expr (exp, nbytes)
 
       get = exp->X_add_number;
       use = get & unmask;
-      if ((get & mask) != 0 && (get & mask) != mask)
+      if ((get & mask) != 0
+         && ((get & mask) != mask
+             || (get & hibit) == 0))
        {               /* Leading bits contain both 0s & 1s. */
-         as_warn ("Value 0x%lx truncated to 0x%lx.",
+         as_warn (_("Value 0x%lx truncated to 0x%lx."),
                   (unsigned long) get, (unsigned long) use);
        }
       /* put bytes in right order. */
@@ -3226,7 +3521,7 @@ emit_expr (exp, nbytes)
     }
   else if (op == O_big)
     {
-      int size;
+      unsigned int size;
       LITTLENUM_TYPE *nums;
 
       know (nbytes % CHARS_PER_LITTLENUM == 0);
@@ -3234,7 +3529,7 @@ emit_expr (exp, nbytes)
       size = exp->X_add_number * CHARS_PER_LITTLENUM;
       if (nbytes < size)
        {
-         as_warn ("Bignum truncated to %d bytes", nbytes);
+         as_warn (_("Bignum truncated to %d bytes"), nbytes);
          size = nbytes;
        }
 
@@ -3311,7 +3606,7 @@ emit_expr (exp, nbytes)
            r = BFD_RELOC_64;
            break;
          default:
-           as_bad ("unsupported BFD relocation size %u", nbytes);
+           as_bad (_("unsupported BFD relocation size %u"), nbytes);
            r = BFD_RELOC_32;
            break;
          }
@@ -3400,7 +3695,7 @@ parse_bitfield_cons (exp, nbytes)
 
          if (exp->X_op == O_absent)
            {
-             as_warn ("using a bit field width of zero");
+             as_warn (_("using a bit field width of zero"));
              exp->X_add_number = 0;
              exp->X_op = O_constant;
            }                   /* implied zero width bitfield */
@@ -3408,7 +3703,7 @@ parse_bitfield_cons (exp, nbytes)
          if (exp->X_op != O_constant)
            {
              *input_line_pointer = '\0';
-             as_bad ("field width \"%s\" too complex for a bitfield", hold);
+             as_bad (_("field width \"%s\" too complex for a bitfield"), hold);
              *input_line_pointer = ':';
              demand_empty_rest_of_line ();
              return;
@@ -3416,7 +3711,7 @@ parse_bitfield_cons (exp, nbytes)
 
          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",
+             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 */
@@ -3437,7 +3732,7 @@ parse_bitfield_cons (exp, nbytes)
              char cache = *input_line_pointer;
 
              *input_line_pointer = '\0';
-             as_bad ("field value \"%s\" too complex for a bitfield", hold);
+             as_bad (_("field value \"%s\" too complex for a bitfield"), hold);
              *input_line_pointer = cache;
              demand_empty_rest_of_line ();
              return;
@@ -3479,7 +3774,7 @@ parse_mri_cons (exp, nbytes)
     TC_PARSE_CONS_EXPRESSION (exp, nbytes);
   else
     {
-      int scan = 0;
+      unsigned int scan;
       unsigned int result = 0;
 
       /* An MRI style string.  Cut into as many bytes as will fit into
@@ -3489,7 +3784,7 @@ parse_mri_cons (exp, nbytes)
        ++input_line_pointer;
       else if (*input_line_pointer == 'E')
        {
-         as_bad ("EBCDIC constants are not supported");
+         as_bad (_("EBCDIC constants are not supported"));
          ++input_line_pointer;
        }
 
@@ -3559,7 +3854,7 @@ parse_repeat_cons (exp, nbytes)
   if (count.X_op != O_constant
       || count.X_add_number <= 0)
     {
-      as_warn ("Unresolvable or nonpositive repeat count; using 1");
+      as_warn (_("Unresolvable or nonpositive repeat count; using 1"));
       return;
     }
 
@@ -3610,7 +3905,7 @@ hex_float (float_type, bytes)
       break;
 
     default:
-      as_bad ("Unknown floating type type '%c'", float_type);
+      as_bad (_("Unknown floating type type '%c'"), float_type);
       return -1;
     }
 
@@ -3632,7 +3927,7 @@ hex_float (float_type, bytes)
 
       if (i >= length)
        {
-         as_warn ("Floating point constant too large");
+         as_warn (_("Floating point constant too large"));
          return -1;
        }
       d = hex_value (*input_line_pointer) << 4;
@@ -3712,7 +4007,8 @@ float_cons (float_type)
        * has no use for such information. Lusers beware: you get
        * diagnostics if your input is ill-conditioned.
        */
-      if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
+      if (input_line_pointer[0] == '0'
+         && isalpha ((unsigned char) input_line_pointer[1]))
        input_line_pointer += 2;
 
       /* Accept :xxxx, where the x's are hex digits, for a floating
@@ -3734,7 +4030,7 @@ float_cons (float_type)
          know (length > 0);
          if (err)
            {
-             as_bad ("Bad floating literal: %s", err);
+             as_bad (_("Bad floating literal: %s"), err);
              ignore_rest_of_line ();
              return;
            }
@@ -3756,7 +4052,7 @@ float_cons (float_type)
              if (count_exp.X_op != O_constant
                  || count_exp.X_add_number <= 0)
                {
-                 as_warn ("unresolvable or nonpositive repeat count; using 1");
+                 as_warn (_("unresolvable or nonpositive repeat count; using 1"));
                }
              else
                count = count_exp.X_add_number;
@@ -3777,6 +4073,306 @@ float_cons (float_type)
   demand_empty_rest_of_line ();
 }                              /* float_cons() */
 \f
+/* Return the size of a LEB128 value */
+
+static inline int
+sizeof_sleb128 (value)
+     offsetT value;
+{
+  register int size = 0;
+  register unsigned byte;
+
+  do
+    {
+      byte = (value & 0x7f);
+      /* Sadly, we cannot rely on typical arithmetic right shift behaviour.
+        Fortunately, we can structure things so that the extra work reduces
+        to a noop on systems that do things "properly".  */
+      value = (value >> 7) | ~(-(offsetT)1 >> 7);
+      size += 1;
+    }
+  while (!(((value == 0) && ((byte & 0x40) == 0))
+          || ((value == -1) && ((byte & 0x40) != 0))));
+
+  return size;
+}
+
+static inline int
+sizeof_uleb128 (value)
+     valueT value;
+{
+  register int size = 0;
+  register unsigned byte;
+
+  do
+    {
+      byte = (value & 0x7f);
+      value >>= 7;
+      size += 1;
+    }
+  while (value != 0);
+
+  return size;
+}
+
+int
+sizeof_leb128 (value, sign)
+     valueT value;
+     int sign;
+{
+  if (sign)
+    return sizeof_sleb128 ((offsetT) value);
+  else
+    return sizeof_uleb128 (value);
+}
+
+/* Output a LEB128 value.  */
+
+static inline int
+output_sleb128 (p, value)
+     char *p;
+     offsetT value;
+{
+  register char *orig = p;
+  register int more;
+
+  do
+    {
+      unsigned byte = (value & 0x7f);
+
+      /* Sadly, we cannot rely on typical arithmetic right shift behaviour.
+        Fortunately, we can structure things so that the extra work reduces
+        to a noop on systems that do things "properly".  */
+      value = (value >> 7) | ~(-(offsetT)1 >> 7);
+
+      more = !((((value == 0) && ((byte & 0x40) == 0))
+               || ((value == -1) && ((byte & 0x40) != 0))));
+      if (more)
+       byte |= 0x80;
+
+      *p++ = byte;
+    }
+  while (more);
+
+  return p - orig;
+}
+
+static inline int
+output_uleb128 (p, value)
+     char *p;
+     valueT value;
+{
+  char *orig = p;
+
+  do
+    {
+      unsigned byte = (value & 0x7f);
+      value >>= 7;
+      if (value != 0)
+       /* More bytes to follow.  */
+       byte |= 0x80;
+
+      *p++ = byte;
+    }
+  while (value != 0);
+
+  return p - orig;
+}
+
+inline int
+output_leb128 (p, value, sign)
+     char *p;
+     valueT value;
+     int sign;
+{
+  if (sign)
+    return output_sleb128 (p, (offsetT) value);
+  else
+    return output_uleb128 (p, value);
+}
+
+/* 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.  */
+
+static int
+output_big_sleb128 (p, bignum, size)
+     char *p;
+     LITTLENUM_TYPE *bignum;
+     int size;
+{
+  char *orig = p;
+  valueT val = 0;
+  int loaded = 0;
+  unsigned byte;
+
+  /* Strip leading sign extensions off the bignum.  */
+  while (size > 0 && bignum[size-1] == (LITTLENUM_TYPE)-1)
+    size--;
+
+  do
+    {
+      if (loaded < 7 && size > 0)
+       {
+         val |= (*bignum << loaded);
+         loaded += 8 * CHARS_PER_LITTLENUM;
+         size--;
+         bignum++;
+       }
+
+      byte = val & 0x7f;
+      loaded -= 7;
+      val >>= 7;
+
+      if (size == 0)
+       {
+         if ((val == 0 && (byte & 0x40) == 0)
+             || (~(val | ~(((valueT)1 << loaded) - 1)) == 0
+                 && (byte & 0x40) != 0))
+           byte |= 0x80;
+       }
+
+      if (orig)
+       *p = byte;
+      p++;
+    }
+  while (byte & 0x80);
+
+  return p - orig;
+}
+
+static int
+output_big_uleb128 (p, bignum, size)
+     char *p;
+     LITTLENUM_TYPE *bignum;
+     int size;
+{
+  char *orig = p;
+  valueT val = 0;
+  int loaded = 0;
+  unsigned byte;
+
+  /* Strip leading zeros off the bignum.  */
+  /* XXX: Is this needed?  */
+  while (size > 0 && bignum[size-1] == 0)
+    size--;
+
+  do
+    {
+      if (loaded < 7 && size > 0)
+       {
+         val |= (*bignum << loaded);
+         loaded += 8 * CHARS_PER_LITTLENUM;
+         size--;
+         bignum++;
+       }
+
+      byte = val & 0x7f;
+      loaded -= 7;
+      val >>= 7;
+
+      if (size > 0 || val)
+       byte |= 0x80;
+
+      if (orig)
+       *p = byte;
+      p++;
+    }
+  while (byte & 0x80);
+
+  return p - orig;
+}
+
+static inline int
+output_big_leb128 (p, bignum, size, sign)
+     char *p;
+     LITTLENUM_TYPE *bignum;
+     int size, sign;
+{
+  if (sign)
+    return output_big_sleb128 (p, bignum, size);
+  else
+    return output_big_uleb128 (p, bignum, size);
+}
+
+/* Generate the appropriate fragments for a given expression to emit a
+   leb128 value.  */
+
+void
+emit_leb128_expr(exp, sign)
+     expressionS *exp;
+     int sign;
+{
+  operatorT op = exp->X_op;
+
+  if (op == O_absent || op == O_illegal)
+    {
+      as_warn (_("zero assumed for missing expression"));
+      exp->X_add_number = 0;
+      op = O_constant;
+    }
+  else if (op == O_big && exp->X_add_number <= 0)
+    {
+      as_bad (_("floating point number invalid; zero assumed"));
+      exp->X_add_number = 0;
+      op = O_constant;
+    }
+  else if (op == O_register)
+    {
+      as_warn (_("register value used as expression"));
+      op = O_constant;
+    }
+
+  if (op == O_constant)
+    {
+      /* If we've got a constant, emit the thing directly right now.  */
+
+      valueT value = exp->X_add_number;
+      int size;
+      char *p;
+
+      size = sizeof_leb128 (value, sign);
+      p = frag_more (size);
+      output_leb128 (p, value, sign);
+    }
+  else if (op == O_big)
+    {
+      /* O_big is a different sort of constant.  */
+
+      int size;
+      char *p;
+
+      size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign);
+      p = frag_more (size);
+      output_big_leb128 (p, generic_bignum, exp->X_add_number, sign);
+    }
+  else
+    {
+      /* Otherwise, we have to create a variable sized fragment and 
+        resolve things later.  */
+
+      frag_var (rs_leb128, sizeof_uleb128 (~(valueT)0), 0, sign,
+               make_expr_symbol (exp), 0, (char *) NULL);
+    }
+}
+
+/* Parse the .sleb128 and .uleb128 pseudos.  */
+
+void
+s_leb128 (sign)
+     int sign;
+{
+  expressionS exp;
+
+  do {
+    expression (&exp);
+    emit_leb128_expr (&exp, sign);
+  } while (*input_line_pointer++ == ',');
+
+  input_line_pointer--;
+  demand_empty_rest_of_line ();
+}
+\f
 /*
  *                     stringer()
  *
@@ -3792,6 +4388,7 @@ stringer (append_zero)            /* Worker to do .ascii etc statements. */
      register int append_zero; /* 0: don't append '\0', else 1 */
 {
   register unsigned int c;
+  char *start;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
@@ -3799,7 +4396,7 @@ stringer (append_zero)            /* Worker to do .ascii etc statements. */
 
   /*
    * The following awkward logic is to parse ZERO or more strings,
-   * comma seperated. Recall a string expression includes spaces
+   * comma separated. Recall a string expression includes spaces
    * before the opening '\"' and spaces after the closing '\"'.
    * We fake a leading ',' if there is (supposed to be)
    * a 1st, expression. We keep demanding expressions for each
@@ -3821,6 +4418,7 @@ stringer (append_zero)            /* Worker to do .ascii etc statements. */
        {
        case '\"':
          ++input_line_pointer; /*->1st char of string. */
+         start = input_line_pointer;
          while (is_a_char (c = next_char_of_string ()))
            {
              FRAG_APPEND_1_CHAR (c);
@@ -3830,6 +4428,27 @@ stringer (append_zero)           /* Worker to do .ascii etc statements. */
              FRAG_APPEND_1_CHAR (0);
            }
          know (input_line_pointer[-1] == '\"');
+
+#ifndef NO_LISTING
+#ifdef OBJ_ELF
+         /* In ELF, when gcc is emitting DWARF 1 debugging output, it
+             will emit .string with a filename in the .debug section
+             after a sequence of constants.  See the comment in
+             emit_expr for the sequence.  emit_expr will set
+             dwarf_file_string to non-zero if this string might be a
+             source file name.  */
+         if (strcmp (segment_name (now_seg), ".debug") != 0)
+           dwarf_file_string = 0;
+         else if (dwarf_file_string)
+           {
+             c = input_line_pointer[-1];
+             input_line_pointer[-1] = '\0';
+             listing_source_file (start);
+             input_line_pointer[-1] = c;
+           }
+#endif
+#endif
+
          break;
        case '<':
          input_line_pointer++;
@@ -3837,7 +4456,7 @@ stringer (append_zero)            /* Worker to do .ascii etc statements. */
          FRAG_APPEND_1_CHAR (c);
          if (*input_line_pointer != '>')
            {
-             as_bad ("Expected <nn>");
+             as_bad (_("Expected <nn>"));
            }
          input_line_pointer++;
          break;
@@ -3870,7 +4489,7 @@ next_char_of_string ()
       break;
 
     case '\n':
-      as_warn ("Unterminated string: Newline inserted.");
+      as_warn (_("Unterminated string: Newline inserted."));
       bump_line_counters ();
       break;
 
@@ -3953,7 +4572,7 @@ next_char_of_string ()
 
        case '\n':
          /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
-         as_warn ("Unterminated string: Newline inserted.");
+         as_warn (_("Unterminated string: Newline inserted."));
          c = '\n';
          bump_line_counters ();
          break;
@@ -3961,7 +4580,7 @@ next_char_of_string ()
        default:
 
 #ifdef ONLY_STANDARD_ESCAPES
-         as_bad ("Bad escaped character in string, '?' assumed");
+         as_bad (_("Bad escaped character in string, '?' assumed"));
          c = '?';
 #endif /* ONLY_STANDARD_ESCAPES */
 
@@ -3987,7 +4606,7 @@ get_segmented_expression (expP)
       || expP->X_op == O_absent
       || expP->X_op == O_big)
     {
-      as_bad ("expected address expression; zero assumed");
+      as_bad (_("expected address expression; zero assumed"));
       expP->X_op = O_constant;
       expP->X_add_number = 0;
       retval = absolute_section;
@@ -4007,10 +4626,10 @@ get_known_segmented_expression (expP)
         expression.  */
       if (expP->X_add_symbol != NULL
          && S_GET_SEGMENT (expP->X_add_symbol) != expr_section)
-       as_warn ("symbol \"%s\" undefined; zero assumed",
+       as_warn (_("symbol \"%s\" undefined; zero assumed"),
                 S_GET_NAME (expP->X_add_symbol));
       else
-       as_warn ("some symbol undefined; zero assumed");
+       as_warn (_("some symbol undefined; zero assumed"));
       retval = absolute_section;
       expP->X_op = O_constant;
       expP->X_add_number = 0;
@@ -4028,7 +4647,7 @@ get_absolute_expression ()
   if (exp.X_op != O_constant)
     {
       if (exp.X_op != O_absent)
-       as_bad ("bad or irreducible absolute expression; zero assumed");
+       as_bad (_("bad or irreducible absolute expression; zero assumed"));
       exp.X_add_number = 0;
     }
   return exp.X_add_number;
@@ -4066,7 +4685,7 @@ demand_copy_C_string (len_pointer)
              s = 0;
              len = 1;
              *len_pointer = 0;
-             as_bad ("This string may not contain \'\\0\'");
+             as_bad (_("This string may not contain \'\\0\'"));
            }
        }
     }
@@ -4105,7 +4724,7 @@ demand_copy_string (lenP)
     }
   else
     {
-      as_warn ("Missing string");
+      as_warn (_("Missing string"));
       retval = NULL;
       ignore_rest_of_line ();
     }
@@ -4130,11 +4749,12 @@ is_it_end_of_statement ()
 }                              /* is_it_end_of_statement() */
 
 void 
-equals (sym_name)
+equals (sym_name, reassign)
      char *sym_name;
+     int reassign;
 {
   register symbolS *symbolP;   /* symbol we are working with */
-  char *stop;
+  char *stop = NULL;
   char stopc;
 
   input_line_pointer++;
@@ -4160,11 +4780,19 @@ equals (sym_name)
   else
     {
       symbolP = symbol_find_or_make (sym_name);
+      /* Permit register names to be redefined.  */
+      if (! reassign
+         && S_IS_DEFINED (symbolP)
+         && S_GET_SEGMENT (symbolP) != reg_section)
+       as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
       pseudo_set (symbolP);
     }
 
   if (flag_mri)
-    mri_comment_end (stop, stopc);
+     {
+       ignore_rest_of_line (); /* check garbage after the expression */
+       mri_comment_end (stop, stopc);
+     }
 }                              /* equals() */
 
 /* .include -- include a file at this point. */
@@ -4181,7 +4809,15 @@ s_include (arg)
   char *path;
 
   if (! flag_m68k_mri)
-    filename = demand_copy_string (&i);
+    {
+      filename = demand_copy_string (&i);
+      if (filename == NULL)
+       {
+         /* demand_copy_string has already printed an error and
+             called ignore_rest_of_line.  */
+         return;
+       }
+    }
   else
     {
       SKIP_WHITESPACE ();
@@ -4216,6 +4852,7 @@ s_include (arg)
   path = filename;
 gotit:
   /* malloc Storage leak when file is found on path.  FIXME-SOMEDAY. */
+  register_dependency (path);
   newbuf = input_scrub_include_file (path, input_line_pointer);
   buffer_limit = input_scrub_next_buffer (&input_line_pointer);
 }                              /* s_include() */
@@ -4245,7 +4882,140 @@ add_include_dir (path)
   if (i > include_dir_maxlen)
     include_dir_maxlen = i;
 }                              /* add_include_dir() */
+\f
+/* Output debugging information to denote the source file.  */
+
+static void
+generate_file_debug ()
+{
+  if (debug_type == DEBUG_STABS)
+    stabs_generate_asm_file ();
+}
+
+/* Output line number debugging information for the current source line.  */
+
+static void
+generate_lineno_debug ()
+{
+#ifdef ECOFF_DEBUGGING
+  /* ECOFF assemblers automatically generate debugging information. 
+     FIXME: This should probably be handled elsewhere.  */
+  if (debug_type == DEBUG_UNSPECIFIED)
+    {
+      if (ECOFF_DEBUGGING && ecoff_no_current_file ())
+        debug_type = DEBUG_ECOFF;
+      else
+       debug_type = DEBUG_NONE;
+    }
+#endif
+
+  switch (debug_type)
+    {
+      case DEBUG_UNSPECIFIED:
+      case DEBUG_NONE:
+       break;
+      case DEBUG_STABS:
+       stabs_generate_asm_lineno ();
+       break;
+      case DEBUG_ECOFF:
+       ecoff_generate_asm_lineno ();
+       break;
+    }
+}
+
+/* Output debugging information to mark a function entry point or end point.
+   END_P is zero for .func, and non-zero for .endfunc.  */
+
+void
+s_func (end_p)
+     int end_p;
+{
+  do_s_func (end_p, NULL);
+}
+
+/* Subroutine of s_func so targets can choose a different default prefix.
+   If DEFAULT_PREFIX is NULL, use the target's "leading char".  */
+
+void
+do_s_func (end_p, default_prefix)
+     int end_p;
+     const char *default_prefix;
+{
+  /* Record the current function so that we can issue an error message for
+     misplaced .func,.endfunc, and also so that .endfunc needs no
+     arguments.  */
+  static char *current_name;
+  static char *current_label;
 
+  if (end_p)
+    {
+      if (current_name == NULL)
+       {
+         as_bad (_("missing .func"));
+         ignore_rest_of_line ();
+         return;
+       }
+
+      if (debug_type == DEBUG_STABS)
+       stabs_generate_asm_endfunc (current_name, current_label);
+
+      current_name = current_label = NULL;
+    }
+  else /* ! end_p */
+    {
+      char *name,*label;
+      char delim1,delim2;
+
+      if (current_name != NULL)
+       {
+         as_bad (_(".endfunc missing for previous .func"));
+         ignore_rest_of_line ();
+         return;
+       }
+
+      name = input_line_pointer;
+      delim1 = get_symbol_end ();
+      name = xstrdup (name);
+      *input_line_pointer = delim1;
+      SKIP_WHITESPACE ();
+      if (*input_line_pointer != ',')
+       {
+         if (default_prefix)
+           asprintf (&label, "%s%s", default_prefix, name);
+         else
+           {
+             char leading_char = 0;
+#ifdef BFD_ASSEMBLER
+             leading_char = bfd_get_symbol_leading_char (stdoutput);
+#endif
+             /* Missing entry point, use function's name with the leading
+                char prepended.  */
+             if (leading_char)
+               asprintf (&label, "%c%s", leading_char, name);
+             else
+               label = name;
+           }
+       }
+      else
+       {
+         ++input_line_pointer;
+         SKIP_WHITESPACE ();
+         label = input_line_pointer;
+         delim2 = get_symbol_end ();
+         label = xstrdup (label);
+         *input_line_pointer = delim2;
+       }
+
+      if (debug_type == DEBUG_STABS)
+       stabs_generate_asm_func (name, label);
+
+      current_name = name;
+      current_label = label;
+    }
+
+  demand_empty_rest_of_line ();
+}
+\f
 void 
 s_ignore (arg)
      int arg;