* config/tc-sparc.c (U0x80000000, U0xffffffff): New constants.
[binutils-gdb.git] / gas / config / tc-mips.c
index 87b665ffbd1c16d6cca13fd55e96c09208310770..d64d4eb3e562b2e5016240c5557ade497f8741af 100644 (file)
@@ -113,6 +113,20 @@ extern int target_big_endian;
                            ? ".rodata" \
                            : (abort (), ""))
 
+/* The ABI to use.  */
+enum mips_abi_level
+{
+  NO_ABI = 0,
+  O32_ABI,
+  O64_ABI,
+  N32_ABI,
+  N64_ABI,
+  EABI_ABI
+};
+
+/* MIPS ABI we are using for this output file.  */
+static enum mips_abi_level file_mips_abi = NO_ABI;
+
 /* This is the set of options which may be modified by the .set
    pseudo-op.  We use a struct so that .set push and .set pop are more
    reliable.  */
@@ -149,15 +163,29 @@ struct mips_set_options
   /* Non-zero if we should not autoextend mips16 instructions.
      Changed by `.set autoextend' and `.set noautoextend'.  */
   int noautoextend;
+  /* Restrict general purpose registers and floating point registers
+     to 32 bit.  This is initially determined when -mgp32 or -mfp32
+     is passed but can changed if the assembler code uses .set mipsN.  */
+  int gp32;
+  int fp32;
+  /* The ABI currently in use. This is changed by .set mipsN to loosen
+     restrictions and doesn't affect the whole file.  */
+  enum mips_abi_level abi;
 };
 
+/* True if -mgp32 was passed.  */
+static int file_mips_gp32 = -1;
+
+/* True if -mfp32 was passed.  */
+static int file_mips_fp32 = -1;
+
 /* This is the struct we use to hold the current set of options.  Note
    that we must set the isa field to ISA_UNKNOWN and the mips16 field to
    -1 to indicate that they have not been initialized.  */
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, 0, 0, 0, 0, 0, 0
+  ISA_UNKNOWN, -1, 0, 0, 0, 0, 0, 0, 0, 0, NO_ABI
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -179,19 +207,6 @@ static int mips_arch = CPU_UNKNOWN;
    are optimizing.  */
 static int mips_tune = CPU_UNKNOWN;
 
-/* The ABI to use.  */
-enum mips_abi_level
-{
-  NO_ABI = 0,
-  O32_ABI,
-  O64_ABI,
-  N32_ABI,
-  N64_ABI,
-  EABI_ABI
-};
-
-static enum mips_abi_level mips_abi = NO_ABI;
-
 /* Whether we should mark the file EABI64 or EABI32.  */
 static int mips_eabi64 = 0;
 
@@ -199,12 +214,6 @@ static int mips_eabi64 = 0;
    mips3 or greater, then mark the object file 32BITMODE.  */
 static int mips_32bitmode = 0;
 
-/* True if -mgp32 was passed.  */
-static int mips_gp32 = 0;
-
-/* True if -mfp32 was passed.  */
-static int mips_fp32 = 0;
-
 /* Some ISA's have delay slots for instructions which read or write
    from a coprocessor (eg. mips1-mips3); some don't (eg mips4).
    Return true if instructions marked INSN_LOAD_COPROC_DELAY,
@@ -228,21 +237,21 @@ static int mips_fp32 = 0;
    )
 
 #define HAVE_32BIT_GPRS                                   \
-    (mips_gp32                                     \
-     || mips_abi == O32_ABI                        \
+    (mips_opts.gp32                                \
+     || mips_opts.abi == O32_ABI                   \
      || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
 
 #define HAVE_32BIT_FPRS                            \
-    (mips_fp32                                     \
-     || mips_abi == O32_ABI                        \
+    (mips_opts.fp32                                \
+     || mips_opts.abi == O32_ABI                   \
      || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
 
 #define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS)
 #define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS)
 
-#define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
+#define HAVE_NEWABI (mips_opts.abi == N32_ABI || mips_opts.abi == N64_ABI)
 
-#define HAVE_64BIT_OBJECTS (mips_abi == N64_ABI)
+#define HAVE_64BIT_OBJECTS (mips_opts.abi == N64_ABI)
 
 /* We can only have 64bit addresses if the object file format
    supports it.  */
@@ -398,15 +407,23 @@ static offsetT mips_cprestore_offset = -1;
 
 /* Similiar for NewABI PIC code, where $gp is callee-saved.  NewABI has some
    more optimizations, it can use a register value instead of a memory-saved
-   offset and even an other than GP as global pointer.  */
+   offset and even an other register than $gp as global pointer.  */
 static offsetT mips_cpreturn_offset = -1;
 static int mips_cpreturn_register = -1;
 static int mips_gp_register = GP;
 
+/* Whether mips_cprestore_offset has been set in the current function
+   (or whether it has already been warned about, if not).  */
+static int mips_cprestore_valid = 0;
+
 /* This is the register which holds the stack frame, as set by the
    .frame pseudo-op.  This is needed to implement .cprestore.  */
 static int mips_frame_reg = SP;
 
+/* Whether mips_frame_reg has been set in the current function
+   (or whether it has already been warned about, if not).  */
+static int mips_frame_reg_valid = 0;
+
 /* To output NOP instructions correctly, we need to keep information
    about the previous two instructions.  */
 
@@ -685,10 +702,13 @@ static void mips16_ip PARAMS ((char *str, struct mips_cl_insn * ip));
 static void mips16_immed PARAMS ((char *, unsigned int, int, offsetT, boolean,
                                  boolean, boolean, unsigned long *,
                                  boolean *, unsigned short *));
+static int my_getPercentOp PARAMS ((char **, unsigned int *, int *));
 static int my_getSmallParser PARAMS ((char **, unsigned int *, int *));
 static int my_getSmallExpression PARAMS ((expressionS *, char *));
 static void my_getExpression PARAMS ((expressionS *, char *));
+#ifdef OBJ_ELF
 static int support_64bit_objects PARAMS((void));
+#endif
 static symbolS *get_symbol PARAMS ((void));
 static void mips_align PARAMS ((int to, int fill, symbolS *label));
 static void s_align PARAMS ((int));
@@ -723,6 +743,9 @@ static const char *mips_isa_to_str PARAMS ((int));
 static const char *mips_cpu_to_str PARAMS ((int));
 static int validate_mips_insn PARAMS ((const struct mips_opcode *));
 static void show PARAMS ((FILE *, char *, int *, int *));
+#ifdef OBJ_ELF
+static int mips_need_elf_addend_fixup PARAMS ((fixS *));
+#endif
 
 /* Return values of my_getSmallExpression().  */
 
@@ -1042,6 +1065,71 @@ md_begin ()
                  "Use -march instead of -mcpu."));
     }
 
