public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] morello: Add mechanism to prevent over-accessing a bitfield in memory
@ 2022-02-28 12:08 Matthew Malcomson
  0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2022-02-28 12:08 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:120ae017c0f5b24125337dcca67fa885c10a97e3

commit 120ae017c0f5b24125337dcca67fa885c10a97e3
Author: Stam Markianos-Wright <stam.markianos-wright@arm.com>
Date:   Fri Dec 10 16:33:29 2021 +0000

    morello: Add mechanism to prevent over-accessing a bitfield in memory
    
    This patch adds a new mechanism to prevent over-reading when
    accessing a bitfield in memory. This would previously cause a
    Capability Bounds Fault exception to be raised at execution time.
    
    So GCC's internals did already have a mechanism to prevent
    over-writing/over-storing bitfields using the bitregion_end
    and bitregion_start parameters in the store_*_bitfield_*
    functions.
    For loading from memory this mechanism doesn't exit. The
    extract_*_bitfield_* functions all don't even have the
    bitregion_end, bitregion_start parameters and GCC would
    always assume that over-reading is fine.
    
    To resolve this I have extended the extract_* functions so
    that they do take the bitregion_end, bitregion_start
    parameters and can use the same low-level logic (in
    get_best_mode and next_mode) to limit the mode of the memory
    access to prevent over-reading.
    Similarly, further logic is transferred over to become aware
    of these limits.

Diff:
---
 gcc/calls.c    |   6 +--
 gcc/expmed.c   | 121 +++++++++++++++++++++++++++++++++++++++++++++++----------
 gcc/expmed.h   |   3 +-
 gcc/expr.c     |  61 ++++++++++++++++++++++-------
 gcc/function.c |   2 +-
 5 files changed, 154 insertions(+), 39 deletions(-)

diff --git a/gcc/calls.c b/gcc/calls.c
index 36c52447f77..6c38afee29b 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1192,7 +1192,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
 	    int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD);
 
 	    args[i].aligned_regs[j] = reg;
-	    word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX,
+	    word = extract_bit_field (word, bitsize, 0, 1, 0, 0, NULL_RTX,
 				      word_mode, word_mode, false, NULL);
 
 	    /* There is no need to restrict this code to loading items
@@ -3130,8 +3130,8 @@ load_register_parameters (struct arg_data *args, int num_actuals,
 		  rtx dest = gen_rtx_REG (word_mode, REGNO (reg) + nregs - 1);
 		  unsigned int bitoff = (nregs - 1) * BITS_PER_WORD;
 		  unsigned int bitsize = const_size * BITS_PER_UNIT - bitoff;
-		  rtx x = extract_bit_field (mem, bitsize, bitoff, 1, dest,
-					     word_mode, word_mode, false,
+		  rtx x = extract_bit_field (mem, bitsize, bitoff, 1, 0, 0,
+					     dest, word_mode, word_mode, false,
 					     NULL);
 		  if (BYTES_BIG_ENDIAN)
 		    x = expand_shift (LSHIFT_EXPR, word_mode, x,
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 04d0e14028d..e6cb4cb5600 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -71,18 +71,21 @@ static void store_split_bit_field (rtx, opt_scalar_int_mode,
 				   rtx, scalar_int_mode, bool);
 static rtx extract_integral_bit_field (rtx, opt_scalar_int_mode,
 				       unsigned HOST_WIDE_INT,
-				       unsigned HOST_WIDE_INT, int, rtx,
+				       unsigned HOST_WIDE_INT,
+				       poly_uint64, poly_uint64, int, rtx,
 				       machine_mode, machine_mode, bool, bool);
 static rtx extract_fixed_bit_field (machine_mode, rtx, opt_scalar_int_mode,
 				    unsigned HOST_WIDE_INT,
-				    unsigned HOST_WIDE_INT, rtx, int, bool);
+				    unsigned HOST_WIDE_INT, poly_uint64,
+				    poly_uint64, rtx, int, bool);
 static rtx extract_fixed_bit_field_1 (machine_mode, rtx, scalar_int_mode,
 				      unsigned HOST_WIDE_INT,
 				      unsigned HOST_WIDE_INT, rtx, int, bool);
 static rtx lshift_value (machine_mode, unsigned HOST_WIDE_INT, int);
 static rtx extract_split_bit_field (rtx, opt_scalar_int_mode,
 				    unsigned HOST_WIDE_INT,
-				    unsigned HOST_WIDE_INT, int, bool);
+				    unsigned HOST_WIDE_INT, poly_uint64,
+				    poly_uint64, int, bool);
 static void do_cmp_and_jump (rtx, rtx, enum rtx_code, machine_mode, rtx_code_label *);
 static rtx expand_smod_pow2 (scalar_int_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (scalar_int_mode, rtx, HOST_WIDE_INT);
@@ -975,8 +978,9 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	  rtx value_word
 	    = fieldmode == BLKmode
 	      ? extract_bit_field (value, new_bitsize, wordnum * BITS_PER_WORD,
-				   1, NULL_RTX, word_mode, word_mode, false,
-				   NULL)
+				   1, wordnum * BITS_PER_WORD, bitregion_end,
+				   NULL_RTX, word_mode, word_mode,
+				   false, NULL)
 	      : operand_subword_force (value, wordnum, value_mode);
 
 	  if (!store_bit_field_1 (op0, new_bitsize,
@@ -1421,6 +1425,7 @@ store_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	    part = extract_fixed_bit_field (word_mode, value, value_mode,
 					    thissize,
 					    bitsize - bitsdone - thissize,
+					    bitregion_start, bitregion_end,
 					    NULL_RTX, 1, false);
 	  else
 	    /* The args are chosen so that the last part includes the
@@ -1429,6 +1434,7 @@ store_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	    part = extract_fixed_bit_field (word_mode, value, value_mode,
 					    thissize,
 					    total_bits - bitsize + bitsdone,
+					    bitregion_start, bitregion_end,
 					    NULL_RTX, 1, false);
 	}
       else
@@ -1443,11 +1449,13 @@ store_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	    part = extract_fixed_bit_field (word_mode, value, value_mode,
 					    thissize,
 					    total_bits - bitsdone - thissize,
+					    bitregion_start, bitregion_end,
 					    NULL_RTX, 1, false);
 	  else
 	    part = extract_fixed_bit_field (word_mode, value, value_mode,
-					    thissize, bitsdone, NULL_RTX,
-					    1, false);
+					    thissize, bitsdone,
+					    bitregion_start, bitregion_end,
+					    NULL_RTX, 1, false);
 	}
 
       /* If OP0 is a register, then handle OFFSET here.  */
