* config/tc-mips.c (enum mips_pic_level): New enum.
authorIan Lance Taylor <ian@airs.com>
Tue, 22 Mar 1994 20:27:58 +0000 (20:27 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 22 Mar 1994 20:27:58 +0000 (20:27 +0000)
(mips_pic): Change from int to enum mips_pic_level.  Change all
uses (0 becomes NO_PIC, 2 becomes SVR4_PIC).
(load_address): Handle EMBEDDED_PIC.
(macro): Handle EMBEDDED_PIC in all PIC cases.
(md_parse_option): Accept -membedded-pic to use EMBEDDED_PIC.  If
OBJ_ELF, accept -KPIC and -call_shared to use SVR4_PIC and accept
-non_shared to use NO_PIC (this is how the Irix 5 assembler
works).  Do not permit -G with SVR4_PIC.
(s_abicalls): Warn if -G was used, and force -G 0.
(tc_gen_reloc): Set reloc->addend to 0 for a PC relative reloc for
anything but a.out, not just for ELF.  For ECOFF, don't generate a
BFD_RELOC_16_PCREL_S2 reloc unless using EMBEDDED_PIC.

gas/ChangeLog
gas/config/tc-mips.c

index f79c0dbcce84da0a1309f0974bb12b7581465fcb..2ae5314fd10509d367c1887fd418e3dbb3cceb13 100644 (file)
@@ -1,5 +1,19 @@
 Tue Mar 22 13:58:37 1994  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
 
+       * config/tc-mips.c (enum mips_pic_level): New enum.
+       (mips_pic): Change from int to enum mips_pic_level.  Change all
+       uses (0 becomes NO_PIC, 2 becomes SVR4_PIC).
+       (load_address): Handle EMBEDDED_PIC.
+       (macro): Handle EMBEDDED_PIC in all PIC cases.
+       (md_parse_option): Accept -membedded-pic to use EMBEDDED_PIC.  If
+       OBJ_ELF, accept -KPIC and -call_shared to use SVR4_PIC and accept
+       -non_shared to use NO_PIC (this is how the Irix 5 assembler
+       works).  Do not permit -G with SVR4_PIC.
+       (s_abicalls): Warn if -G was used, and force -G 0.
+       (tc_gen_reloc): Set reloc->addend to 0 for a PC relative reloc for
+       anything but a.out, not just for ELF.  For ECOFF, don't generate a
+       BFD_RELOC_16_PCREL_S2 reloc unless using EMBEDDED_PIC.
+
        * config/obj-ecoff.h (obj_sec_sym_ok_for_reloc): Define to be 1.
 
 Sun Mar 20 16:31:55 1994  Jeffrey A. Law  (law@snake.cs.utah.edu)
index af28018caee34c2e559baa179d9013cb7047ea92..275c7e03822757ebfdfb243676aef6618a06462d 100644 (file)
@@ -103,9 +103,28 @@ static int mips_isa = -1;
 /* MIPS ISA we are using for this output file.  */
 static int file_mips_isa;
 
-/* MIPS PIC level.  0 is normal, non-PIC code.  2 means to generate
-   SVR4 ABI PIC calls.  1 doesn't mean anything.  */
-static int mips_pic;
+/* MIPS PIC level.  */
+
+enum mips_pic_level
+{
+  /* Do not generate PIC code.  */
+  NO_PIC,
+
+  /* Generate PIC code as in Irix 4.  This is not implemented, and I'm
+     not sure what it is supposed to do.  */
+  IRIX4_PIC,
+
+  /* Generate PIC code as in the SVR4 MIPS ABI.  */
+  SVR4_PIC,
+
+  /* Generate PIC code without using a global offset table: the data
+     segment has a maximum size of 64K, all data references are off
+     the $gp register, and all text references are PC relative.  This
+     is used on some embedded systems.  */
+  EMBEDDED_PIC
+};
+
+static enum mips_pic_level mips_pic;
 
 /* 1 if trap instructions should used for overflow rather than break
    instructions.  */
@@ -1406,7 +1425,7 @@ macro_build_lui (place, counter, ep, regnum)
     {
       assert (ep->X_op == O_symbol);
       /* _gp_disp is a special case, used from s_cpload.  */
-      assert (mips_pic == 0
+      assert (mips_pic == NO_PIC
              || strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0);
       r = BFD_RELOC_HI16_S;
     }
@@ -1558,8 +1577,12 @@ load_address (counter, reg, ep)
     }
 
   if (ep->X_op == O_constant)
-    load_register (counter, reg, ep);
-  else if (mips_pic == 0)
+    {
+      load_register (counter, reg, ep);
+      return;
+    }
+
+  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)
@@ -1586,7 +1609,7 @@ load_address (counter, reg, ep)
                   mips_isa < 3 ? "addiu" : "daddiu",
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
     }