+#if 1
+  /* For backward compatibility, let -mipsN set various defaults.  */
+  /* This code should go away, to be replaced with something rather more
+     draconian.  Until GCC 3.1 has been released for some reasonable
+     amount of time, however, we need to support this.  */
+  if (mips_opts.isa != ISA_UNKNOWN)
+    {
+      /* Translate -mipsN to the appropriate settings of file_mips_gp32
+        and file_mips_fp32.  Tag binaries as using the mipsN ISA.  */
+      if (file_mips_gp32 < 0)
+       {
+         if (ISA_HAS_64BIT_REGS (mips_opts.isa))
+           file_mips_gp32 = 0;
+         else
+           file_mips_gp32 = 1;
+       }
+      if (file_mips_fp32 < 0)
+       {
+         if (ISA_HAS_64BIT_REGS (mips_opts.isa))
+           file_mips_fp32 = 0;
+         else
+           file_mips_fp32 = 1;
+       }
+
+      ci = mips_cpu_info_from_isa (mips_opts.isa);
+      assert (ci != NULL);
+      /* -mipsN has higher priority than -mcpu but lower than -march.  */
+      if (mips_arch == CPU_UNKNOWN)
+       mips_arch = ci->cpu;
+
+      /* Default mips_abi.  */
+      if (mips_opts.abi == NO_ABI)
+       {
+         if (mips_opts.isa == ISA_MIPS1 || mips_opts.isa == ISA_MIPS2)
+           mips_opts.abi = O32_ABI;
+         else if (mips_opts.isa == ISA_MIPS3 || mips_opts.isa == ISA_MIPS4)
+           mips_opts.abi = O64_ABI;
+       }
+    }
+
+  if (mips_arch == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
+    {
+      ci = mips_cpu_info_from_cpu (mips_cpu);
+      assert (ci != NULL);
+      mips_arch = ci->cpu;
+      as_warn (_("The -mcpu option is deprecated.  Please use -march and "
+                "-mtune instead."));
+    }
+
+  /* Set tune from -mcpu, not from -mipsN.  */
+  if (mips_tune == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
+    {
+      ci = mips_cpu_info_from_cpu (mips_cpu);
+      assert (ci != NULL);
+      mips_tune = ci->cpu;
+    }
+
+  /* At this point, mips_arch will either be CPU_UNKNOWN if no ARCH was
+     specified on the command line, or some other value if one was.
+     Similarly, mips_opts.isa will be ISA_UNKNOWN if not specified on
+     the command line, or will be set otherwise if one was.  */
+
+  if (mips_arch != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
+    /* Handled above.  */;
+#else
   if (mips_arch == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
     {
       ci = mips_cpu_info_from_cpu (mips_cpu);
@@ -1055,6 +1143,7 @@ md_begin ()
      specified on the command line, or some other value if one was.
      Similarly, mips_opts.isa will be ISA_UNKNOWN if not specified on
      the command line, or will be set otherwise if one was.  */
+
   if (mips_arch != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
     {
       /* We have to check if the isa is the default isa of arch.  Otherwise
@@ -1075,6 +1164,7 @@ md_begin ()
          mips_arch = ci->cpu;
        }
     }
+#endif
   else if (mips_arch != CPU_UNKNOWN && mips_opts.isa == ISA_UNKNOWN)
     {
       /* We have ARCH, we need ISA.  */
@@ -1123,7 +1213,7 @@ md_begin ()
      to change the ISA with directives.  This isn't really
      the best, but then neither is basing the abi on the isa.  */
   if (ISA_HAS_64BIT_REGS (mips_opts.isa)
-      && mips_abi == EABI_ABI)
+      && mips_opts.abi == EABI_ABI)
     mips_eabi64 = 1;
 
   /* If they asked for mips1 or mips2 and a cpu that is
@@ -1136,7 +1226,15 @@ md_begin ()
   if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_arch))
     as_warn (_("Could not set architecture and machine"));
 
+  if (file_mips_gp32 < 0)
+    file_mips_gp32 = 0;
+  if (file_mips_fp32 < 0)
+    file_mips_fp32 = 0;
+
   file_mips_isa = mips_opts.isa;
+  file_mips_abi = mips_opts.abi;
+  mips_opts.gp32 = file_mips_gp32;
+  mips_opts.fp32 = file_mips_fp32;
 
   op_hash = hash_new ();
 
@@ -1375,12 +1473,11 @@ md_assemble (str)
   else
     {
       if (imm_expr.X_op != O_absent)
-       append_insn ((char *) NULL, &insn, &imm_expr, imm_reloc,
-                    imm_unmatched_hi);
+       append_insn (NULL, &insn, &imm_expr, imm_reloc, imm_unmatched_hi);
       else if (offset_expr.X_op != O_absent)
-       append_insn ((char *) NULL, &insn, &offset_expr, offset_reloc, false);
+       append_insn (NULL, &insn, &offset_expr, offset_reloc, false);
       else
-       append_insn ((char *) NULL, &insn, NULL, unused_reloc, false);
+       append_insn (NULL, &insn, NULL, unused_reloc, false);
     }
 }
 
@@ -1894,8 +1991,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                                          & INSN_UNCOND_BRANCH_DELAY),
                                         (*prev_insn_reloc_type
                                          == BFD_RELOC_MIPS16_JMP)),
-                   make_expr_symbol (address_expr), (offsetT) 0,
-                   (char *) NULL);
+                   make_expr_symbol (address_expr), 0, NULL);
     }
   else if (place != NULL)
     f = place;
@@ -1959,6 +2055,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              if ((address_expr->X_add_number & 3) != 0)
                as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
+             if (address_expr->X_add_number & ~0xfffffff
+                 || address_expr->X_add_number > 0x7fffffc)
+               as_bad (_("jump address range overflow (0x%lx)"),
+                       (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
              break;
 
@@ -1966,6 +2066,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              if ((address_expr->X_add_number & 3) != 0)
                as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
+             if (address_expr->X_add_number & ~0xfffffff
+                 || address_expr->X_add_number > 0x7fffffc)
+               as_bad (_("jump address range overflow (0x%lx)"),
+                       (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |=
                (((address_expr->X_add_number & 0x7c0000) << 3)
                 | ((address_expr->X_add_number & 0xf800000) >> 7)
@@ -2871,7 +2975,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
        case 'j':
        case 'o':
          *r = (bfd_reloc_code_real_type) va_arg (args, int);
-         assert (*r == BFD_RELOC_MIPS_GPREL
+         assert (*r == BFD_RELOC_GPREL16
                  || *r == BFD_RELOC_MIPS_LITERAL
                  || *r == BFD_RELOC_MIPS_HIGHER
                  || *r == BFD_RELOC_HI16_S
@@ -3044,9 +3148,9 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
              *r = BFD_RELOC_UNUSED + c;
            else
              {
-               mips16_immed ((char *) NULL, 0, c, ep->X_add_number, false,
-                             false, false, &insn.insn_opcode,
-                             &insn.use_extend, &insn.extend);
+               mips16_immed (NULL, 0, c, ep->X_add_number, false, false,
+                             false, &insn.insn_opcode, &insn.use_extend,
+                             &insn.extend);
                ep = NULL;
                *r = BFD_RELOC_UNUSED;
              }
@@ -3154,7 +3258,7 @@ set_at (counter, reg, unsignedp)
   else
     {
       load_register (counter, AT, &imm_expr, 0);
-      macro_build ((char *) NULL, counter, NULL,
+      macro_build ((char *) NULL, counter, (expressionS *) NULL,
                   unsignedp ? "sltu" : "slt",
                   "d,v,t", AT, reg, AT);
     }
@@ -3249,6 +3353,11 @@ check_absolute_expr (ip, ex)
            ? 1                          \
            : 0)
 
+/* Is the given value a sign-extended 32-bit value?  */
+#define IS_SEXT_32BIT_NUM(x)                                           \
+  (((x) &~ (offsetT) 0x7fffffff) == 0                                  \
+   || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff))
+
 /*                     load_register()
  *  This routine generates the least number of instructions neccessary to load
  *  an absolute expression value into a register.
@@ -3288,9 +3397,7 @@ load_register (counter, reg, ep, dbl)
                       (int) BFD_RELOC_LO16);
          return;
        }
-      else if ((((ep->X_add_number &~ (offsetT) 0x7fffffff) == 0
-                || ((ep->X_add_number &~ (offsetT) 0x7fffffff)
-                    == ~ (offsetT) 0x7fffffff))
+      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)
                && (! dbl
                    || ! ep->X_unsigned
                    || sizeof (ep->X_add_number) > 4
@@ -3316,7 +3423,8 @@ load_register (counter, reg, ep, dbl)
 
   if (HAVE_32BIT_GPRS)
     {
-      as_bad (_("Number larger than 32 bits"));
+      as_bad (_("Number (0x%lx) larger than 32 bits"),
+             (unsigned long) ep->X_add_number);
       macro_build ((char *) NULL, counter, ep, "addiu", "t,r,j", reg, 0,
                   (int) BFD_RELOC_LO16);
       return;
@@ -3351,7 +3459,7 @@ load_register (counter, reg, ep, dbl)
       int shift, bit;
       unsigned long hi, lo;
 
-      if (hi32.X_add_number == 0xffffffff)
+      if (hi32.X_add_number == (offsetT) 0xffffffff)
        {
          if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
            {
@@ -3402,7 +3510,7 @@ load_register (counter, reg, ep, dbl)
              macro_build ((char *) NULL, counter, &tmp,
                           "ori", "t,r,i", reg, 0,
                           (int) BFD_RELOC_LO16);
-             macro_build ((char *) NULL, counter, NULL,
+             macro_build ((char *) NULL, counter, (expressionS *) NULL,
                           (shift >= 32) ? "dsll32" : "dsll",
                           "d,w,<", reg, reg,
                           (shift >= 32) ? shift - 32 : shift);
@@ -3457,12 +3565,12 @@ load_register (counter, reg, ep, dbl)
              if (bit != 0)
                {
                  bit += shift;
-                 macro_build ((char *) NULL, counter, NULL,
+                 macro_build ((char *) NULL, counter, (expressionS *) NULL,
                               (bit >= 32) ? "dsll32" : "dsll",
                               "d,w,<", reg, reg,
                               (bit >= 32) ? bit - 32 : bit);
                }
-             macro_build ((char *) NULL, counter, NULL,
+             macro_build ((char *) NULL, counter, (expressionS *) NULL,
                           (shift >= 32) ? "dsrl32" : "dsrl",
                           "d,w,<", reg, reg,
                           (shift >= 32) ? shift - 32 : shift);
@@ -3481,8 +3589,8 @@ load_register (counter, reg, ep, dbl)
     {
       if (freg != 0)
        {
-         macro_build ((char *) NULL, counter, NULL, "dsll32", "d,w,<", reg,
-                      freg, 0);
+         macro_build ((char *) NULL, counter, (expressionS *) NULL,
+                      "dsll32", "d,w,<", reg, freg, 0);
          freg = reg;
        }
     }
@@ -3490,27 +3598,27 @@ load_register (counter, reg, ep, dbl)
     {
       expressionS mid16;
 
-      if ((freg == 0) && (lo32.X_add_number == 0xffffffff))
+      if ((freg == 0) && (lo32.X_add_number == (offsetT) 0xffffffff))
        {
          macro_build ((char *) NULL, counter, &lo32, "lui", "t,u", reg,
                       (int) BFD_RELOC_HI16);
-         macro_build ((char *) NULL, counter, NULL, "dsrl32", "d,w,<", reg,
-                      reg, 0);
+         macro_build ((char *) NULL, counter, (expressionS *) NULL,
+                      "dsrl32", "d,w,<", reg, reg, 0);
          return;
        }
 
       if (freg != 0)
        {
-         macro_build ((char *) NULL, counter, NULL, "dsll", "d,w,<", reg,
-                      freg, 16);
+         macro_build ((char *) NULL, counter, (expressionS *) NULL, "dsll",
+                      "d,w,<", reg, freg, 16);
          freg = reg;
        }
       mid16 = lo32;
       mid16.X_add_number >>= 16;
       macro_build ((char *) NULL, counter, &mid16, "ori", "t,r,i", reg,
                   freg, (int) BFD_RELOC_LO16);
-      macro_build ((char *) NULL, counter, NULL, "dsll", "d,w,<", reg,
-                  reg, 16);
+      macro_build ((char *) NULL, counter, (expressionS *) NULL, "dsll",
+                  "d,w,<", reg, reg, 16);
       freg = reg;
     }
   if ((lo32.X_add_number & 0xffff) != 0)
@@ -3546,7 +3654,7 @@ load_address (counter, reg, ep, dbl, used_at)
   if (mips_pic == NO_PIC)
     {
       /* If this is a reference to a GP relative symbol, we want
-          addiu        $reg,$gp,<sym>          (BFD_RELOC_MIPS_GPREL)
+          addiu        $reg,$gp,<sym>          (BFD_RELOC_GPREL16)
         Otherwise we want
           lui          $reg,<sym>              (BFD_RELOC_HI16_S)
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
@@ -3569,7 +3677,7 @@ load_address (counter, reg, ep, dbl, used_at)
           dsll         $reg,16
           daddiu       $reg,<sym>              (BFD_RELOC_LO16)
        */
-      if (HAVE_64BIT_ADDRESSES)
+      if (dbl)
        {
          p = NULL;
 
@@ -3586,10 +3694,10 @@ load_address (counter, reg, ep, dbl, used_at)
                           reg, reg, (int) BFD_RELOC_MIPS_HIGHER);
              macro_build (p, counter, ep, "daddiu", "t,r,j",
                           AT, AT, (int) BFD_RELOC_LO16);
-             macro_build (p, counter, NULL, "dsll32", "d,w,<",
-                          reg, reg, 0);
-             macro_build (p, counter, NULL, "dadd", "d,v,t",
-                          reg, reg, AT);
+             macro_build (p, counter, (expressionS *) NULL, "dsll32",
+                          "d,w,<", reg, reg, 0);
+             macro_build (p, counter, (expressionS *) NULL, "dadd",
+                          "d,v,t", reg, reg, AT);
              *used_at = 1;
            }
          else
@@ -3598,12 +3706,12 @@ load_address (counter, reg, ep, dbl, used_at)
                           reg, (int) BFD_RELOC_MIPS_HIGHEST);
              macro_build (p, counter, ep, "daddiu", "t,r,j",
                           reg, reg, (int) BFD_RELOC_MIPS_HIGHER);
-             macro_build (p, counter, NULL, "dsll", "d,w,<",
-                          reg, reg, 16);
+             macro_build (p, counter, (expressionS *) NULL, "dsll",
+                          "d,w,<", reg, reg, 16);
              macro_build (p, counter, ep, "daddiu", "t,r,j",
                           reg, reg, (int) BFD_RELOC_HI16_S);
-             macro_build (p, counter, NULL, "dsll", "d,w,<",
-                          reg, reg, 16);
+             macro_build (p, counter, (expressionS *) NULL, "dsll",
+                          "d,w,<", reg, reg, 16);
              macro_build (p, counter, ep, "daddiu", "t,r,j",
                           reg, reg, (int) BFD_RELOC_LO16);
            }
@@ -3616,18 +3724,17 @@ load_address (counter, reg, ep, dbl, used_at)
            {
              frag_grow (20);
              macro_build ((char *) NULL, counter, ep,
-                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                          "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
+                          dbl ? "daddiu" : "addiu", "t,r,j", reg, GP,
+                          (int) BFD_RELOC_GPREL16);
              p = frag_var (rs_machine_dependent, 8, 0,
                            RELAX_ENCODE (4, 8, 0, 4, 0,
                                          mips_opts.warn_about_macros),
-                           ep->X_add_symbol, (offsetT) 0, (char *) NULL);
+                           ep->X_add_symbol, 0, NULL);
            }
          macro_build_lui (p, counter, ep, reg);
          if (p != NULL)
            p += 4;
-         macro_build (p, counter, ep,
-                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+         macro_build (p, counter, ep, dbl ? "daddiu" : "addiu",
                       "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
     }
@@ -3690,15 +3797,13 @@ load_address (counter, reg, ep, dbl, used_at)
       macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg,
                   (int) BFD_RELOC_MIPS_GOT_HI16);
       macro_build ((char *) NULL, counter, (expressionS *) NULL,
-                  HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                  "d,v,t", reg, reg, GP);
-      macro_build ((char *) NULL, counter, ep,
-                  HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                  dbl ? "daddu" : "addu", "d,v,t", reg, reg, GP);
+      macro_build ((char *) NULL, counter, ep, dbl ? "ld" : "lw",
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT_LO16, reg);
       p = frag_var (rs_machine_dependent, 12 + off, 0,
                    RELAX_ENCODE (12, 12 + off, off, 8 + off, 0,
                                  mips_opts.warn_about_macros),
-                   ep->X_add_symbol, (offsetT) 0, (char *) NULL);
+                   ep->X_add_symbol, 0, NULL);
       if (off > 0)
        {
          /* We need a nop before loading from $gp.  This special
@@ -3708,31 +3813,29 @@ load_address (counter, reg, ep, dbl, used_at)
          macro_build (p, counter, (expressionS *) NULL, "nop", "");
          p += 4;
        }
-      macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+      macro_build (p, counter, ep, dbl ? "ld" : "lw",
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, GP);
       p += 4;
       macro_build (p, counter, (expressionS *) NULL, "nop", "");
       p += 4;
-      macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+      macro_build (p, counter, ep, dbl ? "daddiu" : "addiu",
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
       if (ex.X_add_number != 0)
        {
          if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          ex.X_op = O_constant;
-         macro_build ((char *) NULL, counter, &ex,
-                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+         macro_build ((char *) NULL, counter, &ex, dbl ? "daddiu" : "addiu",
                       "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
     }
   else if (mips_pic == EMBEDDED_PIC)
     {
       /* We always do
-          addiu        $reg,$gp,<sym>          (BFD_RELOC_MIPS_GPREL)
+          addiu        $reg,$gp,<sym>          (BFD_RELOC_GPREL16)
         */
-      macro_build ((char *) NULL, counter, ep,
-                  HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                  "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
+      macro_build ((char *) NULL, counter, ep, dbl ? "daddiu" : "addiu",
+                  "t,r,j", reg, GP, (int) BFD_RELOC_GPREL16);
     }
   else
     abort ();
@@ -3822,10 +3925,11 @@ macro (ip)
       expr1.X_add_number = 8;
       macro_build ((char *) NULL, &icnt, &expr1, "bgez", "s,p", sreg);
       if (dreg == sreg)
-       macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "",
+                    0);
       else
        move_register (&icnt, dreg, sreg);
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
 
       --mips_opts.noreorder;
@@ -3858,7 +3962,8 @@ macro (ip)
          return;
        }
       load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build ((char *) NULL, &icnt, NULL, s2, "d,v,t", treg, sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s2, "d,v,t",
+                  treg, sreg, AT);
       break;
 
     case M_AND_I:
@@ -3888,14 +3993,15 @@ macro (ip)
            {
              macro_build ((char *) NULL, &icnt, &imm_expr, "ori", "t,r,i",
                           treg, sreg, (int) BFD_RELOC_LO16);
-             macro_build ((char *) NULL, &icnt, NULL, "nor", "d,v,t",
-                          treg, treg, 0);
+             macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nor",
+                          "d,v,t", treg, treg, 0);
            }
          return;
        }
 
       load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build ((char *) NULL, &icnt, NULL, s2, "d,v,t", treg, sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s2, "d,v,t",
+                  treg, sreg, AT);
       break;
 
     case M_BEQ_I:
@@ -3928,18 +4034,17 @@ macro (ip)
       if (treg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bgezl" : "bgez",
-                      "s,p", sreg);
+                      likely ? "bgezl" : "bgez", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "blezl" : "blez",
-                      "s,p", treg);
+                      likely ? "blezl" : "blez", "s,p", treg);
          return;
        }
-      macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "slt", "d,v,t",
+                  AT, sreg, treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
@@ -3967,7 +4072,8 @@ macro (ip)
              if (warn_nops)
                as_warn (_("Branch %s is always false (nop)"),
                         ip->insn_mo->name);
-             macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
+             macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop",
+                          "", 0);
            }
          else
            {
@@ -4034,8 +4140,8 @@ macro (ip)
                       likely ? "beql" : "beq", "s,t,p", 0, treg);
          return;
        }
-      macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, sreg,
-                  treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                  "d,v,t", AT, sreg, treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
@@ -4046,7 +4152,7 @@ macro (ip)
       if (sreg == 0
          || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
-             && imm_expr.X_add_number == 0xffffffff))
+             && imm_expr.X_add_number == (offsetT) 0xffffffff))
        goto do_false;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
@@ -4084,7 +4190,8 @@ macro (ip)
                       likely ? "bltzl" : "bltz", "s,p", treg);
          return;
        }
-      macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "slt", "d,v,t",
+                  AT, treg, sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
@@ -4100,8 +4207,8 @@ macro (ip)
        }
       if (sreg == 0)
        goto do_false;
-      macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, treg,
-                  sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                  "d,v,t", AT, treg, sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
@@ -4121,7 +4228,8 @@ macro (ip)
                       likely ? "bgezl" : "bgez", "s,p", treg);
          return;
        }
-      macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "slt", "d,v,t",
+                  AT, treg, sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
@@ -4177,8 +4285,8 @@ macro (ip)
        }
       if (sreg == 0)
        goto do_true;
-      macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, treg,
-                  sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                  "d,v,t", AT, treg, sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
@@ -4189,7 +4297,7 @@ macro (ip)
       if (sreg == 0
          || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
-             && imm_expr.X_add_number == 0xffffffff))
+             && imm_expr.X_add_number == (offsetT) 0xffffffff))
        goto do_true;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
@@ -4228,7 +4336,8 @@ macro (ip)
                       likely ? "bgtzl" : "bgtz", "s,p", treg);
          return;
        }
-      macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "slt", "d,v,t",
+                  AT, sreg, treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
@@ -4244,7 +4353,8 @@ macro (ip)
                       likely ? "bnel" : "bne", "s,t,p", 0, treg);
          return;
        }
-      macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, sreg,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                  "d,v,t", AT, sreg,
                   treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
                   likely ? "bnel" : "bne", "s,t,p", AT, 0);
@@ -4264,9 +4374,11 @@ macro (ip)
        {
          as_warn (_("Divide by zero."));
          if (mips_trap)
-           macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
+                        "s,t", 0, 0);
          else
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                        "c", 7);
          return;
        }
 
@@ -4275,17 +4387,19 @@ macro (ip)
       mips_any_noreorder = 1;
       if (mips_trap)
        {
-         macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", treg, 0);
-         macro_build ((char *) NULL, &icnt, NULL,
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
+                      "s,t", treg, 0);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
        }
       else
        {
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "bne", "s,t,p", treg, 0);
-         macro_build ((char *) NULL, &icnt, NULL,
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                      "c", 7);
        }
       expr1.X_add_number = -1;
       macro_build ((char *) NULL, &icnt, &expr1,
@@ -4298,8 +4412,8 @@ macro (ip)
          expr1.X_add_number = 1;
          macro_build ((char *) NULL, &icnt, &expr1, "daddiu", "t,r,j", AT, 0,
                       (int) BFD_RELOC_LO16);
-         macro_build ((char *) NULL, &icnt, NULL, "dsll32", "d,w,<", AT, AT,
-                      31);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsll32",
+                      "d,w,<", AT, AT, 31);
        }
       else
        {
@@ -4309,7 +4423,8 @@ macro (ip)
        }
       if (mips_trap)
        {
-         macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", sreg, AT);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
+                      "s,t", sreg, AT);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
@@ -4318,15 +4433,17 @@ macro (ip)
        {
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "bne", "s,t,p", sreg, AT);
-         macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "",
+                      0);
 
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
 
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                      "c", 6);
        }
-      macro_build ((char *) NULL, &icnt, NULL, s, "d", dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d", dreg);
       break;
 
     case M_DIV_3I:
@@ -4369,9 +4486,11 @@ macro (ip)
        {
          as_warn (_("Divide by zero."));
          if (mips_trap)
-           macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
+                        "s,t", 0, 0);
          else
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                        "c", 7);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
@@ -4388,8 +4507,8 @@ macro (ip)
        {
          if (strcmp (s2, "mflo") == 0)
            {
-             macro_build ((char *) NULL, &icnt, NULL, dbl ? "dneg" : "neg",
-                          "d,w", dreg, sreg);
+             macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                          dbl ? "dneg" : "neg", "d,w", dreg, sreg);
            }
          else
            move_register (&icnt, dreg, 0);
@@ -4397,8 +4516,9 @@ macro (ip)
        }
 
       load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build ((char *) NULL, &icnt, NULL, s, "z,s,t", sreg, AT);
-      macro_build ((char *) NULL, &icnt, NULL, s2, "d", dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "z,s,t",
+                  sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s2, "d", dreg);
       break;
 
     case M_DIVU_3:
@@ -4422,8 +4542,10 @@ macro (ip)
       mips_any_noreorder = 1;
       if (mips_trap)
        {
-         macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", treg, 0);
-         macro_build ((char *) NULL, &icnt, NULL, s, "z,s,t", sreg, treg);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
+                      "s,t", treg, 0);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "z,s,t",
+                      sreg, treg);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
@@ -4432,14 +4554,16 @@ macro (ip)
        {
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "bne", "s,t,p", treg, 0);
-         macro_build ((char *) NULL, &icnt, NULL, s, "z,s,t", sreg, treg);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "z,s,t",
+                      sreg, treg);
 
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                      "c", 7);
        }
-      macro_build ((char *) NULL, &icnt, NULL, s2, "d", dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s2, "d", dreg);
       return;
 
     case M_DLA_AB:
@@ -4515,7 +4639,7 @@ macro (ip)
       else if (mips_pic == NO_PIC)
        {
          /* If this is a reference to a GP relative symbol, we want
-              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
+              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_GPREL16)
             Otherwise we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
@@ -4555,9 +4679,9 @@ macro (ip)
                             tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
                macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
                             AT, AT, (int) BFD_RELOC_LO16);
-               macro_build (p, &icnt, NULL, "dsll32", "d,w,<",
-                            tempreg, tempreg, 0);
-               macro_build (p, &icnt, NULL, "dadd", "d,v,t",
+               macro_build (p, &icnt, (expressionS *) NULL, "dsll32",
+                            "d,w,<", tempreg, tempreg, 0);
+               macro_build (p, &icnt, (expressionS *) NULL, "dadd", "d,v,t",
                             tempreg, tempreg, AT);
                used_at = 1;
              }
@@ -4567,11 +4691,11 @@ macro (ip)
                             tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
                macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
                             tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
-               macro_build (p, &icnt, NULL, "dsll", "d,w,<",
+               macro_build (p, &icnt, (expressionS *) NULL, "dsll", "d,w,<",
                             tempreg, tempreg, 16);
                macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
                             tempreg, tempreg, (int) BFD_RELOC_HI16_S);
-               macro_build (p, &icnt, NULL, "dsll", "d,w,<",
+               macro_build (p, &icnt, (expressionS *) NULL, "dsll", "d,w,<",
                             tempreg, tempreg, 16);
                macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
                             tempreg, tempreg, (int) BFD_RELOC_LO16);
@@ -4585,12 +4709,11 @@ macro (ip)
                frag_grow (20);
                macro_build ((char *) NULL, &icnt, &offset_expr,
                             HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                            "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
+                            "t,r,j", tempreg, GP, (int) BFD_RELOC_GPREL16);
                p = frag_var (rs_machine_dependent, 8, 0,
                              RELAX_ENCODE (4, 8, 0, 4, 0,
                                            mips_opts.warn_about_macros),
-                             offset_expr.X_add_symbol, (offsetT) 0,
-                             (char *) NULL);
+                             offset_expr.X_add_symbol, 0, NULL);
              }
            macro_build_lui (p, &icnt, &offset_expr, tempreg);
            if (p != NULL)
@@ -4637,8 +4760,7 @@ macro (ip)
          frag_grow (32);
          if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
            lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
-         macro_build ((char *) NULL, &icnt, &offset_expr,
-                      dbl ? "ld" : "lw",
+         macro_build ((char *) NULL, &icnt, &offset_expr, dbl ? "ld" : "lw",
                       "t,o(b)", tempreg, lw_reloc_type, GP);
          if (expr1.X_add_number == 0)
            {
@@ -4660,8 +4782,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_opts.warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
              if (breg == 0)
                {
                  macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -4682,10 +4803,9 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, &expr1,
                           HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
-             (void) frag_var (rs_machine_dependent, 0, 0,
-                              RELAX_ENCODE (0, 0, -12, -4, 0, 0),
-                              offset_expr.X_add_symbol, (offsetT) 0,
-                              (char *) NULL);
+             frag_var (rs_machine_dependent, 0, 0,
+                       RELAX_ENCODE (0, 0, -12, -4, 0, 0),
+                       offset_expr.X_add_symbol, 0, NULL);
            }
          else
            {
@@ -4716,7 +4836,7 @@ macro (ip)
                 inserting an unnecessary nop after the lw.  */
              hold_mips_optimize = mips_optimize;
              mips_optimize = 2;
-             macro_build_lui ((char *) NULL, &icnt, &expr1, AT);
+             macro_build_lui (NULL, &icnt, &expr1, AT);
              mips_optimize = hold_mips_optimize;
 
              macro_build ((char *) NULL, &icnt, &expr1,
@@ -4725,10 +4845,9 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                           HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", tempreg, tempreg, AT);
-             (void) frag_var (rs_machine_dependent, 0, 0,
-                              RELAX_ENCODE (0, 0, -16 + off1, -8, 0, 0),
-                              offset_expr.X_add_symbol, (offsetT) 0,
-                              (char *) NULL);
+             frag_var (rs_machine_dependent, 0, 0,
+                       RELAX_ENCODE (0, 0, -16 + off1, -8, 0, 0),
+                       offset_expr.X_add_symbol, 0, NULL);
              used_at = 1;
            }
        }
@@ -4820,8 +4939,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_opts.warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
            }
          else if (expr1.X_add_number >= -0x8000
                   && expr1.X_add_number < 0x8000)
@@ -4837,8 +4955,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_opts.warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
            }
          else
            {
@@ -4872,7 +4989,7 @@ macro (ip)
                 inserting an unnecessary nop after the lw.  */
              hold_mips_optimize = mips_optimize;
              mips_optimize = 2;
-             macro_build_lui ((char *) NULL, &icnt, &expr1, AT);
+             macro_build_lui (NULL, &icnt, &expr1, AT);
              mips_optimize = hold_mips_optimize;
 
              macro_build ((char *) NULL, &icnt, &expr1,
@@ -4888,8 +5005,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_opts.warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
 
              used_at = 1;
            }
@@ -4953,11 +5069,11 @@ macro (ip)
       else if (mips_pic == EMBEDDED_PIC)
        {
          /* We use
-              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
+              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_GPREL16)
             */
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                      "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
+                      "t,r,j", tempreg, GP, (int) BFD_RELOC_GPREL16);
        }
       else
        abort ();
