* config/tc-mips.c (macro_build_jalr): New Function.
authorThiemo Seufer <ths@networkno.de>
Thu, 30 May 2002 23:32:47 +0000 (23:32 +0000)
committerThiemo Seufer <ths@networkno.de>
Thu, 30 May 2002 23:32:47 +0000 (23:32 +0000)
(md_begin): NewABI uses big GOTs.
(macro_build): Recognize BFD_RELOC_MIPS_GOT_DISP,
BFD_RELOC_MIPS_GOT_PAGE, BFD_RELOC_MIPS_GOT_OFST as valid.
(load_address): Add some NewABI PIC support.
(macro): Likewise.
(md_apply_fix): Special handling for BFD_RELOC_MIPS_JALR.
(tc_gen_reloc): Don't encode NewABI vtables in REL relocations.

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

index 6f3d2bddd8a0812377bae2a9d5ae12dd18ace79c..80a0db7303f2515d9e05c80d2a21d104cccf977f 100644 (file)
@@ -1,3 +1,14 @@
+2002-05-31  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+
+       * config/tc-mips.c (macro_build_jalr): New Function.
+       (md_begin): NewABI uses big GOTs.
+       (macro_build): Recognize BFD_RELOC_MIPS_GOT_DISP,
+       BFD_RELOC_MIPS_GOT_PAGE, BFD_RELOC_MIPS_GOT_OFST as valid.
+       (load_address): Add some NewABI PIC support.
+       (macro): Likewise.
+       (md_apply_fix): Special handling for BFD_RELOC_MIPS_JALR.
+       (tc_gen_reloc): Don't encode NewABI vtables in REL relocations.
+
 2002-05-31  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
 
        * config/tc-mips.c (load_address): Use mips_gp_register instead
index c9ec49709a973e0ad0b212ab034a5787b72b2747..47199f753b550b58b442e0a925c335e4c676d424 100644 (file)
@@ -697,6 +697,7 @@ static void macro_build ();
 static void mips16_macro_build PARAMS ((char *, int *, expressionS *,
                                        const char *, const char *,
                                        va_list));
+static void macro_build_jalr PARAMS ((int, expressionS *));
 static void macro_build_lui PARAMS ((char *place, int *counter,
                                     expressionS * ep, int regnum));
 static void set_at PARAMS ((int *counter, int reg, int unsignedp));
@@ -1255,6 +1256,9 @@ md_begin ()
   mips_opts.gp32 = file_mips_gp32;
   mips_opts.fp32 = file_mips_fp32;
 
+  if (HAVE_NEWABI)
+    mips_big_got = 1;
+
   op_hash = hash_new ();
 
   for (i = 0; i < NUMOPCODES;)
@@ -3014,6 +3018,9 @@ macro_build (place, counter, ep, name, fmt, va_alist)
                  || *r == BFD_RELOC_LO16
                  || *r == BFD_RELOC_MIPS_GOT16
                  || *r == BFD_RELOC_MIPS_CALL16
+                 || *r == BFD_RELOC_MIPS_GOT_DISP
+                 || *r == BFD_RELOC_MIPS_GOT_PAGE
+                 || *r == BFD_RELOC_MIPS_GOT_OFST
                  || *r == BFD_RELOC_MIPS_GOT_LO16
                  || *r == BFD_RELOC_MIPS_CALL_LO16
                  || (ep->X_op == O_subtract
@@ -3202,6 +3209,23 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
   append_insn (place, &insn, ep, r, false);
 }
 
+/*
+ * Generate a "jalr" instruction with a relocation hint to the called
+ * function.  This occurs in NewABI PIC code.
+ */
+static void
+macro_build_jalr (icnt, ep)
+     int icnt;
+     expressionS *ep;
+{
+  if (HAVE_NEWABI)
+    frag_more (0);
+  macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "d,s",
+              RA, PIC_CALL_REG);
+  if (HAVE_NEWABI)
+    fix_new_exp (frag_now, 0, 0, ep, false, BFD_RELOC_MIPS_JALR);
+}
+
 /*
  * Generate a "lui" instruction.
  */
@@ -3815,43 +3839,60 @@ load_address (counter, reg, ep, used_at)
           lw           $reg,<sym>($gp)         (BFD_RELOC_MIPS_GOT16)
           nop
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
+        If we have NewABI, we want
+          lw           $reg,<sym>($gp)         (BFD_RELOC_MIPS_GOT_PAGE)
+          addiu        $reg,$reg,<sym>         (BFD_RELOC_MIPS_GOT_OFST)
         If there is a constant, it must be added in after.  */
       ex.X_add_number = ep->X_add_number;
       ep->X_add_number = 0;
