gas signed overflow fixes

Alan Modra amodra@gmail.com
Thu Dec 12 11:10:00 GMT 2019


	* config/tc-aarch64.c (get_aarch64_insn): Avoid signed overflow.
	* config/tc-metag.c (parse_dalu): Likewise.
	* config/tc-tic4x.c (md_pcrel_from): Likewise.
	* config/tc-tic6x.c (tic6x_output_unwinding): Likewise.
	* config/tc-csky.c (parse_fexp): Use an unsigned char temp buffer.
	Don't use register keyword.  Avoid signed overflow and remove now
	unneccesary char masks.  Formatting.
	* config/tc-ia64.c (operand_match): Don't use shifts to sign extend.
	* config/tc-mep.c (mep_apply_fix): Likewise.
	* config/tc-pru.c (md_apply_fix): Likewise.
	* config/tc-riscv.c (load_const): Likewise.
	* config/tc-nios2.c (md_apply_fix): Likewise.  Don't potentially
	truncate fixup before right shift.  Tidy BFD_RELOC_NIOS2_HIADJ16
	calculation.

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index cd4601682b..8879451440 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -5024,7 +5024,8 @@ get_aarch64_insn (char *buf)
 {
   unsigned char *where = (unsigned char *) buf;
   uint32_t result;
-  result = (where[0] | (where[1] << 8) | (where[2] << 16) | (where[3] << 24));
+  result = ((where[0] | (where[1] << 8) | (where[2] << 16)
+	     | ((uint32_t) where[3] << 24)));
   return result;
 }
 
diff --git a/gas/config/tc-csky.c b/gas/config/tc-csky.c
index 970c72afaf..6fa6ee5dd6 100644
--- a/gas/config/tc-csky.c
+++ b/gas/config/tc-csky.c
@@ -1777,8 +1777,8 @@ static char *
 parse_fexp (char *s, expressionS *e, unsigned char isdouble, uint64_t *dbnum)
 {
   int length;                       /* Number of chars in an object.  */
-  register char const *err = NULL;  /* Error from scanning float literal.  */
-  char temp[8];
+  const char *err = NULL;           /* Error from scanning float literal.  */
+  unsigned char temp[8];
 
   /* input_line_pointer->1st char of a flonum (we hope!).  */
   input_line_pointer = s;
@@ -1788,9 +1788,9 @@ parse_fexp (char *s, expressionS *e, unsigned char isdouble, uint64_t *dbnum)
     input_line_pointer += 2;
 
   if (isdouble)
-    err = md_atof ('d', temp, &length);
+    err = md_atof ('d', (char *) temp, &length);
   else
-    err = md_atof ('f', temp, &length);
+    err = md_atof ('f', (char *) temp, &length);
   know (length <= 8);
   know (err != NULL || length > 0);
 
@@ -1818,41 +1818,42 @@ parse_fexp (char *s, expressionS *e, unsigned char isdouble, uint64_t *dbnum)
     {
       uint32_t fnum;
       if (target_big_endian)
-	fnum = (((temp[0] << 24) & 0xffffffff)
-		| ((temp[1] << 16) & 0xffffff)
-		| ((temp[2] << 8) & 0xffff)
-		| (temp[3] & 0xff));
+	fnum = (((uint32_t) temp[0] << 24)
+		| (temp[1] << 16)
+		| (temp[2] << 8)
+		| temp[3]);
       else
-	fnum = (((temp[3] << 24) & 0xffffffff)
-			   | ((temp[2] << 16) & 0xffffff)
-			   | ((temp[1] << 8) & 0xffff)
-			   | (temp[0] & 0xff));
-      e->X_add_number = fnum;    }
+	fnum = (((uint32_t) temp[3] << 24)
+		| (temp[2] << 16)
+		| (temp[1] << 8)
+		| temp[0]);
+      e->X_add_number = fnum;
+    }
   else
     {
       if (target_big_endian)
 	{
-	  *dbnum = (((temp[0] << 24) & 0xffffffff)
-		    | ((temp[1] << 16) & 0xffffff)
-		    | ((temp[2] << 8) & 0xffff)
-		    | (temp[3] & 0xff));
+	  *dbnum = (((uint32_t) temp[0] << 24)
+		    | (temp[1] << 16)
+		    | (temp[2] << 8)
+		    | temp[3]);
 	  *dbnum <<= 32;
-	  *dbnum |= (((temp[4] << 24) & 0xffffffff)
-		     | ((temp[5] << 16) & 0xffffff)
-		     | ((temp[6] << 8) & 0xffff)
-		     | (temp[7] & 0xff));
+	  *dbnum |= (((uint32_t) temp[4] << 24)
+		     | (temp[5] << 16)
+		     | (temp[6] << 8)
+		     | temp[7]);
 	}
       else
 	{
-	  *dbnum = (((temp[7] << 24) & 0xffffffff)
-		    | ((temp[6] << 16) & 0xffffff)
-		    | ((temp[5] << 8) & 0xffff)
-		    | (temp[4] & 0xff));
+	  *dbnum = (((uint32_t) temp[7] << 24)
+		    | (temp[6] << 16)
+		    | (temp[5] << 8)
+		    | temp[4]);
 	  *dbnum <<= 32;
-	  *dbnum |= (((temp[3] << 24) & 0xffffffff)
-		     | ((temp[2] << 16) & 0xffffff)
-		     | ((temp[1] << 8) & 0xffff)
-		     | (temp[0] & 0xff));
+	  *dbnum |= (((uint32_t) temp[3] << 24)
+		     | (temp[2] << 16)
+		     | (temp[1] << 8)
+		     | temp[0]);
       }
     }
   return input_line_pointer;
diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c
index 0c618e811e..5eb024e92b 100644
--- a/gas/config/tc-ia64.c
+++ b/gas/config/tc-ia64.c
@@ -5839,9 +5839,8 @@ operand_match (const struct ia64_opcode *idesc, int res_index, expressionS *e)
 	  /* Sign-extend 32-bit unsigned numbers, so that the following range
 	     checks will work.  */
 	  val = e->X_add_number;
-	  if (((val & (~(bfd_vma) 0 << 32)) == 0)
-	      && ((val & ((bfd_vma) 1 << 31)) != 0))
-	    val = ((val << 32) >> 32);
+	  if ((val & (~(bfd_vma) 0 << 32)) == 0)
+	    val = (val ^ ((bfd_vma) 1 << 31)) - ((bfd_vma) 1 << 31);
 
 	  /* Check for 0x100000000.  This is valid because
 	     0x100000000-1 is the same as ((uint32_t) -1).  */
@@ -5879,9 +5878,8 @@ operand_match (const struct ia64_opcode *idesc, int res_index, expressionS *e)
 	  /* Sign-extend 32-bit unsigned numbers, so that the following range
 	     checks will work.  */
 	  val = e->X_add_number;
-	  if (((val & (~(bfd_vma) 0 << 32)) == 0)
-	      && ((val & ((bfd_vma) 1 << 31)) != 0))
-	    val = ((val << 32) >> 32);
+	  if ((val & (~(bfd_vma) 0 << 32)) == 0)
+	    val = (val ^ ((bfd_vma) 1 << 31)) - ((bfd_vma) 1 << 31);
 	}
       else
 	val = e->X_add_number;
diff --git a/gas/config/tc-mep.c b/gas/config/tc-mep.c
index c0d48e8354..18e96c8046 100644
--- a/gas/config/tc-mep.c
+++ b/gas/config/tc-mep.c
@@ -1790,7 +1790,7 @@ mep_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     switch (fixP->fx_cgen.opinfo)
       {
       case BFD_RELOC_MEP_LOW16:
-	*valP = ((long)(*valP & 0xffff)) << 16 >> 16;
+	*valP = ((*valP & 0xffff) ^ 0x8000) - 0x8000;
 	break;
       case BFD_RELOC_MEP_HI16U:
 	*valP >>= 16;
diff --git a/gas/config/tc-metag.c b/gas/config/tc-metag.c
index c7bb36d5b9..d056e9adf7 100644
--- a/gas/config/tc-metag.c
+++ b/gas/config/tc-metag.c
@@ -5340,7 +5340,7 @@ parse_dalu (const char *line, metag_insn *insn,
 	      /* Only MOV instructions have a DSP register as a
 		 destination. Set the MOV DSPe.r opcode. The simple
 		 OR'ing is OK because the usual MOV opcode is 0x00.  */
-	      insn->bits = (0x91 << 24);
+	      insn->bits = 0x91u << 24;
 	      du_shift = 0;
 	      l1_shift = 2;
 	      regs_shift[0] = 19;
@@ -5455,7 +5455,7 @@ parse_dalu (const char *line, metag_insn *insn,
 			  du_shift = 0;
 			  l1_shift = 2;
 			  regs_shift[1] = 14;
-			  insn->bits = (0x92 << 24); /* Set opcode.  */
+			  insn->bits = 0x92u << 24; /* Set opcode.  */
 			}
 		    }
 		}
diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c
index ec572a61ce..f1a02001f8 100644
--- a/gas/config/tc-nios2.c
+++ b/gas/config/tc-nios2.c
@@ -1384,7 +1384,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	    nios2_diagnose_overflow (fixup, howto, fixP, value);
 
 	  /* Apply the right shift.  */
-	  fixup = ((signed)fixup) >> howto->rightshift;
+	  fixup = (offsetT) fixup >> howto->rightshift;
 
 	  /* Truncate the fixup to right size.  */
 	  switch (fixP->fx_r_type)
@@ -1396,13 +1396,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	      fixup = fixup & 0xFFFF;
 	      break;
 	    case BFD_RELOC_NIOS2_HIADJ16:
-	      fixup = ((((fixup >> 16) & 0xFFFF) + ((fixup >> 15) & 0x01))
-		       & 0xFFFF);
+	      fixup = ((fixup + 0x8000) >> 16) & 0xFFFF;
 	      break;
 	    default:
 	      {
-		int n = sizeof (fixup) * 8 - howto->bitsize;
-		fixup = (fixup << n) >> n;
+		fixup &= ((valueT) 1 << howto->bitsize) - 1;
 		break;
 	      }
 	    }
diff --git a/gas/config/tc-pru.c b/gas/config/tc-pru.c
index 2e2058c1de..6de9f3ce48 100644
--- a/gas/config/tc-pru.c
+++ b/gas/config/tc-pru.c
@@ -642,7 +642,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   unsigned char *where;
   valueT value = *valP;
-  long n;
 
   /* Assert that the fixup is one we can handle.  */
   gas_assert (fixP != NULL && valP != NULL
@@ -801,11 +800,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	    pru_diagnose_overflow (fixup, howto, fixP, insn);
 
 	  /* Apply the right shift.  */
-	  fixup = ((offsetT)fixup) >> howto->rightshift;
+	  fixup = (offsetT) fixup >> howto->rightshift;
 
 	  /* Truncate the fixup to right size.  */
-	  n = sizeof (fixup) * 8 - howto->bitsize;
-	  fixup = (fixup << n) >> n;
+	  if (howto->bitsize == 0)
+	    fixup = 0;
+	  else
+	    fixup &= ((valueT) 2 << (howto->bitsize - 1)) - 1;
 
 	  /* Fix up the instruction.  Non-contiguous bitfields need
 	     special handling.  */
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 055d80c344..7ec1028b28 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1043,9 +1043,9 @@ static void
 load_const (int reg, expressionS *ep)
 {
   int shift = RISCV_IMM_BITS;
-  bfd_vma upper_imm;
+  bfd_vma upper_imm, sign = (bfd_vma) 1 << (RISCV_IMM_BITS - 1);
   expressionS upper = *ep, lower = *ep;
-  lower.X_add_number = (int32_t) ep->X_add_number << (32-shift) >> (32-shift);
+  lower.X_add_number = ((ep->X_add_number & (sign + sign - 1)) ^ sign) - sign;
   upper.X_add_number -= lower.X_add_number;
 
   if (ep->X_op != O_constant)
diff --git a/gas/config/tc-tic4x.c b/gas/config/tc-tic4x.c
index b5588b9c46..bbbd696e43 100644
--- a/gas/config/tc-tic4x.c
+++ b/gas/config/tc-tic4x.c
@@ -2937,7 +2937,7 @@ md_pcrel_from (fixS *fixP)
   unsigned int op;
 
   buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
-  op = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+  op = ((unsigned) buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
 
   return ((fixP->fx_where + fixP->fx_frag->fr_address) >> 2) +
     tic4x_pc_offset (op);
diff --git a/gas/config/tc-tic6x.c b/gas/config/tc-tic6x.c
index cd12c82dce..6260ecb983 100644
--- a/gas/config/tc-tic6x.c
+++ b/gas/config/tc-tic6x.c
@@ -5060,7 +5060,7 @@ tic6x_output_unwinding (bfd_boolean need_extab)
       if (unwind->personality_index == -1)
 	{
 	  tmp = md_chars_to_number (unwind->frag_start + 4, 4);
-	  tmp |= ((unwind->data_bytes - 8) >> 2) << 24;
+	  tmp |= (valueT) ((unwind->data_bytes - 8) >> 2) << 24;
 	  md_number_to_chars (unwind->frag_start + 4, tmp, 4);
 	}
       else if (unwind->personality_index == 1 || unwind->personality_index == 2)

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list