-  else
+  else if (mips_pic == SVR4_PIC)
     {
       expressionS ex;
 
@@ -1596,7 +1619,7 @@ load_address (counter, reg, ep)
           lw           $reg,<sym>($gp)         (BFD_RELOC_MIPS_GOT16)
           nop
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
-        If there is a constant, it must be added in afterward.  */
+        If there is a constant, it must be added in after.  */
       ex.X_add_number = ep->X_add_number;
       ep->X_add_number = 0;
       frag_grow (20);
@@ -1619,7 +1642,18 @@ load_address (counter, reg, ep)
                       mips_isa < 3 ? "addiu" : "daddiu",
                       "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)
+        */
+      macro_build ((char *) NULL, counter, ep,
+                  mips_isa < 3 ? "addiu" : "daddiu",
+                  "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
+    }
+  else
+    abort ();
 }
 
 /*
@@ -2292,8 +2326,8 @@ macro (ip)
       return;
 
     case M_LA_AB:
-      /* Load the address of a symbol into a register.  If M_LA_AB, we
-        then add a base register to it.  */
+      /* Load the address of a symbol into a register.  If breg is not
+        zero, we then add a base register to it.  */
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
@@ -2314,7 +2348,7 @@ macro (ip)
 
       if (offset_expr.X_op == O_constant)
        load_register (&icnt, tempreg, &offset_expr);
-      else if (mips_pic == 0)
+      else if (mips_pic == NO_PIC)
        {
          /* If this is a reference to an GP relative symbol, we want
               addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
@@ -2344,7 +2378,7 @@ macro (ip)
                       mips_isa < 3 ? "addiu" : "daddiu",
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
        }
-      else
+      else if (mips_pic == SVR4_PIC)
        {
          /* If this is a reference to an external symbol, and there
             is no constant, we want
@@ -2464,6 +2498,17 @@ macro (ip)
              used_at = 1;
            }
        }
+      else if (mips_pic == EMBEDDED_PIC)
+       {
+         /* We use
+              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
+            */
+         macro_build ((char *) NULL, &icnt, &offset_expr,
+                      mips_isa < 3 ? "addiu" : "daddiu",
+                      "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
+       }
+      else
+       abort ();
 
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -2479,7 +2524,7 @@ macro (ip)
       /* The j instruction may not be used in PIC code, since it
         requires an absolute address.  We convert it to a b
         instruction.  */
-      if (mips_pic == 0)
+      if (mips_pic == NO_PIC)
        macro_build ((char *) NULL, &icnt, &offset_expr, "j", "a");
       else
        macro_build ((char *) NULL, &icnt, &offset_expr, "b", "p");
@@ -2492,83 +2537,86 @@ macro (ip)
       dreg = RA;
       /* Fall through.  */
     case M_JAL_2:
-      if (mips_pic == 0)
-       {
+      if (mips_pic == NO_PIC
+         || mips_pic == EMBEDDED_PIC)
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr",
+                    "d,s", dreg, sreg);
+      else if (mips_pic == SVR4_PIC)
+       {
+         if (sreg != PIC_CALL_REG)
+           as_warn ("MIPS PIC call to register other than $25");
+      
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr",
                       "d,s", dreg, sreg);
-         return;
+         if (mips_cprestore_offset < 0)
+           as_warn ("No .cprestore pseudo-op used in PIC code");
+         else
+           {
+             expr1.X_add_number = mips_cprestore_offset;
+             macro_build ((char *) NULL, &icnt, &expr1,
+                          mips_isa < 3 ? "lw" : "ld",
+                          "t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
+           }
        }
-
-      /* I only know how to handle pic2.  */
-      assert (mips_pic == 2);
-
-      if (sreg != PIC_CALL_REG)
-       as_warn ("MIPS PIC call to register other than $25");
-      
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "d,s",
-                  dreg, sreg);
-      if (mips_cprestore_offset < 0)
-       as_warn ("No .cprestore pseudo-op used in PIC code");
       else
