[PATCH] Handle triple relocations in MIPS gas

Thiemo Seufer ica2_ts@csv.ica.uni-stuttgart.de
Wed Oct 3 18:50:00 GMT 2001


Hi All,

this adds basic handling for the three-in-one relocations of MIPS
ELF64 to gas. No new testcases for this yet, it requires some more
work to actually use this code. More to follow.

Tested for mips64-linux, mips-elf, mips64el-elf.


Thiemo


2001-10-03  Thiemo Seufer  <seufer@csv.ica.uni-stuttgart.de>

	/gas/ChangeLog
	* config/tc-mips.c (prev_insn_reloc_type): Make it an array to hold a
	relocation triple.
	(prev_insn_fixp): Likewise.
	(append_insn): Changed prototype to accept a relocation pointer.
	(imm_reloc): Make it an array.
	(offset_reloc): Likewise.
	(md_assemble): Handle triple relocations.
	(append_insn): Likewise. Add handling for some NewABI relocations.
	(mips_no_prev_insn): Handle triple relocations.
	(macro_build): Likewise. Add handling for some NewABI relocations.
	Move handling for the 'u' case to append_insn().
	(mips16_macro_build): Handle triple relocations.
	(macro_build_lui): Likewise. Don't handle _gp_disp as special symbol
	for NewABI.
	(mips_ip): Handle triple relocations.
	(mips16_ip): Likewise.
	(mips_force_relocation): Force handling of triple relocations
	without symbols for NewABI.
	(md_apply_fix): Add handling for some NewABI relocations.


diff -BurpNX /bigdisk/src/binutils-exclude src-orig/gas/config/tc-mips.c src/gas/config/tc-mips.c
--- src-orig/gas/config/tc-mips.c	Wed Oct  3 01:35:26 2001
+++ src/gas/config/tc-mips.c	Wed Oct  3 21:07:11 2001
@@ -450,10 +450,10 @@ static struct frag *prev_insn_frag;
 static long prev_insn_where;
 
 /* The reloc type for the previous instruction, if any.  */
-static bfd_reloc_code_real_type prev_insn_reloc_type;
+static bfd_reloc_code_real_type prev_insn_reloc_type[3];
 
 /* The reloc for the previous instruction, if any.  */
-static fixS *prev_insn_fixp;
+static fixS *prev_insn_fixp[3];
 
 /* Non-zero if the previous instruction was in a delay slot.  */
 static int prev_insn_is_delay_slot;
@@ -663,7 +663,7 @@ static void mips16_mark_labels PARAMS ((
 static void append_insn PARAMS ((char *place,
 				 struct mips_cl_insn * ip,
 				 expressionS * p,
-				 bfd_reloc_code_real_type r,
+				 bfd_reloc_code_real_type *r,
 				 boolean));
 static void mips_no_prev_insn PARAMS ((int));
 static void mips_emit_delays PARAMS ((boolean));
@@ -887,8 +887,10 @@ static expressionS offset_expr;
 
 /* Relocs associated with imm_expr and offset_expr.  */
 
-static bfd_reloc_code_real_type imm_reloc;
-static bfd_reloc_code_real_type offset_reloc;
+static bfd_reloc_code_real_type imm_reloc[3]
+  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
+static bfd_reloc_code_real_type offset_reloc[3]
+  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
 /* This is set by mips_ip if imm_reloc is an unmatched HI16_S reloc.  */
 
@@ -1290,12 +1292,18 @@ md_assemble (str)
      char *str;
 {
   struct mips_cl_insn insn;
+  bfd_reloc_code_real_type unused_reloc[3]
+    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
   imm_expr.X_op = O_absent;
-  imm_reloc = BFD_RELOC_UNUSED;
   imm_unmatched_hi = false;
   offset_expr.X_op = O_absent;
-  offset_reloc = BFD_RELOC_UNUSED;
+  imm_reloc[0] = BFD_RELOC_UNUSED;
+  imm_reloc[1] = BFD_RELOC_UNUSED;
+  imm_reloc[2] = BFD_RELOC_UNUSED;
+  offset_reloc[0] = BFD_RELOC_UNUSED;
+  offset_reloc[1] = BFD_RELOC_UNUSED;
+  offset_reloc[2] = BFD_RELOC_UNUSED;
 
   if (mips_opts.mips16)
     mips16_ip (str, &insn);
@@ -1327,7 +1335,7 @@ md_assemble (str)
       else if (offset_expr.X_op != O_absent)
 	append_insn ((char *) NULL, &insn, &offset_expr, offset_reloc, false);
       else
-	append_insn ((char *) NULL, &insn, NULL, BFD_RELOC_UNUSED, false);
+	append_insn ((char *) NULL, &insn, NULL, unused_reloc, false);
     }
 }
 
@@ -1479,12 +1487,12 @@ append_insn (place, ip, address_expr, re
      char *place;
      struct mips_cl_insn *ip;
      expressionS *address_expr;
-     bfd_reloc_code_real_type reloc_type;
+     bfd_reloc_code_real_type *reloc_type;
      boolean unmatched_hi;
 {
   register unsigned long prev_pinfo, pinfo;
   char *f;
-  fixS *fixp;
+  fixS *fixp[3];
   int nops = 0;
 
   /* Mark instruction labels in mips16 mode.  */
@@ -1830,16 +1838,16 @@ append_insn (place, ip, address_expr, re
 	}
     }
 
-  if (reloc_type > BFD_RELOC_UNUSED)
+  if (*reloc_type > BFD_RELOC_UNUSED)
     {
       /* We need to set up a variant frag.  */
       assert (mips_opts.mips16 && address_expr != NULL);
       f = frag_var (rs_machine_dependent, 4, 0,
-		    RELAX_MIPS16_ENCODE (reloc_type - BFD_RELOC_UNUSED,
+		    RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED,
 					 mips16_small, mips16_ext,
 					 (prev_pinfo
 					  & INSN_UNCOND_BRANCH_DELAY),
-					 (prev_insn_reloc_type
+					 (*prev_insn_reloc_type
 					  == BFD_RELOC_MIPS16_JMP)),
 		    make_expr_symbol (address_expr), (offsetT) 0,
 		    (char *) NULL);
@@ -1848,7 +1856,7 @@ append_insn (place, ip, address_expr, re
     f = place;
   else if (mips_opts.mips16
 	   && ! ip->use_extend
-	   && reloc_type != BFD_RELOC_MIPS16_JMP)
+	   && *reloc_type != BFD_RELOC_MIPS16_JMP)
     {
       /* Make sure there is enough room to swap this instruction with
          a following jump instruction.  */
@@ -1865,17 +1873,39 @@ append_insn (place, ip, address_expr, re
       f = frag_more (4);
     }
 
-  fixp = NULL;
-  if (address_expr != NULL && reloc_type < BFD_RELOC_UNUSED)
+  fixp[0] = fixp[1] = fixp[2] = NULL;
+  if (address_expr != NULL && *reloc_type < BFD_RELOC_UNUSED)
     {
       if (address_expr->X_op == O_constant)
 	{
-	  switch (reloc_type)
+	  unsigned long tmp;
+
+	  switch (*reloc_type)
 	    {
 	    case BFD_RELOC_32:
 	      ip->insn_opcode |= address_expr->X_add_number;
 	      break;
 
+	    case BFD_RELOC_MIPS_HIGHEST:
+	      tmp = (address_expr->X_add_number + 0x800080008000) >> 16;
+	      tmp >>= 16;
+	      ip->insn_opcode |= (tmp >> 16) & 0xffff;
+	      break;
+
+	    case BFD_RELOC_MIPS_HIGHER:
+	      tmp = (address_expr->X_add_number + 0x80008000) >> 16;
+	      ip->insn_opcode |= (tmp >> 16) & 0xffff;
+	      break;
+
+	    case BFD_RELOC_HI16_S:
+	      ip->insn_opcode |= ((address_expr->X_add_number + 0x8000)
+				  >> 16) & 0xffff;
+	      break;
+
+	    case BFD_RELOC_HI16:
+	      ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
+	      break;
+
 	    case BFD_RELOC_LO16:
 	      ip->insn_opcode |= address_expr->X_add_number & 0xffff;
 	      break;
@@ -1911,34 +1941,122 @@ append_insn (place, ip, address_expr, re
       else
 	{
 	need_reloc:
-	  /* Don't generate a reloc if we are writing into a variant
-	     frag.  */
+	  /* Don't generate a reloc if we are writing into a variant frag.  */
 	  if (place == NULL)
 	    {
-	      fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
-				  address_expr,
-				  (reloc_type == BFD_RELOC_16_PCREL
-				   || reloc_type == BFD_RELOC_16_PCREL_S2),
-				  reloc_type);
+	      fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+				     address_expr,
+				     (*reloc_type == BFD_RELOC_16_PCREL
+				      || *reloc_type == BFD_RELOC_16_PCREL_S2),
+				     reloc_type[0]);
+
+	      /* These relocations can have a addend that won't fit in
+	         4 octets for 64bit assembly.  */
+	      if (HAVE_64BIT_GPRS &&
+		  (*reloc_type == BFD_RELOC_16
+		  || *reloc_type == BFD_RELOC_32
+		  || *reloc_type == BFD_RELOC_MIPS_JMP
+		  || *reloc_type == BFD_RELOC_HI16_S
+		  || *reloc_type == BFD_RELOC_LO16
+		  || *reloc_type == BFD_RELOC_GPREL16
+		  || *reloc_type == BFD_RELOC_MIPS_LITERAL
+		  || *reloc_type == BFD_RELOC_GPREL32
+		  || *reloc_type == BFD_RELOC_64
+		  || *reloc_type == BFD_RELOC_CTOR
+		  || *reloc_type == BFD_RELOC_MIPS_SUB
+		  || *reloc_type == BFD_RELOC_MIPS_HIGHEST
+		  || *reloc_type == BFD_RELOC_MIPS_HIGHER
+		  || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
+		  || *reloc_type == BFD_RELOC_MIPS_REL16
+		  || *reloc_type == BFD_RELOC_MIPS_RELGOT))
+		fixp[0]->fx_no_overflow = 1;
+
 	      if (unmatched_hi)
 		{
 		  struct mips_hi_fixup *hi_fixup;
 
-		  assert (reloc_type == BFD_RELOC_HI16_S);
+		  assert (*reloc_type == BFD_RELOC_HI16_S);
 		  hi_fixup = ((struct mips_hi_fixup *)
 			      xmalloc (sizeof (struct mips_hi_fixup)));
-		  hi_fixup->fixp = fixp;
+		  hi_fixup->fixp = fixp[0];
 		  hi_fixup->seg = now_seg;
 		  hi_fixup->next = mips_hi_fixup_list;
 		  mips_hi_fixup_list = hi_fixup;
 		}
+
+	      if (reloc_type[1] != BFD_RELOC_UNUSED)
+		{
+		  /* FIXME: This symbol can be one of
+		     RSS_UNDEF, RSS_GP, RSS_GP0, RSS_LOC.  */
+		  address_expr->X_op = O_absent;
+		  address_expr->X_add_symbol = 0;
+		  address_expr->X_add_number = 0;
+
+		  fixp[1] = fix_new_exp (frag_now, f - frag_now->fr_literal,
+					 4, address_expr, false,
+					 reloc_type[1]);
+
+		  /* These relocations can have a addend that won't fit in
+		     4 octets for 64bit assembly.  */
+		  if (HAVE_64BIT_GPRS &&
+		      (*reloc_type == BFD_RELOC_16
+		       || *reloc_type == BFD_RELOC_32
+		       || *reloc_type == BFD_RELOC_MIPS_JMP
+		       || *reloc_type == BFD_RELOC_HI16_S
+		       || *reloc_type == BFD_RELOC_LO16
+		       || *reloc_type == BFD_RELOC_GPREL16
+		       || *reloc_type == BFD_RELOC_MIPS_LITERAL
+		       || *reloc_type == BFD_RELOC_GPREL32
+		       || *reloc_type == BFD_RELOC_64
+		       || *reloc_type == BFD_RELOC_CTOR
+		       || *reloc_type == BFD_RELOC_MIPS_SUB
+		       || *reloc_type == BFD_RELOC_MIPS_HIGHEST
+		       || *reloc_type == BFD_RELOC_MIPS_HIGHER
+		       || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
+		       || *reloc_type == BFD_RELOC_MIPS_REL16
+		       || *reloc_type == BFD_RELOC_MIPS_RELGOT))
+		     fixp[1]->fx_no_overflow = 1;
+
+		  if (reloc_type[2] != BFD_RELOC_UNUSED)
+		    {
+		      address_expr->X_op = O_absent;
+		      address_expr->X_add_symbol = 0;
+		      address_expr->X_add_number = 0;
+
+		      fixp[2] = fix_new_exp (frag_now,
+					     f - frag_now->fr_literal, 4,
+					     address_expr, false,
+					     reloc_type[2]);
+
+		      /* These relocations can have a addend that won't fit in
+			 4 octets for 64bit assembly.  */
+		      if (HAVE_64BIT_GPRS &&
+			  (*reloc_type == BFD_RELOC_16
+			   || *reloc_type == BFD_RELOC_32
+			   || *reloc_type == BFD_RELOC_MIPS_JMP
+			   || *reloc_type == BFD_RELOC_HI16_S
+			   || *reloc_type == BFD_RELOC_LO16
+			   || *reloc_type == BFD_RELOC_GPREL16
+			   || *reloc_type == BFD_RELOC_MIPS_LITERAL
+			   || *reloc_type == BFD_RELOC_GPREL32
+			   || *reloc_type == BFD_RELOC_64
+			   || *reloc_type == BFD_RELOC_CTOR
+			   || *reloc_type == BFD_RELOC_MIPS_SUB
+			   || *reloc_type == BFD_RELOC_MIPS_HIGHEST
+			   || *reloc_type == BFD_RELOC_MIPS_HIGHER
+			   || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
+			   || *reloc_type == BFD_RELOC_MIPS_REL16
+			   || *reloc_type == BFD_RELOC_MIPS_RELGOT))
+		       fixp[2]->fx_no_overflow = 1;
+		    }
+		}
 	    }
 	}
     }
 
   if (! mips_opts.mips16)
     md_number_to_chars (f, ip->insn_opcode, 4);
-  else if (reloc_type == BFD_RELOC_MIPS16_JMP)
+  else if (*reloc_type == BFD_RELOC_MIPS16_JMP)
     {
       md_number_to_chars (f, ip->insn_opcode >> 16, 2);
       md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2);
@@ -2222,7 +2340,7 @@ append_insn (place, ip, address_expr, re
 	      /* If the previous instruction had a fixup in mips16
                  mode, we can not swap.  This normally means that the
                  previous instruction was a 4 byte branch anyhow.  */
-	      || (mips_opts.mips16 && prev_insn_fixp)
+	      || (mips_opts.mips16 && prev_insn_fixp[0])
 	      /* If the previous instruction is a sync, sync.l, or
 		 sync.p, we can not swap.  */
 	      || (prev_pinfo & INSN_SYNC))
@@ -2248,15 +2366,35 @@ append_insn (place, ip, address_expr, re
 		  memcpy (temp, prev_f, 4);
 		  memcpy (prev_f, f, 4);
 		  memcpy (f, temp, 4);
-		  if (prev_insn_fixp)
+		  if (prev_insn_fixp[0])
+		    {
+		      prev_insn_fixp[0]->fx_frag = frag_now;
+		      prev_insn_fixp[0]->fx_where = f - frag_now->fr_literal;
+		    }
+		  if (prev_insn_fixp[1])
+		    {
+		      prev_insn_fixp[1]->fx_frag = frag_now;
+		      prev_insn_fixp[1]->fx_where = f - frag_now->fr_literal;
+		    }
+		  if (prev_insn_fixp[2])
+		    {
+		      prev_insn_fixp[2]->fx_frag = frag_now;
+		      prev_insn_fixp[2]->fx_where = f - frag_now->fr_literal;
+		    }
+		  if (fixp[0])
+		    {
+		      fixp[0]->fx_frag = prev_insn_frag;
+		      fixp[0]->fx_where = prev_insn_where;
+		    }
+		  if (fixp[1])
 		    {
-		      prev_insn_fixp->fx_frag = frag_now;
-		      prev_insn_fixp->fx_where = f - frag_now->fr_literal;
+		      fixp[1]->fx_frag = prev_insn_frag;
+		      fixp[1]->fx_where = prev_insn_where;
 		    }
-		  if (fixp)
+		  if (fixp[2])
 		    {
-		      fixp->fx_frag = prev_insn_frag;
-		      fixp->fx_where = prev_insn_where;
+		      fixp[2]->fx_frag = prev_insn_frag;
+		      fixp[2]->fx_where = prev_insn_where;
 		    }
 		}
 	      else
@@ -2264,13 +2402,15 @@ append_insn (place, ip, address_expr, re
 		  char *prev_f;
 		  char temp[2];
 
-		  assert (prev_insn_fixp == NULL);
+		  assert (prev_insn_fixp[0] == NULL);
+		  assert (prev_insn_fixp[1] == NULL);
+		  assert (prev_insn_fixp[2] == NULL);
 		  prev_f = prev_insn_frag->fr_literal + prev_insn_where;
 		  memcpy (temp, prev_f, 2);
 		  memcpy (prev_f, f, 2);
-		  if (reloc_type != BFD_RELOC_MIPS16_JMP)
+		  if (*reloc_type != BFD_RELOC_MIPS16_JMP)
 		    {
-		      assert (reloc_type == BFD_RELOC_UNUSED);
+		      assert (*reloc_type == BFD_RELOC_UNUSED);
 		      memcpy (f, temp, 2);
 		    }
 		  else
@@ -2278,10 +2418,20 @@ append_insn (place, ip, address_expr, re
 		      memcpy (f, f + 2, 2);
 		      memcpy (f + 2, temp, 2);
 		    }
-		  if (fixp)
+		  if (fixp[0])
 		    {
-		      fixp->fx_frag = prev_insn_frag;
-		      fixp->fx_where = prev_insn_where;
+		      fixp[0]->fx_frag = prev_insn_frag;
+		      fixp[0]->fx_where = prev_insn_where;
+		    }
+		  if (fixp[1])
+		    {
+		      fixp[1]->fx_frag = prev_insn_frag;
+		      fixp[1]->fx_where = prev_insn_where;
+		    }
+		  if (fixp[2])
+		    {
+		      fixp[2]->fx_frag = prev_insn_frag;
+		      fixp[2]->fx_where = prev_insn_where;
 		    }
 		}
 
@@ -2299,8 +2449,12 @@ append_insn (place, ip, address_expr, re
 	      prev_insn.insn_mo = &dummy_opcode;
 	    }
 
-	  prev_insn_fixp = NULL;
-	  prev_insn_reloc_type = BFD_RELOC_UNUSED;
+	  prev_insn_fixp[0] = NULL;
+	  prev_insn_fixp[1] = NULL;
+	  prev_insn_fixp[2] = NULL;
+	  prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
+	  prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
+	  prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
 	  prev_insn_extended = 0;
 	}
       else if (pinfo & INSN_COND_BRANCH_LIKELY)
@@ -2313,8 +2467,12 @@ append_insn (place, ip, address_expr, re
 	  /* Update the previous insn information.  */
 	  prev_prev_insn = *ip;
 	  prev_insn.insn_mo = &dummy_opcode;
-	  prev_insn_fixp = NULL;
-	  prev_insn_reloc_type = BFD_RELOC_UNUSED;
+	  prev_insn_fixp[0] = NULL;
+	  prev_insn_fixp[1] = NULL;
+	  prev_insn_fixp[2] = NULL;
+	  prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
+	  prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
+	  prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
 	  prev_insn_extended = 0;
 	}
       else
@@ -2331,11 +2489,15 @@ append_insn (place, ip, address_expr, re
 	     is not in a delay slot.  */
 	  prev_insn_is_delay_slot = 0;
 
-	  prev_insn_fixp = fixp;
-	  prev_insn_reloc_type = reloc_type;
+	  prev_insn_fixp[0] = fixp[0];
+	  prev_insn_fixp[1] = fixp[1];
+	  prev_insn_fixp[2] = fixp[2];
+	  prev_insn_reloc_type[0] = reloc_type[0];
+	  prev_insn_reloc_type[1] = reloc_type[1];
+	  prev_insn_reloc_type[2] = reloc_type[2];
 	  if (mips_opts.mips16)
 	    prev_insn_extended = (ip->use_extend
-				  || reloc_type > BFD_RELOC_UNUSED);
+				  || *reloc_type > BFD_RELOC_UNUSED);
 	}
 
       prev_prev_insn_unreordered = prev_insn_unreordered;
@@ -2351,7 +2513,9 @@ append_insn (place, ip, address_expr, re
          PC relative relocs.  */
       prev_prev_insn = prev_insn;
       prev_insn = *ip;
-      prev_insn_reloc_type = reloc_type;
+      prev_insn_reloc_type[0] = reloc_type[0];
+      prev_insn_reloc_type[1] = reloc_type[1];
+      prev_insn_reloc_type[2] = reloc_type[2];
       prev_prev_insn_unreordered = prev_insn_unreordered;
       prev_insn_unreordered = 1;
     }
@@ -2391,7 +2555,9 @@ mips_no_prev_insn (preserve)
   prev_insn_is_delay_slot = 0;
   prev_insn_unreordered = 0;
   prev_insn_extended = 0;
-  prev_insn_reloc_type = BFD_RELOC_UNUSED;
+  prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
+  prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
+  prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
   prev_prev_insn_unreordered = 0;
   mips_clear_insn_labels ();
 }
@@ -2531,7 +2697,7 @@ macro_build (place, counter, ep, name, f
 #endif
 {
   struct mips_cl_insn insn;
-  bfd_reloc_code_real_type r;
+  bfd_reloc_code_real_type r[3];
   va_list args;
 
 #ifdef USE_STDARG
@@ -2558,7 +2724,9 @@ macro_build (place, counter, ep, name, f
       return;
     }
 
-  r = BFD_RELOC_UNUSED;
+  r[0] = BFD_RELOC_UNUSED;
+  r[1] = BFD_RELOC_UNUSED;
+  r[2] = BFD_RELOC_UNUSED;
   insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
   assert (insn.insn_mo);
   assert (strcmp (name, insn.insn_mo->name) == 0);
@@ -2657,35 +2825,33 @@ macro_build (place, counter, ep, name, f
 	case 'i':
 	case 'j':
 	case 'o':
-	  r = (bfd_reloc_code_real_type) va_arg (args, int);
-	  assert (r == BFD_RELOC_MIPS_GPREL
-		  || r == BFD_RELOC_MIPS_LITERAL
-		  || r == BFD_RELOC_LO16
-		  || r == BFD_RELOC_MIPS_GOT16
-		  || r == BFD_RELOC_MIPS_CALL16
-		  || r == BFD_RELOC_MIPS_GOT_LO16
-		  || r == BFD_RELOC_MIPS_CALL_LO16
+	  *r = (bfd_reloc_code_real_type) va_arg (args, int);
+	  assert (*r == BFD_RELOC_MIPS_GPREL
+		  || *r == BFD_RELOC_MIPS_LITERAL
+		  || *r == BFD_RELOC_MIPS_HIGHER
+		  || *r == BFD_RELOC_HI16_S
+		  || *r == BFD_RELOC_LO16
+		  || *r == BFD_RELOC_MIPS_GOT16
+		  || *r == BFD_RELOC_MIPS_CALL16
+		  || *r == BFD_RELOC_MIPS_GOT_LO16
+		  || *r == BFD_RELOC_MIPS_CALL_LO16
 		  || (ep->X_op == O_subtract
-		      && r == BFD_RELOC_PCREL_LO16));
+		      && *r == BFD_RELOC_PCREL_LO16));
 	  continue;
 
 	case 'u':
-	  r = (bfd_reloc_code_real_type) va_arg (args, int);
+	  *r = (bfd_reloc_code_real_type) va_arg (args, int);
 	  assert (ep != NULL
 		  && (ep->X_op == O_constant
 		      || (ep->X_op == O_symbol
-			  && (r == BFD_RELOC_HI16_S
-			      || r == BFD_RELOC_HI16
-			      || r == BFD_RELOC_MIPS_GOT_HI16
-			      || r == BFD_RELOC_MIPS_CALL_HI16))
+			  && (*r == BFD_RELOC_MIPS_HIGHEST
+			      || *r == BFD_RELOC_HI16_S
+			      || *r == BFD_RELOC_HI16
+			      || *r == BFD_RELOC_GPREL16
+			      || *r == BFD_RELOC_MIPS_GOT_HI16
+			      || *r == BFD_RELOC_MIPS_CALL_HI16))
 		      || (ep->X_op == O_subtract
-			  && r == BFD_RELOC_PCREL_HI16_S)));
-	  if (ep->X_op == O_constant)
-	    {
-	      insn.insn_opcode |= (ep->X_add_number >> 16) & 0xffff;
-	      ep = NULL;
-	      r = BFD_RELOC_UNUSED;
-	    }
+			  && *r == BFD_RELOC_PCREL_HI16_S)));
 	  continue;
 
 	case 'p':
@@ -2704,14 +2870,14 @@ macro_build (place, counter, ep, name, f
 	    }
 	  else
 	    if (mips_pic == EMBEDDED_PIC)
-	      r = BFD_RELOC_16_PCREL_S2;
+	      *r = BFD_RELOC_16_PCREL_S2;
 	    else
-	      r = BFD_RELOC_16_PCREL;
+	      *r = BFD_RELOC_16_PCREL;
 	  continue;
 
 	case 'a':
 	  assert (ep != NULL);
-	  r = BFD_RELOC_MIPS_JMP;
+	  *r = BFD_RELOC_MIPS_JMP;
 	  continue;
 
 	case 'C':
@@ -2724,7 +2890,7 @@ macro_build (place, counter, ep, name, f
       break;
     }
   va_end (args);
-  assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
   append_insn (place, &insn, ep, r, false);
 }
@@ -2739,9 +2905,9 @@ mips16_macro_build (place, counter, ep, 
      va_list args;
 {
   struct mips_cl_insn insn;
-  bfd_reloc_code_real_type r;
+  bfd_reloc_code_real_type r[3]
+    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
-  r = BFD_RELOC_UNUSED;
   insn.insn_mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
   assert (insn.insn_mo);
   assert (strcmp (name, insn.insn_mo->name) == 0);
@@ -2830,14 +2996,14 @@ mips16_macro_build (place, counter, ep, 
 	    assert (ep != NULL);
 
 	    if (ep->X_op != O_constant)
-	      r = BFD_RELOC_UNUSED + c;
+	      *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);
 		ep = NULL;
-		r = BFD_RELOC_UNUSED;
+		*r = BFD_RELOC_UNUSED;
 	      }
 	  }
 	  continue;
@@ -2850,7 +3016,7 @@ mips16_macro_build (place, counter, ep, 
       break;
     }
 
-  assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
   append_insn (place, &insn, ep, r, false);
 }
@@ -2867,7 +3033,8 @@ macro_build_lui (place, counter, ep, reg
 {
   expressionS high_expr;
   struct mips_cl_insn insn;
-  bfd_reloc_code_real_type r;
+  bfd_reloc_code_real_type r[3]
+    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
   CONST char *name = "lui";
   CONST char *fmt = "t,u";
 
@@ -2886,15 +3053,15 @@ macro_build_lui (place, counter, ep, reg
       /* we can compute the instruction now without a relocation entry */
       high_expr.X_add_number = ((high_expr.X_add_number + 0x8000)
 				>> 16) & 0xffff;
-      r = BFD_RELOC_UNUSED;
+      *r = BFD_RELOC_UNUSED;
     }
-  else
+  else if (! HAVE_NEWABI)
     {
       assert (ep->X_op == O_symbol);
       /* _gp_disp is a special case, used from s_cpload.  */
       assert (mips_pic == NO_PIC
 	      || strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0);
-      r = BFD_RELOC_HI16_S;
+      *r = BFD_RELOC_HI16_S;
     }
 
   /*
@@ -2914,7 +3081,7 @@ macro_build_lui (place, counter, ep, reg
   assert (strcmp (fmt, insn.insn_mo->args) == 0);
 
   insn.insn_opcode = insn.insn_mo->match | (regnum << OP_SH_RT);
-  if (r == BFD_RELOC_UNUSED)
+  if (*r == BFD_RELOC_UNUSED)
     {
       insn.insn_opcode |= high_expr.X_add_number;
       append_insn (place, &insn, NULL, r, false);
@@ -7479,7 +7646,7 @@ mips_ip (str, ip)
 
 	    case 'A':
 	      my_getExpression (&offset_expr, s);
-	      imm_reloc = BFD_RELOC_32;
+	      *imm_reloc = BFD_RELOC_32;
 	      s = expr_end;
 	      continue;
 
@@ -7691,7 +7858,7 @@ mips_ip (str, ip)
 
 	    case 'i':		/* 16 bit unsigned immediate */
 	    case 'j':		/* 16 bit signed immediate */
-	      imm_reloc = BFD_RELOC_LO16;
+	      *imm_reloc = BFD_RELOC_LO16;
 	      c = my_getSmallExpression (&imm_expr, s);
 	      if (c != S_EX_NONE)
 		{
@@ -7701,16 +7868,16 @@ mips_ip (str, ip)
 			imm_expr.X_add_number =
 			  (imm_expr.X_add_number >> 16) & 0xffff;
 		      else if (c == S_EX_HIGHEST)
-			  imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+			  *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
 		      else if (c == S_EX_HIGHER)
-			  imm_reloc = BFD_RELOC_MIPS_HIGHER;
+			  *imm_reloc = BFD_RELOC_MIPS_HIGHER;
 		      else if (c == S_EX_HI)
 			{
-			  imm_reloc = BFD_RELOC_HI16_S;
+			  *imm_reloc = BFD_RELOC_HI16_S;
 			  imm_unmatched_hi = true;
 			}
 		      else
-			imm_reloc = BFD_RELOC_HI16;
+			*imm_reloc = BFD_RELOC_HI16;
 		    }
 		  else if (imm_expr.X_op == O_constant)
 		    imm_expr.X_add_number &= 0xffff;
@@ -7801,22 +7968,22 @@ mips_ip (str, ip)
 		  offset_expr.X_add_number =
 		    (offset_expr.X_add_number >> 16) & 0xffff;
 		}
-	      offset_reloc = BFD_RELOC_LO16;
+	      *offset_reloc = BFD_RELOC_LO16;
 	      s = expr_end;
 	      continue;
 
 	    case 'p':		/* pc relative offset */
 	      if (mips_pic == EMBEDDED_PIC)
-		offset_reloc = BFD_RELOC_16_PCREL_S2;
+		*offset_reloc = BFD_RELOC_16_PCREL_S2;
 	      else
-		offset_reloc = BFD_RELOC_16_PCREL;
+		*offset_reloc = BFD_RELOC_16_PCREL;
 	      my_getExpression (&offset_expr, s);
 	      s = expr_end;
 	      continue;
 
 	    case 'u':		/* upper 16 bits */
 	      c = my_getSmallExpression (&imm_expr, s);
-	      imm_reloc = BFD_RELOC_LO16;
+	      *imm_reloc = BFD_RELOC_LO16;
 	      if (c != S_EX_NONE)
 		{
 		  if (c != S_EX_LO)
@@ -7825,14 +7992,14 @@ mips_ip (str, ip)
 			imm_expr.X_add_number =
 			  (imm_expr.X_add_number >> 16) & 0xffff;
 		      else if (c == S_EX_HIGHEST)
-			  imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+			  *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
 		      else if (c == S_EX_HI)
 			{
-			  imm_reloc = BFD_RELOC_HI16_S;
+			  *imm_reloc = BFD_RELOC_HI16_S;
 			  imm_unmatched_hi = true;
 			}
 		      else
-			imm_reloc = BFD_RELOC_HI16;
+			*imm_reloc = BFD_RELOC_HI16;
 		    }
 		  else if (imm_expr.X_op == O_constant)
 		    imm_expr.X_add_number &= 0xffff;
@@ -7847,7 +8014,7 @@ mips_ip (str, ip)
 	    case 'a':		/* 26 bit address */
 	      my_getExpression (&offset_expr, s);
 	      s = expr_end;
-	      offset_reloc = BFD_RELOC_MIPS_JMP;
+	      *offset_reloc = BFD_RELOC_MIPS_JMP;
 	      continue;
 
 	    case 'N':		/* 3 bit branch condition code */
@@ -7990,9 +8157,13 @@ mips16_ip (str, ip)
       ip->insn_opcode = insn->match;
       ip->use_extend = false;
       imm_expr.X_op = O_absent;
-      imm_reloc = BFD_RELOC_UNUSED;
+      imm_reloc[0] = BFD_RELOC_UNUSED;
+      imm_reloc[1] = BFD_RELOC_UNUSED;
+      imm_reloc[2] = BFD_RELOC_UNUSED;
       offset_expr.X_op = O_absent;
-      offset_reloc = BFD_RELOC_UNUSED;
+      offset_reloc[0] = BFD_RELOC_UNUSED;
+      offset_reloc[1] = BFD_RELOC_UNUSED;
+      offset_reloc[2] = BFD_RELOC_UNUSED;
       for (args = insn->args; 1; ++args)
 	{
 	  int c;
@@ -8012,16 +8183,16 @@ mips16_ip (str, ip)
 		{
 		  /* Stuff the immediate value in now, if we can.  */
 		  if (imm_expr.X_op == O_constant
-		      && imm_reloc > BFD_RELOC_UNUSED
+		      && *imm_reloc > BFD_RELOC_UNUSED
 		      && insn->pinfo != INSN_MACRO)
 		    {
 		      mips16_immed ((char *) NULL, 0,
-				    imm_reloc - BFD_RELOC_UNUSED,
+				    *imm_reloc - BFD_RELOC_UNUSED,
 				    imm_expr.X_add_number, true, mips16_small,
 				    mips16_ext, &ip->insn_opcode,
 				    &ip->use_extend, &ip->extend);
 		      imm_expr.X_op = O_absent;
-		      imm_reloc = BFD_RELOC_UNUSED;
+		      *imm_reloc = BFD_RELOC_UNUSED;
 		    }
 
 		  return;
@@ -8246,7 +8417,7 @@ mips16_ip (str, ip)
 		  if (imm_expr.X_op == O_symbol)
 		    {
 		      mips16_ext = true;
-		      imm_reloc = BFD_RELOC_MIPS16_GPREL;
+		      *imm_reloc = BFD_RELOC_MIPS16_GPREL;
 		      s = expr_end;
 		      ip->use_extend = true;
 		      ip->extend = 0;
@@ -8273,7 +8444,7 @@ mips16_ip (str, ip)
 			 explicit extensions correctly.  */
 		      imm_expr.X_op = O_constant;
 		      imm_expr.X_add_number = 0;
-		      imm_reloc = (int) BFD_RELOC_UNUSED + c;
+		      *imm_reloc = (int) BFD_RELOC_UNUSED + c;
 		      continue;
 		    }
 
@@ -8281,7 +8452,7 @@ mips16_ip (str, ip)
 		}
 
 	      /* We need to relax this instruction.  */
-	      imm_reloc = (int) BFD_RELOC_UNUSED + c;
+	      *imm_reloc = (int) BFD_RELOC_UNUSED + c;
 	      s = expr_end;
 	      continue;
 
@@ -8299,7 +8470,7 @@ mips16_ip (str, ip)
 		break;
 
 	      /* We need to relax this instruction.  */
-	      offset_reloc = (int) BFD_RELOC_UNUSED + c;
+	      *offset_reloc = (int) BFD_RELOC_UNUSED + c;
 	      s = expr_end;
 	      continue;
 
@@ -8321,7 +8492,7 @@ mips16_ip (str, ip)
 	    case 'a':		/* 26 bit address */
 	      my_getExpression (&offset_expr, s);
 	      s = expr_end;
-	      offset_reloc = BFD_RELOC_MIPS16_JMP;
+	      *offset_reloc = BFD_RELOC_MIPS16_JMP;
 	      ip->insn_opcode <<= 16;
 	      continue;
 
@@ -9569,7 +9740,10 @@ mips_frob_file ()
 
 /* When generating embedded PIC code we must keep all PC relative
    relocations, in case the linker has to relax a call.  We also need
-   to keep relocations for switch table entries.  */
+   to keep relocations for switch table entries.
+
+   We may have combined relocations without symbols in the N32/N64 ABI.
+   We have to prevent gas from dropping them.  */
 
 int
 mips_force_relocation (fixp)
@@ -9579,6 +9753,13 @@ mips_force_relocation (fixp)
       || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 1;
 
+  if (HAVE_NEWABI
+      && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
+      && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
+	  || fixp->fx_r_type == BFD_RELOC_HI16_S
+	  || fixp->fx_r_type == BFD_RELOC_LO16))
+    return 1;
+
   return (mips_pic == EMBEDDED_PIC
 	  && (fixp->fx_pcrel
 	      || SWITCH_TABLE (fixp)
@@ -9599,7 +9780,21 @@ md_apply_fix (fixP, valueP)
 
   assert (fixP->fx_size == 4
 	  || fixP->fx_r_type == BFD_RELOC_16
+	  || fixP->fx_r_type == BFD_RELOC_32
+	  || fixP->fx_r_type == BFD_RELOC_MIPS_JMP
+	  || fixP->fx_r_type == BFD_RELOC_HI16_S
+	  || fixP->fx_r_type == BFD_RELOC_LO16
+	  || fixP->fx_r_type == BFD_RELOC_GPREL16
+	  || fixP->fx_r_type == BFD_RELOC_MIPS_LITERAL 
+	  || fixP->fx_r_type == BFD_RELOC_GPREL32
 	  || fixP->fx_r_type == BFD_RELOC_64
+	  || fixP->fx_r_type == BFD_RELOC_CTOR
+	  || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+	  || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHEST
+	  || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHER
+	  || fixP->fx_r_type == BFD_RELOC_MIPS_SCN_DISP
+	  || 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);
 



More information about the Binutils mailing list