@@ -1616,6 +1624,7 @@ extract_bit_field_as_subreg (machine_mode mode, rtx op0,
 
 static rtx
 extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
+		     poly_uint64 bitregion_start, poly_uint64 bitregion_end,
 		     int unsignedp, rtx target, machine_mode mode,
 		     machine_mode tmode, bool reverse, bool fallback_p,
 		     rtx *alt_rtl)
@@ -1845,7 +1854,8 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
 
   /* From here on we need to be looking at a fixed-size insertion.  */
   return extract_integral_bit_field (op0, op0_mode, bitsize.to_constant (),
-				     bitnum.to_constant (), unsignedp,
+				     bitnum.to_constant (), bitregion_start,
+				     bitregion_end, unsignedp,
 				     target, mode, tmode, reverse, fallback_p);
 }
 
@@ -1857,7 +1867,9 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
 static rtx
 extract_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 			    unsigned HOST_WIDE_INT bitsize,
-			    unsigned HOST_WIDE_INT bitnum, int unsignedp,
+			    unsigned HOST_WIDE_INT bitnum,
+			    poly_uint64 bitregion_start,
+			    poly_uint64 bitregion_end, int unsignedp,
 			    rtx target, machine_mode mode, machine_mode tmode,
 			    bool reverse, bool fallback_p)
 {
@@ -1909,7 +1921,8 @@ extract_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	  rtx result_part
 	    = extract_bit_field_1 (op0, MIN (BITS_PER_WORD,
 					     bitsize - i * BITS_PER_WORD),
-				   bitnum + bit_offset, 1, target_part,
+				   bitnum + bit_offset, bitregion_start,
+				   bitregion_end, 1, target_part,
 				   mode, word_mode, reverse, fallback_p, NULL);
 
 	  gcc_assert (target_part);
@@ -1958,6 +1971,7 @@ extract_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	  if (!fallback_p)
 	    return NULL_RTX;
 	  target = extract_split_bit_field (op0, op0_mode, bitsize, bitnum,
+					    bitregion_start, bitregion_end,
 					    unsignedp, reverse);
 	  return convert_extracted_bit_field (target, mode, tmode, unsignedp);
 	}
@@ -2009,11 +2023,13 @@ extract_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	 bitfield from that.  */
       unsigned HOST_WIDE_INT bitpos;
       rtx xop0 = adjust_bit_field_mem_for_reg (pattern, op0, bitsize, bitnum,
-					       0, 0, tmode, &bitpos);
+					       bitregion_start, bitregion_end,
+					       tmode, &bitpos);
       if (xop0)
 	{
 	  xop0 = copy_to_reg (xop0);
 	  rtx result = extract_bit_field_1 (xop0, bitsize, bitpos,
+					    bitregion_start, bitregion_end,
 					    unsignedp, target,
 					    mode, tmode, reverse, false, NULL);
 	  if (result)
@@ -2034,7 +2050,8 @@ extract_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
     int_mode = int_mode_for_mode (mode).require ();
 
   target = extract_fixed_bit_field (int_mode, op0, op0_mode, bitsize,
-				    bitnum, target, unsignedp, reverse);
+				    bitnum, bitregion_start, bitregion_end,
+				    target, unsignedp, reverse);
 
   /* Complex values must be reversed piecewise, so we need to undo the global
      reversal, convert to the complex mode and reverse again.  */
@@ -2073,7 +2090,8 @@ extract_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 
 rtx
 extract_bit_field (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
-		   int unsignedp, rtx target, machine_mode mode,
+		   int unsignedp, poly_uint64 bitregion_start,
+		   poly_uint64 bitregion_end, rtx target, machine_mode mode,
 		   machine_mode tmode, bool reverse, rtx *alt_rtl)
 {
   machine_mode mode1;
@@ -2092,7 +2110,7 @@ extract_bit_field (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
       && bitnum.is_constant (&ibitnum)
       && is_a <scalar_int_mode> (mode1, &int_mode)
       && strict_volatile_bitfield_p (str_rtx, ibitsize, ibitnum,
-				     int_mode, 0, 0))
+				     int_mode, bitregion_start, bitregion_end))
     {
       /* Extraction of a full INT_MODE value can be done with a simple load.
 	 We know here that the field can be accessed with one single
@@ -2112,11 +2130,38 @@ extract_bit_field (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
 				      &ibitnum);
       gcc_assert (ibitnum + ibitsize <= GET_MODE_BITSIZE (int_mode));
       str_rtx = copy_to_reg (str_rtx);
-      return extract_bit_field_1 (str_rtx, ibitsize, ibitnum, unsignedp,
+      return extract_bit_field_1 (str_rtx, ibitsize, ibitnum, bitregion_start,
+				  bitregion_end, unsignedp,
 				  target, mode, tmode, reverse, true, alt_rtl);
     }
 
-  return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp,
+  /* If bitregion_start has been set to a value, then we are compiling for a
+     target that limits memory accesses to tight bounds so we must not touch
+     bits outside the bit region.  Adjust the address to start at the beginning of the
+     bit region.  */
+  if (MEM_P (str_rtx) && maybe_ne (bitregion_start, 0U))
+    {
+      scalar_int_mode best_mode;
+      machine_mode addr_mode = VOIDmode;
+
+      poly_uint64 offset = exact_div (bitregion_start, BITS_PER_UNIT);
+      bitnum -= bitregion_start;
+      poly_int64 size = bits_to_bytes_round_up (bitnum + bitsize);
+      bitregion_end -= bitregion_start;
+      bitregion_start = 0;
+      if (bitsize.is_constant (&ibitsize)
+	  && bitnum.is_constant (&ibitnum)
+	  && get_best_mode (ibitsize, ibitnum,
+			    bitregion_start, bitregion_end,
+			    MEM_ALIGN (str_rtx), INT_MAX,
+			    MEM_VOLATILE_P (str_rtx), &best_mode))
+	addr_mode = best_mode;
+      str_rtx = adjust_bitfield_address_size (str_rtx, addr_mode,
+					      offset, size);
+    }
+
+  return extract_bit_field_1 (str_rtx, bitsize, bitnum, bitregion_start,
+			      bitregion_end, unsignedp,
 			      target, mode, tmode, reverse, true, alt_rtl);
 }
 \f
@@ -2135,17 +2180,27 @@ static rtx
 extract_fixed_bit_field (machine_mode tmode, rtx op0,
 			 opt_scalar_int_mode op0_mode,
 			 unsigned HOST_WIDE_INT bitsize,
-			 unsigned HOST_WIDE_INT bitnum, rtx target,
+			 unsigned HOST_WIDE_INT bitnum,
+			 poly_uint64 bitregion_start,
+			 poly_uint64 bitregion_end, rtx target,
 			 int unsignedp, bool reverse)
 {
   scalar_int_mode mode;
   if (MEM_P (op0))
     {
-      if (!get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0),
-			  BITS_PER_WORD, MEM_VOLATILE_P (op0), &mode))
+      unsigned int max_bitsize = BITS_PER_WORD;
+      scalar_int_mode imode;
+      if (op0_mode.exists (&imode) && GET_MODE_BITSIZE (imode) < max_bitsize
+	  && maybe_ne (bitregion_end, 0U))
+	max_bitsize = GET_MODE_BITSIZE (imode);
+
+      if (!get_best_mode (bitsize, bitnum, bitregion_start, bitregion_end,
+			  MEM_ALIGN (op0), max_bitsize, MEM_VOLATILE_P (op0),
+			  &mode))
 	/* The only way this should occur is if the field spans word
 	   boundaries.  */
 	return extract_split_bit_field (op0, op0_mode, bitsize, bitnum,
+					bitregion_start, bitregion_end,
 					unsignedp, reverse);
 
       op0 = narrow_bit_field_mem (op0, mode, bitsize, bitnum, &bitnum);
