diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4da1c6227520..9eda3cd36d9a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2018-10-01 Tamar Christina <tamar.christina@arm.com> + + PR target/86486 + * explow.c (anti_adjust_stack_and_probe_stack_clash): Support custom + probe ranges. + * target.def (stack_clash_protection_alloca_probe_range): New. + (stack_clash_protection_final_dynamic_probe): Remove. + * targhooks.h (default_stack_clash_protection_alloca_probe_range) New. + (default_stack_clash_protection_final_dynamic_probe): Remove. + * targhooks.c: Likewise. + * doc/tm.texi.in (TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE): New. + (TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE): Remove. + * doc/tm.texi: Regenerate. + 2018-10-01 Tamar Christina <tamar.christina@arm.com> PR target/86486 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 561bda38899d..b00e4b60bc55 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3450,8 +3450,12 @@ GCC computed the default from the values of the above macros and you will normally not need to override that default. @end defmac -@deftypefn {Target Hook} bool TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE (rtx @var{residual}) -Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero. +@deftypefn {Target Hook} HOST_WIDE_INT TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE (void) +Some targets have an ABI defined interval for which no probing needs to be done. +When a probe does need to be done this same interval is used as the probe distance up when doing stack clash protection for alloca. +On such targets this value can be set to override the default probing up interval. +Define this variable to return nonzero if such a probe range is required or zero otherwise. Defining this hook also requires your functions which make use of alloca to have at least 8 byesof outgoing arguments. If this is not the case the stack will be corrupted. +You need not define this macro if it would always have the value zero. @end deftypefn @need 2000 diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index c509a9b4be66..e2b6f945d298 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -2841,7 +2841,7 @@ GCC computed the default from the values of the above macros and you will normally not need to override that default. @end defmac -@hook TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE +@hook TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE @need 2000 @node Frame Registers diff --git a/gcc/explow.c b/gcc/explow.c index 7d83eb16b6dd..1dabd6ff9aa9 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -1958,10 +1958,21 @@ anti_adjust_stack_and_probe_stack_clash (rtx size) /* We can get here with a constant size on some targets. */ rtx rounded_size, last_addr, residual; - HOST_WIDE_INT probe_interval; + HOST_WIDE_INT probe_interval, probe_range; + bool target_probe_range_p = false; compute_stack_clash_protection_loop_data (&rounded_size, &last_addr, &residual, &probe_interval, size); + /* Get the back-end specific probe ranges. */ + probe_range = targetm.stack_clash_protection_alloca_probe_range (); + target_probe_range_p = probe_range != 0; + gcc_assert (probe_range >= 0); + + /* If no back-end specific range defined, default to the top of the newly + allocated range. */ + if (probe_range == 0) + probe_range = probe_interval - GET_MODE_SIZE (word_mode); + if (rounded_size != CONST0_RTX (Pmode)) { if (CONST_INT_P (rounded_size) @@ -1972,13 +1983,12 @@ anti_adjust_stack_and_probe_stack_clash (rtx size) i += probe_interval) { anti_adjust_stack (GEN_INT (probe_interval)); - /* The prologue does not probe residuals. Thus the offset here to probe just beyond what the prologue had already allocated. */ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, - (probe_interval - - GET_MODE_SIZE (word_mode)))); + probe_range)); + emit_insn (gen_blockage ()); } } @@ -1992,10 +2002,10 @@ anti_adjust_stack_and_probe_stack_clash (rtx size) anti_adjust_stack (GEN_INT (probe_interval)); /* The prologue does not probe residuals. Thus the offset here - to probe just beyond what the prologue had already allocated. */ + to probe just beyond what the prologue had already + allocated. */ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, - (probe_interval - - GET_MODE_SIZE (word_mode)))); + probe_range)); emit_stack_clash_protection_probe_loop_end (loop_lab, end_loop, last_addr, rotate_loop); @@ -2010,48 +2020,55 @@ anti_adjust_stack_and_probe_stack_clash (rtx size) hold live data. Furthermore, we do not want to probe into the red zone. - Go ahead and just guard the probe at *sp on RESIDUAL != 0 at - runtime if RESIDUAL is not a compile time constant. */ - if (!CONST_INT_P (residual)) - { - label = gen_label_rtx (); - emit_cmp_and_jump_insns (residual, CONST0_RTX (GET_MODE (residual)), - EQ, NULL_RTX, Pmode, 1, label); - } + If TARGET_PROBE_RANGE_P then the target has promised it's safe to + probe at offset 0. In which case we no longer have to check for + RESIDUAL == 0. However we still need to probe at the right offset + when RESIDUAL > PROBE_RANGE, in which case we probe at PROBE_RANGE. - rtx x = force_reg (Pmode, plus_constant (Pmode, residual, - -GET_MODE_SIZE (word_mode))); + If !TARGET_PROBE_RANGE_P then go ahead and just guard the probe at *sp + on RESIDUAL != 0 at runtime if RESIDUAL is not a compile time constant. + */ anti_adjust_stack (residual); - emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x)); - emit_insn (gen_blockage ()); + if (!CONST_INT_P (residual)) - emit_label (label); - } - - /* Some targets make optimistic assumptions in their prologues about - how the caller may have probed the stack. Make sure we honor - those assumptions when needed. */ - if (size != CONST0_RTX (Pmode) - && targetm.stack_clash_protection_final_dynamic_probe (residual)) - { - /* SIZE could be zero at runtime and in that case *sp could hold - live data. Furthermore, we don't want to probe into the red - zone. - - Go ahead and just guard the probe at *sp on SIZE != 0 at runtime - if SIZE is not a compile time constant. */ - rtx label = NULL_RTX; - if (!CONST_INT_P (size)) { label = gen_label_rtx (); - emit_cmp_and_jump_insns (size, CONST0_RTX (GET_MODE (size)), - EQ, NULL_RTX, Pmode, 1, label); + rtx_code op = target_probe_range_p ? LT : EQ; + rtx probe_cmp_value = target_probe_range_p + ? gen_rtx_CONST_INT (GET_MODE (residual), probe_range) + : CONST0_RTX (GET_MODE (residual)); + + if (target_probe_range_p) + emit_stack_probe (stack_pointer_rtx); + + emit_cmp_and_jump_insns (residual, probe_cmp_value, + op, NULL_RTX, Pmode, 1, label); } - emit_stack_probe (stack_pointer_rtx); + rtx x = NULL_RTX; + + /* If RESIDUAL isn't a constant and TARGET_PROBE_RANGE_P then we probe up + by the ABI defined safe value. */ + if (!CONST_INT_P (residual) && target_probe_range_p) + x = GEN_INT (probe_range); + /* If RESIDUAL is a constant but smaller than the ABI defined safe value, + we still want to probe up, but the safest amount if a word. */ + else if (target_probe_range_p) + { + if (INTVAL (residual) <= probe_range) + x = GEN_INT (GET_MODE_SIZE (word_mode)); + else + x = GEN_INT (probe_range); + } + else + /* If nothing else, probe at the top of the new allocation. */ + x = plus_constant (Pmode, residual, -GET_MODE_SIZE (word_mode)); + + emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x)); + emit_insn (gen_blockage ()); - if (!CONST_INT_P (size)) - emit_label (label); + if (!CONST_INT_P (residual)) + emit_label (label); } } diff --git a/gcc/target.def b/gcc/target.def index 9e22423d466c..9733edff8139 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5854,10 +5854,17 @@ these registers when the target switches are opposed to them.)", hook_void_void) DEFHOOK -(stack_clash_protection_final_dynamic_probe, - "Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero.", - bool, (rtx residual), - default_stack_clash_protection_final_dynamic_probe) +(stack_clash_protection_alloca_probe_range, + "Some targets have an ABI defined interval for which no probing needs to be done.\n\ +When a probe does need to be done this same interval is used as the probe distance \ +up when doing stack clash protection for alloca.\n\ +On such targets this value can be set to override the default probing up interval.\n\ +Define this variable to return nonzero if such a probe range is required or zero otherwise. \ +Defining this hook also requires your functions which make use of alloca to have at least 8 byes\ +of outgoing arguments. If this is not the case the stack will be corrupted.\n\ +You need not define this macro if it would always have the value zero.", + HOST_WIDE_INT, (void), + default_stack_clash_protection_alloca_probe_range) /* Functions specific to the C family of frontends. */ diff --git a/gcc/targhooks.c b/gcc/targhooks.c index afd56f3ec457..3d8b3b9d69be 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -2310,8 +2310,10 @@ default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED) return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT; } -bool -default_stack_clash_protection_final_dynamic_probe (rtx residual ATTRIBUTE_UNUSED) +/* Default implementation for + TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE. */ +HOST_WIDE_INT +default_stack_clash_protection_alloca_probe_range (void) { return 0; } diff --git a/gcc/targhooks.h b/gcc/targhooks.h index f92ca5ca997d..176c64d23f53 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -277,7 +277,7 @@ extern unsigned int default_min_arithmetic_precision (void); extern enum flt_eval_method default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED); -extern bool default_stack_clash_protection_final_dynamic_probe (rtx); +extern HOST_WIDE_INT default_stack_clash_protection_alloca_probe_range (void); extern void default_select_early_remat_modes (sbitmap); extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *);