* subsegs.c (subseg_new): Set output_section of new section.
authorIan Lance Taylor <ian@airs.com>
Thu, 1 Apr 1993 02:14:29 +0000 (02:14 +0000)
committerIan Lance Taylor <ian@airs.com>
Thu, 1 Apr 1993 02:14:29 +0000 (02:14 +0000)
* as.c (perform_an_assemly_pass): Don't set output_section here.
* expr.c (expr_part, expr): Turn off section assertions for ECOFF,
since it has additional sections.
* read.c (s_lcomm): For MIPS ECOFF, put small objects in .sbss,
not bss_section.
* config/obj-ecoff.h (TARGET_SYMBOL_FIELDS): Added
ecoff_undefined field.
* config/obj-ecoff.c (obj_symbol_new_hook): Initialize
ecoff_undefined field.
(add_file): If using stabs, just output a stabs symbol rather than
creating a new fdr.
(obj_ecoff_begin, obj_ecoff_bend): Ignore line number by reading
it with get_absolute_expression, rather than skipping it by hand.
(obj_ecoff_loc): If using stabs, just output a stabs symbol rather
than ECOFF line number information.
(obj_ecoff_stab): Accept non-zero values for stabs line number.
(ecoff_build_symbols): Set ifilesym correctly.  Set storage class
to small, undefined and/or readonly sections if appropriate.
Don't output symbol names containing \001 characters.
(ecoff_frob_file): Make sure at least one fdr is output.
* config/tc-mips.h: Define TC_MIPS.
* config/tc-mips.c (g_switch_value): New static variable.
(md_assemble): Set gp size of output BFD.
(gp_reference): New function; returns 1 if expression can be
accesssed via gp.  Always returns 0 if not using ECOFF.
(macro_build): Convert BFD_RELOC_LO16 to BFD_RELOC_MIPS_GPREL if
possible.
(macro): Generate sequences using gp if possible.
(md_parse_option): Ignore -EL and -EB.  Parse -G.
(md_apply_fix): Added BFD_RELOC_MIPS_GPREL to ignored case.
(s_change_sec): Handle .rdata and .sdata for ECOFF.
(s_extern): Mark symbol as external.  Set ecoff_undefined field.

gas/ChangeLog
gas/config/obj-ecoff.c
gas/config/tc-mips.c
gas/config/tc-mips.h [new file with mode: 0644]

index 951b1a7b8afbaf27d8ffb42b27c8993d2a764bde..ce9a9dbb000f214ebac0e31d4fc85a443466cbc1 100644 (file)
@@ -1,5 +1,47 @@
+Wed Mar 31 17:53:54 1993  Ian Lance Taylor  (ian@cygnus.com)
+
+       * subsegs.c (subseg_new): Set output_section of new section.
+       * as.c (perform_an_assemly_pass): Don't set output_section here.
+       * expr.c (expr_part, expr): Turn off section assertions for ECOFF,
+       since it has additional sections.
+       * read.c (s_lcomm): For MIPS ECOFF, put small objects in .sbss,
+       not bss_section.
+       * config/obj-ecoff.h (TARGET_SYMBOL_FIELDS): Added
+       ecoff_undefined field.
+       * config/obj-ecoff.c (obj_symbol_new_hook): Initialize
+       ecoff_undefined field.
+       (add_file): If using stabs, just output a stabs symbol rather than
+       creating a new fdr.
+       (obj_ecoff_begin, obj_ecoff_bend): Ignore line number by reading
+       it with get_absolute_expression, rather than skipping it by hand.
+       (obj_ecoff_loc): If using stabs, just output a stabs symbol rather
+       than ECOFF line number information.
+       (obj_ecoff_stab): Accept non-zero values for stabs line number.
+       (ecoff_build_symbols): Set ifilesym correctly.  Set storage class
+       to small, undefined and/or readonly sections if appropriate.
+       Don't output symbol names containing \001 characters.
+       (ecoff_frob_file): Make sure at least one fdr is output.
+       * config/tc-mips.h: Define TC_MIPS.
+       * config/tc-mips.c (g_switch_value): New static variable.
+       (md_assemble): Set gp size of output BFD.
+       (gp_reference): New function; returns 1 if expression can be
+       accesssed via gp.  Always returns 0 if not using ECOFF.
+       (macro_build): Convert BFD_RELOC_LO16 to BFD_RELOC_MIPS_GPREL if
+       possible.
+       (macro): Generate sequences using gp if possible.
+       (md_parse_option): Ignore -EL and -EB.  Parse -G.
+       (md_apply_fix): Added BFD_RELOC_MIPS_GPREL to ignored case.
+       (s_change_sec): Handle .rdata and .sdata for ECOFF.
+       (s_extern): Mark symbol as external.  Set ecoff_undefined field.
+
 Tue Mar 30 10:11:41 1993  Ken Raeburn  (raeburn@cambridge.cygnus.com)
 
+       * output-file.c (output_file_create): Don't call as_perror for
+       filename rejected by application.
+
+       * as.c (main) [BFD_ASSEMBLER]: If errors occur, close and unlink
+       the output file.
+
        * doc/as.texinfo: Don't use @value in node names for the moment;
        references don't appear to work right.
 
index d0a9b044e93d0a3c87681719e34c9c3bc5681a99..5677ee142750825ef04ed40519cf1149896d0169 100644 (file)
@@ -30,6 +30,8 @@
 #include "aout/stab_gnu.h"
 #include "../bfd/libecoff.h"
 
+#include <ctype.h>
+
 /* Why isn't this in coff/sym.h?  */
 #define ST_RFDESCAPE 0xfff
 
@@ -1578,6 +1580,7 @@ obj_symbol_new_hook (symbolP)
 {
   symbolP->ecoff_file = cur_file_ptr;
   symbolP->ecoff_symbol = 0;
+  symbolP->ecoff_undefined = 0;
 }
 \f
 /* Add a page to a varray object.  */
@@ -2203,6 +2206,8 @@ add_procedure (func)
 
   new_proc_ptr->pdr.isym = -1;
   new_proc_ptr->pdr.iline = -1;
+  new_proc_ptr->pdr.lnLow = -1;
+  new_proc_ptr->pdr.lnHigh = -1;
 
   /* Push the start of the function.  */
   new_proc_ptr->sym = add_ecoff_symbol ((const char *) NULL, st_Proc, sc_Text,
@@ -2261,6 +2266,17 @@ add_file (file_name, indx)
        }
     }
 
+  /* If we're creating stabs, then we don't actually make a new FDR.
+     Instead, we just create a stabs symbol.  */
+  if (stabs_seen)
+    {
+      (void) add_ecoff_symbol (file_name, st_Nil, sc_Nil,
+                              symbol_new ("L0\001", now_seg,
+                                          frag_now_fix (), frag_now),
+                              0, MIPS_MARK_STAB (N_SOL));
+      return;
+    }
+
   first_ch = *file_name;
 
   /* See if the file has already been created.  */
@@ -2440,9 +2456,8 @@ obj_ecoff_begin (ignore)
   *input_line_pointer = name_end;
 
   /* The line number follows, but we don't use it.  */
-  while (! is_end_of_line[*input_line_pointer])
-    input_line_pointer++;
-  input_line_pointer++;
+  (void) get_absolute_expression ();
+  demand_empty_rest_of_line ();
 }
 \f
 /* Parse .bend directives which have a label as the first argument
@@ -2486,9 +2501,8 @@ obj_ecoff_bend (ignore)
   *input_line_pointer = name_end;
 
   /* The line number follows, but we don't use it.  */
-  while (! is_end_of_line[*input_line_pointer])
-    input_line_pointer++;
-  input_line_pointer++;
+  (void) get_absolute_expression ();
+  demand_empty_rest_of_line ();
 }
 \f
 /* COFF debugging information is provided as a series of directives
@@ -3201,7 +3215,6 @@ static void
 obj_ecoff_loc (ignore)
      int ignore;
 {
-  char buf[20];
   lineno_list_t *list;
 
   if (cur_file_ptr == (efdr_t *) NULL)
@@ -3223,6 +3236,17 @@ obj_ecoff_loc (ignore)
   get_absolute_expression ();
   SKIP_WHITESPACE ();
 
+  /* If we're building stabs, then output a special label rather than
+     ECOFF line number info.  */
+  if (stabs_seen)
+    {
+      (void) add_ecoff_symbol ((char *) NULL, st_Label, sc_Text,
+                              symbol_new ("L0\001", now_seg,
+                                          frag_now_fix (), frag_now),
+                              0, get_absolute_expression ());
+      return;
+    }
+
   list = allocate_lineno_list ();
 
   list->next = (lineno_list_t *) NULL;
@@ -3395,17 +3419,14 @@ obj_ecoff_stab (type)
 
       value = 0;
       st = st_Label;
-      sc = sc_Undefined;
+      sc = sc_Text;
     }
   else
     {
-      /* Skip 0, */
-      if (get_absolute_expression () != 0)
-       {
-         as_warn ("Bad .stab%c directive (expected 0)", type);
-         demand_empty_rest_of_line ();
-         return;
-       }
+      /* The next number is sometimes the line number of the
+        declaration.  We have nowhere to put it, so we just ignore
+        it.  */
+      (void) get_absolute_expression ();
       
       SKIP_WHITESPACE ();
       if (*input_line_pointer++ != ',')
@@ -3442,17 +3463,8 @@ obj_ecoff_stab (type)
 
          sym = symbol_find_or_make (name);
 
-         /* Traditionally, N_LBRAC and N_RBRAC are *not* relocated. */
-         if (code == N_LBRAC || code == N_RBRAC)
-           {
-             sc = sc_Nil;
-             st = st_Nil;
-           }
-         else
-           {
-             sc = sc_Undefined;
-             st = st_Nil;
-           }
+         sc = sc_Nil;
+         st = st_Nil;
          value = 0;
 
          *input_line_pointer = name_end;
@@ -3512,6 +3524,7 @@ ecoff_longword_adjust (buf, bufend, offset, bufptrptr)
       add = 4 - (offset & 3);
       if (*bufend - (*buf + offset) < add)
        (void) ecoff_add_bytes (buf, bufend, *buf + offset, add);
+      memset (*buf + offset, 0, add);
       offset += add;
       if (bufptrptr != (char **) NULL)
        *bufptrptr = *buf + offset;
@@ -3536,6 +3549,7 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
   proc_t *proc;
   long c;
   long iline;
+  long totcount;
 
   bufptr = *buf + offset;
 
@@ -3544,11 +3558,28 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
   last = (lineno_list_t *) NULL;
   c = offset;
   iline = 0;
+  totcount = 0;
   for (l = first_lineno; l != (lineno_list_t *) NULL; l = l->next)
     {
       long count;
       long delta;
-      int didone;
+
+      /* Get the offset to the memory address of the next line number
+        (in words).  Do this first, so that we can skip ahead to the
+        next useful line number entry.  */
+      if (l->next == (lineno_list_t *) NULL)
+       count = 0;
+      else
+       {
+         count = ((l->next->frag->fr_address + l->next->paddr
+                   - (l->frag->fr_address + l->paddr))
+                  >> 2);
+         if (count <= 0)
+           {
+             /* Don't change last, so we still get the right delta.  */
+             continue;
+           }
+       }
 
       if (l->file != file || l->proc != proc)
        {
@@ -3557,11 +3588,11 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
          if (l->file != file && file != (efdr_t *) NULL)
            {
              file->fdr.cbLine = c - file->fdr.cbLineOffset;
-             file->fdr.cline = iline - file->fdr.ilineBase;
+             /* The cline field is ill-documented.  This is a guess
+                at the right value.  */
+             file->fdr.cline = totcount + count;
            }
 
-         c = ecoff_longword_adjust (buf, bufend, c, &bufptr);
-
          if (l->file != file)
            {
              file = l->file;
@@ -3573,33 +3604,18 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
              proc = l->proc;
              if (proc != (proc_t *) NULL)
                {
-                 /* The iline field is ill-documented.  This is a
-                    guess at the right value.  */
-                 proc->pdr.iline = l->frag->fr_address + l->paddr;
                  proc->pdr.lnLow = l->lineno;
                  proc->pdr.cbLineOffset = c - file->fdr.cbLineOffset;
+                 /* The iline field is ill-documented.  This is a
+                    guess at the right value.  */
+                 proc->pdr.iline = totcount;
                }
            }
 
          last = (lineno_list_t *) NULL;
        }      
 
-      /* Get the offset to the memory address of the next line number
-        (in words).  */
-      if (l->next == (lineno_list_t *) NULL)
-       count = 0;
-      else
-       {
-         count = (((l->next->frag->fr_address + l->next->paddr
-                    - (l->frag->fr_address + l->paddr))
-                   >> 2)
-                  - 1);
-         if (count < 0)
-           {
-             /* Don't change last, so we still get the right delta.  */
-             continue;
-           }
-       }
+      totcount += count;
 
       /* Get the offset to this line number.  */
       if (last == (lineno_list_t *) NULL)
@@ -3607,40 +3623,30 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
       else
        delta = l->lineno - last->lineno;
 
-      /* We can only adjust the address by 16 words at a time.  */
-      didone = 0;
-      while (count > 0x10)
+      /* Put in the offset to this line number.  */
+      while (delta != 0)
        {
-         if (bufptr >= *bufend)
-           bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1);
-         if (delta >= 7)
-           {
-             *bufptr++ = 0x0f + (7 << 4);
-             delta -= 7;
-           }
-         else if (delta <= -7)
+         int setcount;
+
+         /* 1 is added to each count read.  */
+         --count;
+         /* We can only adjust the word count by up to 15 words at a
+            time.  */
+         if (count <= 0x0f)
            {
-             *bufptr++ = 0x0f + (-7 << 4);
-             delta += 7;
+             setcount = count;
+             count = 0;
            }
          else
            {
-             *bufptr++ = 0x0f + (delta << 4);
-             delta = 0;
+             setcount = 0x0f;
+             count -= 0x0f;
            }
-         ++c;
-         count -= 0x10;
-         didone = 1;
-       }
-
-      /* Put in the offset to this line number.  */
-      while (delta != 0 || ! didone)
-       {
          if (delta >= -7 && delta <= 7)
            {
              if (bufptr >= *bufend)
                bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1);
-             *bufptr++ = count + (delta << 4);
+             *bufptr++ = setcount + (delta << 4);
              delta = 0;
              ++c;
            }
@@ -3650,7 +3656,7 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
 
              if (*bufend - bufptr < 3)
                bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 3);
-             *bufptr++ = count + (8 << 4);
+             *bufptr++ = setcount + (8 << 4);
              if (delta < -0x8000)
                {
                  set = -0x8000;
@@ -3670,8 +3676,26 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
              *bufptr++ = set & 0xffff;
              c += 3;
            }
-         count = 0;
-         didone = 1;
+       }
+
+      /* Finish adjusting the count.  */
+      while (count > 0)
+       {
+         if (bufptr >= *bufend)
+           bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1);
+         /* 1 is added to each count read.  */
+         --count;
+         if (count > 0x0f)
+           {
+             *bufptr++ = 0x0f;
+             count -= 0x0f;
+           }
+         else
+           {
+             *bufptr++ = count;
+             count = 0;
+           }
+         ++c;
        }
 
       ++iline;
@@ -3683,7 +3707,7 @@ ecoff_build_lineno (buf, bufend, offset, linecntptr)
   if (file != (efdr_t *) NULL)
     {
       file->fdr.cbLine = c - file->fdr.cbLineOffset;
-      file->fdr.cline = iline - file->fdr.ilineBase;
+      file->fdr.cline = totcount;
     }
 
   c = ecoff_longword_adjust (buf, bufend, c, &bufptr);
