This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] MIPS/gas: load/store address overflow on binutils 2.14


Maciej W. Rozycki wrote:
[snip]
> > better done with
> > 
> >   x = ((x & 0xffffffff) ^ 0x80000000) - 0x80000000;
> 
>  Now that's a neat trick I haven't seen before -- I'll have to remember
> it.

It is already used in tc-mips.c, but I didn't notice it. :-)

> Thiemo, I think you could use it here. 

The appended version does so. It gets also rid of the bogus
HAVE_64_BIT_ADDRESS_CONSTANTS define, which was effectively an alias for
HAVE_64_BIT_GPRS, and fixes the generation of constant 64-bit addresses
which are not 32-bit sign extended values. I guess the latter went
unnoticed for so long because kernels are usually built in the 32-bit
compatibility space and userland is PIC code.


Thiemo


2003-09-12  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>

	/gas/ChangeLog
	* config/tc-mips.c (HAVE_64BIT_ADDRESS_CONSTANTS): Remove.
	(macro_build_ldst_constoffset): Sign-extend 32-bit constants. Change
	the function prototype.
	(load_register): Likewise. Simplify the checks for sign-extended
	constants.
	(macro): Likewise. Fix code generation for 64-bit address constants
	outside the 32-bit compatibility space. Adjust
	macro_build_ldst_constoffset calls.
	(s_cprestore): Adjust macro_build_ldst_constoffset call.


--- source-orig/gas/config/tc-mips.c	Wed Jul  2 12:57:09 2003
+++ source/gas/config/tc-mips.c	Fri Sep 12 16:46:53 2003
@@ -293,8 +293,6 @@ static int mips_32bitmode = 0;
         && mips_pic != EMBEDDED_PIC))
 
 #define HAVE_64BIT_ADDRESSES (! HAVE_32BIT_ADDRESSES)
-#define HAVE_64BIT_ADDRESS_CONSTANTS (HAVE_64BIT_ADDRESSES \
-				      || HAVE_64BIT_GPRS)
 
 /* Addresses are loaded in different ways, depending on the address size
    in use.  The n32 ABI Documentation also mandates the use of additions
@@ -3215,10 +3213,15 @@ macro_build_lui (char *place, int *count
    using AT if necessary.  */
 static void
 macro_build_ldst_constoffset (char *place, int *counter, expressionS *ep,
-			      const char *op, int treg, int breg)
+			      const char *op, int treg, int breg, int dbl)
 {
   assert (ep->X_op == O_constant);
 
+  /* Sign-extending 32-bit constants makes their handling easier.  */
+  if (! dbl)
+    ep->X_add_number = (((ep->X_add_number & 0xffffffff) ^ 0x80000000)
+			- 0x80000000);
+
   /* Right now, this routine can only handle signed 32-bit contants.  */
   if (! IS_SEXT_32BIT_NUM(ep->X_add_number))
     as_warn (_("operand overflow"));
@@ -3371,12 +3377,13 @@ load_register (int *counter, int reg, ex
   if (ep->X_op != O_big)
     {
       assert (ep->X_op == O_constant);
-      if (ep->X_add_number < 0x8000
-	  && (ep->X_add_number >= 0
-	      || (ep->X_add_number >= -0x8000
-		  && (! dbl
-		      || ! ep->X_unsigned
-		      || sizeof (ep->X_add_number) > 4))))
+
+      /* Sign-extending 32-bit constants makes their handling easier.  */
+      if (! dbl)
+	ep->X_add_number = (((ep->X_add_number & 0xffffffff) ^ 0x80000000)
+			    - 0x80000000);
+
+      if (IS_SEXT_16BIT_NUM (ep->X_add_number))
 	{
 	  /* We can handle 16 bit signed values with an addiu to
 	     $zero.  No need to ever use daddiu here, since $zero and
@@ -3393,17 +3400,7 @@ load_register (int *counter, int reg, ex
 		       BFD_RELOC_LO16);
 	  return;
 	}
-      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)
-		&& (! dbl
-		    || ! ep->X_unsigned
-		    || sizeof (ep->X_add_number) > 4
-		    || (ep->X_add_number & 0x80000000) == 0))
-	       || ((HAVE_32BIT_GPRS || ! dbl)
-		   && (ep->X_add_number &~ (offsetT) 0xffffffff) == 0)
-	       || (HAVE_32BIT_GPRS
-		   && ! dbl
-		   && ((ep->X_add_number &~ (offsetT) 0xffffffff)
-		       == ~ (offsetT) 0xffffffff)))
+      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)))
 	{
 	  /* 32 bit values require an lui.  */
 	  macro_build (NULL, counter, ep, "lui", "t,u", reg, BFD_RELOC_HI16);
@@ -5440,7 +5437,8 @@ macro (struct mips_cl_insn *ip)
   		  macro_build_ldst_constoffset (NULL, &icnt, &expr1,
 						ADDRESS_LOAD_INSN,
 						mips_gp_register,
-						mips_frame_reg);
+						mips_frame_reg,
+						HAVE_64BIT_ADDRESSES);
 		}
 	    }
 	}