-      if (reg_needs_delay (mips_gp_register))
-       off = 4;
+      if (HAVE_NEWABI)
+       {
+         macro_build ((char *) NULL, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg,
+                      (int) BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
+         macro_build (p, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j",
+                      reg, reg, (int) BFD_RELOC_MIPS_GOT_OFST);
+       }
       else
-       off = 0;
-      frag_grow (32);
-      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, mips_gp_register);
-      macro_build ((char *) NULL, counter, ep,
-                  HAVE_32BIT_ADDRESSES ? "lw" : "ld", "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, 0, NULL);
-      if (off > 0)
-       {
-         /* We need a nop before loading from $gp.  This special
-             check is required because the lui which starts the main
-             instruction stream does not refer to $gp, and so will not
-             insert the nop which may be required.  */
+       {
+         if (reg_needs_delay (mips_gp_register))
+           off = 4;
+         else
+           off = 0;
+         frag_grow (32);
+         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, mips_gp_register);
+         macro_build ((char *) NULL, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                      "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, 0, NULL);
+         if (off > 0)
+           {
+             /* We need a nop before loading from $gp.  This special
+                check is required because the lui which starts the main
+                instruction stream does not refer to $gp, and so will not
+                insert the nop which may be required.  */
+             macro_build (p, counter, (expressionS *) NULL, "nop", "");
+               p += 4;
+           }
+         macro_build (p, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg,
+                      (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
+         p += 4;
          macro_build (p, counter, (expressionS *) NULL, "nop", "");
          p += 4;
+         macro_build (p, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+                      "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
-      macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                  "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16,
-                  mips_gp_register);
-      p += 4;
-      macro_build (p, counter, (expressionS *) NULL, "nop", "");
-      p += 4;
-      macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                  "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)
@@ -4940,7 +4981,32 @@ macro (ip)
               lui      $at,<hiconstant>
               addiu    $at,$at,<loconstant>    (BFD_RELOC_LO16)
               addu     $tempreg,$tempreg,$at
-            */
+
+            For NewABI, we want for data addresses
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_DISP)
+            If tempreg is PIC_CALL_REG pointing to a external symbol, we want
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_CALL16)
+          */
+         if (HAVE_NEWABI)
+           {
+             int reloc_type = (tempreg == PIC_CALL_REG
+                               ? BFD_RELOC_MIPS_CALL16
+                               : BFD_RELOC_MIPS_GOT_DISP);
+
+             macro_build ((char *) NULL, &icnt, &offset_expr,
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                          "t,o(b)", tempreg, reloc_type, mips_gp_register);
+
+             if (breg != 0)
+               macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                            HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
+                            "d,v,t", treg, tempreg, breg);
+
+             if (! used_at)
+               return;
+
+             break;
+           }
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          frag_grow (52);
@@ -5229,65 +5295,78 @@ macro (ip)
               addiu    $25,$25,<sym>           (BFD_RELOC_LO16)
               jalr     $ra,$25
               nop
-              lw $gp,cprestore($sp) */
-         frag_grow (40);
-         if (! mips_big_got)
+              lw $gp,cprestore($sp)
+            For NewABI, we want
+              lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_GOT_DISP)
+              jalr     $ra,$25                 (BFD_RELOC_MIPS_JALR)
+          */
+         if (HAVE_NEWABI)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr,
                           HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                           "t,o(b)", PIC_CALL_REG,
-                          (int) BFD_RELOC_MIPS_CALL16, mips_gp_register);
-             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, 0, NULL);
+                          (int) BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+             macro_build_jalr (icnt, &offset_expr);
            }
          else
            {
-             int gpdel;
-
-             if (reg_needs_delay (mips_gp_register))
-               gpdel = 4;
+             frag_grow (40);
+             if (! mips_big_got)
+               {
+                 macro_build ((char *) NULL, &icnt, &offset_expr,
+                              HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                              "t,o(b)", PIC_CALL_REG,
+                              (int) BFD_RELOC_MIPS_CALL16, mips_gp_register);
+                 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, 0, NULL);
+               }
              else