@@ -5006,6 +5122,18 @@ macro (ip)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
                {
+                 if (! mips_frame_reg_valid)
+                   {
+                     as_warn (_("No .frame pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_frame_reg_valid = 1;
+                   }
+                 if (! mips_cprestore_valid)
+                   {
+                     as_warn (_("No .cprestore pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_cprestore_valid = 1;
+                   }
                  expr1.X_add_number = mips_cprestore_offset;
                  macro_build ((char *) NULL, &icnt, &expr1,
                               HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)",
@@ -5057,8 +5185,7 @@ macro (ip)
                           "nop", "");
              p = frag_var (rs_machine_dependent, 4, 0,
                            RELAX_ENCODE (0, 4, -8, 0, 0, 0),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
            }
          else
            {
@@ -5082,8 +5209,7 @@ macro (ip)
              p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
                            RELAX_ENCODE (16, 12 + gpdel, gpdel, 8 + gpdel,
                                          0, 0),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
              if (gpdel > 0)
                {
                  macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -5109,6 +5235,18 @@ macro (ip)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
                {
+                 if (! mips_frame_reg_valid)
+                   {
+                     as_warn (_("No .frame pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_frame_reg_valid = 1;
+                   }
+                 if (! mips_cprestore_valid)
+                   {
+                     as_warn (_("No .cprestore pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_cprestore_valid = 1;
+                   }
                  if (mips_opts.noreorder)
                    macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                             "nop", "");
@@ -5359,7 +5497,7 @@ macro (ip)
        {
          /* If this is a reference to a GP relative symbol, and there
             is no base register, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
             Otherwise, if there is no base register, we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
@@ -5369,7 +5507,7 @@ macro (ip)
             If we have a base register, and this is a reference to a
             GP relative symbol, we want
               addu     $tempreg,$breg,$gp
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_GPREL16)
             Otherwise we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               addu     $tempreg,$tempreg,$breg
@@ -5409,8 +5547,17 @@ macro (ip)
               dsll     $tempreg,16
               daddu    $tempreg,$tempreg,$breg
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+
+            If we have 64-bit addresses, as an optimization, for
+            addresses which are 32-bit constants (e.g. kseg0/kseg1
+            addresses) we fall back to the 32-bit address generation
+            mechanism since it is more efficient.  This code should
+            probably attempt to generate 64-bit constants more
+            efficiently in general.
           */
-         if (HAVE_64BIT_ADDRESSES)
+         if (HAVE_64BIT_ADDRESSES
+             && !(offset_expr.X_op == O_constant
+                  && IS_SEXT_32BIT_NUM (offset_expr.X_add_number)))
            {
              p = NULL;
 
@@ -5426,12 +5573,12 @@ macro (ip)
                  macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
                  if (breg != 0)
-                   macro_build (p, &icnt, NULL, "daddu", "d,v,t",
-                                AT, AT, breg);
-                 macro_build (p, &icnt, NULL, "dsll32", "d,w,<",
-                              tempreg, tempreg, 0);
-                 macro_build (p, &icnt, NULL, "daddu", "d,v,t",
-                              tempreg, tempreg, AT);
+                   macro_build (p, &icnt, (expressionS *) NULL, "daddu",
+                                "d,v,t", AT, AT, breg);
+                 macro_build (p, &icnt, (expressionS *) NULL, "dsll32",
+                              "d,w,<", tempreg, tempreg, 0);
+                 macro_build (p, &icnt, (expressionS *) NULL, "daddu",
+                              "d,v,t", tempreg, tempreg, AT);
                  macro_build (p, &icnt, &offset_expr, s,
                               fmt, treg, (int) BFD_RELOC_LO16, tempreg);
                  used_at = 1;
@@ -5442,15 +5589,15 @@ macro (ip)
                               tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
                  macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
-                 macro_build (p, &icnt, NULL, "dsll", "d,w,<",
-                              tempreg, tempreg, 16);
+                 macro_build (p, &icnt, (expressionS *) NULL, "dsll",
+                              "d,w,<", tempreg, tempreg, 16);
                  macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, (int) BFD_RELOC_HI16_S);
-                 macro_build (p, &icnt, NULL, "dsll", "d,w,<",
-                              tempreg, tempreg, 16);
+                 macro_build (p, &icnt, (expressionS *) NULL, "dsll",
+                              "d,w,<", tempreg, tempreg, 16);
                  if (breg != 0)
-                   macro_build (p, &icnt, NULL, "daddu", "d,v,t",
-                                tempreg, tempreg, breg);
+                   macro_build (p, &icnt, (expressionS *) NULL, "daddu",
+                                "d,v,t", tempreg, tempreg, breg);
                  macro_build (p, &icnt, &offset_expr, s,
                               fmt, treg, (int) BFD_RELOC_LO16, tempreg);
                }
@@ -5467,14 +5614,13 @@ macro (ip)
                {
                  frag_grow (20);
                  macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                              treg, (int) BFD_RELOC_MIPS_GPREL, GP);
+                              treg, (int) BFD_RELOC_GPREL16, GP);
                  p = frag_var (rs_machine_dependent, 8, 0,
                                RELAX_ENCODE (4, 8, 0, 4, 0,
                                              (mips_opts.warn_about_macros
                                               || (used_at
                                                   && mips_opts.noat))),
-                               offset_expr.X_add_symbol, (offsetT) 0,
-                               (char *) NULL);
+                               offset_expr.X_add_symbol, 0, NULL);
                  used_at = 0;
                }
              macro_build_lui (p, &icnt, &offset_expr, tempreg);
@@ -5495,11 +5641,10 @@ macro (ip)
                               HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                               "d,v,t", tempreg, breg, GP);
                  macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                              treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                              treg, (int) BFD_RELOC_GPREL16, tempreg);
                  p = frag_var (rs_machine_dependent, 12, 0,
                                RELAX_ENCODE (8, 12, 0, 8, 0, 0),
-                               offset_expr.X_add_symbol, (offsetT) 0,
-                               (char *) NULL);
+                               offset_expr.X_add_symbol, 0, NULL);
                }
              macro_build_lui (p, &icnt, &offset_expr, tempreg);
              if (p != NULL)
@@ -5543,8 +5688,7 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          p = frag_var (rs_machine_dependent, 4, 0,
                        RELAX_ENCODE (0, 4, -8, 0, 0, 0),
-                       offset_expr.X_add_symbol, (offsetT) 0,
-                       (char *) NULL);
+                       offset_expr.X_add_symbol, 0, NULL);
          macro_build (p, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
@@ -5597,7 +5741,7 @@ macro (ip)
                       tempreg);
          p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
                        RELAX_ENCODE (12, 12 + gpdel, gpdel, 8 + gpdel, 0, 0),
-                       offset_expr.X_add_symbol, (offsetT) 0, (char *) NULL);
+                       offset_expr.X_add_symbol, 0, NULL);
          if (gpdel > 0)
            {
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -5622,16 +5766,16 @@ macro (ip)
       else if (mips_pic == EMBEDDED_PIC)
        {
          /* If there is no base register, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
             If there is a base register, we want
               addu     $tempreg,$breg,$gp
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_GPREL16)
             */
          assert (offset_expr.X_op == O_symbol);
          if (breg == 0)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                          treg, (int) BFD_RELOC_MIPS_GPREL, GP);
+                          treg, (int) BFD_RELOC_GPREL16, GP);
              used_at = 0;
            }
          else
@@ -5640,7 +5784,7 @@ macro (ip)
                           HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", tempreg, breg, GP);
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                          treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                          treg, (int) BFD_RELOC_GPREL16, tempreg);
            }
        }
       else
@@ -5724,8 +5868,7 @@ macro (ip)
         upper 16 bits of the address.  */
       if (mips_pic == NO_PIC)
        {
-         /* FIXME: This won't work for a 64 bit address.  */
-         macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
+         macro_build_lui (NULL, &icnt, &offset_expr, AT);
        }
       else if (mips_pic == SVR4_PIC)
        {
@@ -5739,7 +5882,7 @@ macro (ip)
             a single instruction.  */
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                      "t,r,j", AT, GP, (int) BFD_RELOC_MIPS_GPREL);
+                      "t,r,j", AT, GP, (int) BFD_RELOC_GPREL16);
          offset_expr.X_op = O_constant;
          offset_expr.X_add_number = 0;
        }
@@ -5829,7 +5972,7 @@ macro (ip)
          else
            {
              /* FIXME: This won't work for a 64 bit address.  */
-             macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
+             macro_build_lui (NULL, &icnt, &offset_expr, AT);
            }
 
          if (mips_opts.isa != ISA_MIPS1)
@@ -5972,12 +6115,12 @@ macro (ip)
          || offset_expr.X_op == O_constant)
        {
          /* If this is a reference to a GP relative symbol, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
             If we have a base register, we use this
               addu     $at,$breg,$gp
-              <op>     $treg,<sym>($at)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($at)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_GPREL16)
             If this is not a GP relative symbol, we want
               lui      $at,<sym>               (BFD_RELOC_HI16_S)
               <op>     $treg,<sym>($at)        (BFD_RELOC_LO16)
@@ -6016,7 +6159,7 @@ macro (ip)
              /* Itbl support may require additional care here.  */
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           coproc ? treg + 1 : treg,
-                          (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                          (int) BFD_RELOC_GPREL16, tempreg);
              offset_expr.X_add_number += 4;
 
              /* Set mips_optimize to 2 to avoid inserting an
@@ -6026,14 +6169,13 @@ macro (ip)
              /* Itbl support may require additional care here.  */
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           coproc ? treg : treg + 1,
-                          (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                          (int) BFD_RELOC_GPREL16, tempreg);
              mips_optimize = hold_mips_optimize;
 
              p = frag_var (rs_machine_dependent, 12 + off, 0,
                            RELAX_ENCODE (8 + off, 12 + off, 0, 4 + off, 1,
                                          used_at && mips_opts.noat),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
 
              /* We just generated two relocs.  When tc_gen_reloc
                 handles this case, it will skip the first reloc and
@@ -6134,8 +6276,7 @@ macro (ip)
 
          (void) frag_var (rs_machine_dependent, 0, 0,
                           RELAX_ENCODE (0, 0, -16 - off, -8, 1, 0),
-                          offset_expr.X_add_symbol, (offsetT) 0,
-                          (char *) NULL);
+                          offset_expr.X_add_symbol, 0, NULL);
        }
       else if (mips_pic == SVR4_PIC)
        {
@@ -6204,8 +6345,7 @@ macro (ip)
          p = frag_var (rs_machine_dependent, 16 + gpdel + off, 0,
                        RELAX_ENCODE (24 + off, 16 + gpdel + off, gpdel,
                                      8 + gpdel + off, 1, 0),
-                       offset_expr.X_add_symbol, (offsetT) 0,
-                       (char *) NULL);
+                       offset_expr.X_add_symbol, 0, NULL);
          if (gpdel > 0)
            {
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -6244,12 +6384,12 @@ macro (ip)
       else if (mips_pic == EMBEDDED_PIC)
        {
          /* If there is no base register, we use
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
             If we have a base register, we use
               addu     $at,$breg,$gp
-              <op>     $treg,<sym>($at)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($at)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_GPREL16)
             */
          if (breg == 0)
            {
@@ -6268,12 +6408,12 @@ macro (ip)
          /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                       coproc ? treg + 1 : treg,
-                      (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                      (int) BFD_RELOC_GPREL16, tempreg);
          offset_expr.X_add_number += 4;
          /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                       coproc ? treg : treg + 1,
-                      (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                      (int) BFD_RELOC_GPREL16, tempreg);
        }
       else
        abort ();
@@ -6402,10 +6542,10 @@ macro2 (ip)
     case M_DMUL:
       dbl = 1;
     case M_MUL:
-      macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dmultu" : "multu",
-                  "s,t", sreg, treg);
-      macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                  dbl ? "dmultu" : "multu", "s,t", sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d",
+                  dreg);
       return;
 
     case M_DMUL_I:
@@ -6415,9 +6555,10 @@ macro2 (ip)
         not trying to be that fancy. GCC should do this for us
         anyway.  */
       load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dmult" : "mult", "s,t", sreg, AT);
-      macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d",
+                  dreg);
       break;
 
     case M_DMULO_I:
@@ -6435,23 +6576,29 @@ macro2 (ip)
       mips_any_noreorder = 1;
       if (imm)
        load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
-      macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d",
+                  dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, 31);
-      macro_build ((char *) NULL, &icnt, NULL, "mfhi", "d", AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mfhi", "d",
+                  AT);
       if (mips_trap)
-       macro_build ((char *) NULL, &icnt, NULL, "tne", "s,t", dreg, AT);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne", "s,t",
+                    dreg, AT);
       else
        {
          expr1.X_add_number = 8;
-         macro_build ((char *) NULL, &icnt, &expr1, "beq", "s,t,p", dreg, AT);
-         macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+         macro_build ((char *) NULL, &icnt, &expr1, "beq", "s,t,p", dreg,
+                      AT);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "",
+                      0);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                      "c", 6);
        }
       --mips_opts.noreorder;
-      macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d", dreg);
       break;
 
     case M_DMULOU_I:
@@ -6469,57 +6616,70 @@ macro2 (ip)
       mips_any_noreorder = 1;
       if (imm)
        load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dmultu" : "multu",
                   "s,t", sreg, imm ? AT : treg);
-      macro_build ((char *) NULL, &icnt, NULL, "mfhi", "d", AT);
-      macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mfhi", "d",
+                  AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d",
+                  dreg);
       if (mips_trap)