@@ -5591,7 +5589,8 @@ macro (struct mips_cl_insn *ip)
   		  macro_build_ldst_constoffset (NULL, &icnt, &expr1,
 					        ADDRESS_LOAD_INSN,
 						mips_gp_register,
-						mips_frame_reg);
+						mips_frame_reg,
+						HAVE_64BIT_ADDRESSES);
 		}
 	    }
 	}
@@ -5781,6 +5780,15 @@ macro (struct mips_cl_insn *ip)
       else
 	fmt = "t,o(b)";
 
+      /* Sign-extending 32-bit constants makes their handling easier.
+         The HAVE_64BIT_GPRS... part is due to the linux kernel hack
+         described below.  */
+      if ((! HAVE_64BIT_ADDRESSES
+	   && (! HAVE_64BIT_GPRS && offset_expr.X_op == O_constant))
+          && (offset_expr.X_op == O_constant))
+	offset_expr.X_add_number = (((offset_expr.X_add_number & 0xffffffff)
+				     ^ 0x80000000) - 0x80000000);
+
       /* For embedded PIC, we allow loads where the offset is calculated
          by subtracting a symbol in the current segment from an unknown
          symbol, relative to a base register, e.g.:
@@ -5913,10 +5921,12 @@ macro (struct mips_cl_insn *ip)
 	     end up converting the binary to ELF32 for a number of
 	     platforms whose boot loaders don't support ELF64
 	     binaries.  */
-	  if ((offset_expr.X_op != O_constant && HAVE_64BIT_ADDRESSES)
-	      || (offset_expr.X_op == O_constant
-		  && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)
-		  && HAVE_64BIT_ADDRESS_CONSTANTS))
+	  if ((HAVE_64BIT_ADDRESSES
+	       && ! (offset_expr.X_op == O_constant
+		     && IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)))
+	      || (HAVE_64BIT_GPRS
+		  && offset_expr.X_op == O_constant
+		  && ! IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)))
 	    {
 	      p = NULL;
 
@@ -5963,9 +5973,9 @@ macro (struct mips_cl_insn *ip)
 
 	      return;
 	    }
-	  else if (offset_expr.X_op == O_constant
-		   && !HAVE_64BIT_ADDRESS_CONSTANTS
-		   && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
+
+	  if (offset_expr.X_op == O_constant
+	      && ! IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
 	    as_bad (_("load/store address overflow (max 32 bits)"));
 
 	  if (breg == 0)
@@ -12279,7 +12290,7 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED
   ex.X_add_number = mips_cprestore_offset;
 
   macro_build_ldst_constoffset (NULL, &icnt, &ex, ADDRESS_STORE_INSN,
-				mips_gp_register, SP);
+				mips_gp_register, SP, HAVE_64BIT_ADDRESSES);
 
   demand_empty_rest_of_line ();
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]