-       {
-         expr1.X_add_number = mips_cprestore_offset;
-         macro_build ((char *) NULL, &icnt, &expr1,
-                      mips_isa < 3 ? "lw" : "ld",
-                      "t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
-       }
+       abort ();
+
       return;
 
     case M_JAL_A:
-      if (mips_pic == 0)
+      if (mips_pic == NO_PIC)
+       macro_build ((char *) NULL, &icnt, &offset_expr, "jal", "a");
+      else if (mips_pic == SVR4_PIC)
        {
-         macro_build ((char *) NULL, &icnt, &offset_expr, "jal", "a");
-         return;
-       }
-
-      /* I only know how to handle pic2.  */
-      assert (mips_pic == 2);
-
-      /* If this is a reference to an external symbol, we want
-          lw           $25,<sym>($gp)          (BFD_RELOC_MIPS_CALL16)
-          nop
-          jalr         $25
-          nop
-          lw           $gp,cprestore($sp)
-        The cprestore value is set using the .cprestore pseudo-op.
-        If the symbol is not external, we want
-          lw           $25,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
-          nop
-          addiu        $25,$25,<sym>           (BFD_RELOC_LO16)
-          jalr         $25
-          nop
-          lw           $gp,cprestore($sp)
-        */
-      frag_grow (20);
-      macro_build ((char *) NULL, &icnt, &offset_expr,
-                  mips_isa < 3 ? "lw" : "ld",
-                  "t,o(b)", PIC_CALL_REG, (int) BFD_RELOC_MIPS_CALL16, GP);
-      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, (long) 0, (char *) NULL);
-      macro_build (p, &icnt, &offset_expr,
-                  mips_isa < 3 ? "addiu" : "daddiu",
-                  "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
-                  (int) BFD_RELOC_LO16);
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "s",
-                  PIC_CALL_REG);
-      if (mips_cprestore_offset < 0)
-       as_warn ("No .cprestore pseudo-op used in PIC code");
-      else
-       {
-         if (mips_noreorder)
-           macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        "nop", "");
-         expr1.X_add_number = mips_cprestore_offset;
-         macro_build ((char *) NULL, &icnt, &expr1,
+         /* If this is a reference to an external symbol, we want
+              lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_CALL16)
+              nop
+              jalr     $25
+              nop
+              lw       $gp,cprestore($sp)
+            The cprestore value is set using the .cprestore
+            pseudo-op.  If the symbol is not external, we want
+              lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
+              nop
+              addiu    $25,$25,<sym>           (BFD_RELOC_LO16)
+              jalr     $25
+              nop
+              lw       $gp,cprestore($sp)
+            */
+         frag_grow (20);
+         macro_build ((char *) NULL, &icnt, &offset_expr,
                       mips_isa < 3 ? "lw" : "ld",
-                      "t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
+                      "t,o(b)", PIC_CALL_REG,
+                      (int) BFD_RELOC_MIPS_CALL16, GP);
+         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, (long) 0, (char *) NULL);
+         macro_build (p, &icnt, &offset_expr,
+                      mips_isa < 3 ? "addiu" : "daddiu",
+                      "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
+                      (int) BFD_RELOC_LO16);
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                      "jalr", "s", PIC_CALL_REG);
+         if (mips_cprestore_offset < 0)
+           as_warn ("No .cprestore pseudo-op used in PIC code");
+         else
+           {
+             if (mips_noreorder)
+               macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                            "nop", "");
+             expr1.X_add_number = mips_cprestore_offset;
+             macro_build ((char *) NULL, &icnt, &expr1,
+                          mips_isa < 3 ? "lw" : "ld",
+                          "t,o(b)", GP, (int) BFD_RELOC_LO16,
+                          mips_frame_reg);
+           }
        }
+      else if (mips_pic == EMBEDDED_PIC)
+       macro_build ((char *) NULL, &icnt, &offset_expr, "bal", "p");
+      else
+       abort ();
+
       return;
 
     case M_LB_AB:
@@ -2725,13 +2773,13 @@ macro (ip)
 
       /* A constant expression in PIC code can be handled just as it
         is in non PIC code.  */
-      if (mips_pic == 0
+      if (mips_pic == NO_PIC
          || offset_expr.X_op == O_constant)
        {
          /* 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)
-            Otherwise we want
+            Otherwise, if there is no base register, we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
             If we have a constant, we need two instructions anyhow,
@@ -2798,7 +2846,7 @@ macro (ip)
                           (int) BFD_RELOC_LO16, tempreg);
            }
        }
-      else
+      else if (mips_pic == SVR4_PIC)
        {
          /* If this is a reference to an external symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
@@ -2840,6 +2888,32 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg,
                       (int) BFD_RELOC_LO16, tempreg);
        }
+      else if (mips_pic == EMBEDDED_PIC)
+       {
+         /* If there is no base register, we want
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
+            If there is a base register, we want
+              addu     $tempreg,$breg,$gp
+              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GPREL)
+            */
+         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);
+             used_at = 0;
+           }
+         else
+           {
+             macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                          mips_isa < 3 ? "addu" : "daddu",
+                          "d,v,t", tempreg, breg, GP);
+             macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
+                          treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
+           }
+       }
+      else
+       abort ();
 
       if (! used_at)
        return;
@@ -2852,7 +2926,7 @@ macro (ip)
       return;
 
     case M_LI_SS:
-      if (mips_pic == 0)
+      if (mips_pic == NO_PIC)
        {
          assert (offset_expr.X_op == O_symbol
                  && strcmp (segment_name (S_GET_SEGMENT
@@ -2862,27 +2936,44 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
                       treg, (int) BFD_RELOC_MIPS_LITERAL, GP);
        }
-      else
+      else if (mips_pic == SVR4_PIC
+              || mips_pic == EMBEDDED_PIC)
        {
          assert (imm_expr.X_op == O_constant);
          load_register (&icnt, treg, &imm_expr);
        }
+      else
+       abort ();
+
       return;
 
     case M_LI_D:
-      /* We know that sym is in the .rdata instruction.  First we get
-        the upper 16 bits of the address.  */
-      if (mips_pic == 0)
+      /* We know that sym is in the .rdata section.  First we get the
+        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);
        }
-      else
+      else if (mips_pic == SVR4_PIC)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       mips_isa < 3 ? "lw" : "ld",
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
        }
+      else if (mips_pic == EMBEDDED_PIC)
+       {
+         /* For embedded PIC we pick up the entire address off $gp in
+            a single instruction.  */
+         macro_build ((char *) NULL, &icnt, &offset_expr,
+                      mips_isa < 3 ? "addiu" : "daddiu",
+                      "t,r,j", AT, GP, (int) BFD_RELOC_MIPS_GPREL);
+         offset_expr.X_op = O_constant;
+         offset_expr.X_add_number = 0;
+       }
+      else
+       abort ();
+       
       /* Now we load the register(s).  */
       if (mips_isa >= 3)
        macro_build ((char *) NULL, &icnt, &offset_expr, "ld", "t,o(b)",
@@ -2904,7 +2995,8 @@ macro (ip)
       break;
 
     case M_LI_DD:
-      if (mips_pic == 0)
+      if (mips_pic == NO_PIC
+         || mips_pic == EMBEDDED_PIC)
        {
          /* Load a floating point number from the .lit8 section.  */
          assert (offset_expr.X_op == O_symbol
@@ -2922,7 +3014,7 @@ macro (ip)
          r = BFD_RELOC_MIPS_LITERAL;
          goto dob;
        }
-      else
+      else if (mips_pic == SVR4_PIC)
        {
          /* Load the double from the .rdata section.  */
          macro_build ((char *) NULL, &icnt, &offset_expr,
@@ -2938,6 +3030,8 @@ macro (ip)
          r = BFD_RELOC_LO16;
          goto dob;
        }
+      else
+       abort ();
 
     case M_L_DOB:
       /* Even on a big endian machine $fn comes before $fn+1.  We have
@@ -3028,7 +3122,7 @@ macro (ip)
       if (byte_order == LITTLE_ENDIAN)
        coproc = 0;
 
-      if (mips_pic == 0
+      if (mips_pic == NO_PIC
          || offset_expr.X_op == O_constant)
        {
          /* If this is a reference to a GP relative symbol, we want
@@ -3118,7 +3212,7 @@ macro (ip)
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
        }         
-      else
+      else if (mips_pic == SVR4_PIC)
        {
          int off;
 
@@ -3166,6 +3260,40 @@ macro (ip)
                           offset_expr.X_add_symbol, (long) 0,
                           (char *) NULL);
        }
+      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)
+            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)
+            */
+         if (breg == 0)
+           {
+             tempreg = GP;
+             used_at = 0;
+           }
+         else
+           {
+             macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                          mips_isa < 3 ? "addu" : "daddu",
+                          "d,v,t", AT, breg, GP);
+             tempreg = AT;
+             used_at = 1;
+           }
+
+         macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
+                      coproc ? treg + 1 : treg,
+                      (int) BFD_RELOC_MIPS_GPREL, tempreg);
+         offset_expr.X_add_number += 4;
+         macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
+                      coproc ? treg : treg + 1,
+                      (int) BFD_RELOC_MIPS_GPREL, tempreg);
+       }
+      else
+       abort ();
 
       if (! used_at)
        return;
@@ -4242,9 +4370,15 @@ mips_ip (str, ip)
                    f -- immediate value
                    l -- .lit4
 
-                   When generating PIC code, we do not use the .lit8
-                   or .lit4 sections at all, in order to reserve the
-                   entire global offset table.  */
+                   When generating SVR4 PIC code, we do not use the
+                   .lit8 or .lit4 sections at all, in order to
+                   reserve the entire global offset table.  When
+                   generating embedded PIC code, we use the .lit8
+                   section but not the .lit4 section (we can do .lit4
+                   inline easily; we need to put .lit8 somewhere in
+                   the data segment, and using .lit8 permits the
+                   linker to eventually combine identical .lit8
+                   entries).  */
 
                f64 = *args == 'F' || *args == 'L';
 