-       macro_build ((char *) NULL, &icnt, NULL, "tne", "s,t", AT, 0);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne", "s,t",
+                    AT, 0);
       else
        {
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "beq", "s,t,p", AT, 0);
-         macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "",
+                      0);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                      "c", 6);
        }
       --mips_opts.noreorder;
       break;
 
     case M_ROL:
-      macro_build ((char *) NULL, &icnt, NULL, "subu", "d,v,t", AT, 0, treg);
-      macro_build ((char *) NULL, &icnt, NULL, "srlv", "d,t,s", AT, sreg, AT);
-      macro_build ((char *) NULL, &icnt, NULL, "sllv", "d,t,s", dreg, sreg,
-                  treg);
-      macro_build ((char *) NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "subu",
+                  "d,v,t", AT, 0, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srlv",
+                  "d,t,s", AT, sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sllv",
+                  "d,t,s", dreg, sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                  "d,v,t", dreg, dreg, AT);
       break;
 
     case M_ROL_I:
       if (imm_expr.X_op != O_constant)
        as_bad (_("rotate count too large"));
-      macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", AT, sreg,
-                  (int) (imm_expr.X_add_number & 0x1f));
-      macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", dreg, sreg,
-                  (int) ((0 - imm_expr.X_add_number) & 0x1f));
-      macro_build ((char *) NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
+                  AT, sreg, (int) (imm_expr.X_add_number & 0x1f));
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl", "d,w,<",
+                  dreg, sreg, (int) ((0 - imm_expr.X_add_number) & 0x1f));
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or", "d,v,t",
+                  dreg, dreg, AT);
       break;
 
     case M_ROR:
-      macro_build ((char *) NULL, &icnt, NULL, "subu", "d,v,t", AT, 0, treg);
-      macro_build ((char *) NULL, &icnt, NULL, "sllv", "d,t,s", AT, sreg, AT);
-      macro_build ((char *) NULL, &icnt, NULL, "srlv", "d,t,s", dreg, sreg,
-                  treg);
-      macro_build ((char *) NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "subu",
+                  "d,v,t", AT, 0, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sllv",
+                  "d,t,s", AT, sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srlv",
+                  "d,t,s", dreg, sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                  "d,v,t", dreg, dreg, AT);
       break;
 
     case M_ROR_I:
       if (imm_expr.X_op != O_constant)
        as_bad (_("rotate count too large"));
-      macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", AT, sreg,
-                  (int) (imm_expr.X_add_number & 0x1f));
-      macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", dreg, sreg,
-                  (int) ((0 - imm_expr.X_add_number) & 0x1f));
-      macro_build ((char *) NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl", "d,w,<",
+                  AT, sreg, (int) (imm_expr.X_add_number & 0x1f));
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
+                  dreg, sreg, (int) ((0 - imm_expr.X_add_number) & 0x1f));
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or", "d,v,t",
+                  dreg, dreg, AT);
       break;
 
     case M_S_DOB:
@@ -6549,8 +6709,8 @@ macro2 (ip)
                     sreg, (int) BFD_RELOC_LO16);
       else
        {
-         macro_build ((char *) NULL, &icnt, NULL, "xor", "d,v,t", dreg,
-                      sreg, treg);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "xor",
+                      "d,v,t", dreg, sreg, treg);
          macro_build ((char *) NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg,
                       dreg, (int) BFD_RELOC_LO16);
        }
@@ -6592,8 +6752,8 @@ macro2 (ip)
       else
        {
          load_register (&icnt, AT, &imm_expr, 0);
-         macro_build ((char *) NULL, &icnt, NULL, "xor", "d,v,t", dreg,
-                      sreg, AT);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "xor",
+                      "d,v,t", dreg, sreg, AT);
          used_at = 1;
        }
       macro_build ((char *) NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg, dreg,
@@ -6608,7 +6768,8 @@ macro2 (ip)
     case M_SGEU:
       s = "sltu";
     sge:
-      macro_build ((char *) NULL, &icnt, NULL, s, "d,v,t", dreg, sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t",
+                  dreg, sreg, treg);
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
                   (int) BFD_RELOC_LO16);
       return;
@@ -6627,9 +6788,9 @@ macro2 (ip)
       else
        {
          load_register (&icnt, AT, &imm_expr, 0);
-         macro_build ((char *) NULL, &icnt, NULL,
-                      mask == M_SGE_I ? "slt" : "sltu",
-                      "d,v,t", dreg, sreg, AT);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                      mask == M_SGE_I ? "slt" : "sltu", "d,v,t", dreg, sreg,
+                      AT);
          used_at = 1;
        }
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
@@ -6644,7 +6805,8 @@ macro2 (ip)
     case M_SGTU:
       s = "sltu";
     sgt:
-      macro_build ((char *) NULL, &icnt, NULL, s, "d,v,t", dreg, treg, sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t",
+                  dreg, treg, sreg);
       return;
 
     case M_SGT_I:              /* sreg > I  <==>  I < sreg */
@@ -6654,28 +6816,31 @@ macro2 (ip)
       s = "sltu";
     sgti:
       load_register (&icnt, AT, &imm_expr, 0);
-      macro_build ((char *) NULL, &icnt, NULL, s, "d,v,t", dreg, AT, sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t",
+                  dreg, AT, sreg);
       break;
 
-    case M_SLE:                /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
+    case M_SLE:        /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
       s = "slt";
       goto sle;
     case M_SLEU:
       s = "sltu";
     sle:
-      macro_build ((char *) NULL, &icnt, NULL, s, "d,v,t", dreg, treg, sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t",
+                  dreg, treg, sreg);
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
                   (int) BFD_RELOC_LO16);
       return;
 
-    case M_SLE_I:              /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
+    case M_SLE_I:      /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
       s = "slt";
       goto slei;
     case M_SLEU_I:
       s = "sltu";
     slei:
       load_register (&icnt, AT, &imm_expr, 0);
-      macro_build ((char *) NULL, &icnt, NULL, s, "d,v,t", dreg, AT, sreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t",
+                  dreg, AT, sreg);
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
                   (int) BFD_RELOC_LO16);
       break;
@@ -6690,7 +6855,8 @@ macro2 (ip)
          return;
        }
       load_register (&icnt, AT, &imm_expr, 0);
-      macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", dreg, sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "slt", "d,v,t",
+                  dreg, sreg, AT);
       break;
 
     case M_SLTU_I:
@@ -6703,31 +6869,31 @@ macro2 (ip)
          return;
        }
       load_register (&icnt, AT, &imm_expr, 0);
-      macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, sreg,
-                  AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                  "d,v,t", dreg, sreg, AT);
       break;
 
     case M_SNE:
       if (sreg == 0)
-       macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0,
-                    treg);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                    "d,v,t", dreg, 0, treg);
       else if (treg == 0)
-       macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0,
-                    sreg);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                    "d,v,t", dreg, 0, sreg);
       else
        {
-         macro_build ((char *) NULL, &icnt, NULL, "xor", "d,v,t", dreg,
-                      sreg, treg);
-         macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0,
-                      dreg);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "xor",
+                      "d,v,t", dreg, sreg, treg);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                      "d,v,t", dreg, 0, dreg);
        }
       return;
 
     case M_SNE_I:
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0,
-                      sreg);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                      "d,v,t", dreg, 0, sreg);
          return;
        }
       if (sreg == 0)
@@ -6760,11 +6926,12 @@ macro2 (ip)
       else
        {
          load_register (&icnt, AT, &imm_expr, 0);
-         macro_build ((char *) NULL, &icnt, NULL, "xor", "d,v,t", dreg,
-                      sreg, AT);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "xor",
+                      "d,v,t", dreg, sreg, AT);
          used_at = 1;
        }
-      macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
+                  "d,v,t", dreg, 0, dreg);
       if (used_at)
        break;
       return;
@@ -6783,7 +6950,7 @@ macro2 (ip)
          return;
        }
       load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dsub" : "sub", "d,v,t", dreg, sreg, AT);
       break;
 
@@ -6801,7 +6968,7 @@ macro2 (ip)
          return;
        }
       load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dsubu" : "subu", "d,v,t", dreg, sreg, AT);
       break;
 
@@ -6824,7 +6991,8 @@ macro2 (ip)
       s = "tne";
     trap:
       load_register (&icnt, AT, &imm_expr, 0);
-      macro_build ((char *) NULL, &icnt, NULL, s, "s,t", sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "s,t", sreg,
+                  AT);
       break;
 
     case M_TRUNCWS:
@@ -6840,21 +7008,25 @@ macro2 (ip)
       mips_emit_delays (true);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
-      macro_build ((char *) NULL, &icnt, NULL, "cfc1", "t,G", treg, 31);
-      macro_build ((char *) NULL, &icnt, NULL, "cfc1", "t,G", treg, 31);
-      macro_build ((char *) NULL, &icnt, NULL, "nop", "");
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "cfc1", "t,G",
+                  treg, 31);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "cfc1", "t,G",
+                  treg, 31);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
       expr1.X_add_number = 3;
       macro_build ((char *) NULL, &icnt, &expr1, "ori", "t,r,i", AT, treg,
                   (int) BFD_RELOC_LO16);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", AT, AT,
                     (int) BFD_RELOC_LO16);
-      macro_build ((char *) NULL, &icnt, NULL, "ctc1", "t,G", AT, 31);
-      macro_build ((char *) NULL, &icnt, NULL, "nop", "");
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "ctc1", "t,G",
+                  AT, 31);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
              mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S", dreg, sreg);
-      macro_build ((char *) NULL, &icnt, NULL, "ctc1", "t,G", treg, 31);
-      macro_build ((char *) NULL, &icnt, NULL, "nop", "");
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "ctc1", "t,G",
+                  treg, 31);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
       --mips_opts.noreorder;
       break;
 
@@ -6877,8 +7049,10 @@ macro2 (ip)
        offset_expr.X_add_number += 1;
       macro_build ((char *) NULL, &icnt, &offset_expr, "lbu", "t,o(b)", AT,
                   (int) BFD_RELOC_LO16, breg);
-      macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", treg, treg, 8);
-      macro_build ((char *) NULL, &icnt, NULL, "or", "d,v,t", treg, treg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
+                  treg, treg, 8);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or", "d,v,t",
+                  treg, treg, AT);
       break;
 
     case M_ULD:
@@ -6954,10 +7128,10 @@ macro2 (ip)
        expr1.X_add_number = 0;
       macro_build ((char *) NULL, &icnt, &expr1, "lbu", "t,o(b)", AT,
                   (int) BFD_RELOC_LO16, AT);
-      macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", treg,
-                  treg, 8);
-      macro_build ((char *) NULL, &icnt, NULL, "or", "d,v,t", treg,
-                  treg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
+                  treg, treg, 8);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or", "d,v,t",
+                  treg, treg, AT);
       break;
 
     case M_USH:
@@ -6967,7 +7141,8 @@ macro2 (ip)
        offset_expr.X_add_number += 1;
       macro_build ((char *) NULL, &icnt, &offset_expr, "sb", "t,o(b)", treg,
                   (int) BFD_RELOC_LO16, breg);
-      macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", AT, treg, 8);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl", "d,w,<",
+                  AT, treg, 8);
       if (target_big_endian)
        offset_expr.X_add_number -= 1;
       else
@@ -7041,8 +7216,8 @@ macro2 (ip)
        expr1.X_add_number = 0;
       macro_build ((char *) NULL, &icnt, &expr1, "sb", "t,o(b)", treg,
                   (int) BFD_RELOC_LO16, AT);
-      macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", treg,
-                  treg, 8);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl", "d,w,<",
+                  treg, treg, 8);
       if (! target_big_endian)
        expr1.X_add_number = 1;
       else
@@ -7055,10 +7230,10 @@ macro2 (ip)
        expr1.X_add_number = 1;
       macro_build ((char *) NULL, &icnt, &expr1, "lbu", "t,o(b)", AT,
                   (int) BFD_RELOC_LO16, AT);
-      macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", treg,
-                  treg, 8);
-      macro_build ((char *) NULL, &icnt, NULL, "or", "d,v,t", treg,
-                  treg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
+                  treg, treg, 8);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or", "d,v,t",
+                  treg, treg, AT);
       break;
 
     default:
@@ -7117,19 +7292,20 @@ mips16_macro (ip)
       mips_emit_delays (true);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "ddiv" : "div",
                   "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-      macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break", "6",
+                  7);
 
       /* FIXME: The normal code checks for of -1 / -0x80000000 here,
          since that causes an overflow.  We should do that as well,
          but I don't see how to do the comparisons without a temporary
          register.  */
       --mips_opts.noreorder;
-      macro_build ((char *) NULL, &icnt, NULL, s, "x", zreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "x", zreg);
       break;
 
     case M_DIVU_3:
@@ -7151,20 +7327,23 @@ mips16_macro (ip)
       mips_emit_delays (true);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
-      macro_build ((char *) NULL, &icnt, NULL, s, "0,x,y", xreg, yreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "0,x,y",
+                  xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-       macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                    "6", 7);
       --mips_opts.noreorder;