@@ -2263,7 +2318,10 @@ lshift_value (machine_mode mode, unsigned HOST_WIDE_INT value,
 static rtx
 extract_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 			 unsigned HOST_WIDE_INT bitsize,
-			 unsigned HOST_WIDE_INT bitpos, int unsignedp,
+			 unsigned HOST_WIDE_INT bitpos,
+			 poly_uint64 bitregion_start,
+			 poly_uint64 bitregion_end,
+			 int unsignedp,
 			 bool reverse)
 {
   unsigned int unit;
@@ -2278,6 +2336,13 @@ extract_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
   else
     unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
 
+  /* For capability targets, if OP0 is a memory with a mode,
+     then UNIT must not be larger than OP0's mode as well.
+     Otherwise, extract_fixed_bit_field will call us
+     again, and we will mutually recurse forever.  */
+  if (MEM_P (op0) && op0_mode.exists () && maybe_ne (bitregion_end, 0U))
+    unit = MIN (unit, GET_MODE_BITSIZE (op0_mode.require ()));
+
   while (bitsdone < bitsize)
     {
       unsigned HOST_WIDE_INT thissize;
@@ -2288,6 +2353,19 @@ extract_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
       offset = (bitpos + bitsdone) / unit;
       thispos = (bitpos + bitsdone) % unit;
 
+      /* For capability targets the region of bytes we can read is restricted
+	 by the capability bounds, so we must decrease UNIT close to the end
+	 of the region as needed.  */
+      if (maybe_ne (bitregion_end, 0U)
+	  && unit > BITS_PER_UNIT
+	  && maybe_gt (bitpos + bitsdone - thispos + unit, bitregion_end + 1)
+	  && !REG_P (op0)
+	  && (GET_CODE (op0) != SUBREG || !REG_P (SUBREG_REG (op0))))
+	{
+	  unit = unit / 2;
+	  continue;
+	}
+
       /* THISSIZE must not overrun a word boundary.  Otherwise,
 	 extract_fixed_bit_field will call us again, and we will mutually
 	 recurse forever.  */
@@ -2309,7 +2387,8 @@ extract_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	 OFFSET is in UNITs, and UNIT is in bits.  */
       part = extract_fixed_bit_field (word_mode, op0_piece, op0_piece_mode,
 				      thissize, offset * unit + thispos,
-				      0, 1, reverse);
+				      bitregion_start, bitregion_end,
+				      NULL_RTX, 1, reverse);
       bitsdone += thissize;
 
       /* Shift this part into place for the result.  */
diff --git a/gcc/expmed.h b/gcc/expmed.h
index c10d1182c31..f3c5374a452 100644
--- a/gcc/expmed.h
+++ b/gcc/expmed.h
@@ -740,7 +740,8 @@ extern rtx expand_divmod (int, enum tree_code, machine_mode, rtx, rtx,
 extern void store_bit_field (rtx, poly_uint64, poly_uint64,
 			     poly_uint64, poly_uint64,
 			     machine_mode, rtx, bool);
-extern rtx extract_bit_field (rtx, poly_uint64, poly_uint64, int, rtx,
+extern rtx extract_bit_field (rtx, poly_uint64, poly_uint64, int,
+			      poly_uint64, poly_uint64, rtx,
 			      machine_mode, machine_mode, bool, rtx *);
 extern rtx extract_low_bits (machine_mode, machine_mode, rtx);
 extern rtx expand_mult (machine_mode, rtx, rtx, rtx, int, bool = false);
diff --git a/gcc/expr.c b/gcc/expr.c
index c19e5c560f3..7102fa96cef 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -2288,6 +2288,8 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type,
       poly_int64 bytepos = rtx_to_poly_int64 (XEXP (XVECEXP (dst, 0, i), 1));
       poly_int64 bytelen = GET_MODE_SIZE (mode);
       poly_int64 shift = 0;
+      poly_int64 bitregion_start = 0;
+      poly_int64 bitregion_end = 0;
 
       /* Handle trailing fragments that run over the size of the struct.
 	 It's the target's responsibility to make sure that the fragment
@@ -2308,7 +2310,12 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type,
 	      )
 	    shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
 	  bytelen = ssize - bytepos;
-	  gcc_assert (maybe_gt (bytelen, 0));
+	  if (MEM_P (orig_src)
+	      && CAPABILITY_MODE_P (GET_MODE (XEXP (orig_src, 0))))
+	  {
+	    bitregion_start = bytepos * BITS_PER_UNIT;
+	    bitregion_end = (bytepos + bytelen) * BITS_PER_UNIT - 1;
+	  }
 	}
 
       /* If we won't be loading directly from memory, protect the real source
@@ -2364,8 +2371,9 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type,
 		      && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode)))
 		tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
 					     subpos * BITS_PER_UNIT,
-					     1, NULL_RTX, mode, mode, false,
-					     NULL);
+					     1, bitregion_start, bitregion_end,
+					     NULL_RTX, mode, mode,
+					     false, NULL);
 	    }
 	  else
 	    {
@@ -2375,8 +2383,9 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type,
 	      mem = assign_stack_temp (GET_MODE (src), slen);
 	      emit_move_insn (mem, src);
 	      tmps[i] = extract_bit_field (mem, bytelen * BITS_PER_UNIT,
-					   0, 1, NULL_RTX, mode, mode, false,
-					   NULL);
+					   0, 1, bitregion_start, bitregion_end,
+					   NULL_RTX, mode, mode,
+					   false, NULL);
 	    }
 	}
       /* FIXME: A SIMD parallel will eventually lead to a subreg of a
@@ -2416,8 +2425,9 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type,
 	tmps[i] = src;
       else
 	tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
-				     bytepos * BITS_PER_UNIT, 1, NULL_RTX,
-				     mode, mode, false, NULL);
+				     bytepos * BITS_PER_UNIT, 1,
+				     bitregion_start, bitregion_end,
+				     NULL_RTX, mode, mode, false, NULL);
 
       if (maybe_ne (shift, 0))
 	tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
@@ -2881,7 +2891,7 @@ copy_blkmode_from_reg (rtx target, rtx srcreg, tree type)
 	 bitpos for the destination store (left justified).  */
       store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, 0, 0, copy_mode,
 		       extract_bit_field (src, bitsize,
-					  xbitpos % BITS_PER_WORD, 1,
+					  xbitpos % BITS_PER_WORD, 1, 0, 0,
 					  NULL_RTX, copy_mode, copy_mode,
 					  false, NULL),
 		       false);
@@ -2983,7 +2993,7 @@ copy_blkmode_to_reg (machine_mode mode_in, tree src)
       store_bit_field (dst_word, bitsize, xbitpos % BITS_PER_WORD,
 		       0, 0, word_mode,
 		       extract_bit_field (src_word, bitsize,
-					  bitpos % BITS_PER_WORD, 1,
+					  bitpos % BITS_PER_WORD, 1, 0, 0,
 					  NULL_RTX, word_mode, word_mode,
 					  false, NULL),
 		       false);
@@ -3433,7 +3443,7 @@ read_complex_part (rtx cplx, bool imag_p)
     }
 
   return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0,
-			    true, NULL_RTX, imode, imode, false, NULL);
+			    true, 0, 0, NULL_RTX, imode, imode, false, NULL);
 }
 \f
 /* A subroutine of emit_move_insn_1.  Yet another lowpart generator.
@@ -7380,7 +7390,8 @@ store_field (rtx target, poly_int64 bitsize, poly_int64 bitpos,
       if (GET_MODE (temp) == BLKmode && known_le (bitsize, BITS_PER_WORD))
 	{
 	  temp_mode = smallest_int_mode_for_size (bitsize);
-	  temp = extract_bit_field (temp, bitsize, 0, 1, NULL_RTX, temp_mode,
+	  temp = extract_bit_field (temp, bitsize, 0, 1, bitregion_start,
+				    bitregion_end, NULL_RTX, temp_mode,
 				    temp_mode, false, NULL);
 	}
 
@@ -8697,7 +8708,7 @@ expand_misaligned_mem_ref (rtx temp, machine_mode mode, int unsignedp,
     }
   else if (targetm.slow_unaligned_access (mode, align))
     temp = extract_bit_field (temp, GET_MODE_BITSIZE (mode),
-			      0, unsignedp, target,
+			      0, unsignedp, 0, 0, target,
 			      mode, mode, false, alt_rtl);
   return temp;
 }
@@ -11025,6 +11036,8 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
 				 &unsignedp, &reversep, &volatilep);
 	rtx orig_op0, memloc;
 	bool clear_mem_expr = false;
+      poly_uint64 bitregion_start = 0;
+      poly_uint64 bitregion_end = 0;
 
 	/* If we got back the original object, something is wrong.  Perhaps
 	   we are evaluating an expression too early.  In any event, don't
@@ -11046,6 +11059,24 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
 			      modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
 			      NULL, true);
 
+      /* For capability targets there is a need to limit the memory access to
+	 the bounds of the struct or union.  For bit fields in a struct use
+	 get_bit_range and for other cases fall back to a sensible alternative
+	 based on MEM_SIZE.  This needs to be done here, before
+	 op0 gets modified in a way that increases the MEM_SIZE.  */
+      if (MEM_P (op0) && CAPABILITY_MODE_P (GET_MODE (XEXP (op0, 0)))
+	  && TREE_CODE (exp) == COMPONENT_REF
+	  && DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1))
+	  && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (exp, 1)))
+	get_bit_range (&bitregion_start, &bitregion_end, exp, &bitpos,
+		       &offset);
+      else if (MEM_P (op0) && MEM_SIZE_KNOWN_P (op0)
+	       && CAPABILITY_MODE_P (GET_MODE (XEXP (op0, 0))))
+	{
+	  bitregion_start = force_align_down (bitpos, BITS_PER_UNIT);
+	  bitregion_end = MEM_SIZE (op0) * BITS_PER_UNIT - 1;
+	}
+
 	/* If the field has a mode, we want to access it in the
 	   field's mode, not the computed mode.
 	   If a MEM has VOIDmode (external with incomplete type),
@@ -11194,6 +11225,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
 		&& MEM_ALIGN (op0) >= GET_MODE_ALIGNMENT (mode1))
 	      {
 		op0 = adjust_address (op0, mode1, bytepos);
+		bitregion_start = 0;
+		if (known_ge (bitregion_end, poly_uint64 (bitpos)))
+		  bitregion_end -= bitpos;
 		bitpos = 0;
 	      }
 
@@ -11328,6 +11362,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
 
 	    gcc_checking_assert (known_ge (bitpos, 0));
 	    op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
+				     bitregion_start, bitregion_end,
 				     (modifier == EXPAND_STACK_PARM
 				      ? NULL_RTX : target),
 				     ext_mode, ext_mode, reversep, alt_rtl);
@@ -11566,7 +11601,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
       /* If the output type is a bit-field type, do an extraction.  */
       else if (reduce_bit_field)
 	return extract_bit_field (op0, TYPE_PRECISION (type), 0,
-				  TYPE_UNSIGNED (type), NULL_RTX,
+				  TYPE_UNSIGNED (type), 0, 0, NULL_RTX,
 				  mode, mode, false, NULL);
       /* As a last resort, spill op0 to memory, and reload it in a
 	 different mode.  */
diff --git a/gcc/function.c b/gcc/function.c
index 8fb6a4cfb27..760b038af0e 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -3322,7 +3322,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
       else
 	rtl = parmreg = extract_bit_field (validated_mem,
 			GET_MODE_BITSIZE (promoted_nominal_mode), 0,
-			unsignedp, parmreg,
+			unsignedp, 0, 0, parmreg,
 			promoted_nominal_mode, VOIDmode, false, NULL);
     }
   else


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-02-28 12:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-28 12:08 [gcc(refs/vendors/ARM/heads/morello)] morello: Add mechanism to prevent over-accessing a bitfield in memory Matthew Malcomson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).