@@ -4264,7 +4398,7 @@ mips_ip (str, ip)
                assert (length == (f64 ? 8 : 4));
 
                if (*args == 'f'
-                   || (mips_pic != 0 && *args == 'l'))
+                   || (mips_pic != NO_PIC && *args == 'l'))
                  {
                    imm_expr.X_op = O_constant;
                    if (byte_order == LITTLE_ENDIAN)
@@ -4292,13 +4426,13 @@ mips_ip (str, ip)
                      {
                      default: /* unused default case avoids warnings.  */
                      case 'L':
-                       newname = (mips_pic == 0 ? ".lit8" : ".rdata");
+                       newname = (mips_pic != SVR4_PIC ? ".lit8" : ".rdata");
                        break;
                      case 'F':
                        newname = ".rdata";
                        break;
                      case 'l':
-                       assert (mips_pic == 0);
+                       assert (mips_pic == NO_PIC);
                        newname = ".lit4";
                        break;
                      }
@@ -4359,15 +4493,28 @@ mips_ip (str, ip)
                }
              else
                {
+                 int more;
+                 offsetT max;
+
                  /* The upper bound should be 0x8000, but
                     unfortunately the MIPS assembler accepts numbers
                     from 0x8000 to 0xffff and sign extends them, and
-                    we want to be compatible.  */
+                    we want to be compatible.  We only permit this
+                    extended range for an instruction which does not
+                    provide any further alternates, since those
+                    alternates may handle other cases.  People should
+                    use the numbers they mean, rather than relying on
+                    a mysterious sign extension.  */
+                 more = (insn + 1 < &mips_opcodes[NUMOPCODES] &&
+                         strcmp (insn->name, insn[1].name) == 0);
+                 if (more)
+                   max = 0x8000;
+                 else
+                   max = 0x10000;
                  if (imm_expr.X_add_number < -0x8000 ||
-                     imm_expr.X_add_number >= 0x10000)
+                     imm_expr.X_add_number >= max)
                    {
-                     if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
-                         !strcmp (insn->name, insn[1].name))
+                     if (more)
                        break;
                      as_bad ("16 bit expression not in range -32768..32767");
                    }
@@ -4766,11 +4913,43 @@ md_parse_option (argP, cntP, vecP)
       return 1;
     }
 