-      macro_build ((char *) NULL, &icnt, NULL, s2, "x", zreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s2, "x", zreg);
       break;
 
     case M_DMUL:
       dbl = 1;
     case M_MUL:
-      macro_build ((char *) NULL, &icnt, NULL,
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                   dbl ? "dmultu" : "multu", "x,y", xreg, yreg);
-      macro_build ((char *) NULL, &icnt, NULL, "mflo", "x", zreg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "x",
+                  zreg);
       return;
 
     case M_DSUBU_I:
@@ -8314,14 +8493,14 @@ mips_ip (str, ip)
                      if (imm_expr.X_op == O_constant)
                        imm_expr.X_add_number =
                          (imm_expr.X_add_number >> 16) & 0xffff;
-#ifdef OBJ_ELF
-                     else if (c == S_EX_HIGHEST)
-                         *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
                      else if (c == S_EX_HI)
                        {
                          *imm_reloc = BFD_RELOC_HI16_S;
                          imm_unmatched_hi = true;
                        }
+#ifdef OBJ_ELF
+                     else if (c == S_EX_HIGHEST)
+                         *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
                      else if (c == S_EX_GP_REL)
                        {
                          /* This occurs in NewABI only.  */
@@ -8530,8 +8709,7 @@ mips16_ip (str, ip)
                      && *imm_reloc > BFD_RELOC_UNUSED
                      && insn->pinfo != INSN_MACRO)
                    {
-                     mips16_immed ((char *) NULL, 0,
-                                   *imm_reloc - BFD_RELOC_UNUSED,
+                     mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
                                    imm_expr.X_add_number, true, mips16_small,
                                    mips16_ext, &ip->insn_opcode,
                                    &ip->use_extend, &ip->extend);
@@ -9149,26 +9327,24 @@ static struct percent_op_match
    const enum small_ex_type type;
 } percent_op[] =
 {
-#ifdef OBJ_ELF
-  {"%half", S_EX_HALF},
-#endif
-  {"%hi", S_EX_HI},
   {"%lo", S_EX_LO},
 #ifdef OBJ_ELF
-  {"%gp_rel", S_EX_GP_REL},
-  {"%got", S_EX_GOT},
+  {"%call_hi", S_EX_CALL_HI},
+  {"%call_lo", S_EX_CALL_LO},
   {"%call16", S_EX_CALL16},
   {"%got_disp", S_EX_GOT_DISP},
   {"%got_page", S_EX_GOT_PAGE},
   {"%got_ofst", S_EX_GOT_OFST},
   {"%got_hi", S_EX_GOT_HI},
   {"%got_lo", S_EX_GOT_LO},
-  {"%neg", S_EX_NEG},
-  {"%higher", S_EX_HIGHER},
+  {"%got", S_EX_GOT},
+  {"%gp_rel", S_EX_GP_REL},
+  {"%half", S_EX_HALF},
   {"%highest", S_EX_HIGHEST},
-  {"%call_hi", S_EX_CALL_HI},
-  {"%call_lo", S_EX_CALL_LO}
+  {"%higher", S_EX_HIGHER},
+  {"%neg", S_EX_NEG},
 #endif
+  {"%hi", S_EX_HI}
 };
 
 /* Parse small expression input.  STR gets adjusted to eat up whitespace.
@@ -9182,10 +9358,9 @@ my_getSmallParser (str, len, nestlevel)
      unsigned int *len;
      int *nestlevel;
 {
-  int type = S_EX_NONE;
-
   *len = 0;
   *str += strspn (*str, " \t");
+  /* Check for expression in parentheses.  */
   if (**str == '(')
     {
       char *b = *str + 1 + strspn (*str + 1, " \t");
@@ -9212,50 +9387,68 @@ my_getSmallParser (str, len, nestlevel)
                 }
            }
        }
+      /* Check for percent_op (in parentheses).  */
       else if (b[0] == '%')
        {
          *str = b;
-         goto percent_op;
+         return my_getPercentOp (str, len, nestlevel);
        }
 
-      /* Some other expression in the braces.  */
-      *len = strcspn (*str, ")") + 1;
+      /* Some other expression in the parentheses, which can contain
+        parentheses itself. Attempt to find the matching one.  */
+      {
+       int pcnt = 1;
+       char *s;
+
+       *len = 1;
+       for (s = *str + 1; *s && pcnt; s++, (*len)++)
+         {
+           if (*s == '(')
+             pcnt++;
+           else if (*s == ')')
+             pcnt--;
+         }
+      }
     }
-  /* Check for percent_op.  */
+  /* Check for percent_op (outside of parentheses).  */
   else if (*str[0] == '%')
-    {
-      char *tmp;
-      unsigned int i;
+    return my_getPercentOp (str, len, nestlevel);
 
-percent_op:
-      tmp = *str + 1;
-      i = 0;
+  /* Any other expression.  */
+  return S_EX_NONE;
+}
 
-      while (ISALPHA (*tmp) || *tmp == '_')
-       {
-         *tmp = TOLOWER (*tmp);
-         tmp++;
-       }
-      while (i < (sizeof (percent_op) / sizeof (struct percent_op_match)))
+static int
+my_getPercentOp (str, len, nestlevel)
+     char **str;
+     unsigned int *len;
+     int *nestlevel;
+{
+  char *tmp = *str + 1;
+  unsigned int i = 0;
+
+  while (ISALPHA (*tmp) || *tmp == '_')
+    {
+      *tmp = TOLOWER (*tmp);
+      tmp++;
+    }
+  while (i < (sizeof (percent_op) / sizeof (struct percent_op_match)))
+    {
+      if (strncmp (*str, percent_op[i].str, strlen (percent_op[i].str)))
+         i++;
+      else
        {
-         if (strncmp (*str, percent_op[i].str, strlen (percent_op[i].str)))
-             i++;
-         else
-           {
-             type = percent_op[i].type;
+         int type = percent_op[i].type;
 
-             /* Only %hi and %lo are allowed for OldABI.  */
-             if (! HAVE_NEWABI && type != S_EX_HI && type != S_EX_LO)
-               return S_EX_NONE;
+         /* Only %hi and %lo are allowed for OldABI.  */
+         if (! HAVE_NEWABI && type != S_EX_HI && type != S_EX_LO)
+           return S_EX_NONE;
 
-             *len = strlen (percent_op[i].str);
-             (*nestlevel)++;
-             return type;
-           }
+         *len = strlen (percent_op[i].str);
+         (*nestlevel)++;
+         return type;
        }
     }
-
-  /* Any other expression.  */
   return S_EX_NONE;
 }
 
@@ -9267,46 +9460,59 @@ my_getSmallExpression (ep, str)
   static char *oldstr = NULL;
   int c = S_EX_NONE;
   int oldc;
-  int nest_level = 0;
+  int nestlevel = -1;
   unsigned int len;
 
-  /* Don't update oldstr if the last call had nested percent_op's.  */
+  /* Don't update oldstr if the last call had nested percent_op's. We need
+     it to parse the outer ones later.  */
   if (! oldstr)
     oldstr = str;
 
   do
     {
       oldc = c;
-      c = my_getSmallParser (&str, &len, &nest_level);
+      c = my_getSmallParser (&str, &len, &nestlevel);
       if (c != S_EX_NONE && c != S_EX_REGISTER)
        str += len;
     }
   while (c != S_EX_NONE && c != S_EX_REGISTER);
 
-  /* A percent_op was encountered.  */
-  if (nest_level)
+  if (nestlevel >= 0)
     {
-      /* Don't try to get an expression if it is already blanked out.  */
+      /* A percent_op was encountered.  Don't try to get an expression if
+        it is already blanked out.  */
       if (*(str + strspn (str + 1, " )")) != ')')
        {
          char save;
 
+         /* Let my_getExpression() stop at the closing parenthesis.  */
          save = *(str + len);
          *(str + len) = '\0';
          my_getExpression (ep, str);
          *(str + len) = save;
        }
-      if (nest_level > 1)
+      if (nestlevel > 0)
        {
-         /* blank out including the % sign.  */
-         char *p = strrchr (oldstr, '%');
-         memset (p, ' ', str - p + len);
+         /* Blank out including the % sign and the proper matching
+            parenthesis.  */
+         int pcnt = 1;
+         char *s = strrchr (oldstr, '%');
+         char *end;
+
+         for (end = strchr (s, '(') + 1; *end && pcnt; end++)
+           {
+             if (*end == '(')
+               pcnt++;
+             else if (*end == ')')
+               pcnt--;
+           }
+
+         memset (s, ' ', end - s);
          str = oldstr;
        }
       else
-       {
-         expr_end = strchr (str, ')') + 1;
-       }
+       expr_end = str + len;
+
       c = oldc;
     }
   else if (c == S_EX_NONE)
@@ -9326,7 +9532,8 @@ my_getSmallExpression (ep, str)
       as_fatal(_("internal error"));
     }
 
-  if (nest_level <= 1)
+  if (nestlevel <= 0)
+    /* All percent_op's have been handled.  */
     oldstr = NULL;
 
   return c;
@@ -9429,6 +9636,7 @@ md_number_to_chars (buf, val, n)
     number_to_chars_littleendian (buf, val, n);
 }
 \f
+#ifdef OBJ_ELF
 static int support_64bit_objects(void)
 {
   const char **list, **l;
@@ -9447,6 +9655,7 @@ static int support_64bit_objects(void)
   free (list);
   return (*l != NULL);
 }
+#endif /* OBJ_ELF */
 
 CONST char *md_shortopts = "nO::g::G:";
 
@@ -9461,83 +9670,82 @@ struct option md_longopts[] =
   {"mips3", no_argument, NULL, OPTION_MIPS3},
 #define OPTION_MIPS4 (OPTION_MD_BASE + 4)
   {"mips4", no_argument, NULL, OPTION_MIPS4},
-#define OPTION_MCPU (OPTION_MD_BASE + 5)
-  {"mcpu", required_argument, NULL, OPTION_MCPU},
-#define OPTION_MEMBEDDED_PIC (OPTION_MD_BASE + 6)
+#define OPTION_MIPS5 (OPTION_MD_BASE + 5)
+  {"mips5", no_argument, NULL, OPTION_MIPS5},
+#define OPTION_MIPS32 (OPTION_MD_BASE + 6)
+  {"mips32", no_argument, NULL, OPTION_MIPS32},
+#define OPTION_MIPS64 (OPTION_MD_BASE + 7)
+  {"mips64", no_argument, NULL, OPTION_MIPS64},
+#define OPTION_MEMBEDDED_PIC (OPTION_MD_BASE + 8)
   {"membedded-pic", no_argument, NULL, OPTION_MEMBEDDED_PIC},
-#define OPTION_TRAP (OPTION_MD_BASE + 7)
+#define OPTION_TRAP (OPTION_MD_BASE + 9)
   {"trap", no_argument, NULL, OPTION_TRAP},
   {"no-break", no_argument, NULL, OPTION_TRAP},
-#define OPTION_BREAK (OPTION_MD_BASE + 8)
+#define OPTION_BREAK (OPTION_MD_BASE + 10)
   {"break", no_argument, NULL, OPTION_BREAK},
   {"no-trap", no_argument, NULL, OPTION_BREAK},