-               gpdel = 0;
-             macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
-                          PIC_CALL_REG, (int) BFD_RELOC_MIPS_CALL_HI16);
-             macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                          "d,v,t", PIC_CALL_REG, PIC_CALL_REG,
-                          mips_gp_register);
-             macro_build ((char *) NULL, &icnt, &offset_expr,
-                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                          "t,o(b)", PIC_CALL_REG,
-                          (int) BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG);
-             macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          "nop", "");
-             p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
-                           RELAX_ENCODE (16, 12 + gpdel, gpdel, 8 + gpdel,
-                                         0, 0),
-                           offset_expr.X_add_symbol, 0, NULL);
-             if (gpdel > 0)
                {
+                 int gpdel;
+
+                 if (reg_needs_delay (mips_gp_register))
+                   gpdel = 4;
+                 else
+                   gpdel = 0;
+                 macro_build ((char *) NULL, &icnt, &offset_expr, "lui",
+                              "t,u", PIC_CALL_REG,
+                              (int) BFD_RELOC_MIPS_CALL_HI16);
+                 macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
+                              "d,v,t", PIC_CALL_REG, PIC_CALL_REG,
+                              mips_gp_register);
+                 macro_build ((char *) NULL, &icnt, &offset_expr,
+                              HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                              "t,o(b)", PIC_CALL_REG,
+                              (int) BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG);
+                 macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                              "nop", "");
+                 p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
+                               RELAX_ENCODE (16, 12 + gpdel, gpdel,
+                                             8 + gpdel, 0, 0),
+                               offset_expr.X_add_symbol, 0, NULL);
+                 if (gpdel > 0)
+                   {
+                     macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
+                     p += 4;
+                   }
+                 macro_build (p, &icnt, &offset_expr,
+                              HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                              "t,o(b)", PIC_CALL_REG,
+                              (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
+                 p += 4;
                  macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
                  p += 4;
                }
              macro_build (p, &icnt, &offset_expr,
-                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                          "t,o(b)", PIC_CALL_REG,
-                          (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
-             p += 4;
-             macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
-             p += 4;
-           }
-         macro_build (p, &icnt, &offset_expr,
-                      HAVE_32BIT_ADDRESSES ? "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 (! HAVE_NEWABI)
-           {
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+                          "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
+                          (int) BFD_RELOC_LO16);
+             macro_build_jalr (icnt, &offset_expr);
+
              if (mips_cprestore_offset < 0)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
@@ -5782,13 +5861,41 @@ macro (ip)
             <op> instruction.  We don't handle constants larger than
             16 bits, because we have no way to load the upper 16 bits
             (actually, we could handle them for the subset of cases
-            in which we are not using $at).  */
+            in which we are not using $at).
+
+            For NewABI, we want
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
+              addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_MIPS_GOT_OFST)
+              <op>     $treg,0($tempreg)
+          */
          assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
+         if (HAVE_NEWABI)
+           {
+             macro_build ((char *) NULL, &icnt, &offset_expr,
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                          "t,o(b)", tempreg, BFD_RELOC_MIPS_GOT_PAGE,
+                          mips_gp_register);
+             macro_build ((char *) NULL, &icnt, &offset_expr,
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+                          "t,r,j", tempreg, tempreg,
+                          BFD_RELOC_MIPS_GOT_OFST);
+             if (breg != 0)
+               macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                            HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
+                            "d,v,t", tempreg, tempreg, breg);
+             macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg,
+                          (int) BFD_RELOC_LO16, tempreg);
+
+             if (! used_at)
+               return;
+
+             break;
+           }
          if (reg_needs_delay (mips_gp_register))
            gpdel = 4;
          else
@@ -10623,7 +10730,8 @@ md_apply_fix3 (fixP, valP, seg)
          || fixP->fx_r_type == BFD_RELOC_MIPS_REL16
          || fixP->fx_r_type == BFD_RELOC_MIPS_RELGOT
          || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-         || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY);
+         || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+         || fixP->fx_r_type == BFD_RELOC_MIPS_JALR);
 
   value = *valP;
 
@@ -12580,9 +12688,9 @@ tc_gen_reloc (section, fixp)
        abort ();
     }
 
-  /* Since MIPS ELF uses Rel instead of Rela, encode the vtable entry
-     to be used in the relocation's section offset.  */
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+  /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable
+     entry to be used in the relocation's section offset.  */
+  if (! HAVE_NEWABI && fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     {
       reloc->address = reloc->addend;
       reloc->addend = 0;