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).