-#define OPTION_EB (OPTION_MD_BASE + 9)
+#define OPTION_EB (OPTION_MD_BASE + 11)
   {"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL (OPTION_MD_BASE + 10)
+#define OPTION_EL (OPTION_MD_BASE + 12)
   {"EL", no_argument, NULL, OPTION_EL},
-#define OPTION_M4650 (OPTION_MD_BASE + 11)
-  {"m4650", no_argument, NULL, OPTION_M4650},
-#define OPTION_NO_M4650 (OPTION_MD_BASE + 12)
-  {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
-#define OPTION_M4010 (OPTION_MD_BASE + 13)
-  {"m4010", no_argument, NULL, OPTION_M4010},
-#define OPTION_NO_M4010 (OPTION_MD_BASE + 14)
-  {"no-m4010", no_argument, NULL, OPTION_NO_M4010},
-#define OPTION_M4100 (OPTION_MD_BASE + 15)
-  {"m4100", no_argument, NULL, OPTION_M4100},
-#define OPTION_NO_M4100 (OPTION_MD_BASE + 16)
-  {"no-m4100", no_argument, NULL, OPTION_NO_M4100},
-#define OPTION_MIPS16 (OPTION_MD_BASE + 17)
+#define OPTION_MIPS16 (OPTION_MD_BASE + 13)
   {"mips16", no_argument, NULL, OPTION_MIPS16},
-#define OPTION_NO_MIPS16 (OPTION_MD_BASE + 18)
+#define OPTION_NO_MIPS16 (OPTION_MD_BASE + 14)
   {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
-#define OPTION_M3900 (OPTION_MD_BASE + 19)
-  {"m3900", no_argument, NULL, OPTION_M3900},
-#define OPTION_NO_M3900 (OPTION_MD_BASE + 20)
-  {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
-#define OPTION_MABI (OPTION_MD_BASE + 21)
-  {"mabi", required_argument, NULL, OPTION_MABI},
-#define OPTION_M7000_HILO_FIX (OPTION_MD_BASE + 22)
+#define OPTION_M7000_HILO_FIX (OPTION_MD_BASE + 15)
   {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
-#define OPTION_NO_M7000_HILO_FIX (OPTION_MD_BASE + 23)
+#define OPTION_NO_M7000_HILO_FIX (OPTION_MD_BASE + 16)
   {"no-fix-7000", no_argument, NULL, OPTION_NO_M7000_HILO_FIX},
-#define OPTION_GP32 (OPTION_MD_BASE + 24)
+#define OPTION_FP32 (OPTION_MD_BASE + 17)
+  {"mfp32", no_argument, NULL, OPTION_FP32},
+#define OPTION_GP32 (OPTION_MD_BASE + 18)
   {"mgp32", no_argument, NULL, OPTION_GP32},
-#define OPTION_GP64 (OPTION_MD_BASE + 25)
-  {"mgp64", no_argument, NULL, OPTION_GP64},
-#define OPTION_CONSTRUCT_FLOATS (OPTION_MD_BASE + 26)
+#define OPTION_CONSTRUCT_FLOATS (OPTION_MD_BASE + 19)
   {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
-#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MD_BASE + 27)
+#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MD_BASE + 20)
   {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
-#define OPTION_MIPS32 (OPTION_MD_BASE + 28)
-  {"mips32", no_argument, NULL, OPTION_MIPS32},
-#define OPTION_MIPS5 (OPTION_MD_BASE + 29)
-  {"mips5", no_argument, NULL, OPTION_MIPS5},
-#define OPTION_MIPS64 (OPTION_MD_BASE + 30)
-  {"mips64", no_argument, NULL, OPTION_MIPS64},
-#define OPTION_MARCH (OPTION_MD_BASE + 31)
+#define OPTION_MARCH (OPTION_MD_BASE + 21)
   {"march", required_argument, NULL, OPTION_MARCH},
-#define OPTION_MTUNE (OPTION_MD_BASE + 32)
+#define OPTION_MTUNE (OPTION_MD_BASE + 22)
   {"mtune", required_argument, NULL, OPTION_MTUNE},
-#define OPTION_FP32 (OPTION_MD_BASE + 33)
-  {"mfp32", no_argument, NULL, OPTION_FP32},
+#define OPTION_MCPU (OPTION_MD_BASE + 23)
+  {"mcpu", required_argument, NULL, OPTION_MCPU},
+#define OPTION_M4650 (OPTION_MD_BASE + 24)
+  {"m4650", no_argument, NULL, OPTION_M4650},
+#define OPTION_NO_M4650 (OPTION_MD_BASE + 25)
+  {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
+#define OPTION_M4010 (OPTION_MD_BASE + 26)
+  {"m4010", no_argument, NULL, OPTION_M4010},
+#define OPTION_NO_M4010 (OPTION_MD_BASE + 27)
+  {"no-m4010", no_argument, NULL, OPTION_NO_M4010},
+#define OPTION_M4100 (OPTION_MD_BASE + 28)
+  {"m4100", no_argument, NULL, OPTION_M4100},
+#define OPTION_NO_M4100 (OPTION_MD_BASE + 29)
+  {"no-m4100", no_argument, NULL, OPTION_NO_M4100},
+#define OPTION_M3900 (OPTION_MD_BASE + 30)
+  {"m3900", no_argument, NULL, OPTION_M3900},
+#define OPTION_NO_M3900 (OPTION_MD_BASE + 31)
+  {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
+#define OPTION_GP64 (OPTION_MD_BASE + 32)
+  {"mgp64", no_argument, NULL, OPTION_GP64},
 #ifdef OBJ_ELF
-#define OPTION_ELF_BASE    (OPTION_MD_BASE + 35)
+#define OPTION_ELF_BASE    (OPTION_MD_BASE + 33)
 #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
-#define OPTION_NON_SHARED  (OPTION_ELF_BASE + 1)
-#define OPTION_XGOT        (OPTION_ELF_BASE + 2)
-#define OPTION_32         (OPTION_ELF_BASE + 3)
-#define OPTION_N32        (OPTION_ELF_BASE + 4)
-#define OPTION_64          (OPTION_ELF_BASE + 5)
   {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
+#define OPTION_NON_SHARED  (OPTION_ELF_BASE + 1)
   {"non_shared",  no_argument, NULL, OPTION_NON_SHARED},
+#define OPTION_XGOT        (OPTION_ELF_BASE + 2)
   {"xgot",        no_argument, NULL, OPTION_XGOT},
+#define OPTION_MABI        (OPTION_ELF_BASE + 3)
+  {"mabi", required_argument, NULL, OPTION_MABI},
+#define OPTION_32         (OPTION_ELF_BASE + 4)
   {"32",          no_argument, NULL, OPTION_32},
+#define OPTION_N32        (OPTION_ELF_BASE + 5)
   {"n32",         no_argument, NULL, OPTION_N32},
+#define OPTION_64          (OPTION_ELF_BASE + 6)
   {"64",          no_argument, NULL, OPTION_64},
-#endif
-
+#endif /* OBJ_ELF */
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
@@ -9799,58 +10007,80 @@ md_parse_option (c, arg)
       break;
 
 #ifdef OBJ_ELF
-      /* The -32 and -64 options tell the assembler to output the 32
-         bit or the 64 bit MIPS ELF format.  */
+      /* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
+        and -mabi=64.  */
     case OPTION_32:
-      mips_abi = O32_ABI;
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-32 is supported for ELF format only"));
+         return 0;
+       }
+      mips_opts.abi = O32_ABI;
       break;
 
     case OPTION_N32:
-      mips_abi = N32_ABI;
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-n32 is supported for ELF format only"));
+         return 0;
+       }
+      mips_opts.abi = N32_ABI;
       break;
 
     case OPTION_64:
-      mips_abi = N64_ABI;
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-64 is supported for ELF format only"));
+         return 0;
+       }
+      mips_opts.abi = N64_ABI;
       if (! support_64bit_objects())
        as_fatal (_("No compiled in support for 64 bit object file format"));
       break;
+#endif /* OBJ_ELF */
 
     case OPTION_GP32:
-      mips_gp32 = 1;
-      if (mips_abi != O32_ABI)
-       mips_abi = NO_ABI;
+      file_mips_gp32 = 1;
+      if (mips_opts.abi != O32_ABI)
+       mips_opts.abi = NO_ABI;
       break;
 
     case OPTION_GP64:
-      mips_gp32 = 0;
-      if (mips_abi == O32_ABI)
-       mips_abi = NO_ABI;
+      file_mips_gp32 = 0;
+      if (mips_opts.abi == O32_ABI)
+       mips_opts.abi = NO_ABI;
       break;
 
     case OPTION_FP32:
-      mips_fp32 = 1;
-      if (mips_abi != O32_ABI)
-       mips_abi = NO_ABI;
+      file_mips_fp32 = 1;
+      if (mips_opts.abi != O32_ABI)
+       mips_opts.abi = NO_ABI;
       break;
 
+#ifdef OBJ_ELF
     case OPTION_MABI:
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-mabi is supported for ELF format only"));
+         return 0;
+       }
       if (strcmp (arg, "32") == 0)
-       mips_abi = O32_ABI;
+       mips_opts.abi = O32_ABI;
       else if (strcmp (arg, "o64") == 0)
-       mips_abi = O64_ABI;
+       mips_opts.abi = O64_ABI;
       else if (strcmp (arg, "n32") == 0)
-       mips_abi = N32_ABI;
+       mips_opts.abi = N32_ABI;
       else if (strcmp (arg, "64") == 0)
        {
-         mips_abi = N64_ABI;
+         mips_opts.abi = N64_ABI;
          if (! support_64bit_objects())
            as_fatal (_("No compiled in support for 64 bit object file "
                        "format"));
        }
       else if (strcmp (arg, "eabi") == 0)
-       mips_abi = EABI_ABI;
+       mips_opts.abi = EABI_ABI;
       else
-       mips_abi = NO_ABI;
+       mips_opts.abi = NO_ABI;
       break;
 #endif /* OBJ_ELF */
 
@@ -9979,6 +10209,19 @@ MIPS options:\n\
 -KPIC, -call_shared    generate SVR4 position independent code\n\
 -non_shared            do not generate position independent code\n\
 -xgot                  assume a 32 bit GOT\n\
+-mabi=ABI              create ABI conformant object file for:\n"));
+
+  first = 1;
+
+  show (stream, "32", &column, &first);
+  show (stream, "o64", &column, &first);
+  show (stream, "n32", &column, &first);
+  show (stream, "64", &column, &first);
+  show (stream, "eabi", &column, &first);
+                            
+  fputc ('\n', stream);
+
+  fprintf (stream, _("\
 -32                    create o32 ABI object file (default)\n\
 -n32                   create n32 ABI object file\n\
 -64                    create 64 ABI object file\n"));
@@ -10032,7 +10275,7 @@ mips_frob_file_before_adjust ()
 }
 
 /* Sort any unmatched HI16_S relocs so that they immediately precede
-   the corresponding LO reloc.  This is called before md_apply_fix and
+   the corresponding LO reloc.  This is called before md_apply_fix3 and
    tc_gen_reloc.  Unmatched HI16_S relocs can only be generated by
    explicit use of the %hi modifier.  */
 
@@ -10156,12 +10399,32 @@ mips_force_relocation (fixp)
              || fixp->fx_r_type == BFD_RELOC_PCREL_LO16));
 }
 
+#ifdef OBJ_ELF
+static int
+mips_need_elf_addend_fixup (fixP)
+     fixS *fixP;
+{
+  return (S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16
+         || ((S_IS_WEAK (fixP->fx_addsy)
+              || S_IS_EXTERN (fixP->fx_addsy))
+             && !S_IS_COMMON (fixP->fx_addsy))
+         || (symbol_used_in_reloc_p (fixP->fx_addsy)
+             && (((bfd_get_section_flags (stdoutput,
+                                          S_GET_SEGMENT (fixP->fx_addsy))
+                   & SEC_LINK_ONCE) != 0)
+                 || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
+                              ".gnu.linkonce",
+                              sizeof (".gnu.linkonce") - 1))));
+}
+#endif
+
 /* Apply a fixup to the object file.  */
 
-int
-md_apply_fix (fixP, valueP)
+void
+md_apply_fix3 (fixP, valP, seg)
      fixS *fixP;
-     valueT *valueP;
+     valueT * valP;
+     segT seg ATTRIBUTE_UNUSED;
 {
   unsigned char *buf;
   long insn;
@@ -10187,31 +10450,19 @@ md_apply_fix (fixP, valueP)
          || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
          || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY);
 
-  value = *valueP;
+  value = * valP;
 
   /* If we aren't adjusting this fixup to be against the section
      symbol, we need to adjust the value.  */
 #ifdef OBJ_ELF
   if (fixP->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour)
     {
-      if (S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16
-         || ((S_IS_WEAK (fixP->fx_addsy)
-              || S_IS_EXTERN (fixP->fx_addsy))
-             && !S_IS_COMMON (fixP->fx_addsy))
-         || (symbol_used_in_reloc_p (fixP->fx_addsy)
-             && (((bfd_get_section_flags (stdoutput,
-                                          S_GET_SEGMENT (fixP->fx_addsy))
-                   & SEC_LINK_ONCE) != 0)
-                 || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
-                              ".gnu.linkonce",
-                              sizeof (".gnu.linkonce") - 1))))
-
+      if (mips_need_elf_addend_fixup (fixP))
        {
          valueT symval = S_GET_VALUE (fixP->fx_addsy);
+
          value -= symval;
-         if (value != 0
-             && ! fixP->fx_pcrel
-             && fixP->fx_r_type != BFD_RELOC_MIPS_GPREL)
+         if (value != 0 && ! fixP->fx_pcrel)
            {
              /* In this case, the bfd_install_relocation routine will
                 incorrectly add the symbol value back in.  We just want
@@ -10275,7 +10526,7 @@ md_apply_fix (fixP, valueP)
     }
 #endif
 
-  fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc */
+  fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc */
 
   if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel)
     fixP->fx_done = 1;
@@ -10300,11 +10551,11 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_MIPS_JALR:
     case BFD_RELOC_HI16:
     case BFD_RELOC_HI16_S:
-    case BFD_RELOC_MIPS_GPREL:
+    case BFD_RELOC_GPREL16:
     case BFD_RELOC_MIPS_LITERAL:
     case BFD_RELOC_MIPS_CALL16:
     case BFD_RELOC_MIPS_GOT16:
-    case BFD_RELOC_MIPS_GPREL32:
+    case BFD_RELOC_GPREL32:
     case BFD_RELOC_MIPS_GOT_HI16:
     case BFD_RELOC_MIPS_GOT_LO16:
     case BFD_RELOC_MIPS_CALL_HI16:
@@ -10515,8 +10766,6 @@ md_apply_fix (fixP, valueP)
     default:
       internalError ();
     }
-
-  return 1;
 }
 
 #if 0