@@ -3736,8 +3760,6 @@ ecoff_build_symbols (buf,
       efdr_t *fil_ptr;
       efdr_t *fil_end;
 
-      ifilesym = isym;
-
       if (file_link->next == (vlinks_t *) NULL)
        fil_cnt = file_desc.objects_last_page;
       else
@@ -3749,6 +3771,7 @@ ecoff_build_symbols (buf,
          vlinks_t *sym_link;
 
          fil_ptr->fdr.isymBase = isym;
+         ifilesym = isym;
          for (sym_link = fil_ptr->symbols.first;
               sym_link != (vlinks_t *) NULL;
               sym_link = sym_link->next)
@@ -3782,35 +3805,79 @@ ecoff_build_symbols (buf,
                  as_sym = sym_ptr->as_sym;
                  if (as_sym != (symbolS *) NULL)
                    {
-                     sym_ptr->ecoff_sym.value = S_GET_VALUE (as_sym);
+                     symint_t indx;
+
+                     /* The value of a block start symbol is the
+                        offset from the start of the procedure.  For
+                        other symbols we just use the gas value.  */
+                     if (sym_ptr->ecoff_sym.st == (int) st_Block
+                         && sym_ptr->ecoff_sym.sc == (int) sc_Text)
+                       {
+                         know (sym_ptr->proc_ptr != (proc_t *) NULL);
+                         sym_ptr->ecoff_sym.value =
+                           (S_GET_VALUE (as_sym)
+                            - S_GET_VALUE (sym_ptr->proc_ptr->sym->as_sym));
+                       }
+                     else
+                       sym_ptr->ecoff_sym.value = S_GET_VALUE (as_sym);
 
                      /* Get the type and storage class based on where
-                        the symbol actually wound up.  */
+                        the symbol actually wound up.  Traditionally,
+                        N_LBRAC and N_RBRAC are *not* relocated. */
+                     indx = sym_ptr->ecoff_sym.index;
                      if (sym_ptr->ecoff_sym.st == st_Nil
                          && sym_ptr->ecoff_sym.sc == sc_Nil
-                         && ! MIPS_IS_STAB (&sym_ptr->ecoff_sym))
+                         && (! MIPS_IS_STAB (&sym_ptr->ecoff_sym)
+                             || ((MIPS_UNMARK_STAB (indx) != N_LBRAC)
+                                 && (MIPS_UNMARK_STAB (indx) != N_RBRAC))))
                        {
+                         segT seg;
+                         const char *segname;
                          st_t st;
                          sc_t sc;
 
+                         seg = S_GET_SEGMENT (as_sym);
+                         segname = segment_name (seg);
+
                          if (S_IS_EXTERNAL (as_sym)
                              || ! S_IS_DEFINED (as_sym))
                            st = st_Global;
-                         else if (S_GET_SEGMENT (as_sym) == text_section)
+                         else if (seg == text_section)
                            st = st_Label;
                          else
                            st = st_Static;
 
-                         if (! S_IS_DEFINED (as_sym))
-                           sc = sc_Undefined;
+                         if (! S_IS_DEFINED (as_sym)
+                             || as_sym->ecoff_undefined)
+                           {
+                             if (S_GET_VALUE (as_sym) > 0
+                                 && (S_GET_VALUE (as_sym)
+                                     <= bfd_get_gp_size (stdoutput)))
+                               sc = sc_SUndefined;
+                             else
+                               sc = sc_Undefined;
+                           }
                          else if (S_IS_COMMON (as_sym))
-                           sc = sc_Common;
-                         else if (S_GET_SEGMENT (as_sym) == text_section)
+                           {
+                             if (S_GET_VALUE (as_sym) > 0
+                                 && (S_GET_VALUE (as_sym)
+                                     <= bfd_get_gp_size (stdoutput)))
+                               sc = sc_SCommon;
+                             else
+                               sc = sc_Common;
+                           }
+                         else if (seg == text_section)
                            sc = sc_Text;
-                         else if (S_GET_SEGMENT (as_sym) == data_section)
+                         else if (seg == data_section)
                            sc = sc_Data;
-                         else if (S_GET_SEGMENT (as_sym) == bss_section)
+                         else if (strcmp (segname, ".rdata") == 0)
+                           sc = sc_RData;
+                         else if (strcmp (segname, ".sdata") == 0)
+                           sc = sc_SData;
+                         else if (seg == bss_section)
                            sc = sc_Bss;
+                         else if (strcmp (segname, ".sbss") == 0)
+                           sc = sc_SBss;
                          else
                            abort ();
 
@@ -3827,13 +3894,17 @@ ecoff_build_symbols (buf,
                      if ((S_IS_EXTERNAL (as_sym)
                           || ! S_IS_DEFINED (as_sym))
                          && sym_ptr->proc_ptr == (proc_t *) NULL
-                         && sym_ptr->ecoff_sym.st != (int) st_Nil)
+                         && sym_ptr->ecoff_sym.st != (int) st_Nil
+                         && ! MIPS_IS_STAB (&sym_ptr->ecoff_sym))
                        local = 0;
 
                      /* If an st_end symbol has an associated gas
                         symbol, then it is a local label created for
-                        a .bend or .end directive.  */
-                     if (local && sym_ptr->ecoff_sym.st != st_End)
+                        a .bend or .end directive.  Stabs line
+                        numbers will have \001 in the names.  */
+                     if (local
+                         && sym_ptr->ecoff_sym.st != st_End
+                         && strchr (sym_ptr->name, '\001') == 0)
                        sym_ptr->ecoff_sym.iss =
                          add_string (&fil_ptr->strings,
                                      fil_ptr->str_hash,
@@ -3876,10 +3947,11 @@ ecoff_build_symbols (buf,
                        }
 
                      /* The value of the symbol marking the end of a
-                        procedure or block is the size of the
-                        procedure or block.  */
-                     if ((begin_type == st_Proc || begin_type == st_Block)
-                         && sym_ptr->ecoff_sym.sc != (int) sc_Info)
+                        procedure is the size of the procedure.  The
+                        value of the symbol marking the end of a
+                        block is the offset from the start of the
+                        procedure to the block.  */
+                     if (begin_type == st_Proc)
                        {
                          know (as_sym != (symbolS *) NULL);
                          know (begin_ptr->as_sym != (symbolS *) NULL);
@@ -3887,6 +3959,15 @@ ecoff_build_symbols (buf,
                            (S_GET_VALUE (as_sym)
                             - S_GET_VALUE (begin_ptr->as_sym));
                        }
+                     else if (begin_type == st_Block
+                              && sym_ptr->ecoff_sym.sc != (int) sc_Info)
+                       {
+                         know (as_sym != (symbolS *) NULL);
+                         know (sym_ptr->proc_ptr != (proc_t *) NULL);
+                         sym_ptr->ecoff_sym.value =
+                           (S_GET_VALUE (as_sym)
+                            - S_GET_VALUE (sym_ptr->proc_ptr->sym->as_sym));
+                       }
                    }
 
                  for (f = sym_ptr->forward_ref;
@@ -3908,18 +3989,21 @@ ecoff_build_symbols (buf,
                      ecoff_swap_sym_out (stdoutput, &sym_ptr->ecoff_sym,
                                          sym_out);
                      ++sym_out;
+
                      sym_ptr->sym_index = isym;
-                     ++isym;
 
                      if (sym_ptr->proc_ptr != (proc_t *) NULL
                          && sym_ptr->proc_ptr->sym == sym_ptr)
                        sym_ptr->proc_ptr->pdr.isym = isym - ifilesym;
+
+                     ++isym;
                    }
 
                  /* If this is an external symbol, swap it out.  */
                  if (as_sym != (symbolS *) NULL
                      && (S_IS_EXTERNAL (as_sym)
-                         || ! S_IS_DEFINED (as_sym)))
+                         || ! S_IS_DEFINED (as_sym))
+                     && ! MIPS_IS_STAB (&sym_ptr->ecoff_sym))
                    {
                      EXTR ext;
 
@@ -4325,6 +4409,10 @@ ecoff_frob_file ()
   struct hash_control *ext_str_hash;
   char *set;
 
+  /* Make sure we have a file.  */
+  if (first_file == (efdr_t *) NULL)
+    add_file ((const char *) NULL, 0);
+
   /* Handle any top level tags.  */
   for (ptag = top_tag_head->first_tag;
        ptag != (tag_t *) NULL;
@@ -4477,8 +4565,6 @@ ecoff_frob_file ()
 
 #undef SET
 
-  /* FIXME: set the gp value.  */
-
   /* FIXME: set the register masks.  */
 
   ecoff_data (stdoutput)->raw_size = offset;
index e37e5f70aba3f56962638d6b25ce53ffec9d9cd5..3a853f210d53b58f9fb027fc19d77cc6c2ce1b11 100644 (file)
@@ -41,6 +41,7 @@
 #include "mips-opcode.h"
 
 #define AT  1
+#define GP  28
 #define RA  31
 
 static int mips_warn_about_macros;
@@ -49,6 +50,11 @@ static int mips_nomove;
 static int mips_noat;
 static int mips_nobopt;
 
+#ifdef OBJ_ECOFF
+/* The size of the small data section.  */
+static int g_switch_value = 8;
+#endif
+
 #define N_RMASK 0xc4
 #define N_VFP   0xd4
 
@@ -84,7 +90,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
    but nothing is ideal around here.
  */
 
-static char    *insn_error;
+static char *insn_error;
 
 static int byte_order = BYTE_ORDER;
 
@@ -99,25 +105,26 @@ static int auto_align = 1;
 #define internalError() as_fatal ("MIPS internal Error");
 #endif
 
-static void append_insn PARAMS ((struct mips_cl_insn *ip,
-                                expressionS *p,
+static void append_insn PARAMS ((struct mips_cl_insn * ip,
+                                expressionS * p,
                                 bfd_reloc_code_real_type r));
-static void macro_build PARAMS ((int *counter, expressionS *ep,
+static int gp_reference PARAMS ((expressionS * ep));
+static void macro_build PARAMS ((int *counter, expressionS * ep,
                                 const char *name, const char *fmt,
                                 ...));
-static void macro_build_lui PARAMS ((int *counter, expressionS *ep,
+static void macro_build_lui PARAMS ((int *counter, expressionS * ep,
                                     int regnum));
 static void set_at PARAMS ((int *counter, int reg));
 static void set_at_unsigned PARAMS ((int *counter, int reg));
-static void check_absolute_expr PARAMS ((struct mips_cl_insn *ip,
-                                        expressionS *expr));
+static void check_absolute_expr PARAMS ((struct mips_cl_insn * ip,
+                                        expressionS * expr));
 static void load_register PARAMS ((int *counter,
-                                  struct mips_cl_insn *ip,
-                                  int reg, expressionS *ep));
-static void macro PARAMS ((struct mips_cl_insn *ip));
-static void mips_ip PARAMS ((char *str, struct mips_cl_insn *ip));
-static int my_getSmallExpression PARAMS ((expressionS *ep, char *str));
-static void my_getExpression PARAMS ((expressionS *ep, char *str));
+                                  struct mips_cl_insn * ip,
+                                  int reg, expressionS * ep));
+static void macro PARAMS ((struct mips_cl_insn * ip));
+static void mips_ip PARAMS ((char *str, struct mips_cl_insn * ip));
+static int my_getSmallExpression PARAMS ((expressionS * ep, char *str));
+static void my_getExpression PARAMS ((expressionS * ep, char *str));
 static symbolS *get_symbol PARAMS ((void));
 static long get_optional_absolute_expression PARAMS ((void));
 static void s_align PARAMS ((int));
@@ -160,51 +167,52 @@ static void s_mask PARAMS ((char));
 
 const pseudo_typeS md_pseudo_table[] =
 {
 /* MIPS specific pseudo-ops.  */
-  { "option",          s_option,       0       },
-  { "set",             s_mipsset,      0       },
-  { "rdata",           s_change_sec,   'r',    },
-  { "sdata",           s_change_sec,   's',    },
+ /* MIPS specific pseudo-ops.  */
+  {"option", s_option, 0},
+  {"set", s_mipsset, 0},
+  {"rdata", s_change_sec, 'r',},
+  {"sdata", s_change_sec, 's',},
 
 /* Relatively generic pseudo-ops that happen to be used on MIPS
+ /* Relatively generic pseudo-ops that happen to be used on MIPS
      chips.  */
-  { "asciiz",          stringer,       1       },
-  { "bss",             s_change_sec,   'b'     },
-  { "err",             s_err,          0       },
-  { "half",            s_cons,         1       },
+  {"asciiz", stringer, 1},
+  {"bss", s_change_sec, 'b'},
+  {"err", s_err, 0},
+  {"half", s_cons, 1},
 
 /* These pseudo-ops are defined in read.c, but must be overridden
+ /* These pseudo-ops are defined in read.c, but must be overridden
      here for one reason or another.  */
-  { "align",           s_align,        0       },
-  { "byte",            s_cons,         0       },
-  { "data",            s_change_sec,   'd'     },
-  { "double",          s_float_cons,   1       },
-  { "extern",          s_extern,       0       },
-  { "float",           s_float_cons,   0       },
-  { "text",            s_change_sec,   't'     },
-  { "word",            s_cons,         2       },
+  {"align", s_align, 0},
+  {"byte", s_cons, 0},
+  {"data", s_change_sec, 'd'},
+  {"double", s_float_cons, 1},
+  {"extern", s_extern, 0},
+  {"float", s_float_cons, 0},
+  {"text", s_change_sec, 't'},
+  {"word", s_cons, 2},
 
 #ifndef OBJ_ECOFF
 /* These pseudo-ops should be defined by the object file format.
+ /* These pseudo-ops should be defined by the object file format.
      However, ECOFF is the only format which currently defines them,
      so we have versions here for a.out.  */
-  { "aent",            s_ent,          1       },
-  { "end",             s_mipsend,      0       },
-  { "ent",             s_ent,          0       },
-  { "file",            s_file,         0       },
-  { "fmask",           s_ignore,       'F'     },
-  { "frame",           s_ignore,       0       },
-  { "loc",             s_ignore,       0       },
-  { "mask",            s_ignore,       'R'     },
-  { "verstamp",                s_ignore,       0       },
+  {"aent", s_ent, 1},
+  {"end", s_mipsend, 0},
+  {"ent", s_ent, 0},
+  {"file", s_file, 0},
+  {"fmask", s_ignore, 'F'},
+  {"frame", s_ignore, 0},
+  {"loc", s_ignore, 0},
+  {"mask", s_ignore, 'R'},
+  {"verstamp", s_ignore, 0},
 #endif
 
 /* Sentinel.  */
-  { NULL }
+ /* Sentinel.  */
+  {NULL}
 };
 \f
-const relax_typeS md_relax_table[] = {
-       0
+const relax_typeS md_relax_table[] =
+{
+  0
 };
 
 
@@ -220,36 +228,42 @@ static bfd_reloc_code_real_type offset_reloc;
  * set up all the tables, etc. that the MD part of the assembler will need.
  */
 void
-md_begin()
+md_begin ()
 {
-    register char *retval = NULL;
-    register unsigned int i = 0;
+  register char *retval = NULL;
+  register unsigned int i = 0;
 
-    if ((op_hash = hash_new()) == NULL) {
-       as_fatal("Virtual memory exhausted");
+  if ((op_hash = hash_new ()) == NULL)
+    {
+      as_fatal ("Virtual memory exhausted");
     }
-    for (i = 0; i < NUMOPCODES;) {
-       const char *name = mips_opcodes[i].name;
-
-       retval = hash_insert(op_hash, name, &mips_opcodes[i]);
-       if (retval != NULL && *retval != '\0') {
-           fprintf (stderr, "internal error: can't hash `%s': %s\n",
-               mips_opcodes[i].name, retval);
-           as_fatal ("Broken assembler.  No assembly attempted.");
-       }
-       do {
-           if ((mips_opcodes[i].match & mips_opcodes[i].mask) !=
-             mips_opcodes[i].match) {
-               fprintf (stderr, "internal error: bad opcode: `%s' \"%s\"\n",
-                   mips_opcodes[i].name, mips_opcodes[i].args);
-               as_fatal ("Broken assembler.  No assembly attempted.");
+  for (i = 0; i < NUMOPCODES;)
+    {
+      const char *name = mips_opcodes[i].name;
+
+      retval = hash_insert (op_hash, name, &mips_opcodes[i]);
+      if (retval != NULL && *retval != '\0')
+       {
+         fprintf (stderr, "internal error: can't hash `%s': %s\n",
+                  mips_opcodes[i].name, retval);
+         as_fatal ("Broken assembler.  No assembly attempted.");
+       }
+      do
+       {
+         if ((mips_opcodes[i].match & mips_opcodes[i].mask) !=
+             mips_opcodes[i].match)
+           {
+             fprintf (stderr, "internal error: bad opcode: `%s' \"%s\"\n",
+                      mips_opcodes[i].name, mips_opcodes[i].args);
+             as_fatal ("Broken assembler.  No assembly attempted.");
            }
-           ++i;
-       } while ((i < NUMOPCODES) && !strcmp(mips_opcodes[i].name, name));
+         ++i;
+       }
+      while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
     }
 
 #ifndef OBJ_ECOFF
-    md_obj_begin ();
+  md_obj_begin ();
 #endif
 }
 
@@ -262,36 +276,42 @@ md_end ()
 }
 
 void
-md_assemble(str)
-    char *str;
+md_assemble (str)
+     char *str;
 {
-    struct mips_cl_insn insn;
-    static int init;
-
-    if (!init) {
-       /* set the default alignment for the text section (2**2) */
-       /* This should go in md_begin but text_section isn't initialized then */
-       record_alignment(text_section, 2);
-       init = 1;
+  struct mips_cl_insn insn;
+  static int init;
+
+  if (!init)
+    {
+      /* set the default alignment for the text section (2**2) */
+      /* This should go in md_begin but text_section isn't initialized then */
+      record_alignment (text_section, 2);
+      bfd_set_gp_size (stdoutput, g_switch_value);
+      init = 1;
     }
 
-    imm_expr.X_seg = absent_section;
-    offset_expr.X_seg = absent_section;
+  imm_expr.X_seg = absent_section;
+  offset_expr.X_seg = absent_section;
 
-    mips_ip(str, &insn);
-    if (insn_error) {
-       as_bad("%s `%s'", insn_error, str);
-       return;
+  mips_ip (str, &insn);
+  if (insn_error)
+    {
+      as_bad ("%s `%s'", insn_error, str);
+      return;
+    }
+  if (insn.insn_mo->pinfo == INSN_MACRO)
+    {
+      macro (&insn);
     }
-    if (insn.insn_mo->pinfo == INSN_MACRO) {
-       macro(&insn);
-    } else {
-       if (imm_expr.X_seg != absent_section)
-           append_insn(&insn, &imm_expr, imm_reloc);
-       else if (offset_expr.X_seg != absent_section)
-           append_insn(&insn, &offset_expr, offset_reloc);
-       else
-           append_insn(&insn, NULL, BFD_RELOC_UNUSED);
+  else
+    {
+      if (imm_expr.X_seg != absent_section)
+       append_insn (&insn, &imm_expr, imm_reloc);
+      else if (offset_expr.X_seg != absent_section)
+       append_insn (&insn, &offset_expr, offset_reloc);
+      else
+       append_insn (&insn, NULL, BFD_RELOC_UNUSED);
     }
 }
 
@@ -303,75 +323,116 @@ md_assemble(str)
  * Output an instruction.
  */
 static void
-append_insn(ip, address_expr, reloc_type)
-    struct mips_cl_insn *ip;
-    expressionS *address_expr;
-    bfd_reloc_code_real_type reloc_type;
+append_insn (ip, address_expr, reloc_type)
+     struct mips_cl_insn *ip;
+     expressionS *address_expr;
+     bfd_reloc_code_real_type reloc_type;
 {
-    char *f;
+  char *f;
 
-    f = frag_more(4);
-#if 0 /* This is testing the address of the frag, not the alignment of
+  f = frag_more (4);
+#if 0                          /* This is testing the address of the frag, not the alignment of
         the instruction in the current section.  */
-    if ((int) f & 3) {
-       as_bad(ALIGN_ERR);
-       as_bad(ALIGN_ERR2);
+  if ((int) f & 3)
+    {
+      as_bad (ALIGN_ERR);
+      as_bad (ALIGN_ERR2);
     }
 #endif
-    if (address_expr != NULL) {
-       fixS *fixP;
+  if (address_expr != NULL)
+    {
+      fixS *fixP;
 
-       if (address_expr->X_seg == &bfd_abs_section) {
-           switch (reloc_type) {
+      if (address_expr->X_seg == &bfd_abs_section)
+       {
+         switch (reloc_type)
+           {
            case BFD_RELOC_32:
-               ip->insn_opcode |= address_expr->X_add_number;
-               break;
+             ip->insn_opcode |= address_expr->X_add_number;
+             break;
 
            case BFD_RELOC_LO16:
-               ip->insn_opcode |= address_expr->X_add_number & 0xffff;
-               break;
+             ip->insn_opcode |= address_expr->X_add_number & 0xffff;
+             break;
 
            case BFD_RELOC_MIPS_JMP:
            case BFD_RELOC_16_PCREL_S2:
-               goto need_reloc;
+             goto need_reloc;
 
            default:
-               internalError();
+             internalError ();
            }
-       } else {
-           assert(reloc_type != BFD_RELOC_UNUSED);
+       }
+      else
+       {
+         assert (reloc_type != BFD_RELOC_UNUSED);
        need_reloc:
-           fixP = fix_new(frag_now, f - frag_now->fr_literal, 4,
-               address_expr->X_add_symbol,
-               address_expr->X_subtract_symbol,
-               address_expr->X_add_number,
-                reloc_type == BFD_RELOC_16_PCREL_S2,
-               reloc_type);
+         fixP = fix_new (frag_now, f - frag_now->fr_literal, 4,
+                         address_expr->X_add_symbol,
+                         address_expr->X_subtract_symbol,
+                         address_expr->X_add_number,
+                         reloc_type == BFD_RELOC_16_PCREL_S2,
+                         reloc_type);
        }
     }
-    md_number_to_chars(f, ip->insn_opcode, 4);
-
-    /*
-     * Fill all delay slots with nops.
-     */
-    if (!mips_noreorder) {
-       if (ip->insn_mo->pinfo & ANY_DELAY) {
-           f = frag_more(4);
-           md_number_to_chars(f, 0, 4);
+  md_number_to_chars (f, ip->insn_opcode, 4);
+
+  /*
+   * Fill all delay slots with nops.
+   */
+  if (!mips_noreorder)
+    {
+      if (ip->insn_mo->pinfo & ANY_DELAY)
+       {
+         f = frag_more (4);
+         md_number_to_chars (f, 0, 4);
        };
 
-       /* One extra nop */
-       if (ip->insn_mo->pinfo & INSN_EXTRA_DELAY) {
-           f = frag_more(4);
-           md_number_to_chars(f, 0, 4);
+      /* One extra nop */
+      if (ip->insn_mo->pinfo & INSN_EXTRA_DELAY)
+       {
+         f = frag_more (4);
+         md_number_to_chars (f, 0, 4);
        }
     }
 }
 
+/* Return 1 if an expression can be accessed via the GP register.  */
+
+static int
+gp_reference (ep)
+     expressionS *ep;
+{
+#ifdef OBJ_ECOFF
+  symbolS *sym;
+  const char *segname;
+
+  sym = ep->X_add_symbol;
+  if (sym == (symbolS *) NULL
+      || ep->X_subtract_symbol != (symbolS *) NULL)
+    return 0;
+  if (! S_IS_DEFINED (sym)
+      && S_GET_VALUE (sym) != 0
+      && S_GET_VALUE (sym) <= g_switch_value)
+    return 1;
+  segname = segment_name (S_GET_SEGMENT (ep->X_add_symbol));
+  return (strcmp (segname, ".sdata") == 0
+         || strcmp (segname, ".sbss") == 0);
+#else /* ! defined (OBJ_ECOFF) */
+  /* The GP register is only used for ECOFF.  */
+  return 0;
+#endif /* ! defined (OBJ_ECOFF) */  
+}
+
+/* Build an instruction created by a macro expansion.  This is passed
+   a pointer to the count of instructions created so far, an
+   expression, the name of the instruction to build, an operand format
+   string, and corresponding arguments.  */
+
 #ifndef NO_STDARG
 static void
 macro_build (int *counter,
-            expressionS *ep,
+            expressionS * ep,
             const char *name,
             const char *fmt,
             ...)
@@ -385,113 +446,124 @@ macro_build (counter, ep, name, fmt, va_alist)
      va_dcl
 #endif /* ! defined (NO_STDARG) */
 {
-    struct mips_cl_insn insn;
-    bfd_reloc_code_real_type r;
-    va_list args;
+  struct mips_cl_insn insn;
+  bfd_reloc_code_real_type r;
+  va_list args;
 
 #ifndef NO_STDARG
-    va_start(args, fmt);
+  va_start (args, fmt);
 #else
-    va_start(args);
+  va_start (args);
 #endif
 
-    /*
-     * If the macro is about to expand into a second instruction,
-     * print a warning if needed. We need to pass ip as a parameter
-     * to generate a better warning message here...
-     */
-    if (mips_warn_about_macros && *counter == 1)
-      as_warn("Macro instruction expanded into multiple instructions");
-
-    *counter += 1;  /* bump instruction counter */
-
-    r = BFD_RELOC_UNUSED;
-    insn.insn_mo = (struct mips_opcode *) hash_find(op_hash, name);
-    assert(insn.insn_mo);
-    assert(strcmp(name, insn.insn_mo->name) == 0);
-
-    while (strcmp(fmt, insn.insn_mo->args) != 0) {
-       ++insn.insn_mo;
-       assert(insn.insn_mo->name);
-       assert(strcmp(name, insn.insn_mo->name) == 0);
+  /*
+   * If the macro is about to expand into a second instruction,
+   * print a warning if needed. We need to pass ip as a parameter
+   * to generate a better warning message here...
+   */
+  if (mips_warn_about_macros && *counter == 1)
+    as_warn ("Macro instruction expanded into multiple instructions");
+
+  *counter += 1;               /* bump instruction counter */
+
+  r = BFD_RELOC_UNUSED;
+  insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
+  assert (insn.insn_mo);
+  assert (strcmp (name, insn.insn_mo->name) == 0);
+
+  while (strcmp (fmt, insn.insn_mo->args) != 0)
+    {
+      ++insn.insn_mo;
+      assert (insn.insn_mo->name);
+      assert (strcmp (name, insn.insn_mo->name) == 0);
     }
-    assert(insn.insn_mo->pinfo != INSN_MACRO);
-    insn.insn_opcode = insn.insn_mo->match;
-    for (;;) {
-       switch (*fmt++) {
+  assert (insn.insn_mo->pinfo != INSN_MACRO);
+  insn.insn_opcode = insn.insn_mo->match;
+  for (;;)
+    {
+      switch (*fmt++)
+       {
        case '\0':
-           break;
+         break;
 
        case ',':
        case '(':
        case ')':
-           continue;
+         continue;
 
        case 't':
        case 'w':
-           insn.insn_opcode |= va_arg(args, int) << 16;
-           continue;
+         insn.insn_opcode |= va_arg (args, int) << 16;
+         continue;
 
        case 'c':
        case 'T':
        case 'W':
-           insn.insn_opcode |= va_arg(args, int) << 16;
-           continue;
+         insn.insn_opcode |= va_arg (args, int) << 16;
+         continue;
 
        case 'd':
-           insn.insn_opcode |= va_arg(args, int) << 11;
-           continue;
+         insn.insn_opcode |= va_arg (args, int) << 11;
+         continue;
 
        case 'V':
        case 'S':
-           insn.insn_opcode |= va_arg(args, int) << 11;
-           continue;
+         insn.insn_opcode |= va_arg (args, int) << 11;
+         continue;
 
        case '<':
-           insn.insn_opcode |= va_arg(args, int) << 6;
-           continue;
+         insn.insn_opcode |= va_arg (args, int) << 6;
+         continue;
 
        case 'D':
-           insn.insn_opcode |= va_arg(args, int) << 6;
-           continue;
+         insn.insn_opcode |= va_arg (args, int) << 6;
+         continue;
 
        case 'b':
        case 's':
        case 'r':
        case 'v':
-           insn.insn_opcode |= va_arg(args, int) << 21;
-           continue;
+         insn.insn_opcode |= va_arg (args, int) << 21;
+         continue;
 
        case 'i':
        case 'j':
        case 'o':
-           r = BFD_RELOC_LO16;
-           continue;
+         r = BFD_RELOC_LO16;
+         continue;
 
        case 'p':
-           assert(ep != NULL);
-           /*
-            * This allows macro() to pass an immediate expression for
-            * creating short branches without creating a symbol.
-            * Note that the expression still might come from the assembly
-            * input, in which case the value is not checked for range nor
-            * is a relocation entry generated (yuck).
-            */
-           if (ep->X_add_symbol == NULL && ep->X_seg == &bfd_abs_section) {
-               insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff;
-               ep = NULL;
-           } else
-               r = BFD_RELOC_16_PCREL_S2;
-           continue;
+         assert (ep != NULL);
+         /*
+          * This allows macro() to pass an immediate expression for
+          * creating short branches without creating a symbol.
+          * Note that the expression still might come from the assembly
+          * input, in which case the value is not checked for range nor
+          * is a relocation entry generated (yuck).
+          */
+         if (ep->X_add_symbol == NULL && ep->X_seg == &bfd_abs_section)
+           {
+             insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff;
+             ep = NULL;
+           }
+         else
+           r = BFD_RELOC_16_PCREL_S2;
+         continue;
 
        default:
-           internalError();
+         internalError ();
        }
-       break;
+      break;
     }
-    va_end(args);
-    assert(r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
-    append_insn(&insn, ep, r);
+  va_end (args);
+  assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+
+  /* Use GP relative addressing if possible.  */
+  if (r == BFD_RELOC_LO16
+      && gp_reference (ep))
+    r = BFD_RELOC_MIPS_GPREL;
+
+  append_insn (&insn, ep, r);
 }
 
 /*
@@ -503,45 +575,49 @@ macro_build_lui (counter, ep, regnum)
      expressionS *ep;
      int regnum;
 {
-    expressionS high_expr;
-    struct mips_cl_insn insn;
-    bfd_reloc_code_real_type r;
-    CONST char *name = "lui";
-    CONST char *fmt = "t,u";
-
-    high_expr = *ep;
-
-    if (high_expr.X_seg == &bfd_abs_section) {
-       /* we can compute the instruction now without a relocation entry */
-       if (high_expr.X_add_number & 0x8000)
-           high_expr.X_add_number += 0x10000;
-       high_expr.X_add_number =
-           ((unsigned long) high_expr.X_add_number >> 16) & 0xffff;
-       r = BFD_RELOC_UNUSED;
-    } else
-       r = BFD_RELOC_HI16_S;
-
-    /*
-     * If the macro is about to expand into a second instruction,
-     * print a warning if needed. We need to pass ip as a parameter
-     * to generate a better warning message here...
-     */
-    if (mips_warn_about_macros && *counter == 1)
-      as_warn("Macro instruction expanded into multiple instructions");
-
-    *counter += 1;  /* bump instruction counter */
-
-    insn.insn_mo = (struct mips_opcode *) hash_find(op_hash, name);
-    assert(insn.insn_mo);
-    assert(strcmp(name, insn.insn_mo->name) == 0);
-    assert(strcmp(fmt, insn.insn_mo->args) == 0);
-
-    insn.insn_opcode = insn.insn_mo->match | (regnum << 16);
-    if (r == BFD_RELOC_UNUSED) {
-       insn.insn_opcode |= high_expr.X_add_number;
-       append_insn(&insn, NULL, r);
-    } else
-       append_insn(&insn, &high_expr, r);
+  expressionS high_expr;
+  struct mips_cl_insn insn;
+  bfd_reloc_code_real_type r;
+  CONST char *name = "lui";
+  CONST char *fmt = "t,u";
+
+  high_expr = *ep;
+
+  if (high_expr.X_seg == &bfd_abs_section)
+    {
+      /* we can compute the instruction now without a relocation entry */
+      if (high_expr.X_add_number & 0x8000)
+       high_expr.X_add_number += 0x10000;
+      high_expr.X_add_number =
+       ((unsigned long) high_expr.X_add_number >> 16) & 0xffff;
+      r = BFD_RELOC_UNUSED;
+    }
+  else
+    r = BFD_RELOC_HI16_S;
+
+  /*
+   * If the macro is about to expand into a second instruction,
+   * print a warning if needed. We need to pass ip as a parameter
+   * to generate a better warning message here...
+   */
+  if (mips_warn_about_macros && *counter == 1)
+    as_warn ("Macro instruction expanded into multiple instructions");
+
+  *counter += 1;               /* bump instruction counter */
+
+  insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
+  assert (insn.insn_mo);
+  assert (strcmp (name, insn.insn_mo->name) == 0);
+  assert (strcmp (fmt, insn.insn_mo->args) == 0);
+
+  insn.insn_opcode = insn.insn_mo->match | (regnum << 16);
+  if (r == BFD_RELOC_UNUSED)
+    {
+      insn.insn_opcode |= high_expr.X_add_number;
+      append_insn (&insn, NULL, r);
+    }
+  else
+    append_insn (&insn, &high_expr, r);
 }
 
 /*                     set_at()
@@ -554,22 +630,23 @@ set_at (counter, reg)
      int reg;
 {
 
-  switch (imm_expr.X_add_number & 0xffff8000) {
-  case 0:
-  case 0xffff8000:
-    macro_build(counter, &imm_expr, "slti", "t,r,j", AT, reg);
-    return;
+  switch (imm_expr.X_add_number & 0xffff8000)
+    {
+    case 0:
+    case 0xffff8000:
+      macro_build (counter, &imm_expr, "slti", "t,r,j", AT, reg);
+      return;
 
-  case 0x8000:
-    macro_build(counter, &imm_expr, "ori", "t,r,i", AT, 0);
-    break;
+    case 0x8000:
+      macro_build (counter, &imm_expr, "ori", "t,r,i", AT, 0);
+      break;
 
-  default:
-    macro_build_lui(counter, &imm_expr, AT);
-    if (imm_expr.X_add_number & 0xffff)
-      macro_build(counter, &imm_expr, "addiu", "t,r,j", AT, AT);
-  }
-  macro_build(counter, NULL, "slt", "d,v,t", AT, reg, AT);
+    default:
+      macro_build_lui (counter, &imm_expr, AT);
+      if (imm_expr.X_add_number & 0xffff)
+       macro_build (counter, &imm_expr, "addiu", "t,r,j", AT, AT);
+    }
+  macro_build (counter, NULL, "slt", "d,v,t", AT, reg, AT);
 }
 
 /*                     set_at_unsigned()
@@ -583,22 +660,23 @@ set_at_unsigned (counter, reg)
      int reg;
 {
 
-  switch (imm_expr.X_add_number & 0xffff8000) {
-  case 0:
-  case 0xffff8000:
-    macro_build(counter, &imm_expr, "sltiu", "t,r,j", AT, reg);
-    return;
+  switch (imm_expr.X_add_number & 0xffff8000)
+    {
+    case 0:
+    case 0xffff8000:
+      macro_build (counter, &imm_expr, "sltiu", "t,r,j", AT, reg);
+      return;
 
-  case 0x8000:
-    macro_build(counter, &imm_expr, "ori", "t,r,i", AT, 0);
-    break;
+    case 0x8000:
+      macro_build (counter, &imm_expr, "ori", "t,r,i", AT, 0);
+      break;
 
-  default:
-    macro_build_lui(counter, &imm_expr, AT);
-    if (imm_expr.X_add_number & 0xffff)
-      macro_build(counter, &imm_expr, "addiu", "t,r,j", AT, AT);
-  }
-  macro_build(counter, NULL, "sltu", "d,v,t", AT, reg, AT);
+    default:
+      macro_build_lui (counter, &imm_expr, AT);
+      if (imm_expr.X_add_number & 0xffff)
+       macro_build (counter, &imm_expr, "addiu", "t,r,j", AT, AT);
+    }
+  macro_build (counter, NULL, "sltu", "d,v,t", AT, reg, AT);
 }
 
 static void
@@ -608,7 +686,7 @@ check_absolute_expr (ip, expr)
 {
 
   if (expr->X_seg != &bfd_abs_section)
-    as_warn("Instruction %s requires absolute expression", ip->insn_mo->name);
+    as_warn ("Instruction %s requires absolute expression", ip->insn_mo->name);
 }
 
 /*                     load_register()
@@ -617,26 +695,27 @@ check_absolute_expr (ip, expr)
  */
 static void
 load_register (counter, ip, reg, ep)
-    int *counter;
-    struct mips_cl_insn *ip;
-    int reg;
-    expressionS *ep;
+     int *counter;
+     struct mips_cl_insn *ip;
+     int reg;
+     expressionS *ep;
 {
-  switch (ep->X_add_number & 0xffff8000) {
-  case 0:
-  case 0xffff8000:
-    macro_build(counter, ep, "addiu", "t,r,j", reg, 0);
-    break;
-
-  case 0x8000:
-    macro_build(counter, ep, "ori", "t,r,i", reg, 0);
-    break;
-
-  default:
-    macro_build_lui(counter, ep, reg);
-    if (ep->X_add_number & 0xffff)
-      macro_build(counter, ep, "addiu", "t,r,j", reg, reg);
-  }
+  switch (ep->X_add_number & 0xffff8000)
+    {
+    case 0:
+    case 0xffff8000:
+      macro_build (counter, ep, "addiu", "t,r,j", reg, 0);
+      break;
+
+    case 0x8000:
+      macro_build (counter, ep, "ori", "t,r,i", reg, 0);
+      break;
+
+    default:
+      macro_build_lui (counter, ep, reg);
+      if (ep->X_add_number & 0xffff)
+       macro_build (counter, ep, "addiu", "t,r,j", reg, reg);
+    }
 }
 
 
@@ -662,29 +741,31 @@ static void
 macro (ip)
      struct mips_cl_insn *ip;
 {
-    register int treg, sreg, dreg, breg;
-    int tempreg;
-    int mask;
-    int icnt = 0;
-    int used_at;
-    int save_reorder_condition;
-    expressionS expr1;
-    const char *s;
-
-    treg = (ip->insn_opcode >> 16) & 0x1f;
-    dreg = (ip->insn_opcode >> 11) & 0x1f;
-    sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
-    mask = ip->insn_mo->mask;
-
-    expr1.X_seg = &bfd_abs_section;
-    expr1.X_subtract_symbol = NULL;
-    expr1.X_add_symbol = NULL;
-    expr1.X_add_number = 1;
-
-    switch (mask) {
+  register int treg, sreg, dreg, breg;
+  int tempreg;
+  int mask;
+  int icnt = 0;
+  int used_at;
+  int save_reorder_condition;
+  expressionS expr1;
+  const char *s;
+  const char *fmt;
+
+  treg = (ip->insn_opcode >> 16) & 0x1f;
+  dreg = (ip->insn_opcode >> 11) & 0x1f;
+  sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
+  mask = ip->insn_mo->mask;
+
+  expr1.X_seg = &bfd_abs_section;
+  expr1.X_subtract_symbol = NULL;
+  expr1.X_add_symbol = NULL;
+  expr1.X_add_number = 1;
+
+  switch (mask)
+    {
     case M_ABS:
     case M_ABSU:
-       /*
+      /*
        Note: mips algorithm requires the move in the delay slot.
        <main>:         bgez $a0,0x4001bc <main+12>
        <main+4>:       move v0,$a0
@@ -692,464 +773,521 @@ macro (ip)
        <main+12>:      nop
        */
 
-       save_reorder_condition = mips_noreorder;
-       mips_noreorder = 1;
+      save_reorder_condition = mips_noreorder;
+      mips_noreorder = 1;
 
-       expr1.X_add_number = 8;
-       macro_build(&icnt, &expr1, "bgez", "s,p", sreg);
-       macro_build(&icnt, NULL, "move", "d,s", dreg, sreg, 0);
-       macro_build(&icnt, NULL, mask == M_ABS ? "sub" : "subu", "d,v,t",
-           dreg, 0, sreg);
+      expr1.X_add_number = 8;
+      macro_build (&icnt, &expr1, "bgez", "s,p", sreg);
+      macro_build (&icnt, NULL, "move", "d,s", dreg, sreg, 0);
+      macro_build (&icnt, NULL, mask == M_ABS ? "sub" : "subu", "d,v,t",
+                  dreg, 0, sreg);
 
-       mips_noreorder = save_reorder_condition;
-        return;
+      mips_noreorder = save_reorder_condition;
+      return;
 
     case M_ADD_I:
     case M_ADDU_I:
-       switch (imm_expr.X_add_number & 0xffff8000) {
-       case 0: 
-       case 0xffff8000: 
-           macro_build(&icnt, &imm_expr,
-               mask == M_ADD_I ? "addi" : "addiu", "t,r,j", treg, sreg);
-           return;
-
-       case 0x8000: 
-           macro_build(&icnt, &imm_expr, "ori", "t,r,i", AT, 0);
-           break;
+      switch (imm_expr.X_add_number & 0xffff8000)
+       {
+       case 0:
+       case 0xffff8000:
+         macro_build (&icnt, &imm_expr,
+                  mask == M_ADD_I ? "addi" : "addiu", "t,r,j", treg, sreg);
+         return;
 
-       default: 
-           macro_build_lui(&icnt, &imm_expr, AT);
-           if (imm_expr.X_add_number & 0xffff)
-               macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
-           break;
+       case 0x8000:
+         macro_build (&icnt, &imm_expr, "ori", "t,r,i", AT, 0);
+         break;
+
+       default:
+         macro_build_lui (&icnt, &imm_expr, AT);
+         if (imm_expr.X_add_number & 0xffff)
+           macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
+         break;
        }
-       macro_build(&icnt, NULL,
-           mask == M_ADD_I ? "add" : "addu", "d,v,t", treg, sreg, AT);
-       break;
+      macro_build (&icnt, NULL,
+                mask == M_ADD_I ? "add" : "addu", "d,v,t", treg, sreg, AT);
+      break;
 
     case M_AND_I:
     case M_OR_I:
     case M_NOR_I:
     case M_XOR_I:
-       switch (imm_expr.X_add_number & 0xffff8000) {
+      switch (imm_expr.X_add_number & 0xffff8000)
+       {
        case 0:
        case 0x8000:
-           switch (mask) {
+         switch (mask)
+           {
            case M_AND_I:
-               macro_build(&icnt, &imm_expr, "andi", "t,r,i", treg, sreg);
-               return;
+             macro_build (&icnt, &imm_expr, "andi", "t,r,i", treg, sreg);
+             return;
            case M_OR_I:
-               macro_build(&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
-               return;
+             macro_build (&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
+             return;
            case M_NOR_I:
-               macro_build(&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
-               macro_build(&icnt, &imm_expr, "nor", "d,v,t", treg, treg, 0);
-               return;
+             macro_build (&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
+             macro_build (&icnt, &imm_expr, "nor", "d,v,t", treg, treg, 0);
+             return;
            case M_XOR_I:
-               macro_build(&icnt, &imm_expr, "xori", "t,r,i", treg, sreg);
-               return;
+             macro_build (&icnt, &imm_expr, "xori", "t,r,i", treg, sreg);
+             return;
            default:
-               internalError();
+             internalError ();
            }
 
        case 0xffff8000:
-           macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, 0);
-           break;
+         macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, 0);
+         break;
 
        default:
-           macro_build_lui(&icnt, &imm_expr, AT);
-           if (imm_expr.X_add_number & 0xffff)
-               macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
+         macro_build_lui (&icnt, &imm_expr, AT);
+         if (imm_expr.X_add_number & 0xffff)
+           macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
        }
-       switch (mask) {
+      switch (mask)
+       {
        case M_AND_I:
-           macro_build(&icnt, NULL, "and", "d,v,t", treg, sreg, AT);
-           break;
+         macro_build (&icnt, NULL, "and", "d,v,t", treg, sreg, AT);
+         break;
        case M_OR_I:
-           macro_build(&icnt, NULL, "or", "d,v,t", treg, sreg, AT);
-           break;
+         macro_build (&icnt, NULL, "or", "d,v,t", treg, sreg, AT);
+         break;
        case M_NOR_I:
-           macro_build(&icnt, NULL, "nor", "d,v,t", treg, sreg, AT);
-           break;
+         macro_build (&icnt, NULL, "nor", "d,v,t", treg, sreg, AT);
+         break;
        case M_XOR_I:
-           macro_build(&icnt, NULL, "xor", "d,v,t", treg, sreg, AT);
-           break;
+         macro_build (&icnt, NULL, "xor", "d,v,t", treg, sreg, AT);
+         break;
        default:
-           internalError();
+         internalError ();
        }
-       break;
+      break;
 
     case M_BEQ_I:
     case M_BNE_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
-               "s,t,p", sreg, 0);
-           return;
-       }
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
-           "s,t,p", sreg, AT);
-       break;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
+                      "s,t,p", sreg, 0);
+         return;
+       }
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
+                  "s,t,p", sreg, AT);
+      break;
 
     case M_BGE:
-       if (treg == 0) {
-           macro_build(&icnt, &offset_expr, "bgez", "s,p", sreg);
-           return;
+      if (treg == 0)
+       {
+         macro_build (&icnt, &offset_expr, "bgez", "s,p", sreg);
+         return;
        }
-       macro_build(&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
-       macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
-       break;
+      macro_build (&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
+      macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
+      break;
 
     case M_BGT_I:
-       imm_expr.X_add_number++;
-       /* FALLTHROUGH */
+      imm_expr.X_add_number++;
+      /* FALLTHROUGH */
     case M_BGE_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &offset_expr, "bgez", "s,p", sreg);
-           return;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &offset_expr, "bgez", "s,p", sreg);
+         return;
        }
-       if (imm_expr.X_add_number == 1) {
-           macro_build(&icnt, &offset_expr, "bgtz", "s,p", sreg);
-           return;
+      if (imm_expr.X_add_number == 1)
+       {
+         macro_build (&icnt, &offset_expr, "bgtz", "s,p", sreg);
+         return;
        }
-       set_at(&icnt, sreg);
-       macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
-       break;
+      set_at (&icnt, sreg);
+      macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
+      break;
 
     case M_BGEU:
-       if (treg == 0) {
-           macro_build(&icnt, &offset_expr, "b", "p");
-           return;
+      if (treg == 0)
+       {
+         macro_build (&icnt, &offset_expr, "b", "p");
+         return;
        }
-       macro_build(&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
-       macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
-       break;
+      macro_build (&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
+      macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
+      break;
 
     case M_BGEU_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &offset_expr, "b", "p");
-           return;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &offset_expr, "b", "p");
+         return;
        }
-       if (imm_expr.X_add_number == 1) {
-           macro_build(&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
-           return;
+      if (imm_expr.X_add_number == 1)
+       {
+         macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
+         return;
        }
-       set_at_unsigned(&icnt, sreg);
-       macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
-       break;
+      set_at_unsigned (&icnt, sreg);
+      macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
+      break;
 
     case M_BGT:
-       if (treg == 0) {
-           macro_build(&icnt, &offset_expr, "bgtz", "s,p", sreg);
-           return;
+      if (treg == 0)
+       {
+         macro_build (&icnt, &offset_expr, "bgtz", "s,p", sreg);
+         return;
        }
-       macro_build(&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      macro_build (&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_BGTU:
-       if (treg == 0) {
-           macro_build(&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
-           return;
+      if (treg == 0)
+       {
+         macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
+         return;
        }
-       macro_build(&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      macro_build (&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_BGTU_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
-           return;
-       }
-       if (imm_expr.X_add_number == -1) {
-           /* NOP */
-           if (mips_noreorder)
-               as_warn("Instruction %s is a nop; deleted", ip->insn_mo->name);
-           return;
-       }
-       imm_expr.X_add_number++;
-       set_at_unsigned(&icnt, sreg);
-       macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
-       break;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
+         return;
+       }
+      if (imm_expr.X_add_number == -1)
+       {
+         /* NOP */
+         if (mips_noreorder)
+           as_warn ("Instruction %s is a nop; deleted", ip->insn_mo->name);
+         return;
+       }
+      imm_expr.X_add_number++;
+      set_at_unsigned (&icnt, sreg);
+      macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
+      break;
 
     case M_BLE:
-       if (treg == 0) {
-           macro_build(&icnt, &offset_expr, "blez", "s,p", sreg);
-           return;
-        }
-       macro_build(&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
-       macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
-       break;
+      if (treg == 0)
+       {
+         macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
+         return;
+       }
+      macro_build (&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
+      macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
+      break;
 
     case M_BLE_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &offset_expr, "blez", "s,p", sreg);
-           return;
-        }
-       if (imm_expr.X_add_number == -1) {
-           macro_build(&icnt, &offset_expr, "bltz", "s,p", sreg);
-           return;
-       }
-       imm_expr.X_add_number++;
-       set_at(&icnt, sreg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
+         return;
+       }
+      if (imm_expr.X_add_number == -1)
+       {
+         macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
+         return;
+       }
+      imm_expr.X_add_number++;
+      set_at (&icnt, sreg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_BLEU:
-       if (treg == 0) {
-           macro_build(&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
-           return;
+      if (treg == 0)
+       {
+         macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
+         return;
        }
-       macro_build(&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
-       macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
-       break;
+      macro_build (&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
+      macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
+      break;
 
     case M_BLEU_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
-           return;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
+         return;
        }
-       if (imm_expr.X_add_number == -1) {
-           macro_build(&icnt, &offset_expr, "b", "p");
-           return;
+      if (imm_expr.X_add_number == -1)
+       {
+         macro_build (&icnt, &offset_expr, "b", "p");
+         return;
        }
-       imm_expr.X_add_number++;
-       set_at_unsigned(&icnt, sreg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      imm_expr.X_add_number++;
+      set_at_unsigned (&icnt, sreg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_BLT:
-       if (treg == 0) {
-           macro_build(&icnt, &offset_expr, "bltz", "s,p", sreg);
-           return;
+      if (treg == 0)
+       {
+         macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
+         return;
        }
-       macro_build(&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      macro_build (&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_BLT_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &offset_expr, "bltz", "s,p", sreg);
-           return;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
+         return;
        }
-       if (imm_expr.X_add_number == 1) {
-           macro_build(&icnt, &offset_expr, "blez", "s,p", sreg);
-           return;
+      if (imm_expr.X_add_number == 1)
+       {
+         macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
+         return;
        }
-       set_at(&icnt, sreg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      set_at (&icnt, sreg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_BLTU:
-       if (treg == 0) {
-           /* NOP */
-           if (mips_noreorder)
-               as_warn("Instruction %s is a nop; deleted", ip->insn_mo->name);
-           return;
-       }
-       macro_build(&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      if (treg == 0)
+       {
+         /* NOP */
+         if (mips_noreorder)
+           as_warn ("Instruction %s is a nop; deleted", ip->insn_mo->name);
+         return;
+       }
+      macro_build (&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_BLTU_I:
-       if (imm_expr.X_add_number == 0) {
-           /* NOP */
-           if (mips_noreorder)
-               as_warn("Instruction %s is a nop; deleted", ip->insn_mo->name);
-           return;
-       }
-       if (imm_expr.X_add_number == 1) {
-           macro_build(&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
-           return;
-       }
-       set_at_unsigned(&icnt, sreg);
-       macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
-       break;
+      if (imm_expr.X_add_number == 0)
+       {
+         /* NOP */
+         if (mips_noreorder)
+           as_warn ("Instruction %s is a nop; deleted", ip->insn_mo->name);
+         return;
+       }
+      if (imm_expr.X_add_number == 1)
+       {
+         macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
+         return;
+       }
+      set_at_unsigned (&icnt, sreg);
+      macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
+      break;
 
     case M_DIV_3:
     case M_REM_3:
-       if (treg == 0) {
-           as_warn("Divide by zero.");
-           macro_build(&icnt, NULL, "break", "c", 7);
-           return;
-       }
-
-       save_reorder_condition = mips_noreorder;
-       mips_noreorder = 1;
-       macro_build(&icnt, NULL, "div", "s,t", sreg, treg);
-       expr1.X_add_number = 8;
-       macro_build(&icnt, &expr1, "bne", "s,t,p", treg, 0);
-       macro_build(&icnt, NULL, "nop", "", 0);
-       macro_build(&icnt, NULL, "break", "c", 7);
-       expr1.X_add_number = -1;
-       macro_build(&icnt, &expr1, "addiu", "t,r,j", AT, 0);
-       expr1.X_add_number = 16;
-       macro_build(&icnt, &expr1, "bne", "s,t,p", treg, AT);
-       expr1.X_add_number = 0x80000000;
-       macro_build_lui(&icnt, &expr1, AT);
-       expr1.X_add_number = 8;
-       macro_build(&icnt, &expr1, "bne", "s,t,p", sreg, AT);
-       macro_build(&icnt, NULL, "nop", "", 0);
-       macro_build(&icnt, NULL, "break", "c", 6);
-       mips_noreorder = save_reorder_condition;
-       macro_build(&icnt, NULL, mask == M_DIV_3 ? "mflo" : "mfhi", "d", dreg);
-        /* with reorder on there will be two implicit nop instructions here. */
-        break;
+      if (treg == 0)
+       {
+         as_warn ("Divide by zero.");
+         macro_build (&icnt, NULL, "break", "c", 7);
+         return;
+       }
+
+      save_reorder_condition = mips_noreorder;
+      mips_noreorder = 1;
+      macro_build (&icnt, NULL, "div", "s,t", sreg, treg);
+      expr1.X_add_number = 8;
+      macro_build (&icnt, &expr1, "bne", "s,t,p", treg, 0);
+      macro_build (&icnt, NULL, "nop", "", 0);
+      macro_build (&icnt, NULL, "break", "c", 7);
+      expr1.X_add_number = -1;
+      macro_build (&icnt, &expr1, "addiu", "t,r,j", AT, 0);
+      expr1.X_add_number = 16;
+      macro_build (&icnt, &expr1, "bne", "s,t,p", treg, AT);
+      expr1.X_add_number = 0x80000000;
+      macro_build_lui (&icnt, &expr1, AT);
+      expr1.X_add_number = 8;
+      macro_build (&icnt, &expr1, "bne", "s,t,p", sreg, AT);
+      macro_build (&icnt, NULL, "nop", "", 0);
+      macro_build (&icnt, NULL, "break", "c", 6);
+      mips_noreorder = save_reorder_condition;
+      macro_build (&icnt, NULL, mask == M_DIV_3 ? "mflo" : "mfhi", "d", dreg);
+      /* with reorder on there will be two implicit nop instructions here. */
+      break;
 
     case M_DIV_3I:
     case M_DIVU_3I:
     case M_REM_3I:
     case M_REMU_3I:
-       if (imm_expr.X_add_number == 0) {
-           as_warn("Divide by zero.");
-           macro_build(&icnt, NULL, "break", "c", 7);
-           return;
-       }
-       if (imm_expr.X_add_number == 1) {
-         if (mask == (int)M_DIV_3I || mask == (int)M_DIVU_3I)
-           macro_build(&icnt, NULL, "move", "d,s", dreg, sreg);
+      if (imm_expr.X_add_number == 0)
+       {
+         as_warn ("Divide by zero.");
+         macro_build (&icnt, NULL, "break", "c", 7);
+         return;
+       }
+      if (imm_expr.X_add_number == 1)
+       {
+         if (mask == (int) M_DIV_3I || mask == (int) M_DIVU_3I)
+           macro_build (&icnt, NULL, "move", "d,s", dreg, sreg);
          else
-           macro_build(&icnt, NULL, "move", "d,s", dreg, 0);
+           macro_build (&icnt, NULL, "move", "d,s", dreg, 0);
          return;
        }
 
-       load_register(&icnt, ip, AT, &imm_expr);
-       if (mask == (int)M_DIV_3I || mask == (int)M_REM_3I)
-         macro_build(&icnt, NULL, "div", "s,t", sreg, AT);
-       else
-         macro_build(&icnt, NULL, "divu", "s,t", sreg, AT);
-
-       if (mask == (int)M_DIV_3I || mask == (int)M_DIVU_3I)
-         macro_build(&icnt, NULL, "mflo", "d", dreg);
-       else
-         macro_build(&icnt, NULL, "mfhi", "d", dreg);
-       /* two implicit nop's required for mflo or mfhi */
-       break;
+      load_register (&icnt, ip, AT, &imm_expr);
+      if (mask == (int) M_DIV_3I || mask == (int) M_REM_3I)
+       macro_build (&icnt, NULL, "div", "s,t", sreg, AT);
+      else
+       macro_build (&icnt, NULL, "divu", "s,t", sreg, AT);
 
-      case M_DIVU_3:
-      case M_REMU_3:
-       save_reorder_condition = mips_noreorder;
-       mips_noreorder = 1;
-       macro_build(&icnt, NULL, "divu", "s,t", sreg, treg);
-       expr1.X_add_number = 8;
-       macro_build(&icnt, &expr1, "bne", "s,t,p", treg, 0);
-       macro_build(&icnt, NULL, "nop", "", 0);
-       macro_build(&icnt, NULL, "break", "c", 7);
-       mips_noreorder = save_reorder_condition;
-       macro_build(&icnt, NULL, mask == M_DIVU_3 ? "mflo" : "mfhi", "d", dreg);
-        /* with reorder on there will be two implicit nop instructions here. */
-        return;
+      if (mask == (int) M_DIV_3I || mask == (int) M_DIVU_3I)
+       macro_build (&icnt, NULL, "mflo", "d", dreg);
+      else
+       macro_build (&icnt, NULL, "mfhi", "d", dreg);
+      /* two implicit nop's required for mflo or mfhi */
+      break;
+
+    case M_DIVU_3:
+    case M_REMU_3:
+      save_reorder_condition = mips_noreorder;
+      mips_noreorder = 1;
+      macro_build (&icnt, NULL, "divu", "s,t", sreg, treg);
+      expr1.X_add_number = 8;
+      macro_build (&icnt, &expr1, "bne", "s,t,p", treg, 0);
+      macro_build (&icnt, NULL, "nop", "", 0);
+      macro_build (&icnt, NULL, "break", "c", 7);
+      mips_noreorder = save_reorder_condition;
+      macro_build (&icnt, NULL, mask == M_DIVU_3 ? "mflo" : "mfhi", "d", dreg);
+      /* with reorder on there will be two implicit nop instructions here. */
+      return;
 
     case M_LA:
-       if (offset_expr.X_seg == &bfd_abs_section) {
-           load_register(&icnt, ip, treg, &offset_expr);
-           return;
+      if (offset_expr.X_seg == &bfd_abs_section)
+       {
+         load_register (&icnt, ip, treg, &offset_expr);
+         return;
        }
-       macro_build_lui(&icnt, &offset_expr, treg);
-       macro_build(&icnt, &offset_expr, "addiu", "t,r,j", treg, treg);
-       return;
+      if (gp_reference (&offset_expr))
+       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", treg, GP);
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, treg);
+         macro_build (&icnt, &offset_expr, "addiu", "t,r,j", treg, treg);
+       }
+      return;
 
     case M_LA_AB:
-       tempreg = (breg == treg) ? AT : treg;
-       if (offset_expr.X_seg == &bfd_abs_section)
-           load_register(&icnt, ip, tempreg, &offset_expr);
-       else {
-           macro_build_lui(&icnt, &offset_expr, tempreg);
-           macro_build(&icnt, &offset_expr, "addiu", "t,r,j", tempreg, tempreg);
-        }
-       if (breg != 0)
-           macro_build(&icnt, NULL, "addu", "d,v,t", treg, tempreg, breg);
-       if (breg == treg)
-               break;
-       return;
+      tempreg = (breg == treg) ? AT : treg;
+      if (offset_expr.X_seg == &bfd_abs_section)
+       load_register (&icnt, ip, tempreg, &offset_expr);
+      else if (gp_reference (&offset_expr))
+       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", tempreg, GP);
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, tempreg);
+         macro_build (&icnt, &offset_expr, "addiu", "t,r,j", tempreg, tempreg);
+       }
+      if (breg != 0)
+       macro_build (&icnt, NULL, "addu", "d,v,t", treg, tempreg, breg);
+      if (breg == treg)
+       break;
+      return;
 
     case M_LB_AB:
-       s = "lb";
-       goto ld;
+      s = "lb";
+      goto ld;
     case M_LBU_AB:
-       s = "lbu";
-       goto ld;
+      s = "lbu";
+      goto ld;
     case M_LH_AB:
-       s = "lh";
-       goto ld;
+      s = "lh";
+      goto ld;
     case M_LHU_AB:
-       s = "lhu";
-       goto ld;
+      s = "lhu";
+      goto ld;
     case M_LW_AB:
-       s = "lw";
-       goto ld;
+      s = "lw";
+      goto ld;
     case M_LWC0_AB:
-       s = "lwc0";
-       goto ld;
+      s = "lwc0";
+      goto ld;
     case M_LWC1_AB:
-       s = "lwc1";
-       goto ld;
+      s = "lwc1";
+      goto ld;
     case M_LWC2_AB:
-       s = "lwc2";
-       goto ld;
+      s = "lwc2";
+      goto ld;
     case M_LWC3_AB:
-       s = "lwc3";
-       goto ld;
+      s = "lwc3";
+      goto ld;
     case M_LWL_AB:
-       s = "lwl";
-       goto ld;
+      s = "lwl";
+      goto ld;
     case M_LWR_AB:
-       s = "lwr";
+      s = "lwr";
     ld:
-       if (breg == treg || mask == M_LWC1_AB) {
-               tempreg = AT;
-               used_at = 1;
-       } else {
-               tempreg = treg;
-               used_at = 0;
-       }
-       goto ld_st;
+      if (breg == treg || mask == M_LWC1_AB)
+       {
+         tempreg = AT;
+         used_at = 1;
+       }
+      else
+       {
+         tempreg = treg;
+         used_at = 0;
+       }
+      goto ld_st;
     case M_SB_AB:
-       s = "sb";
-       goto st;
+      s = "sb";
+      goto st;
     case M_SH_AB:
-       s = "sh";
-       goto st;
+      s = "sh";
+      goto st;
     case M_SW_AB:
-       s = "sw";
-       goto st;
+      s = "sw";
+      goto st;
     case M_SWC0_AB:
-       s = "swc0";
-       goto st;
+      s = "swc0";
+      goto st;
     case M_SWC1_AB:
-       s = "swc1";
-       goto st;
+      s = "swc1";
+      goto st;
     case M_SWC2_AB:
-       s = "swc2";
-       goto st;
+      s = "swc2";
+      goto st;
     case M_SWC3_AB:
-       s = "swc3";
-       goto st;
+      s = "swc3";
+      goto st;
     case M_SWL_AB:
-       s = "swl";
-       goto st;
+      s = "swl";
+      goto st;
     case M_SWR_AB:
-       s = "swr";
+      s = "swr";
     st:
-       tempreg = AT;
-       used_at = 1;
+      tempreg = AT;
+      used_at = 1;
     ld_st:
-       macro_build_lui(&icnt, &offset_expr, tempreg);
-       if (breg != 0)
-           macro_build(&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
-       macro_build(&icnt, &offset_expr, s,
-           mask == M_LWC1_AB || mask == M_SWC1_AB ? "T,o(b)" : "t,o(b)",
-           treg, tempreg);
-       if (used_at)
-               break;
-       return;
+      if (mask == M_LWC1_AB || mask == M_SWC1_AB)
+       fmt = "T,o(b)";
+      else
+       fmt = "t,o(b)";
+      if (gp_reference (&offset_expr))
+       {
+         if (breg == 0)
+           {
+             macro_build (&icnt, &offset_expr, s, fmt, treg, GP);
+             return;
+           }
+         macro_build (&icnt, (expressionS *) NULL, "addu", "d,v,t",
+                      tempreg, breg, GP);
+       }
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, tempreg);
+         if (breg != 0)
+           macro_build (&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
+       }
+      macro_build (&icnt, &offset_expr, s, fmt, treg, tempreg);
+      if (used_at)
+       break;
+      return;
 
     case M_LI:
-       load_register(&icnt, ip, treg, &imm_expr);
-       return;
+      load_register (&icnt, ip, treg, &imm_expr);
+      return;
 
     case M_LI_D:
-       /*
+      /*
        0x400370 <main>:        lui $at,%hi(foo)
        0x400374 <main+4>:      lw $v0,%lo(foo)($at)
        0x400378 <main+8>:      lw $v1,%lo(foo+4)($at)
@@ -1157,479 +1295,562 @@ macro (ip)
                 <foo>:
                                .float 3.133435
        */
-       macro_build_lui(&icnt, &offset_expr, AT);
-       macro_build(&icnt, &offset_expr, "lw", "t,o(b)", treg, AT);
-       offset_expr.X_add_number = 4;
-       macro_build(&icnt, &offset_expr, "lw", "t,o(b)", treg+1, AT);
-       break;
+      /* FIXME: I don't think this is used at present, because the 'F'
+        format character is not supported.  When this is supported,
+        it should use the GP register.  */
+      macro_build_lui (&icnt, &offset_expr, AT);
+      macro_build (&icnt, &offset_expr, "lw", "t,o(b)", treg, AT);
+      offset_expr.X_add_number = 4;
+      macro_build (&icnt, &offset_expr, "lw", "t,o(b)", treg + 1, AT);
+      break;
 
     case M_LI_DD:
-       /*
+      /*
        0x4003a0 <main>:        lwc1 $f0,-32752($gp)
        0x4003a4 <main+4>:      lwc1 $f1,-32748($gp)
        0x4003a8 <main+8>:      nop
        */
-       sreg = (ip->insn_opcode >> 11) & 0x1f;  /* Fs reg */
-       macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg, AT);
-       offset_expr.X_add_number = 4;
-       macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg+1, AT);
-       break;
+      /* FIXME: This is nonsense.  It isn't used anyhow.  */
+      sreg = (ip->insn_opcode >> 11) & 0x1f;   /* Fs reg */
+      macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg, AT);
+      offset_expr.X_add_number = 4;
+      macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg + 1, AT);
+      break;
 
     case M_L_DOB:
-       save_reorder_condition = mips_noreorder;
-       mips_noreorder = 1;
-       macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg, breg);
-       /* unecessary implicit nop */
-       mips_noreorder = save_reorder_condition;
-       offset_expr.X_add_number += 4;
-       macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg+1, breg);
-       return;
+      save_reorder_condition = mips_noreorder;
+      mips_noreorder = 1;
+      macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg, breg);
+      /* unecessary implicit nop */
+      mips_noreorder = save_reorder_condition;
+      offset_expr.X_add_number += 4;
+      macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg + 1, breg);
+      return;
 
     case M_L_DAB:
-       /*
-        * The MIPS assembler seems to check for X_add_number not
-        * being double aligned and generating:
-        *      lui     at,%hi(foo+1)
-        *      addu    at,at,v1
-        *      addiu   at,at,%lo(foo+1)
-        *      lwc1    f2,0(at)
-        *      lwc1    f3,4(at)
-        * But, the resulting address is the same after relocation so why
-        * generate the extra instruction?
-        */
-       macro_build_lui(&icnt, &offset_expr, AT);
-       if (breg != 0)
-           macro_build(&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
-       save_reorder_condition = mips_noreorder;
-       mips_noreorder = 1;
-       macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg, AT);
-       /* unecessary implicit nop */
-       mips_noreorder = save_reorder_condition;
-       offset_expr.X_add_number += 4;
-       macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg+1, AT);
+      /*
+       * The MIPS assembler seems to check for X_add_number not
+       * being double aligned and generating:
+       *       lui     at,%hi(foo+1)
+       *       addu    at,at,v1
+       *       addiu   at,at,%lo(foo+1)
+       *       lwc1    f2,0(at)
+       *       lwc1    f3,4(at)
+       * But, the resulting address is the same after relocation so why
+       * generate the extra instruction?
+       */
+      if (gp_reference (&offset_expr))
+       {
+         if (breg == 0)
+           tempreg = GP;
+         else
+           {
+             macro_build (&icnt, &offset_expr, "addu", "d,v,t", AT, breg, GP);
+             tempreg = AT;
+           }
+       }
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, AT);
+         if (breg != 0)
+           macro_build (&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
+         tempreg = AT;
+       }
+      save_reorder_condition = mips_noreorder;
+      mips_noreorder = 1;
+      macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg, tempreg);
+      /* unecessary implicit nop */
+      mips_noreorder = save_reorder_condition;
+      offset_expr.X_add_number += 4;
+      macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg + 1, tempreg);
+      if (tempreg == AT)
        break;
+      return;
 
     case M_LD_OB:
-       s = "lw";
-       goto sd_ob;
+      s = "lw";
+      goto sd_ob;
     case M_SD_OB:
-       s = "sw";
+      s = "sw";
     sd_ob:
-       macro_build(&icnt, &offset_expr, s, "t,o(b)", treg, breg);
-       offset_expr.X_add_number = 4;
-       macro_build(&icnt, &offset_expr, s, "t,o(b)", treg+1, breg);
-       return;
+      macro_build (&icnt, &offset_expr, s, "t,o(b)", treg, breg);
+      offset_expr.X_add_number = 4;
+      macro_build (&icnt, &offset_expr, s, "t,o(b)", treg + 1, breg);
+      return;
 
     case M_LD_AB:
-       s = "lw";
-       if (breg == treg) {
-               tempreg = AT;
-               used_at = 1;
-       } else {
-               tempreg = treg;
-               used_at = 0;
-       }
-       goto sd_ab;
+      s = "lw";
+      if (breg == treg)
+       {
+         tempreg = AT;
+         used_at = 1;
+       }
+      else
+       {
+         tempreg = treg;
+         used_at = 0;
+       }
+      goto sd_ab;
     case M_SD_AB:
-       s = "sw";
-       tempreg = AT;
-       used_at = 1;
+      s = "sw";
+      tempreg = AT;
+      used_at = 1;
     sd_ab:
-       macro_build_lui(&icnt, &offset_expr, tempreg);
-       if (breg != 0)
-           macro_build(&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
-       macro_build(&icnt, &offset_expr, s, "t,o(b)", treg, tempreg);
-       offset_expr.X_add_number += 4;
-       macro_build(&icnt, &offset_expr, s, "t,o(b)", treg+1, tempreg);
-       if (used_at)
-               break;
-       return;
+      if (gp_reference (&offset_expr))
+       {
+         if (breg == 0)
+           {
+             tempreg = GP;
+             used_at = 0;
+           }
+         else
+           macro_build (&icnt, (expressionS *) NULL, "addu", "d,v,t",
+                        tempreg, breg, GP);
+       }
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, tempreg);
+         if (breg != 0)
+           macro_build (&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
+       }
+      macro_build (&icnt, &offset_expr, s, "t,o(b)", treg, tempreg);
+      offset_expr.X_add_number += 4;
+      macro_build (&icnt, &offset_expr, s, "t,o(b)", treg + 1, tempreg);
+      if (used_at)
+       break;
+      return;
 
     case M_MUL:
-       macro_build(&icnt, NULL, "multu", "s,t", sreg, treg);
-       macro_build(&icnt, NULL, "mflo", "d", dreg);
-       /* two implicit nop's required for mflo */
-       return;
+      macro_build (&icnt, NULL, "multu", "s,t", sreg, treg);
+      macro_build (&icnt, NULL, "mflo", "d", dreg);
+      /* two implicit nop's required for mflo */
+      return;
 
     case M_MUL_I:
-       /*
-        * The mips assembler some times generates shifts and adds.
-         * Im not trying to be that fancy. GCC should do this for us
-         * anyway.
-         */
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, NULL, "mult", "s,t", sreg, AT);
-       macro_build(&icnt, NULL, "mflo", "d", dreg);
-       /* two implicit nop's required for mflo */
-       break;
+      /*
+       * The mips assembler some times generates shifts and adds.
+       * Im not trying to be that fancy. GCC should do this for us
+       * anyway.
+       */
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, NULL, "mult", "s,t", sreg, AT);
+      macro_build (&icnt, NULL, "mflo", "d", dreg);
+      /* two implicit nop's required for mflo */
+      break;
 
     case M_ROL:
-       macro_build(&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
-       macro_build(&icnt, NULL, "srlv", "d,t,s", AT, sreg, AT);
-       macro_build(&icnt, NULL, "sllv", "d,t,s", dreg, sreg, treg);
-       macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
-       break;
+      macro_build (&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
+      macro_build (&icnt, NULL, "srlv", "d,t,s", AT, sreg, AT);
+      macro_build (&icnt, NULL, "sllv", "d,t,s", dreg, sreg, treg);
+      macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      break;
 
     case M_ROL_I:
-       macro_build(&icnt, NULL, "sll", "d,w,<", AT, sreg,
-           imm_expr.X_add_number & 0x1f);
-       macro_build(&icnt, NULL, "srl", "d,w,<", dreg, sreg,
-           (0 - imm_expr.X_add_number) & 0x1f);
-       macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
-       break;
+      macro_build (&icnt, NULL, "sll", "d,w,<", AT, sreg,
+                  imm_expr.X_add_number & 0x1f);
+      macro_build (&icnt, NULL, "srl", "d,w,<", dreg, sreg,
+                  (0 - imm_expr.X_add_number) & 0x1f);
+      macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      break;
 
     case M_ROR:
-       macro_build(&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
-       macro_build(&icnt, NULL, "sllv", "d,t,s", AT, sreg, AT);
-       macro_build(&icnt, NULL, "srlv", "d,t,s", dreg, sreg, treg);
-       macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
-       break;
+      macro_build (&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
+      macro_build (&icnt, NULL, "sllv", "d,t,s", AT, sreg, AT);
+      macro_build (&icnt, NULL, "srlv", "d,t,s", dreg, sreg, treg);
+      macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      break;
 
     case M_ROR_I:
-       macro_build(&icnt, NULL, "srl", "d,w,<", AT, sreg,
-           imm_expr.X_add_number & 0x1f);
-       macro_build(&icnt, NULL, "sll", "d,w,<", dreg, sreg,
-           (0 - imm_expr.X_add_number) & 0x1f);
-       macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
-       break;
+      macro_build (&icnt, NULL, "srl", "d,w,<", AT, sreg,
+                  imm_expr.X_add_number & 0x1f);
+      macro_build (&icnt, NULL, "sll", "d,w,<", dreg, sreg,
+                  (0 - imm_expr.X_add_number) & 0x1f);
+      macro_build (&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      break;
 
     case M_S_DOB:
-       macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg, breg);
-       offset_expr.X_add_number += 4;
-       macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg+1, breg);
-       return;
+      macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg, breg);
+      offset_expr.X_add_number += 4;
+      macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg + 1, breg);
+      return;
 
     case M_S_DAB:
-       macro_build_lui(&icnt, &offset_expr, AT);
-       if (breg != 0)
-           macro_build(&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
-       macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg, AT);
-       offset_expr.X_add_number += 4;
-       macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg+1, AT);
+      if (gp_reference (&offset_expr))
+       {
+         if (breg == 0)
+           tempreg = GP;
+         else
+           {
+             macro_build (&icnt, (expressionS *) NULL, "addu", "d,v,t",
+                          AT, breg, GP);
+             tempreg = AT;
+           }
+       }
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, AT);
+         if (breg != 0)
+           macro_build (&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
+         tempreg = AT;
+       }
+      macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg, tempreg);
+      offset_expr.X_add_number += 4;
+      macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg + 1, tempreg);
+      if (tempreg == AT)
        break;
+      return;
 
     case M_SEQ:
-       if (sreg == 0)
-           macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, treg);
-       else if (treg == 0)
-           macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
-       else {
-           macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
-           macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
+      if (sreg == 0)
+       macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, treg);
+      else if (treg == 0)
+       macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
+      else
+       {
+         macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
+         macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
        }
-       return;
+      return;
 
     case M_SEQ_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
-           return;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
+         return;
        }
-       if (sreg == 0) {
-           /* result is always false */
-           macro_build(&icnt, NULL, "move", "d,s", dreg, 0);
-           return;
+      if (sreg == 0)
+       {
+         /* result is always false */
+         macro_build (&icnt, NULL, "move", "d,s", dreg, 0);
+         return;
        }
-       switch (imm_expr.X_add_number & 0xffff8000) {
+      switch (imm_expr.X_add_number & 0xffff8000)
+       {
        case 0:
        case 0x8000:
-           macro_build(&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
-           used_at = 0;
-           break;
+         macro_build (&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
+         used_at = 0;
+         break;
 
        case 0xffff8000:
-           if (imm_expr.X_add_number != -32768) {
-               imm_expr.X_add_number = -imm_expr.X_add_number;
-               macro_build(&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
-               used_at = 0;
-               break;
+         if (imm_expr.X_add_number != -32768)
+           {
+             imm_expr.X_add_number = -imm_expr.X_add_number;
+             macro_build (&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
+             used_at = 0;
+             break;
            }
-           /* FALLTHROUGH */
+         /* FALLTHROUGH */
 
        default:
-           macro_build_lui(&icnt, &imm_expr, AT);
-           if (imm_expr.X_add_number & 0xffff)
-               macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
-           macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
-           used_at = 1;
-       }
-       macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
-       if (used_at)
-               break;
-       return;
+         macro_build_lui (&icnt, &imm_expr, AT);
+         if (imm_expr.X_add_number & 0xffff)
+           macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
+         macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
+         used_at = 1;
+       }
+      macro_build (&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
+      if (used_at)
+       break;
+      return;
 
     case M_SGE:                /* sreg >= treg <==> not (sreg < treg) */
-       s = "slt";
-       goto sge;
+      s = "slt";
+      goto sge;
     case M_SGEU:
-       s = "sltu";
+      s = "sltu";
     sge:
-       macro_build(&icnt, NULL, s, "d,v,t", dreg, sreg, treg);
-       macro_build(&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
-       return;
+      macro_build (&icnt, NULL, s, "d,v,t", dreg, sreg, treg);
+      macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
+      return;
 
-    case M_SGE_I:      /* sreg >= I <==> not (sreg < I) */
+    case M_SGE_I:              /* sreg >= I <==> not (sreg < I) */
     case M_SGEU_I:
-       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769) {
-           macro_build(&icnt, &expr1,
-               mask == M_SGE_I ? "slti" : "sltiu", "t,r,j", dreg, sreg);
-           used_at = 0;
-       } else {
-           load_register(&icnt, ip, AT, &imm_expr);
-           macro_build(&icnt, NULL,
-               mask == M_SGE_I ? "slt" : "sltu", "d,v,t", dreg, sreg, AT);
-           used_at = 1;
-       }
-       macro_build(&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
-       if (used_at)
-               break;
-       return;
+      if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769)
+       {
+         macro_build (&icnt, &expr1,
+                  mask == M_SGE_I ? "slti" : "sltiu", "t,r,j", dreg, sreg);
+         used_at = 0;
+       }
+      else
+       {
+         load_register (&icnt, ip, AT, &imm_expr);
+         macro_build (&icnt, NULL,
+                mask == M_SGE_I ? "slt" : "sltu", "d,v,t", dreg, sreg, AT);
+         used_at = 1;
+       }
+      macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
+      if (used_at)
+       break;
+      return;
 
     case M_SGT:                /* sreg > treg  <==>  treg < sreg */
-       s = "slt";
-       goto sgt;
+      s = "slt";
+      goto sgt;
     case M_SGTU:
-       s = "sltu";
+      s = "sltu";
     sgt:
-       macro_build(&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
-       return;
+      macro_build (&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
+      return;
 
-    case M_SGT_I:      /* sreg > I  <==>  I < sreg */
-       s = "slt";
-       goto sgti;
+    case M_SGT_I:              /* sreg > I  <==>  I < sreg */
+      s = "slt";
+      goto sgti;
     case M_SGTU_I:
-       s = "sltu";
+      s = "sltu";
     sgti:
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
-       break;
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
+      break;
 
-    case M_SLE:        /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
-       s = "slt";
-       goto sle;
+    case M_SLE:                /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
+      s = "slt";
+      goto sle;
     case M_SLEU:
-       s = "sltu";
+      s = "sltu";
     sle:
-       macro_build(&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
-       macro_build(&icnt, &imm_expr, "xori", "t,r,i", dreg, dreg);
-       return;
+      macro_build (&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
+      macro_build (&icnt, &imm_expr, "xori", "t,r,i", dreg, dreg);
+      return;
 
-    case M_SLE_I:  /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
-       s = "slt";
-       goto slei;
+    case M_SLE_I:              /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
+      s = "slt";
+      goto slei;
     case M_SLEU_I:
-       s = "sltu";
+      s = "sltu";
     slei:
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
-       macro_build(&icnt, &offset_expr, "xori", "t,r,i", dreg, dreg);
-       break;
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
+      macro_build (&icnt, &offset_expr, "xori", "t,r,i", dreg, dreg);
+      break;
 
     case M_SLT_I:
-       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769) {
-           macro_build(&icnt, &imm_expr, "slti", "t,r,j", dreg, sreg);
-           return;
+      if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769)
+       {
+         macro_build (&icnt, &imm_expr, "slti", "t,r,j", dreg, sreg);
+         return;
        }
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, NULL, "slt", "d,v,t", dreg, sreg, AT);
-       break;
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, NULL, "slt", "d,v,t", dreg, sreg, AT);
+      break;
 
     case M_SLTU_I:
-       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769) {
-           macro_build(&icnt, &imm_expr, "sltiu", "t,r,j", dreg, sreg);
-           return;
+      if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769)
+       {
+         macro_build (&icnt, &imm_expr, "sltiu", "t,r,j", dreg, sreg);
+         return;
        }
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, sreg, AT);
-       break;
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, sreg, AT);
+      break;
 
     case M_SNE:
-       if (sreg == 0)
-           macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, treg);
-       else if (treg == 0)
-           macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
-       else {
-           macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
-           macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
+      if (sreg == 0)
+       macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, treg);
+      else if (treg == 0)
+       macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
+      else
+       {
+         macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
+         macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
        }
-       return;
+      return;
 
     case M_SNE_I:
-       if (imm_expr.X_add_number == 0) {
-           macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
-           return;
+      if (imm_expr.X_add_number == 0)
+       {
+         macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
+         return;
        }
-       if (sreg == 0) {
-           /* result is always true */
-           macro_build(&icnt, &expr1, "addiu", "t,r,j", dreg, 0);
-           return;
+      if (sreg == 0)
+       {
+         /* result is always true */
+         macro_build (&icnt, &expr1, "addiu", "t,r,j", dreg, 0);
+         return;
        }
-       switch (imm_expr.X_add_number & 0xffff8000) {
+      switch (imm_expr.X_add_number & 0xffff8000)
+       {
        case 0:
        case 0x8000:
-           macro_build(&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
-           used_at = 0;
-           break;
+         macro_build (&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
+         used_at = 0;
+         break;
 
        case 0xffff8000:
-           if (imm_expr.X_add_number != -32768) {
-               imm_expr.X_add_number = -imm_expr.X_add_number;
-               macro_build(&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
-               used_at = 0;
-               break;
+         if (imm_expr.X_add_number != -32768)
+           {
+             imm_expr.X_add_number = -imm_expr.X_add_number;
+             macro_build (&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
+             used_at = 0;
+             break;
            }
-           /* FALLTHROUGH */
+         /* FALLTHROUGH */
 
        default:
-           macro_build_lui(&icnt, &imm_expr, AT);
-           if (imm_expr.X_add_number & 0xffff)
-               macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
-           macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
-           used_at = 1;
-       }
-       macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
-       if (used_at)
-               break;
-       return;
+         macro_build_lui (&icnt, &imm_expr, AT);
+         if (imm_expr.X_add_number & 0xffff)
+           macro_build (&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
+         macro_build (&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
+         used_at = 1;
+       }
+      macro_build (&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
+      if (used_at)
+       break;
+      return;
 
     case M_SUB_I:
-       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768) {
-           imm_expr.X_add_number = -imm_expr.X_add_number;
-           macro_build(&icnt, &imm_expr, "addi", "t,r,j", dreg, sreg);
-           return;
+      if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768)
+       {
+         imm_expr.X_add_number = -imm_expr.X_add_number;
+         macro_build (&icnt, &imm_expr, "addi", "t,r,j", dreg, sreg);
+         return;
        }
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, NULL, "sub", "d,v,t", dreg, sreg, AT);
-       break;
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, NULL, "sub", "d,v,t", dreg, sreg, AT);
+      break;
 
     case M_SUBU_I:
-       if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768) {
-           imm_expr.X_add_number = -imm_expr.X_add_number;
-           macro_build(&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
-           return;
+      if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768)
+       {
+         imm_expr.X_add_number = -imm_expr.X_add_number;
+         macro_build (&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
+         return;
        }
-       load_register(&icnt, ip, AT, &imm_expr);
-       macro_build(&icnt, NULL, "subu", "d,v,t", dreg, sreg, AT);
-       break;
+      load_register (&icnt, ip, AT, &imm_expr);
+      macro_build (&icnt, NULL, "subu", "d,v,t", dreg, sreg, AT);
+      break;
 
     case M_TRUNCWD:
     case M_TRUNCWS:
-       sreg = (ip->insn_opcode >> 11) & 0x1f;  /* floating reg */
-       dreg = (ip->insn_opcode >> 06) & 0x1f;  /* floating reg */
-
-       /*
-        * Is the double cfc1 instruction a bug in the mips assembler;
-        * or is there a reason for it?
-         */
-       save_reorder_condition = mips_noreorder;
-       mips_noreorder = 1;
-       macro_build(&icnt, NULL, "cfc1", "t,d", treg, 31);
-       macro_build(&icnt, NULL, "cfc1", "t,d", treg, 31);
-       macro_build(&icnt, NULL, "nop", "");
-       expr1.X_add_number = 3;
-       macro_build(&icnt, &expr1, "ori", "t,r,i", AT, treg);
-       expr1.X_add_number = 2;
-       macro_build(&icnt, &expr1, "xori", "t,r,i", AT, AT);
-       macro_build(&icnt, NULL, "ctc1", "t,d", AT, 31);
-       macro_build(&icnt, NULL, "nop", "");
-       macro_build(&icnt, NULL,
-           mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S", dreg, sreg);
-       macro_build(&icnt, NULL, "ctc1", "t,d", treg, 31);
-       macro_build(&icnt, NULL, "nop", "");
-       mips_noreorder = save_reorder_condition;
-       break;
+      sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
+      dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
+
+      /*
+       * Is the double cfc1 instruction a bug in the mips assembler;
+       * or is there a reason for it?
+       */
+      save_reorder_condition = mips_noreorder;
+      mips_noreorder = 1;
+      macro_build (&icnt, NULL, "cfc1", "t,d", treg, 31);
+      macro_build (&icnt, NULL, "cfc1", "t,d", treg, 31);
+      macro_build (&icnt, NULL, "nop", "");
+      expr1.X_add_number = 3;
+      macro_build (&icnt, &expr1, "ori", "t,r,i", AT, treg);
+      expr1.X_add_number = 2;
+      macro_build (&icnt, &expr1, "xori", "t,r,i", AT, AT);
+      macro_build (&icnt, NULL, "ctc1", "t,d", AT, 31);
+      macro_build (&icnt, NULL, "nop", "");
+      macro_build (&icnt, NULL,
+             mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S", dreg, sreg);
+      macro_build (&icnt, NULL, "ctc1", "t,d", treg, 31);
+      macro_build (&icnt, NULL, "nop", "");
+      mips_noreorder = save_reorder_condition;
+      break;
 
     case M_ULH:
-       s = "lb";
-       goto ulh;
+      s = "lb";
+      goto ulh;
     case M_ULHU:
-       s = "lbu";
+      s = "lbu";
     ulh:
-       /* avoid load delay */
-       offset_expr.X_add_number += 1;
-       macro_build(&icnt, &offset_expr, s, "t,o(b)", treg, breg);
-       offset_expr.X_add_number -= 1;
-       macro_build(&icnt, &offset_expr, "lbu", "t,o(b)", AT, breg);
-       macro_build(&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
-       macro_build(&icnt,NULL, "or", "d,v,t", treg, treg, AT);
-       break;
+      /* avoid load delay */
+      offset_expr.X_add_number += 1;
+      macro_build (&icnt, &offset_expr, s, "t,o(b)", treg, breg);
+      offset_expr.X_add_number -= 1;
+      macro_build (&icnt, &offset_expr, "lbu", "t,o(b)", AT, breg);
+      macro_build (&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
+      macro_build (&icnt, NULL, "or", "d,v,t", treg, treg, AT);
+      break;
 
     case M_ULW:
-       /* does this work on a big endian machine? */
-       offset_expr.X_add_number += 3;
-       macro_build(&icnt, &offset_expr, "lwl", "t,o(b)", treg, breg);
-       offset_expr.X_add_number -= 3;
-       macro_build(&icnt, &offset_expr, "lwr", "t,o(b)", treg, breg);
-       return;
+      /* does this work on a big endian machine? */
+      offset_expr.X_add_number += 3;
+      macro_build (&icnt, &offset_expr, "lwl", "t,o(b)", treg, breg);
+      offset_expr.X_add_number -= 3;
+      macro_build (&icnt, &offset_expr, "lwr", "t,o(b)", treg, breg);
+      return;
 
     case M_ULH_A:
     case M_ULHU_A:
     case M_ULW_A:
-       if (offset_expr.X_seg == &bfd_abs_section)
-           load_register(&icnt, ip, AT, &offset_expr);
-       else {
-           macro_build_lui(&icnt, &offset_expr, AT);
-           macro_build(&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
-       }
-       if (mask == M_ULW_A) {
-           expr1.X_add_number = 3;
-           macro_build(&icnt, &expr1, "lwl", "t,o(b)", treg, AT);
-           imm_expr.X_add_number = 0;
-           macro_build(&icnt, &expr1, "lwr", "t,o(b)", treg, AT);
-       } else {
-           macro_build(&icnt, &expr1,
-               mask == M_ULH_A ? "lb" : "lbu", "t,o(b)", treg, AT);
-           imm_expr.X_add_number = 0;
-           macro_build(&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
-           macro_build(&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
-           macro_build(&icnt, NULL, "or", "d,v,t", treg, treg, AT);
+      if (offset_expr.X_seg == &bfd_abs_section)
+       load_register (&icnt, ip, AT, &offset_expr);
+      else if (gp_reference (&offset_expr))
+       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, GP);
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, AT);
+         macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
        }
-       break;
+      if (mask == M_ULW_A)
+       {
+         expr1.X_add_number = 3;
+         macro_build (&icnt, &expr1, "lwl", "t,o(b)", treg, AT);
+         imm_expr.X_add_number = 0;
+         macro_build (&icnt, &expr1, "lwr", "t,o(b)", treg, AT);
+       }
+      else
+       {
+         macro_build (&icnt, &expr1,
+                      mask == M_ULH_A ? "lb" : "lbu", "t,o(b)", treg, AT);
+         imm_expr.X_add_number = 0;
+         macro_build (&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
+         macro_build (&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
+         macro_build (&icnt, NULL, "or", "d,v,t", treg, treg, AT);
+       }
+      break;
 
     case M_USH:
-       macro_build(&icnt, &offset_expr, "sb", "t,o(b)", treg, breg);
-       macro_build(&icnt, NULL, "srl", "d,w,<", AT, treg, 8);
-       offset_expr.X_add_number += 1;
-       macro_build(&icnt, &offset_expr, "sb", "t,o(b)", AT, breg);
-       break;
+      macro_build (&icnt, &offset_expr, "sb", "t,o(b)", treg, breg);
+      macro_build (&icnt, NULL, "srl", "d,w,<", AT, treg, 8);
+      offset_expr.X_add_number += 1;
+      macro_build (&icnt, &offset_expr, "sb", "t,o(b)", AT, breg);
+      break;
 
     case M_USW:
-       offset_expr.X_add_number += 3;
-       macro_build(&icnt, &offset_expr, "swl", "t,o(b)", treg, breg);
-       offset_expr.X_add_number -= 3;
-       macro_build(&icnt, &offset_expr, "swr", "t,o(b)", treg, breg);
-       return;
+      offset_expr.X_add_number += 3;
+      macro_build (&icnt, &offset_expr, "swl", "t,o(b)", treg, breg);
+      offset_expr.X_add_number -= 3;
+      macro_build (&icnt, &offset_expr, "swr", "t,o(b)", treg, breg);
+      return;
 
     case M_USH_A:
     case M_USW_A:
-       if (offset_expr.X_seg == &bfd_abs_section)
-           load_register(&icnt, ip, AT, &offset_expr);
-       else {
-           macro_build_lui(&icnt, &offset_expr, AT);
-           macro_build(&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
-       }
-       if (mask == M_USW_A) {
-           expr1.X_add_number = 3;
-           macro_build(&icnt, &expr1, "swl", "t,o(b)", treg, AT);
-           expr1.X_add_number = 0;
-           macro_build(&icnt, &expr1, "swr", "t,o(b)", treg, AT);
-       } else {
-           expr1.X_add_number = 0;
-           macro_build(&icnt, &expr1, "sb", "t,o(b)", treg, AT);
-           macro_build(&icnt, NULL, "srl", "d,w,<", treg, treg, 8);
-           expr1.X_add_number = 1;
-           macro_build(&icnt, &expr1, "sb", "t,o(b)", treg, AT);
-           expr1.X_add_number = 0;
-           macro_build(&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
-           macro_build(&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
-           macro_build(&icnt, NULL, "or", "d,v,t", treg, treg, AT);
+      if (offset_expr.X_seg == &bfd_abs_section)
+       load_register (&icnt, ip, AT, &offset_expr);
+      else if (gp_reference (&offset_expr))
+       macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, GP);
+      else
+       {
+         macro_build_lui (&icnt, &offset_expr, AT);
+         macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
        }
-       break;
+      if (mask == M_USW_A)
+       {
+         expr1.X_add_number = 3;
+         macro_build (&icnt, &expr1, "swl", "t,o(b)", treg, AT);
+         expr1.X_add_number = 0;
+         macro_build (&icnt, &expr1, "swr", "t,o(b)", treg, AT);
+       }
+      else
+       {
+         expr1.X_add_number = 0;
+         macro_build (&icnt, &expr1, "sb", "t,o(b)", treg, AT);
+         macro_build (&icnt, NULL, "srl", "d,w,<", treg, treg, 8);
+         expr1.X_add_number = 1;
+         macro_build (&icnt, &expr1, "sb", "t,o(b)", treg, AT);
+         expr1.X_add_number = 0;
+         macro_build (&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
+         macro_build (&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
+         macro_build (&icnt, NULL, "or", "d,v,t", treg, treg, AT);
+       }
+      break;
 
     default:
-       as_bad("Macro %s not implemented yet", ip->insn_mo->name);
+      as_bad ("Macro %s not implemented yet", ip->insn_mo->name);
     }
-    if (mips_noat)
-       as_warn("Macro used $at after \".set noat\"");
+  if (mips_noat)
+    as_warn ("Macro used $at after \".set noat\"");
 }
 
 
@@ -1643,362 +1864,400 @@ mips_ip (str, ip)
      char *str;
      struct mips_cl_insn *ip;
 {
-    char                *s;
-    const char          *args;
-    char                c;
-    struct mips_opcode  *insn;
-    char                *argsStart;
-    unsigned int       regno;
-    unsigned int       lastregno = 0;
-    char                *s_reset;
-
-    insn_error = NULL;
-
-    for (s = str; islower(*s) || (*s >= '0' && *s <= '3') || *s == '.'; ++s)
-       continue;
-    switch (*s) {
-
+  char *s;
+  const char *args;
+  char c;
+  struct mips_opcode *insn;
+  char *argsStart;
+  unsigned int regno;
+  unsigned int lastregno = 0;
+  char *s_reset;
+
+  insn_error = NULL;
+
+  for (s = str; islower (*s) || (*s >= '0' && *s <= '3') || *s == '.'; ++s)
+    continue;
+  switch (*s)
+    {
     case '\0':
-       break;
+      break;
 
     case ' ':
-       *s++ = '\0';
-       break;
+      *s++ = '\0';
+      break;
 
     default:
-       as_warn("Unknown opcode: `%s'", str);
-       exit(1);
+      as_warn ("Unknown opcode: `%s'", str);
+      exit (1);
     }
-    if ((insn = (struct mips_opcode *) hash_find(op_hash, str)) == NULL) {
-       as_warn("`%s' not in hash table.", str);
-       insn_error = "ERROR: Unrecognized opcode";
-       return;
+  if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
+    {
+      as_warn ("`%s' not in hash table.", str);
+      insn_error = "ERROR: Unrecognized opcode";
+      return;
     }
-    argsStart = s;
-    for (;;) {
-       assert(strcmp(insn->name, str) == 0);
-       ip->insn_mo = insn;
-       ip->insn_opcode = insn->match;
-       for (args = insn->args; ; ++args) {
-           if (*s == ' ')
-               ++s;
-           switch (*args) {
-
-           case '\0':  /* end of args */
-               if (*s == '\0')
-                   return;
-               break;
+  argsStart = s;
+  for (;;)
+    {
+      assert (strcmp (insn->name, str) == 0);
+      ip->insn_mo = insn;
+      ip->insn_opcode = insn->match;
+      for (args = insn->args;; ++args)
+       {
+         if (*s == ' ')
+           ++s;
+         switch (*args)
+           {
+           case '\0':          /* end of args */
+             if (*s == '\0')
+               return;
+             break;
 
            case ',':
-               if (*s++ == *args)
-                   continue;
-               s--;
-               switch (*++args) {
+             if (*s++ == *args)
+               continue;
+             s--;
+             switch (*++args)
+               {
                case 'r':
                case 'v':
-                   ip->insn_opcode |= lastregno << 21;
-                   continue;
+                 ip->insn_opcode |= lastregno << 21;
+                 continue;
 
                case 'w':
                case 'W':
-                   ip->insn_opcode |= lastregno << 16;
-                   continue;
+                 ip->insn_opcode |= lastregno << 16;
+                 continue;
 
                case 'V':
-                   ip->insn_opcode |= lastregno << 11;
-                   continue;
+                 ip->insn_opcode |= lastregno << 11;
+                 continue;
                }
-               break;
+             break;
 
            case '(':
-               /* handle optional base register.
-                  Either the base register is omitted or
-                  we must have a left paren. */
-               /* this is dependent on the next operand specifier
-                  is a 'b' for base register */
-               assert(args[1] == 'b');
-               if (*s == '\0')
-                   return;
-
-           case ')':   /* these must match exactly */
-               if (*s++ == *args)
-                   continue;
-               break;
-
-           case '<':   /* must be at least one digit */
-               /*
-                * According to the manual, if the shift amount is greater
-                 * than 31 or less than 0 the the shift amount should be
-                * mod 32. In reality the mips assembler issues an error.
-                * We issue a warning and do the mod.
-                */
-               my_getExpression(&imm_expr, s);
-               check_absolute_expr(ip, &imm_expr);
-               if ((unsigned long) imm_expr.X_add_number > 31) {
-                   as_warn("Improper shift amount (%d)",
-                       imm_expr.X_add_number);
-                   imm_expr.X_add_number = imm_expr.X_add_number % 32;
-               }
-               ip->insn_opcode |= imm_expr.X_add_number << 6;
-               imm_expr.X_seg = absent_section;
-               s = expr_end;
-               continue;
+             /* handle optional base register.
+                Either the base register is omitted or
+                we must have a left paren. */
+             /* this is dependent on the next operand specifier
+                is a 'b' for base register */
+             assert (args[1] == 'b');
+             if (*s == '\0')
+               return;
 
-           case 'c':       /* break code */
-               my_getExpression(&imm_expr, s);
-               check_absolute_expr(ip, &imm_expr);
-               if ((unsigned)imm_expr.X_add_number > 1023)
-                   as_warn("Illegal break code (%d)", imm_expr.X_add_number);
-               ip->insn_opcode |= imm_expr.X_add_number << 16;
-               imm_expr.X_seg = absent_section;
-               s = expr_end;
+           case ')':           /* these must match exactly */
+             if (*s++ == *args)
                continue;
-
-           case 'b':       /* base register */
-           case 'd':       /* destination register */
-           case 's':       /* source register */
-           case 't':       /* target register */
-           case 'r':       /* both target and source */
-           case 'v':       /* both dest and source */
-           case 'w':       /* both dest and target */
-               s_reset = s;
-               if (s[0] == '$') {
-                   if (isdigit(s[1])) {
-                       ++s;
-                       regno = 0;
-                       do {
-                           regno *= 10;
-                           regno += *s - '0';
-                           ++s;
-                       } while (isdigit(*s));
-                   } else if (s[1] == 'f' && s[2] == 'p') {
-                       s += 3;
-                       regno = 30;
-                   } else if (s[1] == 's' && s[2] == 'p') {
-                       s += 3;
-                       regno = 29;
-                   } else if (s[1] == 'g' && s[2] == 'p') {
-                       s += 3;
-                       regno = 28;
-                   } else if (s[1] == 'a' && s[2] == 't') {
-                       s += 3;
-                       regno = 1;
-                   } else
-                       goto notreg;
-                   if (regno > 31)
-                       as_bad("Invalid register number (%d)", regno);
-                   if (regno == AT && !mips_noat)
-                       as_warn("Used $at without \".set noat\"");
-                   c = *args;
-                   if (*s == ' ')
-                       s++;
-                   if (args[1] != *s) {
-                       if (c == 'r' || c == 'v' || c == 'w') {
-                           regno = lastregno;
-                           s = s_reset;
-                           args++;
-                       }
+             break;
+
+           case '<':           /* must be at least one digit */
+             /*
+              * According to the manual, if the shift amount is greater
+              * than 31 or less than 0 the the shift amount should be
+              * mod 32. In reality the mips assembler issues an error.
+              * We issue a warning and do the mod.
+              */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if ((unsigned long) imm_expr.X_add_number > 31)
+               {
+                 as_warn ("Improper shift amount (%d)",
+                          imm_expr.X_add_number);
+                 imm_expr.X_add_number = imm_expr.X_add_number % 32;
+               }
+             ip->insn_opcode |= imm_expr.X_add_number << 6;
+             imm_expr.X_seg = absent_section;
+             s = expr_end;
+             continue;
+
+           case 'c':           /* break code */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if ((unsigned) imm_expr.X_add_number > 1023)
+               as_warn ("Illegal break code (%d)", imm_expr.X_add_number);
+             ip->insn_opcode |= imm_expr.X_add_number << 16;
+             imm_expr.X_seg = absent_section;
+             s = expr_end;
+             continue;
+
+           case 'b':           /* base register */
+           case 'd':           /* destination register */
+           case 's':           /* source register */
+           case 't':           /* target register */
+           case 'r':           /* both target and source */
+           case 'v':           /* both dest and source */
+           case 'w':           /* both dest and target */
+             s_reset = s;
+             if (s[0] == '$')
+               {
+                 if (isdigit (s[1]))
+                   {
+                     ++s;
+                     regno = 0;
+                     do
+                       {
+                         regno *= 10;
+                         regno += *s - '0';
+                         ++s;
+                       }
+                     while (isdigit (*s));
+                   }
+                 else if (s[1] == 'f' && s[2] == 'p')
+                   {
+                     s += 3;
+                     regno = 30;
+                   }
+                 else if (s[1] == 's' && s[2] == 'p')
+                   {
+                     s += 3;
+                     regno = 29;
+                   }
+                 else if (s[1] == 'g' && s[2] == 'p')
+                   {
+                     s += 3;
+                     regno = 28;
                    }
-                   switch (c) {
+                 else if (s[1] == 'a' && s[2] == 't')
+                   {
+                     s += 3;
+                     regno = 1;
+                   }
+                 else
+                   goto notreg;
+                 if (regno > 31)
+                   as_bad ("Invalid register number (%d)", regno);
+                 if (regno == AT && !mips_noat)
+                   as_warn ("Used $at without \".set noat\"");
+                 c = *args;
+                 if (*s == ' ')
+                   s++;
+                 if (args[1] != *s)
+                   {
+                     if (c == 'r' || c == 'v' || c == 'w')
+                       {
+                         regno = lastregno;
+                         s = s_reset;
+                         args++;
+                       }
+                   }
+                 switch (c)
+                   {
                    case 'r':
                    case 's':
                    case 'v':
                    case 'b':
-                       ip->insn_opcode |= regno << 21;
-                       break;
+                     ip->insn_opcode |= regno << 21;
+                     break;
                    case 'd':
-                       ip->insn_opcode |= regno << 11;
-                       break;
+                     ip->insn_opcode |= regno << 11;
+                     break;
                    case 'w':
                    case 't':
-                       ip->insn_opcode |= regno << 16;
+                     ip->insn_opcode |= regno << 16;
                    }
-                   lastregno = regno;
-                   continue;
+                 lastregno = regno;
+                 continue;
                }
            notreg:
-               switch (*args++) {
+             switch (*args++)
+               {
                case 'r':
                case 'v':
-                   ip->insn_opcode |= lastregno << 21;
-                   continue;
+                 ip->insn_opcode |= lastregno << 21;
+                 continue;
                case 'w':
-                   ip->insn_opcode |= lastregno << 16;
-                   continue;
+                 ip->insn_opcode |= lastregno << 16;
+                 continue;
                }
-               break;
+             break;
 
-           case 'D':       /* floating point destination register */
-           case 'S':       /* floating point source register */
-           case 'T':       /* floating point target register */
+           case 'D':           /* floating point destination register */
+           case 'S':           /* floating point source register */
+           case 'T':           /* floating point target register */
            case 'V':
            case 'W':
-               s_reset = s;
-               if (s[0] == '$' && s[1] == 'f' && isdigit(s[2])) {
-                   s += 2;
-                   regno = 0;
-                   do {
-                       regno *= 10;
-                       regno += *s - '0';
-                       ++s;
-                   } while (isdigit(*s));
-
-                   if (regno > 31)
-                       as_bad("Invalid float register number (%d)", regno);
-
-                   if ((regno & 1) &&
-                        !(strcmp(str, "mtc1") == 0 ||
-                        strcmp(str, "mfc1") == 0 ||
-                        strcmp(str, "lwc1") == 0 ||
-                        strcmp(str, "swc1") == 0))
-                           as_warn("Float register should be even, was %d",
-                               regno);
-
-                   c = *args;
-                   if (*s == ' ')
-                       s++;
-                   if (args[1] != *s) {
-                       if (c == 'V' || c == 'W') {
-                           regno = lastregno;
-                           s = s_reset;
-                           args++;
+             s_reset = s;
+             if (s[0] == '$' && s[1] == 'f' && isdigit (s[2]))
+               {
+                 s += 2;
+                 regno = 0;
+                 do
+                   {
+                     regno *= 10;
+                     regno += *s - '0';
+                     ++s;
+                   }
+                 while (isdigit (*s));
+
+                 if (regno > 31)
+                   as_bad ("Invalid float register number (%d)", regno);
+
+                 if ((regno & 1) &&
+                     !(strcmp (str, "mtc1") == 0 ||
+                       strcmp (str, "mfc1") == 0 ||
+                       strcmp (str, "lwc1") == 0 ||
+                       strcmp (str, "swc1") == 0))
+                   as_warn ("Float register should be even, was %d",
+                            regno);
+
+                 c = *args;
+                 if (*s == ' ')
+                   s++;
+                 if (args[1] != *s)
+                   {
+                     if (c == 'V' || c == 'W')
+                       {
+                         regno = lastregno;
+                         s = s_reset;
+                         args++;
                        }
                    }
-                   switch (c) {
+                 switch (c)
+                   {
                    case 'D':
-                       ip->insn_opcode |= regno <<  6;
-                       break;
+                     ip->insn_opcode |= regno << 6;
+                     break;
                    case 'V':
                    case 'S':
-                       ip->insn_opcode |= regno << 11;
-                       break;
+                     ip->insn_opcode |= regno << 11;
+                     break;
                    case 'W':
                    case 'T':
-                       ip->insn_opcode |= regno << 16;
+                     ip->insn_opcode |= regno << 16;
                    }
-                   lastregno = regno;
-                   continue;
+                 lastregno = regno;
+                 continue;
                }
-               switch (*args++) {
+             switch (*args++)
+               {
                case 'V':
-                   ip->insn_opcode |= lastregno << 11;
-                   continue;
+                 ip->insn_opcode |= lastregno << 11;
+                 continue;
                case 'W':
-                   ip->insn_opcode |= lastregno << 16;
-                   continue;
+                 ip->insn_opcode |= lastregno << 16;
+                 continue;
                }
-               break;
+             break;
 
            case 'I':
-               my_getExpression(&imm_expr, s);
-               check_absolute_expr(ip, &imm_expr);
-               s = expr_end;
-               continue;
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             s = expr_end;
+             continue;
 
            case 'A':
-               my_getExpression(&offset_expr, s);
-               imm_reloc = BFD_RELOC_32;
-               s = expr_end;
-               continue;
+             my_getExpression (&offset_expr, s);
+             imm_reloc = BFD_RELOC_32;
+             s = expr_end;
+             continue;
 
            case 'F':
-               as_bad("Floating point constants only implemented for pseudo ops.");
-               continue;
-
-           case 'i':       /* 16 bit unsigned immediate */
-           case 'j':       /* 16 bit signed immediate */
-               imm_reloc = BFD_RELOC_LO16;
-               c = my_getSmallExpression(&imm_expr, s);
-               if (c) {
-                   if (c != 'l') {
-                       if (imm_expr.X_seg == &bfd_abs_section)
-                           imm_expr.X_add_number =
-                               (imm_expr.X_add_number >> 16) & 0xffff;
-                       else if (c == 'h')
-                           imm_reloc = BFD_RELOC_HI16_S;
-                       else
-                           imm_reloc = BFD_RELOC_HI16;
+             as_bad ("Floating point constants only implemented for pseudo ops.");
+             continue;
+
+           case 'i':           /* 16 bit unsigned immediate */
+           case 'j':           /* 16 bit signed immediate */
+             imm_reloc = BFD_RELOC_LO16;
+             c = my_getSmallExpression (&imm_expr, s);
+             if (c)
+               {
+                 if (c != 'l')
+                   {
+                     if (imm_expr.X_seg == &bfd_abs_section)
+                       imm_expr.X_add_number =
+                         (imm_expr.X_add_number >> 16) & 0xffff;
+                     else if (c == 'h')
+                       imm_reloc = BFD_RELOC_HI16_S;
+                     else
+                       imm_reloc = BFD_RELOC_HI16;
                    }
-               } else
-                   check_absolute_expr(ip, &imm_expr);
-               if (*args == 'i') {
-                   if ((unsigned long) imm_expr.X_add_number > 65535)
-                       as_bad("16 bit expression not in range 0..65535");
-               } else {
-                   if (imm_expr.X_add_number < -32768 ||
+               }
+             else
+               check_absolute_expr (ip, &imm_expr);
+             if (*args == 'i')
+               {
+                 if ((unsigned long) imm_expr.X_add_number > 65535)
+                   as_bad ("16 bit expression not in range 0..65535");
+               }
+             else
+               {
+                 if (imm_expr.X_add_number < -32768 ||
                      imm_expr.X_add_number > 32767)
-                       as_bad("16 bit expression not in range -32768..32767");
+                   as_bad ("16 bit expression not in range -32768..32767");
                }
-               s = expr_end;
-               continue;
-
-           case 'o':       /* 16 bit offset */
-               c = my_getSmallExpression(&offset_expr, s);
-               /*
-                * If this value won't fit into a 16 bit offset, then
-                * go find a macro that will generate the 32 bit offset
-                * code pattern.
-                */
-               if ((offset_expr.X_add_symbol
-                    && offset_expr.X_seg != &bfd_abs_section)
-                   || offset_expr.X_subtract_symbol
-                   || offset_expr.X_add_number > 32767
-                   || offset_expr.X_add_number < -32768)
-                       break;
-
-               offset_reloc = BFD_RELOC_LO16;
-               if (c == 'h' || c == 'H')
-                   offset_expr.X_add_number =
-                       (offset_expr.X_add_number >> 16) & 0xffff;
-               s = expr_end;
-               continue;
-
-           case 'p':       /* pc relative offset */
-               offset_reloc = BFD_RELOC_16_PCREL_S2;
-               my_getExpression(&offset_expr, s);
-               s = expr_end;
-               continue;
+             s = expr_end;
+             continue;
+
+           case 'o':           /* 16 bit offset */
+             c = my_getSmallExpression (&offset_expr, s);
+             /*
+              * If this value won't fit into a 16 bit offset, then
+              * go find a macro that will generate the 32 bit offset
+              * code pattern.
+              */
+             if ((offset_expr.X_add_symbol
+                  && offset_expr.X_seg != &bfd_abs_section)
+                 || offset_expr.X_subtract_symbol
+                 || offset_expr.X_add_number > 32767
+                 || offset_expr.X_add_number < -32768)
+               break;
 
-           case 'u':       /* upper 16 bits */
-               c = my_getSmallExpression(&imm_expr, s);
-               if ((unsigned long)imm_expr.X_add_number > 65535)
-                   as_bad("lui expression not in range 0..65535");
-               imm_reloc = BFD_RELOC_LO16;
-               if (c) {
-                   if (c != 'l') {
-                       if (imm_expr.X_seg == &bfd_abs_section)
-                           imm_expr.X_add_number =
-                               (imm_expr.X_add_number >> 16) & 0xffff;
-                       else if (c == 'h')
-                           imm_reloc = BFD_RELOC_HI16_S;
-                       else
-                           imm_reloc = BFD_RELOC_HI16;
+             offset_reloc = BFD_RELOC_LO16;
+             if (c == 'h' || c == 'H')
+               offset_expr.X_add_number =
+                 (offset_expr.X_add_number >> 16) & 0xffff;
+             s = expr_end;
+             continue;
+
+           case 'p':           /* pc relative offset */
+             offset_reloc = BFD_RELOC_16_PCREL_S2;
+             my_getExpression (&offset_expr, s);
+             s = expr_end;
+             continue;
+
+           case 'u':           /* upper 16 bits */
+             c = my_getSmallExpression (&imm_expr, s);
+             if ((unsigned long) imm_expr.X_add_number > 65535)
+               as_bad ("lui expression not in range 0..65535");
+             imm_reloc = BFD_RELOC_LO16;
+             if (c)
+               {
+                 if (c != 'l')
+                   {
+                     if (imm_expr.X_seg == &bfd_abs_section)
+                       imm_expr.X_add_number =
+                         (imm_expr.X_add_number >> 16) & 0xffff;
+                     else if (c == 'h')
+                       imm_reloc = BFD_RELOC_HI16_S;
+                     else
+                       imm_reloc = BFD_RELOC_HI16;
                    }
                }
-               s = expr_end;
-               continue;
+             s = expr_end;
+             continue;
 
-           case 'a':       /* 26 bit address */
-               my_getExpression(&offset_expr, s);
-               s = expr_end;
-               offset_reloc = BFD_RELOC_MIPS_JMP;
-               continue;
+           case 'a':           /* 26 bit address */
+             my_getExpression (&offset_expr, s);
+             s = expr_end;
+             offset_reloc = BFD_RELOC_MIPS_JMP;
+             continue;
 
            default:
-               fprintf(stderr, "bad char = '%c'\n", *args);
-               internalError();
+             fprintf (stderr, "bad char = '%c'\n", *args);
+             internalError ();
            }
-           break;
+         break;
        }
-       /* Args don't match.  */
-       if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
-           !strcmp(insn->name, insn[1].name)) {
-           ++insn;
-           s = argsStart;
-           continue;
+      /* Args don't match.  */
+      if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
+         !strcmp (insn->name, insn[1].name))
+       {
+         ++insn;
+         s = argsStart;
+         continue;
        }
-       insn_error = "ERROR: Illegal operands";
-       return;
+      insn_error = "ERROR: Illegal operands";
+      return;
     }
 }
 
@@ -2007,101 +2266,114 @@ mips_ip (str, ip)
 
 static int
 my_getSmallExpression (ep, str)
-    expressionS *ep;
-    char *str;
+     expressionS *ep;
+     char *str;
 {
-    char *sp;
-    int c = 0;
-
-    if (*str == ' ')
-       str++;
-    if (*str == LP
-       || (*str == '%' &&
-           ((str[1] == 'h' && str[2] == 'i')
-            || (str[1] == 'H' && str[2] == 'I')
-            || (str[1] == 'l' && str[2] == 'o'))
-           && str[3] == LP)) {
-       if (*str == LP)
-           c = 0;
-       else {
-           c = str[1];
-           str += 3;
-       }
-
-       /*
-        * A small expression may be followed by a base register.
-        * Scan to the end of this operand, and then back over a possible
-        * base register.  Then scan the small expression up to that
-        * point.  (Based on code in sparc.c...)
-        */
-       for (sp = str; *sp && *sp != ','; sp++)
-           ;
-       if (sp - 4 >= str && sp[-1] == RP) {
-           if (isdigit(sp[-2])) {
-               for (sp -= 3; sp >= str && isdigit(*sp); sp--)
-                   ;
-               if (*sp == '$' && sp > str && sp[-1] == LP) {
-                   sp--;
-                   goto do_it;
+  char *sp;
+  int c = 0;
+
+  if (*str == ' ')
+    str++;
+  if (*str == LP
+      || (*str == '%' &&
+         ((str[1] == 'h' && str[2] == 'i')
+          || (str[1] == 'H' && str[2] == 'I')
+          || (str[1] == 'l' && str[2] == 'o'))
+         && str[3] == LP))
+    {
+      if (*str == LP)
+       c = 0;
+      else
+       {
+         c = str[1];
+         str += 3;
+       }
+
+      /*
+       * A small expression may be followed by a base register.
+       * Scan to the end of this operand, and then back over a possible
+       * base register.  Then scan the small expression up to that
+       * point.  (Based on code in sparc.c...)
+       */
+      for (sp = str; *sp && *sp != ','; sp++)
+       ;
+      if (sp - 4 >= str && sp[-1] == RP)
+       {
+         if (isdigit (sp[-2]))
+           {
+             for (sp -= 3; sp >= str && isdigit (*sp); sp--)
+               ;
+             if (*sp == '$' && sp > str && sp[-1] == LP)
+               {
+                 sp--;
+                 goto do_it;
                }
-           } else if (sp - 5 >= str
-                      && sp[-5] == LP
-                      && sp[-4] == '$'
-                      && ((sp[-3] == 'f' && sp[-2] == 'p')
-                          || (sp[-3] == 's' && sp[-2] == 'p')
-                          || (sp[-3] == 'g' && sp[-2] == 'p')
-                          || (sp[-3] == 'a' && sp[-2] == 't'))) {
-               sp -= 5;
+           }
+         else if (sp - 5 >= str
+                  && sp[-5] == LP
+                  && sp[-4] == '$'
+                  && ((sp[-3] == 'f' && sp[-2] == 'p')
+                      || (sp[-3] == 's' && sp[-2] == 'p')
+                      || (sp[-3] == 'g' && sp[-2] == 'p')
+                      || (sp[-3] == 'a' && sp[-2] == 't')))
+           {
+             sp -= 5;
            do_it:
-               if (sp == str) {
-                   /* no expression means zero offset */
-                   if (c) {
-                       /* %xx(reg) is an error */
-                       ep->X_seg = absent_section;
-                       expr_end = str - 3;
-                   } else {
-                       ep->X_seg = &bfd_abs_section;
-                       expr_end = sp;
+             if (sp == str)
+               {
+                 /* no expression means zero offset */
+                 if (c)
+                   {
+                     /* %xx(reg) is an error */
+                     ep->X_seg = absent_section;
+                     expr_end = str - 3;
                    }
-                   ep->X_add_symbol = NULL;
-                   ep->X_subtract_symbol = NULL;
-                   ep->X_add_number = 0;
-               } else {
-                   *sp = '\0';
-                   my_getExpression(ep, str);
-                   *sp = LP;
+                 else
+                   {
+                     ep->X_seg = &bfd_abs_section;
+                     expr_end = sp;
+                   }
+                 ep->X_add_symbol = NULL;
+                 ep->X_subtract_symbol = NULL;
+                 ep->X_add_number = 0;
+               }
+             else
+               {
+                 *sp = '\0';
+                 my_getExpression (ep, str);
+                 *sp = LP;
                }
-               return c;
+             return c;
            }
        }
     }
-    my_getExpression(ep, str);
-    return c;                  /* => %hi or %lo encountered */
+  my_getExpression (ep, str);
+  return c;                    /* => %hi or %lo encountered */
 }
 
 static void
 my_getExpression (ep, str)
-    expressionS *ep;
-    char *str;
+     expressionS *ep;
+     char *str;
 {
-    char *save_in;
-    asection *seg;
-
-    save_in = input_line_pointer;
-    input_line_pointer = str;
-    seg = expression(ep);
-    expr_end = input_line_pointer;
-    input_line_pointer = save_in;
+  char *save_in;
+  asection *seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  seg = expression (ep);
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
 }
 
 char *
-md_atof (type,litP,sizeP)
+md_atof (type, litP, sizeP)
      char type;
      char *litP;
      int *sizeP;
 {
-    internalError();
-    return NULL;
+  internalError ();
+  return NULL;
 }
 
 void
@@ -2110,50 +2382,49 @@ md_number_to_chars (buf, val, n)
      long val;
      int n;
 {
-
-    switch (byte_order) {
+  switch (byte_order)
+    {
     case LITTLE_ENDIAN:
-       switch (n) {
-
+      switch (n)
+       {
        case 4:
-           *buf++ = val;
-           *buf++ = val >> 8;
-           *buf++ = val >> 16;
-           *buf   = val >> 24;
-           return;
+         *buf++ = val;
+         *buf++ = val >> 8;
+         *buf++ = val >> 16;
+         *buf = val >> 24;
+         return;
 
-        case 2:
-           *buf++ = val;
-           *buf   = val >> 8;
-           return;
+       case 2:
+         *buf++ = val;
+         *buf = val >> 8;
+         return;
 
        case 1:
-           *buf   = val;
-           return;
+         *buf = val;
+         return;
 
        default:
-           internalError();
+         internalError ();
        }
 
     case BIG_ENDIAN:
-
-       switch (n) {
-
+      switch (n)
+       {
        case 4:
-           *buf++ = val >> 24;
-           *buf++ = val >> 16;
-        case 2:
-           *buf++ = val >> 8;
+         *buf++ = val >> 24;
+         *buf++ = val >> 16;
+       case 2:
+         *buf++ = val >> 8;
        case 1:
-           *buf = val;
-           return;
+         *buf = val;
+         return;
 
        default:
-           internalError();
+         internalError ();
        }
 
     default:
-       internalError();
+      internalError ();
     }
 }
 
@@ -2163,20 +2434,49 @@ md_parse_option (argP, cntP, vecP)
      int *cntP;
      char ***vecP;
 {
-    /* Accept -nocpp but ignore it. */
-    if (!strcmp(*argP, "nocpp")) {
-       *argP += 5;
-       return 1;
+  /* Accept -nocpp but ignore it. */
+  if (!strcmp (*argP, "nocpp"))
+    {
+      *argP += 5;
+      return 1;
+    }
+
+  if (strcmp (*argP, "EL") == 0
+      || strcmp (*argP, "EB") == 0)
+    {
+      /* FIXME: This breaks -L -EL.  */
+      flagseen['L'] = 0;
+      *argP = "";
+      return 1;
+    }
+
+#ifdef OBJ_ECOFF
+  if (**argP == 'G')
+    {
+      if ((*argP)[1] != '\0')
+       g_switch_value = atoi (*argP + 1);
+      else if (*cntP)
+       {
+         **vecP = (char *) NULL;
+         (*cntP)--;
+         (*vecP)++;
+         g_switch_value = atoi (**vecP);
+       }
+      else
+       as_warn ("Number expected after -G");
+      *argP = "";
+      return 1;
     }
-    return 1; /* pretend you parsed the character */
+#endif
+  return 1;                    /* pretend you parsed the character */
 }
 
 long
 md_pcrel_from (fixP)
      fixS *fixP;
 {
-    /* return the address of the delay slot */
-    return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+  /* return the address of the delay slot */
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
 int
@@ -2184,174 +2484,181 @@ md_apply_fix (fixP, valueP)
      fixS *fixP;
      long *valueP;
 {
-    unsigned char *buf;
-    long insn, value;
+  unsigned char *buf;
+  long insn, value;
 
-    assert(fixP->fx_size == 4);
+  assert (fixP->fx_size == 4);
 
-    value = *valueP;
-    fixP->fx_addnumber = value;        /* Remember value for tc_gen_reloc */
+  value = *valueP;
+  fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc */
 
-    switch (fixP->fx_r_type) {
+  switch (fixP->fx_r_type)
+    {
     case BFD_RELOC_32:
     case BFD_RELOC_MIPS_JMP:
     case BFD_RELOC_HI16:
     case BFD_RELOC_HI16_S:
     case BFD_RELOC_LO16:
-       /* Nothing needed to do. The value comes from the reloc entry */
-       return 1;
+    case BFD_RELOC_MIPS_GPREL:
+      /* Nothing needed to do. The value comes from the reloc entry */
+      return 1;
 
     case BFD_RELOC_16_PCREL_S2:
-       /*
-        * We need to save the bits in the instruction since fixup_segment()
-        * might be deleting the relocation entry (i.e., a branch within
-        * the current segment).
-        */
-       if (value & 0x3)
-           as_warn("Branch to odd address (%x)", value);
-       value >>= 2;
-       if ((value & ~0xFFFF) && (value & ~0xFFFF) != (-1 & ~0xFFFF))
-           as_bad("Relocation overflow");
-
-       /* update old instruction data */
-       buf = (unsigned char *)(fixP->fx_where + fixP->fx_frag->fr_literal);
-       switch (byte_order) {
+      /*
+       * We need to save the bits in the instruction since fixup_segment()
+       * might be deleting the relocation entry (i.e., a branch within
+       * the current segment).
+       */
+      if (value & 0x3)
+       as_warn ("Branch to odd address (%x)", value);
+      value >>= 2;
+      if ((value & ~0xFFFF) && (value & ~0xFFFF) != (-1 & ~0xFFFF))
+       as_bad ("Relocation overflow");
+
+      /* update old instruction data */
+      buf = (unsigned char *) (fixP->fx_where + fixP->fx_frag->fr_literal);
+      switch (byte_order)
+       {
        case LITTLE_ENDIAN:
-           insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
-           break;
+         insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+         break;
 
        case BIG_ENDIAN:
-           insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-           break;
+         insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+         break;
 
        default:
-           internalError();
-           return 0;
+         internalError ();
+         return 0;
        }
-       insn |= value & 0xFFFF;
-       md_number_to_chars(buf, insn, 4);
-       break;
+      insn |= value & 0xFFFF;
+      md_number_to_chars (buf, insn, 4);
+      break;
 
     default:
-       internalError();
+      internalError ();
     }
-    return 1;
+  return 1;
 }
 
 #if 0
 void
-printInsn(oc)
-    unsigned long oc;
+printInsn (oc)
+     unsigned long oc;
 {
-    const struct mips_opcode *p;
-    int treg, sreg, dreg, shamt;
-    short imm;
-    const char *args;
-    int i;
-
-    for (i = 0; i < NUMOPCODES; ++i) {
-       p = &mips_opcodes[i];
-       if (((oc & p->mask) == p->match) && (p->pinfo != INSN_MACRO)) {
-           printf("%08lx %s\t", oc, p->name);
-           treg  = (oc >> 16) & 0x1f;
-           sreg  = (oc >> 21) & 0x1f;
-           dreg  = (oc >> 11) & 0x1f;
-           shamt = (oc >>  6) & 0x1f;
-           imm   = oc;
-           for (args = p->args; ; ++args) {
-               switch (*args) {
+  const struct mips_opcode *p;
+  int treg, sreg, dreg, shamt;
+  short imm;
+  const char *args;
+  int i;
 
+  for (i = 0; i < NUMOPCODES; ++i)
+    {
+      p = &mips_opcodes[i];
+      if (((oc & p->mask) == p->match) && (p->pinfo != INSN_MACRO))
+       {
+         printf ("%08lx %s\t", oc, p->name);
+         treg = (oc >> 16) & 0x1f;
+         sreg = (oc >> 21) & 0x1f;
+         dreg = (oc >> 11) & 0x1f;
+         shamt = (oc >> 6) & 0x1f;
+         imm = oc;
+         for (args = p->args;; ++args)
+           {
+             switch (*args)
+               {
                case '\0':
-                   printf("\n");
-                   break;
+                 printf ("\n");
+                 break;
 
                case ',':
                case '(':
                case ')':
-                   printf("%c", *args);
-                   continue;
+                 printf ("%c", *args);
+                 continue;
 
                case 'r':
-                   assert(treg == sreg);
-                   printf("$%d,$%d", treg, sreg);
-                   continue;
+                 assert (treg == sreg);
+                 printf ("$%d,$%d", treg, sreg);
+                 continue;
 
                case 'd':
-                   printf("$%d", dreg);
-                   continue;
+                 printf ("$%d", dreg);
+                 continue;
 
                case 't':
-                   printf("$%d", treg);
-                   continue;
+                 printf ("$%d", treg);
+                 continue;
 
                case 'b':
                case 's':
-                   printf("$%d", sreg);
-                   continue;
+                 printf ("$%d", sreg);
+                 continue;
 
                case 'a':
-                   printf("0x%08lx", oc & 0x1ffffff);
-                   continue;
+                 printf ("0x%08lx", oc & 0x1ffffff);
+                 continue;
 
                case 'i':
                case 'j':
                case 'o':
                case 'u':
-                   printf("%d", imm);
-                   continue;
+                 printf ("%d", imm);
+                 continue;
 
                case '<':
-                   printf("$%d", shamt);
-                   continue;
+                 printf ("$%d", shamt);
+                 continue;
 
                default:
-                   internalError();
+                 internalError ();
                }
-               break;
+             break;
            }
-           return;
+         return;
        }
     }
-    printf("%08lx  UNDEFINED\n", oc);
+  printf ("%08lx  UNDEFINED\n", oc);
 }
 #endif
 
 static symbolS *
 get_symbol ()
 {
-    int c;
-    char *name;
-    symbolS *p;
-
-    name = input_line_pointer;
-    c = get_symbol_end();
-    p = (symbolS *) symbol_find_or_make(name);
-    *input_line_pointer = c;
-    return p;
+  int c;
+  char *name;
+  symbolS *p;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  p = (symbolS *) symbol_find_or_make (name);
+  *input_line_pointer = c;
+  return p;
 }
 
 static long
 get_optional_absolute_expression ()
 {
-    expressionS        exp;
-    asection *s;
+  expressionS exp;
+  asection *s;
 
-    s = expression(&exp);
-    if (!(s == &bfd_abs_section || s == big_section || s == absent_section)) {
-       as_bad("Bad Absolute Expression.");
+  s = expression (&exp);
+  if (!(s == &bfd_abs_section || s == big_section || s == absent_section))
+    {
+      as_bad ("Bad Absolute Expression.");
     }
-    return exp.X_add_number;
+  return exp.X_add_number;
 }
 
 static void
 s_align (x)
      int x;
 {
-    register int temp;
-    register long temp_fill;
-    long max_alignment = 15;
+  register int temp;
+  register long temp_fill;
+  long max_alignment = 15;
 
-    /*
+  /*
 
     o  Note that the assembler pulls down any immediately preceeding label
        to the aligned address.
@@ -2363,56 +2670,74 @@ s_align (x)
 
     */
 
-    temp = get_absolute_expression ();
-    if (temp > max_alignment)
-      as_bad("Alignment too large: %d. assumed.", temp = max_alignment);
-    else if (temp < 0) {
-       as_warn("Alignment negative: 0 assumed.");
-       temp = 0;
+  temp = get_absolute_expression ();
+  if (temp > max_alignment)
+    as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
+  else if (temp < 0)
+    {
+      as_warn ("Alignment negative: 0 assumed.");
+      temp = 0;
+    }
+  if (*input_line_pointer == ',')
+    {
+      input_line_pointer++;
+      temp_fill = get_absolute_expression ();
+    }
+  else
+    temp_fill = 0;
+  if (temp)
+    {
+      auto_align = 1;
+      if (!need_pass_2)
+       frag_align (temp, (int) temp_fill);
     }
-    if (*input_line_pointer == ',') {
-       input_line_pointer ++;
-       temp_fill = get_absolute_expression ();
-    } else
-      temp_fill = 0;
-    if (temp) {
-       auto_align = 1;
-       if (!need_pass_2)
-         frag_align (temp, (int)temp_fill);
-    } else {
-       auto_align = 0;
+  else
+    {
+      auto_align = 0;
     }
 
-    record_alignment(now_seg, temp);
+  record_alignment (now_seg, temp);
 
-    demand_empty_rest_of_line();
+  demand_empty_rest_of_line ();
 }
 
 static void
 s_change_sec (sec)
      int sec;
 {
-    switch (sec) {
+  switch (sec)
+    {
     case 't':
-       s_text();
-       break;
+      s_text ();
+      break;
     case 'r':
+#ifdef OBJ_ECOFF
+      subseg_new (".rdata", (subsegT) get_absolute_expression ());
+      break;
+#else
+      /* Fall through.  */
+#endif
     case 'd':
-       s_data();
-       break;
+      s_data ();
+      break;
     case 'b':
 #ifdef BFD_ASSEMBLER
-       subseg_set (bss_section, (subsegT) get_absolute_expression ());
+      subseg_set (bss_section, (subsegT) get_absolute_expression ());
 #else
-       subseg_new (bss_section, (subsegT) get_absolute_expression ());
+      subseg_new (bss_section, (subsegT) get_absolute_expression ());
+#endif
+      demand_empty_rest_of_line ();
+      break;
+    case 's':
+#ifdef OBJ_ECOFF
+      subseg_new (".sdata", (subsegT) get_absolute_expression ());
+      break;
+#else
+      as_bad ("Global pointers not supported; recompile -G 0");
+      return;
 #endif
-       demand_empty_rest_of_line ();
-       break;
-    default:
-       as_bad("Global pointers not supported; recompile -G 0");
-       return;
     }
-    auto_align = 1;
+  auto_align = 1;
 }
 
 static void
@@ -2420,146 +2745,190 @@ s_cons (log_size)
      int log_size;
 {
 
-    if (log_size > 0 && auto_align)
-        frag_align(log_size, 0);
-    cons(1 << log_size);
+  if (log_size > 0 && auto_align)
+    frag_align (log_size, 0);
+  cons (1 << log_size);
 }
 
 static void
 s_err (x)
      int x;
 {
-    as_fatal("Encountered `.err', aborting assembly");
+  as_fatal ("Encountered `.err', aborting assembly");
 }
 
 static void
 s_extern (x)
      int x;
 {
-    long size;
-    symbolS *symbolP;
-
-    symbolP = get_symbol();
-    if (*input_line_pointer == ',')
-       input_line_pointer++;
-    size = get_optional_absolute_expression();
-    S_SET_VALUE(symbolP, size);
+  long size;
+  symbolS *symbolP;
+
+  symbolP = get_symbol ();
+  if (*input_line_pointer == ',')
+    input_line_pointer++;
+  size = get_optional_absolute_expression ();
+  S_SET_VALUE (symbolP, size);
+  S_SET_EXTERNAL (symbolP);
+
+#ifdef OBJ_ECOFF
+  /* ECOFF needs to distinguish a .comm symbol from a .extern symbol,
+     so we use an additional ECOFF specific field.  */
+  symbolP->ecoff_undefined = 1;
+#endif
 }
 
 static void
 s_float_cons (is_double)
      int is_double;
 {
-    char *f;
-    short words[4];
-    int error_code, repeat;
-    extern FLONUM_TYPE generic_floating_point_number;
-
-    if (auto_align)
-      if (is_double)
-       frag_align(3, 0);
-      else
-       frag_align(2, 0);
-
-    SKIP_WHITESPACE ();
-    if (! is_end_of_line [(unsigned char) *input_line_pointer]) {
-       do {
-           error_code = atof_generic(&input_line_pointer, ".", EXP_CHARS,
-                                     &generic_floating_point_number);
-           if (error_code) {
-               if (error_code == ERROR_EXPONENT_OVERFLOW)
-                 as_warn("Bad floating-point constant: exponent overflow");
-               else
-                 as_warn("Bad floating-point constant: unknown error code=%d.", error_code);
+  char *f;
+  short words[4];
+  int error_code, repeat;
+  extern FLONUM_TYPE generic_floating_point_number;
+
+  if (auto_align)
+    if (is_double)
+      frag_align (3, 0);
+    else
+      frag_align (2, 0);
+
+  SKIP_WHITESPACE ();
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      do
+       {
+         error_code = atof_generic (&input_line_pointer, ".", EXP_CHARS,
+                                    &generic_floating_point_number);
+         if (error_code)
+           {
+             if (error_code == ERROR_EXPONENT_OVERFLOW)
+               as_warn ("Bad floating-point constant: exponent overflow");
+             else
+               as_warn ("Bad floating-point constant: unknown error code=%d.", error_code);
            }
 
-           if (is_double) {
-               gen_to_words((LITTLENUM_TYPE *)words,
-                            4 /* precision */,
-                            11 /* exponent_bits */ );
-           } else {
-               gen_to_words((LITTLENUM_TYPE *)words,
-                            2 /* precision */,
-                            8 /* exponent_bits */ );
+         if (is_double)
+           {
+             gen_to_words ((LITTLENUM_TYPE *) words,
+                           4 /* precision */ ,
+                           11 /* exponent_bits */ );
+           }
+         else
+           {
+             gen_to_words ((LITTLENUM_TYPE *) words,
+                           2 /* precision */ ,
+                           8 /* exponent_bits */ );
            }
-           if (*input_line_pointer == ':') {
-               input_line_pointer++;
-               repeat = get_absolute_expression();
-           } else {
-               repeat = 1;
+         if (*input_line_pointer == ':')
+           {
+             input_line_pointer++;
+             repeat = get_absolute_expression ();
            }
-           if (is_double) {
-               f = frag_more(repeat * 8);
-               for (;repeat--; f += 8) {
-                   md_number_to_chars(f+6, words[0], 2);
-                   md_number_to_chars(f+4, words[1], 2);
-                   md_number_to_chars(f+2, words[2], 2);
-                   md_number_to_chars(f,   words[3], 2);
+         else
+           {
+             repeat = 1;
+           }
+         if (is_double)
+           {
+             f = frag_more (repeat * 8);
+             for (; repeat--; f += 8)
+               {
+                 md_number_to_chars (f + 6, words[0], 2);
+                 md_number_to_chars (f + 4, words[1], 2);
+                 md_number_to_chars (f + 2, words[2], 2);
+                 md_number_to_chars (f, words[3], 2);
                }
-           } else {
-               f = frag_more(repeat * 4);
-               for (;repeat--; f += 4) {
-                   md_number_to_chars(f+2, words[0], 2);
-                   md_number_to_chars(f,   words[1], 2);
+           }
+         else
+           {
+             f = frag_more (repeat * 4);
+             for (; repeat--; f += 4)
+               {
+                 md_number_to_chars (f + 2, words[0], 2);
+                 md_number_to_chars (f, words[1], 2);
                }
            }
-           SKIP_WHITESPACE();
-           if (*input_line_pointer != ',') break;
-           input_line_pointer++;
-           SKIP_WHITESPACE();
-       } while (1);
+         SKIP_WHITESPACE ();
+         if (*input_line_pointer != ',')
+           break;
+         input_line_pointer++;
+         SKIP_WHITESPACE ();
+       }
+      while (1);
     }
-    demand_empty_rest_of_line();
+  demand_empty_rest_of_line ();
 }
 
 static void
 s_option (x)
      int x;
 {
-    if (strcmp(input_line_pointer, "O1") != 0
-           && strcmp(input_line_pointer, "O2") != 0)
-        as_warn("Unrecognized option");
-    demand_empty_rest_of_line();
+  if (strcmp (input_line_pointer, "O1") != 0
+      && strcmp (input_line_pointer, "O2") != 0)
+    as_warn ("Unrecognized option");
+  demand_empty_rest_of_line ();
 }
 
 static void
 s_mipsset (x)
      int x;
 {
-    char *name = input_line_pointer, ch;
-
-    while (!is_end_of_line[(unsigned char) *input_line_pointer])
-       input_line_pointer++;
-    ch = *input_line_pointer;
-    *input_line_pointer = '\0';
-
-    if (strcmp(name, "reorder") == 0) {
-       mips_noreorder = 0;
-    } else if (strcmp(name, "noreorder") == 0) {
-       mips_noreorder = 1;
-    } else if (strcmp(name, "at") == 0) {
-       mips_noat = 0;
-    } else if (strcmp(name, "noat") == 0) {
-       mips_noat = 1;
-    } else if (strcmp(name, "macro") == 0) {
-       mips_warn_about_macros = 0;
-    } else if (strcmp(name, "nomacro") == 0) {
-       if (mips_noreorder == 0)
-           as_bad("`noreorder' must be set before `nomacro'");
-       mips_warn_about_macros = 1;
-    } else if (strcmp(name, "move") == 0 || strcmp(name, "novolatile") == 0) {
-       mips_nomove = 0;
-    } else if (strcmp(name, "nomove") == 0 || strcmp(name, "volatile") == 0) {
-       mips_nomove = 1;
-    } else if (strcmp(name, "bopt") == 0) {
-       mips_nobopt = 0;
-    } else if (strcmp(name, "nobopt") == 0) {
-       mips_nobopt = 1;
-    } else {
-       as_warn("Tried to set unrecognized symbol: %s\n", name);
+  char *name = input_line_pointer, ch;
+
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
+    input_line_pointer++;
+  ch = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  if (strcmp (name, "reorder") == 0)
+    {
+      mips_noreorder = 0;
+    }
+  else if (strcmp (name, "noreorder") == 0)
+    {
+      mips_noreorder = 1;
+    }
+  else if (strcmp (name, "at") == 0)
+    {
+      mips_noat = 0;
+    }
+  else if (strcmp (name, "noat") == 0)
+    {
+      mips_noat = 1;
     }
-    *input_line_pointer = ch;
-    demand_empty_rest_of_line();
+  else if (strcmp (name, "macro") == 0)
+    {
+      mips_warn_about_macros = 0;
+    }
+  else if (strcmp (name, "nomacro") == 0)
+    {
+      if (mips_noreorder == 0)
+       as_bad ("`noreorder' must be set before `nomacro'");
+      mips_warn_about_macros = 1;
+    }
+  else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
+    {
+      mips_nomove = 0;
+    }
+  else if (strcmp (name, "nomove") == 0 || strcmp (name, "volatile") == 0)
+    {
+      mips_nomove = 1;
+    }
+  else if (strcmp (name, "bopt") == 0)
+    {
+      mips_nobopt = 0;
+    }
+  else if (strcmp (name, "nobopt") == 0)
+    {
+      mips_nobopt = 1;
+    }
+  else
+    {
+      as_warn ("Tried to set unrecognized symbol: %s\n", name);
+    }
+  *input_line_pointer = ch;
+  demand_empty_rest_of_line ();
 }
 
 int
@@ -2623,7 +2992,7 @@ tc_gen_reloc (section, fixp)
 #ifdef OBJ_ELF
     reloc->addend = 0;
 #else
-    reloc->addend = - reloc->address;
+    reloc->addend = -reloc->address;
 #endif
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   assert (reloc->howto != 0);
@@ -2642,23 +3011,23 @@ tc_gen_reloc (section, fixp)
 
 /* should never be called */
 long
-md_section_align(seg, addr)
-    asection *seg;
-    long addr;
+md_section_align (seg, addr)
+     asection *seg;
+     long addr;
 {
-    int align = bfd_get_section_alignment(stdoutput, seg);
+  int align = bfd_get_section_alignment (stdoutput, seg);
 
-    return ((addr + (1 << align) - 1) & (-1 << align));
+  return ((addr + (1 << align) - 1) & (-1 << align));
 }
 
 int
-md_estimate_size_before_relax(fragP, segtype)
-    fragS *fragP;
-    asection *segtype;
+md_estimate_size_before_relax (fragP, segtype)
+     fragS *fragP;
+     asection *segtype;
 {
-    as_fatal("md_estimate_size_before_relax");
-    return(1);
-} /* md_estimate_size_before_relax() */
+  as_fatal ("md_estimate_size_before_relax");
+  return (1);
+}                              /* md_estimate_size_before_relax() */
 \f
 #ifndef OBJ_ECOFF
 
@@ -2669,19 +3038,22 @@ md_estimate_size_before_relax(fragP, segtype)
    any debugging information, but they do simple checking and someday
    somebody may make them useful.  */
 
-typedef struct loc {
-    struct loc *loc_next;
-    unsigned long loc_fileno;
-    unsigned long loc_lineno;
-    unsigned long loc_offset;
-    unsigned short loc_delta;
-    unsigned short loc_count;
+typedef struct loc
+{
+  struct loc *loc_next;
+  unsigned long loc_fileno;
+  unsigned long loc_lineno;
+  unsigned long loc_offset;
+  unsigned short loc_delta;
+  unsigned short loc_count;
 #if 0
-    fragS       *loc_frag;
+  fragS *loc_frag;
 #endif
-} locS;
+}
+locS;
 
-typedef struct proc {
+typedef struct proc
+  {
     struct proc *proc_next;
     struct symbol *proc_isym;
     struct symbol *proc_end;
@@ -2695,16 +3067,19 @@ typedef struct proc {
     locS *proc_iline;
     struct file *proc_file;
     int proc_index;
-} procS;
+  }
+procS;
 
-typedef struct file {
+typedef struct file
+  {
     struct file *file_next;
     unsigned long file_fileno;
     struct symbol *file_symbol;
     struct symbol *file_end;
     struct proc *file_proc;
     int file_numprocs;
-} fileS;
+  }
+fileS;
 
 static struct obstack proc_frags;
 static procS *proc_lastP;
@@ -2714,7 +3089,7 @@ static int numprocs;
 static void
 md_obj_begin ()
 {
-    obstack_begin(&proc_frags, 0x2000);
+  obstack_begin (&proc_frags, 0x2000);
 }
 
 static void
@@ -2722,7 +3097,7 @@ md_obj_end ()
 {
   /* check for premature end, nesting errors, etc */
   if (proc_lastP && proc_lastP->proc_end == NULL)
-    as_warn("missing `.end' at end of assembly");
+    as_warn ("missing `.end' at end of assembly");
 }
 
 extern char hex_value[];
@@ -2730,43 +3105,52 @@ extern char hex_value[];
 static long
 get_number ()
 {
-    int negative = 0;
-    long val = 0;
+  int negative = 0;
+  long val = 0;
 
-    if (*input_line_pointer == '-') {
-       ++input_line_pointer;
-       negative = 1;
+  if (*input_line_pointer == '-')
+    {
+      ++input_line_pointer;
+      negative = 1;
     }
-    if (!isdigit(*input_line_pointer))
-        as_bad("Expected simple number.");
-    if (input_line_pointer[0] == '0') {
-       if (input_line_pointer[1] == 'x') {
-           input_line_pointer += 2;
-           while (isxdigit(*input_line_pointer)) {
-               val <<= 4;
-               val |= hex_value[(int) *input_line_pointer++];
+  if (!isdigit (*input_line_pointer))
+    as_bad ("Expected simple number.");
+  if (input_line_pointer[0] == '0')
+    {
+      if (input_line_pointer[1] == 'x')
+       {
+         input_line_pointer += 2;
+         while (isxdigit (*input_line_pointer))
+           {
+             val <<= 4;
+             val |= hex_value[(int) *input_line_pointer++];
            }
-           return negative ? -val : val;
-       } else {
-           ++input_line_pointer;
-           while (isdigit(*input_line_pointer)) {
-               val <<= 3;
-               val |= *input_line_pointer++ - '0';
+         return negative ? -val : val;
+       }
+      else
+       {
+         ++input_line_pointer;
+         while (isdigit (*input_line_pointer))
+           {
+             val <<= 3;
+             val |= *input_line_pointer++ - '0';
            }
-           return negative ? -val : val;
+         return negative ? -val : val;
        }
     }
-    if (!isdigit(*input_line_pointer)) {
-       printf(" *input_line_pointer == '%c' 0x%02x\n",
-           *input_line_pointer, *input_line_pointer);
-       as_warn("Invalid number");
-       return -1;
+  if (!isdigit (*input_line_pointer))
+    {
+      printf (" *input_line_pointer == '%c' 0x%02x\n",
+             *input_line_pointer, *input_line_pointer);
+      as_warn ("Invalid number");
+      return -1;
     }
-    while (isdigit(*input_line_pointer)) {
-       val *= 10;
-       val += *input_line_pointer++ - '0';
+  while (isdigit (*input_line_pointer))
+    {
+      val *= 10;
+      val += *input_line_pointer++ - '0';
     }
-    return negative ? -val : val;
+  return negative ? -val : val;
 }
 
 /* The .file directive; just like the usual .file directive, but there
@@ -2776,10 +3160,10 @@ static void
 s_file (x)
      int x;
 {
-    int line;
+  int line;
 
-    line = get_number();
-    s_app_file();
+  line = get_number ();
+  s_app_file ();
 }
 
 
@@ -2789,27 +3173,31 @@ static void
 s_mipsend (x)
      int x;
 {
-    symbolS *p;
-
-    if (!is_end_of_line[(unsigned char) *input_line_pointer]) {
-       p = get_symbol();
-       demand_empty_rest_of_line();
-    } else
-       p = NULL;
-    if (now_seg != text_section)
-       as_warn(".end not in text section");
-    if (!proc_lastP) {
-        as_warn(".end and no .ent seen yet.");
-       return;
+  symbolS *p;
+
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      p = get_symbol ();
+      demand_empty_rest_of_line ();
+    }
+  else
+    p = NULL;
+  if (now_seg != text_section)
+    as_warn (".end not in text section");
+  if (!proc_lastP)
+    {
+      as_warn (".end and no .ent seen yet.");
+      return;
     }
 
-    if (p != NULL) {
-       assert(S_GET_NAME(p));
-       if (strcmp(S_GET_NAME(p), S_GET_NAME(proc_lastP->proc_isym)))
-           as_warn(".end symbol does not match .ent symbol.");
+  if (p != NULL)
+    {
+      assert (S_GET_NAME (p));
+      if (strcmp (S_GET_NAME (p), S_GET_NAME (proc_lastP->proc_isym)))
+       as_warn (".end symbol does not match .ent symbol.");
     }
 
-    proc_lastP->proc_end = (symbolS *) 1;
+  proc_lastP->proc_end = (symbolS *) 1;
 }
 
 /* The .aent and .ent directives.  */
@@ -2818,84 +3206,86 @@ static void
 s_ent (aent)
      int aent;
 {
-    int number = 0;
-    procS *procP;
-    symbolS *symbolP;
-
-    symbolP = get_symbol();
-    if (*input_line_pointer == ',')
-       input_line_pointer++;
-    if (isdigit(*input_line_pointer) || *input_line_pointer == '-')
-       number = get_number();
-    if (now_seg != text_section)
-        as_warn(".ent or .aent not in text section.");
-
-    if (!aent && proc_lastP && proc_lastP->proc_end == NULL)
-       as_warn("missing `.end'");
-
-    if (!aent) {
-       procP = (procS *) obstack_alloc(&proc_frags, sizeof(*procP));
-       procP->proc_isym = symbolP;
-       procP->proc_reg_mask = 0;
-       procP->proc_reg_offset = 0;
-       procP->proc_fpreg_mask = 0;
-       procP->proc_fpreg_offset = 0;
-       procP->proc_frameoffset = 0;
-       procP->proc_framereg = 0;
-       procP->proc_pcreg = 0;
-       procP->proc_end = NULL;
-       procP->proc_next = NULL;
-       if (proc_lastP)
-           proc_lastP->proc_next = procP;
-       else
-           proc_rootP = procP;
-       proc_lastP = procP;
-       numprocs++;
+  int number = 0;
+  procS *procP;
+  symbolS *symbolP;
+
+  symbolP = get_symbol ();
+  if (*input_line_pointer == ',')
+    input_line_pointer++;
+  if (isdigit (*input_line_pointer) || *input_line_pointer == '-')
+    number = get_number ();
+  if (now_seg != text_section)
+    as_warn (".ent or .aent not in text section.");
+
+  if (!aent && proc_lastP && proc_lastP->proc_end == NULL)
+    as_warn ("missing `.end'");
+
+  if (!aent)
+    {
+      procP = (procS *) obstack_alloc (&proc_frags, sizeof (*procP));
+      procP->proc_isym = symbolP;
+      procP->proc_reg_mask = 0;
+      procP->proc_reg_offset = 0;
+      procP->proc_fpreg_mask = 0;
+      procP->proc_fpreg_offset = 0;
+      procP->proc_frameoffset = 0;
+      procP->proc_framereg = 0;
+      procP->proc_pcreg = 0;
+      procP->proc_end = NULL;
+      procP->proc_next = NULL;
+      if (proc_lastP)
+       proc_lastP->proc_next = procP;
+      else
+       proc_rootP = procP;
+      proc_lastP = procP;
+      numprocs++;
     }
-    demand_empty_rest_of_line();
+  demand_empty_rest_of_line ();
 }
 
 /* The .frame directive.  */
 
 static void
 s_frame (x)
-    int x;
+     int x;
 {
 #if 0
-    char str[100];
-    symbolS *symP;
-    int frame_reg;
-    int frame_off;
-    int pcreg;
-
-    frame_reg = tc_get_register();
-    if (*input_line_pointer == ',')
-       input_line_pointer++;
-    frame_off = get_optional_absolute_expression();
-    if (*input_line_pointer == ',')
-       input_line_pointer++;
-    pcreg = tc_get_register();
-
-    /* bob third eye */
-    assert(proc_rootP);
-    proc_rootP->proc_framereg = frame_reg;
-    proc_rootP->proc_frameoffset = frame_off;
-    proc_rootP->proc_pcreg = pcreg;
-    /* bob macho .frame */
-
-    /* We don't have to write out a frame stab for unoptimized code. */
-    if (!(frame_reg == 30 && frame_off == 0)) {
-       if (!proc_lastP)
-           as_warn("No .ent for .frame to use." );
-       (void) sprintf(str, "R%d;%d", frame_reg, frame_off );
-       symP = symbol_new(str, N_VFP, 0, frag_now );
-       S_SET_TYPE(symP, N_RMASK);
-       S_SET_OTHER(symP, 0);
-       S_SET_DESC(symP, 0);
-       symP->sy_forward = proc_lastP->proc_isym;
-       /* bob perhaps I should have used pseudo set */
+  char str[100];
+  symbolS *symP;
+  int frame_reg;
+  int frame_off;
+  int pcreg;
+
+  frame_reg = tc_get_register ();
+  if (*input_line_pointer == ',')
+    input_line_pointer++;
+  frame_off = get_optional_absolute_expression ();
+  if (*input_line_pointer == ',')
+    input_line_pointer++;
+  pcreg = tc_get_register ();
+
+  /* bob third eye */
+  assert (proc_rootP);
+  proc_rootP->proc_framereg = frame_reg;
+  proc_rootP->proc_frameoffset = frame_off;
+  proc_rootP->proc_pcreg = pcreg;
+  /* bob macho .frame */
+
+  /* We don't have to write out a frame stab for unoptimized code. */
+  if (!(frame_reg == 30 && frame_off == 0))
+    {
+      if (!proc_lastP)
+       as_warn ("No .ent for .frame to use.");
+      (void) sprintf (str, "R%d;%d", frame_reg, frame_off);
+      symP = symbol_new (str, N_VFP, 0, frag_now);
+      S_SET_TYPE (symP, N_RMASK);
+      S_SET_OTHER (symP, 0);
+      S_SET_DESC (symP, 0);
+      symP->sy_forward = proc_lastP->proc_isym;
+      /* bob perhaps I should have used pseudo set */
     }
-    demand_empty_rest_of_line();
+  demand_empty_rest_of_line ();
 #endif
 }
 
@@ -2906,48 +3296,54 @@ s_mask (reg_type)
      char reg_type;
 {
 #if 0
-    char str[100], *strP;
-    symbolS *symP;
-    int  i;
-    unsigned int mask;
-    int off;
-
-    mask = get_number();
-    if (*input_line_pointer == ',')
-       input_line_pointer++;
-    off = get_absolute_expression();
-
-    /* bob only for coff */
-    assert(proc_rootP);
-    if (reg_type == 'F' ) {
-       proc_rootP->proc_fpreg_mask = mask;
-       proc_rootP->proc_fpreg_offset = off;
-    } else {
-       proc_rootP->proc_reg_mask = mask;
-       proc_rootP->proc_reg_offset = off;
+  char str[100], *strP;
+  symbolS *symP;
+  int i;
+  unsigned int mask;
+  int off;
+
+  mask = get_number ();
+  if (*input_line_pointer == ',')
+    input_line_pointer++;
+  off = get_absolute_expression ();
+
+  /* bob only for coff */
+  assert (proc_rootP);
+  if (reg_type == 'F')
+    {
+      proc_rootP->proc_fpreg_mask = mask;
+      proc_rootP->proc_fpreg_offset = off;
     }
+  else
+    {
+      proc_rootP->proc_reg_mask = mask;
+      proc_rootP->proc_reg_offset = off;
+    }
+
+  /* bob macho .mask + .fmask */
 
-    /* bob macho .mask + .fmask */
-
-    /* We don't have to write out a mask stab if no saved regs. */
-    if (!(mask == 0)) {
-       if (!proc_lastP)
-           as_warn("No .ent for .mask to use." );
-       strP = str;
-       for (i=0; i<32; i++ ) {
-         if (mask%2) {
-            sprintf(strP, "%c%d,", reg_type, i );
-            strP += strlen(strP);
-         }
+  /* We don't have to write out a mask stab if no saved regs. */
+  if (!(mask == 0))
+    {
+      if (!proc_lastP)
+       as_warn ("No .ent for .mask to use.");
+      strP = str;
+      for (i = 0; i < 32; i++)
+       {
+         if (mask % 2)
+           {
+             sprintf (strP, "%c%d,", reg_type, i);
+             strP += strlen (strP);
+           }
          mask /= 2;
-        }
-       sprintf(strP, ";%d,", off );
-       symP = symbol_new(str, N_RMASK, 0, frag_now);
-       S_SET_TYPE(symP, N_RMASK);
-       S_SET_OTHER(symP, 0);
-       S_SET_DESC(symP, 0);
-       symP->sy_forward = proc_lastP->proc_isym;
-       /* bob perhaps I should have used pseudo set */
+       }
+      sprintf (strP, ";%d,", off);
+      symP = symbol_new (str, N_RMASK, 0, frag_now);
+      S_SET_TYPE (symP, N_RMASK);
+      S_SET_OTHER (symP, 0);
+      S_SET_DESC (symP, 0);
+      symP->sy_forward = proc_lastP->proc_isym;
+      /* bob perhaps I should have used pseudo set */
     }
 #endif
 }
@@ -2959,22 +3355,21 @@ s_loc (x)
      int x;
 {
 #if 0
-    symbolS * symbolP;
-    int lineno;
-    int addroff;
+  symbolS *symbolP;
+  int lineno;
+  int addroff;
 
-    assert(now_seg == text_section);
+  assert (now_seg == text_section);
 
-    lineno  = get_number();
-    addroff = obstack_next_free(&frags) - frag_now->fr_literal;
+  lineno = get_number ();
+  addroff = obstack_next_free (&frags) - frag_now->fr_literal;
 
-    symbolP = symbol_new ("", N_SLINE, addroff, frag_now);
-    S_SET_TYPE(symbolP, N_SLINE);
-    S_SET_OTHER(symbolP, 0);
-    S_SET_DESC(symbolP, lineno);
-    symbolP->sy_segment = now_seg;
+  symbolP = symbol_new ("", N_SLINE, addroff, frag_now);
+  S_SET_TYPE (symbolP, N_SLINE);
+  S_SET_OTHER (symbolP, 0);
+  S_SET_DESC (symbolP, lineno);
+  symbolP->sy_segment = now_seg;
 #endif
 }
 
 #endif /* ! defined (OBJ_ECOFF) */
-
diff --git a/gas/config/tc-mips.h b/gas/config/tc-mips.h
new file mode 100644 (file)
index 0000000..b0fb9f7
--- /dev/null
@@ -0,0 +1,94 @@
+/* tc-mips.c -- header file for tc-mips.c.
+   Copyright (C) 1993 Free Software Foundation, Inc.
+   Contributed by the OSF and Ralph Campbell.
+   Written by Keith Knowles and Ralph Campbell, working independently.
+   Modified for ECOFF support by Ian Lance Taylor of Cygnus Support.
+
+   This file is part of GAS.
+
+   GAS is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GAS is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GAS; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define TC_MIPS
+
+#define TARGET_ARCH bfd_arch_mips
+
+#define NO_LISTING
+#define ONLY_STANDARD_ESCAPES
+#define BACKSLASH_V
+#define WORKING_DOT_WORD       1
+#define OLD_FLOAT_READS
+#define LOCAL_LABELS_FB
+
+#ifdef OBJ_ECOFF
+#define LOCAL_LABEL(name) ((name)[0] == '$' && (name)[1] == 'L')
+#endif
+
+#define md_undefined_symbol(name)      (0)
+#define md_operand(x)
+
+#define LITTLE_ENDIAN   1234
+#define BIG_ENDIAN      4321
+
+/* If neither TARGET_BYTES_BIG_ENDIAN nor TARGET_BYTES_LITTLE_ENDIAN
+   is specified, default to big endian.  */
+#ifndef TARGET_BYTES_BIG_ENDIAN
+#ifndef TARGET_BYTES_LITTLE_ENDIAN
+#define TARGET_BYTES_BIG_ENDIAN
+#endif
+#endif
+
+#ifdef TARGET_BYTES_BIG_ENDIAN
+#define BYTE_ORDER     BIG_ENDIAN
+#else
+#define BYTE_ORDER      LITTLE_ENDIAN
+#endif
+
+#ifndef TARGET_FORMAT 
+#ifdef OBJ_AOUT
+#ifdef TARGET_BYTES_BIG_ENDIAN
+#define TARGET_FORMAT "aout-mips-big"
+#else
+#define TARGET_FORMAT "aout-mips-little"
+#endif
+#endif /* OBJ_AOUT */
+#ifdef OBJ_ECOFF
+#ifdef TARGET_BYTES_BIG_ENDIAN
+#define TARGET_FORMAT "ecoff-bigmips"
+#else
+#define TARGET_FORMAT "ecoff-littlemips"
+#endif
+#endif /* OBJ_ECOFF */
+#endif /* ! defined (TARGET_FORMAT) */
+
+struct mips_opcode {
+    const char *name;
+    const char *args;
+    unsigned long match;
+    unsigned long mask;  /* used only for error checking */
+    unsigned long pinfo; /* Information used for insn/pipeline scheduling. */
+};
+
+struct mips_cl_insn {
+    unsigned long              insn_opcode;
+    const struct mips_opcode   *insn_mo;
+};
+
+#ifndef BFD_ASSEMBLER
+#define md_convert_frag(h,f)           {as_fatal ("MIPS convert_frag\n");}
+#else
+#define md_convert_frag(b,s,f)         {as_fatal ("MIPS convert_frag\n");}
+#endif
+
+extern int tc_get_register PARAMS ((void));