+  /* Argument -membedded-pic means to use EMBEDDED_PIC.  */
+  if (strcmp (*argP, "membedded-pic") == 0)
+    {
+      mips_pic = EMBEDDED_PIC;
+      *argP = "";
+      return 1;
+    }
+
+#ifdef OBJ_ELF
+  /* When generating ELF code, we permit -KPIC and -call_shared to
+     select SVR4_PIC, and -non_shared to select no PIC.  This is
+     intended to be compatible with Irix 5.  */
+  if (strcmp (*argP, "KPIC") == 0
+      || strcmp (*argP, "call_shared") == 0)
+    {
+      mips_pic = SVR4_PIC;
+      if (g_switch_seen && g_switch_value != 0)
+       as_warn ("-G may not be used with SVR4 PIC code");
+      g_switch_value = 0;
+      bfd_set_gp_size (stdoutput, 0);
+      *argP = "";
+      return 1;
+    }
+  else if (strcmp (*argP, "non_shared") == 0)
+    {
+      mips_pic = NO_PIC;
+      *argP = "";
+      return 1;
+    }
+#endif /* OBJ_ELF */
 
 #ifdef GPOPT
   if (**argP == 'G')
     {
-      if ((*argP)[1] != '\0')
+      if (mips_pic == SVR4_PIC)
+       as_warn ("-G may not be used with SVR4 PIC code");
+      else if ((*argP)[1] != '\0')
        g_switch_value = atoi (*argP + 1);
       else if (*cntP)
        {
@@ -5241,14 +5420,20 @@ s_option (x)
     }
   else if (strncmp (opt, "pic", 3) == 0)
     {
-      mips_pic = atoi (opt + 3);
-      /* Supposedly no other values are used.  */
-      assert (mips_pic == 0 || mips_pic == 2);
+      int i;
 
-      if (mips_pic == 2)
+      i = atoi (opt + 3);
+      if (i == 0)
+       mips_pic = NO_PIC;
+      else if (i == 2)
+       mips_pic = SVR4_PIC;
+      else
+       as_bad (".option pic%d not supported", i);
+
+      if (mips_pic == SVR4_PIC)
        {
          if (g_switch_seen && g_switch_value != 0)
-           as_warn ("-G may not be used with PIC code");
+           as_warn ("-G may not be used with SVR4 PIC code");
          g_switch_value = 0;
          bfd_set_gp_size (stdoutput, 0);
        }
@@ -5361,7 +5546,11 @@ static void
 s_abicalls (ignore)
      int ignore;
 {
-  mips_pic = 2;
+  mips_pic = SVR4_PIC;
+  if (g_switch_seen && g_switch_value != 0)
+    as_warn ("-G may not be used with SVR4 PIC code");
+  g_switch_value = 0;
+  bfd_set_gp_size (stdoutput, 0);
   demand_empty_rest_of_line ();
 }
 
@@ -5382,8 +5571,8 @@ s_cpload (ignore)
   expressionS ex;
   int icnt = 0;
 
-  /* If we are not generating PIC code, .cpload is ignored.  */
-  if (mips_pic == 0)
+  /* If we are not generating SVR4 PIC code, .cpload is ignored.  */
+  if (mips_pic != SVR4_PIC)
     {
       s_ignore (0);
       return;
@@ -5419,8 +5608,8 @@ s_cprestore (ignore)
   expressionS ex;
   int icnt = 0;
 
-  /* If we are not generating PIC code, .cprestore is ignored.  */
-  if (mips_pic == 0)
+  /* If we are not generating SVR4 PIC code, .cprestore is ignored.  */
+  if (mips_pic != SVR4_PIC)
     {
       s_ignore (0);
       return;
@@ -5452,7 +5641,7 @@ s_gpword (ignore)
   char *p;
 
   /* When not generating PIC code, this is treated as .word.  */
-  if (mips_pic == 0)
+  if (mips_pic == NO_PIC)
     {
       s_cons (2);
       return;
@@ -5491,7 +5680,7 @@ s_cpadd (ignore)
   int reg;
 
   /* This is ignored when not generating SVR4 PIC code.  */
-  if (mips_pic == 0)
+  if (mips_pic == NO_PIC)
     {
       s_ignore (0);
       return;
@@ -5575,7 +5764,7 @@ md_estimate_size_before_relax (fragp, segtype)
 {
   int change;
 
-  if (mips_pic == 0)
+  if (mips_pic == NO_PIC)
     {
 #ifdef GPOPT
       const char *symname;
@@ -5618,7 +5807,7 @@ md_estimate_size_before_relax (fragp, segtype)
       change = 1;
 #endif /* ! defined (GPOPT) */  
     }
-  else
+  else if (mips_pic == SVR4_PIC)
     {
       asection *symsec = fragp->fr_symbol->bsym->section;
 
@@ -5627,6 +5816,8 @@ md_estimate_size_before_relax (fragp, segtype)
                && symsec != &bfd_abs_section
                && ! bfd_is_com_section (symsec));
     }
+  else
+    abort ();
 
   if (change)
     {
@@ -5667,7 +5858,7 @@ tc_gen_reloc (section, fixp)
   if (fixp->fx_pcrel == 0)
     reloc->addend = fixp->fx_addnumber;
   else
-#ifdef OBJ_ELF
+#ifndef OBJ_AOUT
     reloc->addend = 0;
 #else
     reloc->addend = -reloc->address;
@@ -5716,12 +5907,12 @@ tc_gen_reloc (section, fixp)
          reloc3->address += 4;
        }
 
-      if (mips_pic == 0)
+      if (mips_pic == NO_PIC)
        {
          assert (fixp->fx_r_type == BFD_RELOC_MIPS_GPREL);
          fixp->fx_r_type = BFD_RELOC_HI16_S;
        }
-      else
+      else if (mips_pic == SVR4_PIC)
        {
          if (fixp->fx_r_type != BFD_RELOC_MIPS_GOT16)
            {
@@ -5729,9 +5920,20 @@ tc_gen_reloc (section, fixp)
              fixp->fx_r_type = BFD_RELOC_MIPS_GOT16;
            }
        }
+      else
+       abort ();
     }
 
-  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+  /* 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.  */
+#ifdef OBJ_ECOFF
+  if (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
+      && mips_pic != EMBEDDED_PIC)
+    reloc->howto = NULL;
+  else
+#endif
+    reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
 
   if (reloc->howto == NULL)
     {
@@ -5803,7 +6005,7 @@ mips_elf_final_processing ()
      sort of BFD interface for this.  */
   if (mips_any_noreorder)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NOREORDER;
-  if (mips_pic != 0)
+  if (mips_pic != NO_PIC)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
 }