@@ -11005,10 +11254,6 @@ s_mipsset (x)
   else if (strncmp (name, "mips", 4) == 0)
     {
       int isa;
-      static int saved_mips_gp32;
-      static int saved_mips_fp32;
-      static enum mips_abi_level saved_mips_abi;
-      static int is_saved;
 
       /* Permit the user to change the ISA on the fly.  Needless to
         say, misuse can cause serious problems.  */
@@ -11016,41 +11261,28 @@ s_mipsset (x)
       switch (isa)
       {
       case  0:
-       mips_gp32 = saved_mips_gp32;
-       mips_fp32 = saved_mips_fp32;
-       mips_abi = saved_mips_abi;
-       is_saved = 0;
+       mips_opts.gp32 = file_mips_gp32;
+       mips_opts.fp32 = file_mips_fp32;
+       mips_opts.abi = file_mips_abi;
        break;
       case  1:
       case  2:
       case 32:
-       if (! is_saved)
-         {
-           saved_mips_gp32 = mips_gp32;
-           saved_mips_fp32 = mips_fp32;
-           saved_mips_abi = mips_abi;
-         }
-       mips_gp32 = 1;
-       mips_fp32 = 1;
-       is_saved = 1;
+       mips_opts.gp32 = 1;
+       mips_opts.fp32 = 1;
        break;
       case  3:
       case  4:
       case  5:
       case 64:
-       if (! is_saved)
-         {
-           saved_mips_gp32 = mips_gp32;
-           saved_mips_fp32 = mips_fp32;
-           saved_mips_abi = mips_abi;
-         }
-       mips_gp32 = 0;
-       mips_fp32 = 0;
-       mips_abi = NO_ABI;
-       is_saved = 1;
+       /* Loosen ABI register width restriction.  */
+       if (mips_opts.abi == O32_ABI)
+         mips_opts.abi = NO_ABI;
+       mips_opts.gp32 = 0;
+       mips_opts.fp32 = 0;
        break;
       default:
-       as_bad (_("unknown ISA level"));
+       as_bad (_("unknown ISA level %s"), name + 4);
        break;
       }
 
@@ -11064,7 +11296,7 @@ s_mipsset (x)
       case  5: mips_opts.isa = ISA_MIPS5;       break;
       case 32: mips_opts.isa = ISA_MIPS32;      break;
       case 64: mips_opts.isa = ISA_MIPS64;      break;
-      default: as_bad (_("unknown ISA level")); break;
+      default: as_bad (_("unknown ISA level %s"), name + 4); break;
       }
     }
   else if (strcmp (name, "autoextend") == 0)
@@ -11171,7 +11403,7 @@ s_cpload (ignore)
   /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
   symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
 
-  macro_build_lui ((char *) NULL, &icnt, &ex, GP);
+  macro_build_lui (NULL, &icnt, &ex, GP);
   macro_build ((char *) NULL, &icnt, &ex, "addiu", "t,r,j", GP, GP,
               (int) BFD_RELOC_LO16);
 
@@ -11186,14 +11418,14 @@ s_cpload (ignore)
 
    If offset is given, this results in:
      sd                $gp, offset($sp)
-     lui       $gp, %gp_rel(%neg(%hi(label)))
-     daddiu    $gp, $gp, %gp_rel(%neg(%lo(label)))
+     lui       $gp, %hi(%neg(%gp_rel(label)))
+     daddiu    $gp, $gp, %lo(%neg(%gp_rel(label)))
      addu      $gp, $gp, $reg1
 
    If $reg2 is given, this results in:
      daddu     $reg2, $gp, $0
-     lui       $gp, %gp_rel(%neg(%hi(label)))
-     daddiu    $gp, $gp, %gp_rel(%neg(%lo(label)))
+     lui       $gp, %hi(%neg(%gp_rel(label)))
+     daddiu    $gp, $gp, %lo(%neg(%gp_rel(label)))
      addu      $gp, $gp, $reg1
  */
 static void
@@ -11314,6 +11546,7 @@ s_cprestore (ignore)
     }
 
   mips_cprestore_offset = get_absolute_expression ();
+  mips_cprestore_valid = 1;
 
   ex.X_op = O_constant;
   ex.X_add_symbol = NULL;
@@ -11421,7 +11654,7 @@ s_gpword (ignore)
   p = frag_more (4);
   md_number_to_chars (p, (valueT) 0, 4);
   fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, 0,
-              BFD_RELOC_MIPS_GPREL32);
+              BFD_RELOC_GPREL32);
 
   demand_empty_rest_of_line ();
 }
@@ -11512,7 +11745,7 @@ s_mips_weakext (ignore)
     {
       if (S_IS_DEFINED (symbolP))
        {
-         as_bad ("Ignoring attempt to redefine symbol `%s'.",
+         as_bad ("ignoring attempt to redefine symbol %s",
                  S_GET_NAME (symbolP));
          ignore_rest_of_line ();
          return;
@@ -11580,7 +11813,11 @@ tc_get_register (frame)
       input_line_pointer += 2;
     }
   if (frame)
-    mips_frame_reg = reg != 0 ? reg : SP;
+    {
+      mips_frame_reg = reg != 0 ? reg : SP;
+      mips_frame_reg_valid = 1;
+      mips_cprestore_valid = 0;
+    }
   return reg;
 }
 
@@ -12044,32 +12281,43 @@ tc_gen_reloc (section, fixp)
        as_fatal (_("Double check fx_r_type in tc-mips.c:tc_gen_reloc"));
       fixp->fx_r_type = BFD_RELOC_GPREL32;
     }
-  else if (fixp->fx_pcrel == 0 || OUTPUT_FLAVOR == bfd_target_elf_flavour)
-    reloc->addend = fixp->fx_addnumber;
   else if (fixp->fx_r_type == BFD_RELOC_PCREL_LO16)
     {
-      /* We use a special addend for an internal RELLO reloc.  */
-      if (symbol_section_p (fixp->fx_addsy))
-       reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+       reloc->addend = fixp->fx_addnumber;
       else
-       reloc->addend = fixp->fx_addnumber + reloc->address;
+       {
+         /* We use a special addend for an internal RELLO reloc.  */
+         if (symbol_section_p (fixp->fx_addsy))
+           reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
+         else
+           reloc->addend = fixp->fx_addnumber + reloc->address;
+       }
     }
   else if (fixp->fx_r_type == BFD_RELOC_PCREL_HI16_S)
     {
       assert (fixp->fx_next != NULL
              && fixp->fx_next->fx_r_type == BFD_RELOC_PCREL_LO16);
-      /* We use a special addend for an internal RELHI reloc.  The
-        reloc is relative to the RELLO; adjust the addend
+
+      /* The reloc is relative to the RELLO; adjust the addend
         accordingly.  */
-      if (symbol_section_p (fixp->fx_addsy))
-       reloc->addend = (fixp->fx_next->fx_frag->fr_address
-                        + fixp->fx_next->fx_where
-                        - S_GET_VALUE (fixp->fx_subsy));
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+       reloc->addend = fixp->fx_next->fx_addnumber;
       else
-       reloc->addend = (fixp->fx_addnumber
-                        + fixp->fx_next->fx_frag->fr_address
-                        + fixp->fx_next->fx_where);
+       {
+         /* We use a special addend for an internal RELHI reloc.  */
+         if (symbol_section_p (fixp->fx_addsy))
+           reloc->addend = (fixp->fx_next->fx_frag->fr_address
+                            + fixp->fx_next->fx_where
+                            - S_GET_VALUE (fixp->fx_subsy));
+         else
+           reloc->addend = (fixp->fx_addnumber
+                            + fixp->fx_next->fx_frag->fr_address
+                            + fixp->fx_next->fx_where);
+       }
     }
+  else if (fixp->fx_pcrel == 0 || OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    reloc->addend = fixp->fx_addnumber;
   else
     {
       if (OUTPUT_FLAVOR != bfd_target_aout_flavour)
@@ -12083,7 +12331,7 @@ tc_gen_reloc (section, fixp)
   /* If this is a variant frag, we may need to adjust the existing
      reloc and generate a new one.  */
   if (fixp->fx_frag->fr_opcode != NULL
-      && (fixp->fx_r_type == BFD_RELOC_MIPS_GPREL
+      && (fixp->fx_r_type == BFD_RELOC_GPREL16
          || fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
          || fixp->fx_r_type == BFD_RELOC_MIPS_CALL16
          || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16
@@ -12103,8 +12351,8 @@ tc_gen_reloc (section, fixp)
       if (fixp->fx_next != NULL
          && fixp->fx_frag == fixp->fx_next->fx_frag)
        {
-         assert ((fixp->fx_r_type == BFD_RELOC_MIPS_GPREL
-                  && fixp->fx_next->fx_r_type == BFD_RELOC_MIPS_GPREL)
+         assert ((fixp->fx_r_type == BFD_RELOC_GPREL16
+                  && fixp->fx_next->fx_r_type == BFD_RELOC_GPREL16)
                  || (fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16
                      && (fixp->fx_next->fx_r_type
                          == BFD_RELOC_MIPS_GOT_LO16))
@@ -12140,7 +12388,7 @@ tc_gen_reloc (section, fixp)
 
       if (mips_pic == NO_PIC)
        {
-         assert (fixp->fx_r_type == BFD_RELOC_MIPS_GPREL);
+         assert (fixp->fx_r_type == BFD_RELOC_GPREL16);
          fixp->fx_r_type = BFD_RELOC_HI16_S;
        }
       else if (mips_pic == SVR4_PIC)
@@ -12206,6 +12454,19 @@ tc_gen_reloc (section, fixp)
        }
     }
 
+#ifdef OBJ_ELF
+  /* md_apply_fix3 has a double-subtraction hack to get
+     bfd_install_relocation to behave nicely.  GPREL relocations are
+     handled correctly without this hack, so undo it here.  We can't
+     stop md_apply_fix3 from subtracting twice in the first place since
+     the fake addend is required for variant frags above.  */
+  if (fixp->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour
+      && code == BFD_RELOC_GPREL16
+      && reloc->addend != 0
+      && mips_need_elf_addend_fixup (fixp))
+    reloc->addend += S_GET_VALUE (fixp->fx_addsy);
+#endif
+
   /* To support a PC relative reloc when generating embedded PIC code
      for ECOFF, we use a Cygnus extension.  We check for that here to
      make sure that we don't let such a reloc escape normally.  */
@@ -12239,7 +12500,7 @@ mips_relax_frag (fragp, stretch)
   if (! RELAX_MIPS16_P (fragp->fr_subtype))
     return 0;
 
-  if (mips16_extended_frag (fragp, (asection *) NULL, stretch))
+  if (mips16_extended_frag (fragp, NULL, stretch))
     {
       if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
        return 0;
@@ -12477,20 +12738,20 @@ mips_elf_final_processing ()
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
 
   /* Set the MIPS ELF ABI flags.  */
-  if (mips_abi == NO_ABI)
+  if (file_mips_abi == NO_ABI)
     ;
-  else if (mips_abi == O32_ABI)
+  else if (file_mips_abi == O32_ABI)
     elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O32;
-  else if (mips_abi == O64_ABI)
+  else if (file_mips_abi == O64_ABI)
     elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
-  else if (mips_abi == EABI_ABI)
+  else if (file_mips_abi == EABI_ABI)
     {
       if (mips_eabi64)
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
       else
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
     }
-  else if (mips_abi == N32_ABI)
+  else if (file_mips_abi == N32_ABI)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
 
   /* Nothing to do for "64".  */
@@ -12574,7 +12835,7 @@ get_number ()
       negative = 1;
     }
   if (!ISDIGIT (*input_line_pointer))
-    as_bad (_("Expected simple number."));
+    as_bad (_("expected simple number"));
   if (input_line_pointer[0] == '0')
     {
       if (input_line_pointer[1] == 'x')
@@ -12602,7 +12863,7 @@ get_number ()
     {
       printf (_(" *input_line_pointer == '%c' 0x%02x\n"),
              *input_line_pointer, *input_line_pointer);
-      as_warn (_("Invalid number"));
+      as_warn (_("invalid number"));
       return -1;
     }
   while (ISDIGIT (*input_line_pointer))
@@ -12635,6 +12896,10 @@ s_mips_end (x)
   symbolS *p;
   int maybe_text;
 
+  /* Following functions need their own .frame and .cprestore directives.  */
+  mips_frame_reg_valid = 0;
+  mips_cprestore_valid = 0;
+
   if (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
       p = get_symbol ();
@@ -12752,6 +13017,10 @@ s_mips_ent (aent)
 
   if (!aent)
     {
+      /* This function needs its own .frame and .cprestore directives.  */
+      mips_frame_reg_valid = 0;
+      mips_cprestore_valid = 0;
+
       cur_proc_ptr = &cur_proc;
       memset (cur_proc_ptr, '\0', sizeof (procS));