Blame SOURCES/gcc48-rh1469697-3.patch

8178f7
commit a3e2ba88eb09c1eed2f7ed6e17660b345464bb90
8178f7
Author: law <law@138bc75d-0d04-0410-961f-82ee72b054a4>
8178f7
Date:   Wed Sep 20 05:05:12 2017 +0000
8178f7
8178f7
    2017-09-18  Jeff Law  <law@redhat.com>
8178f7
    
8178f7
            * explow.c: Include "params.h" and "dumpfile.h".
8178f7
            (anti_adjust_stack_and_probe_stack_clash): New function.
8178f7
            (get_stack_check_protect): Likewise.
8178f7
            (compute_stack_clash_protection_loop_data): Likewise.
8178f7
            (emit_stack_clash_protection_loop_start): Likewise.
8178f7
            (emit_stack_clash_protection_loop_end): Likewise.
8178f7
            (allocate_dynamic_stack_space): Use get_stack_check_protect.
8178f7
            Use anti_adjust_stack_and_probe_stack_clash.
8178f7
            * explow.h (compute_stack_clash_protection_loop_data): Prototype.
8178f7
            (emit_stack_clash_protection_loop_start): Likewise.
8178f7
            (emit_stack_clash_protection_loop_end): Likewise.
8178f7
            * rtl.h (get_stack_check_protect): Prototype.
8178f7
            * target.def (stack_clash_protection_final_dynamic_probe): New hook.
8178f7
            * targhooks.c (default_stack_clash_protection_final_dynamic_probe): New.
8178f7
            * targhooks.h (default_stack_clash_protection_final_dynamic_probe):
8178f7
            Prototype.
8178f7
            * doc/tm.texi.in (TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE):
8178f7
            Add @hook.
8178f7
            * doc/tm.texi: Rebuilt.
8178f7
            * config/alpha/alpha.c (alpha_expand_prologue): Likewise.
8178f7
            * config/i386/i386.c (ix86_expand_prologue): Likewise.
8178f7
            * config/ia64/ia64.c (ia64_expand_prologue): Likewise.
8178f7
            * config/mips/mips.c (mips_expand_prologue): Likewise.
8178f7
            * config/rs6000/rs6000.c (rs6000_emit_prologue): Likewise.
8178f7
            * config/sparc/sparc.c (sparc_expand_prologue): Likewise.
8178f7
            (sparc_flat_expand_prologue): Likewise.
8178f7
    
8178f7
            * gcc.dg/stack-check-3.c: New test.
8178f7
    
8178f7
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@252995 138bc75d-0d04-0410-961f-82ee72b054a4
8178f7
8178f7
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
8178f7
index 2874b8454a9..5402f5213d6 100644
8178f7
--- a/gcc/config/alpha/alpha.c
8178f7
+++ b/gcc/config/alpha/alpha.c
8178f7
@@ -7625,7 +7625,7 @@ alpha_expand_prologue (void)
8178f7
 
8178f7
   probed_size = frame_size;
8178f7
   if (flag_stack_check)
8178f7
-    probed_size += STACK_CHECK_PROTECT;
8178f7
+    probed_size += get_stack_check_protect ();
8178f7
 
8178f7
   if (probed_size <= 32768)
8178f7
     {
8178f7
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
8178f7
index e36726ba722..d996fd160e8 100644
8178f7
--- a/gcc/config/i386/i386.c
8178f7
+++ b/gcc/config/i386/i386.c
8178f7
@@ -10544,12 +10544,12 @@ ix86_expand_prologue (void)
8178f7
 	  HOST_WIDE_INT size = allocate;
8178f7
 
8178f7
 	  if (TARGET_64BIT && size >= (HOST_WIDE_INT) 0x80000000)
8178f7
-	    size = 0x80000000 - STACK_CHECK_PROTECT - 1;
8178f7
+	    size = 0x80000000 - get_stack_check_protect () - 1;
8178f7
 
8178f7
 	  if (TARGET_STACK_PROBE)
8178f7
-	    ix86_emit_probe_stack_range (0, size + STACK_CHECK_PROTECT);
8178f7
+	    ix86_emit_probe_stack_range (0, size + get_stack_check_protect ());
8178f7
 	  else
8178f7
-	    ix86_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
8178f7
+	    ix86_emit_probe_stack_range (get_stack_check_protect (), size);
8178f7
 	}
8178f7
     }
8178f7
 
8178f7
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
8178f7
index 50bbad6661c..390983936e8 100644
8178f7
--- a/gcc/config/ia64/ia64.c
8178f7
+++ b/gcc/config/ia64/ia64.c
8178f7
@@ -3435,7 +3435,7 @@ ia64_expand_prologue (void)
8178f7
     current_function_static_stack_size = current_frame_info.total_size;
8178f7
 
8178f7
   if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
8178f7
-    ia64_emit_probe_stack_range (STACK_CHECK_PROTECT,
8178f7
+    ia64_emit_probe_stack_range (get_stack_check_protect (),
8178f7
 				 current_frame_info.total_size,
8178f7
 				 current_frame_info.n_input_regs
8178f7
 				   + current_frame_info.n_local_regs);
8178f7
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
8178f7
index 41c5d6b6b1f..9b7eb678f19 100644
8178f7
--- a/gcc/config/mips/mips.c
8178f7
+++ b/gcc/config/mips/mips.c
8178f7
@@ -10746,7 +10746,7 @@ mips_expand_prologue (void)
8178f7
     current_function_static_stack_size = size;
8178f7
 
8178f7
   if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
8178f7
-    mips_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
8178f7
+    mips_emit_probe_stack_range (get_stack_check_protect (), size);
8178f7
 
8178f7
   /* Save the registers.  Allocate up to MIPS_MAX_FIRST_STACK_STEP
8178f7
      bytes beforehand; this is enough to cover the register save area
8178f7
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
8178f7
index 15583055895..a9052c6becf 100644
8178f7
--- a/gcc/config/rs6000/rs6000.c
8178f7
+++ b/gcc/config/rs6000/rs6000.c
8178f7
@@ -23214,7 +23214,8 @@ rs6000_emit_prologue (void)
8178f7
     current_function_static_stack_size = info->total_size;
8178f7
 
8178f7
   if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && info->total_size)
8178f7
-    rs6000_emit_probe_stack_range (STACK_CHECK_PROTECT, info->total_size);
8178f7
+    rs6000_emit_probe_stack_range (get_stack_check_protect (),
8178f7
+				   info->total_size);
8178f7
 
8178f7
   if (TARGET_FIX_AND_CONTINUE)
8178f7
     {
8178f7
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
8178f7
index e5d326cdf23..e5e93c80261 100644
8178f7
--- a/gcc/config/sparc/sparc.c
8178f7
+++ b/gcc/config/sparc/sparc.c
8178f7
@@ -5431,7 +5431,7 @@ sparc_expand_prologue (void)
8178f7
     current_function_static_stack_size = size;
8178f7
 
8178f7
   if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
8178f7
-    sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
8178f7
+    sparc_emit_probe_stack_range (get_stack_check_protect (), size);
8178f7
 
8178f7
   if (size == 0)
8178f7
     ; /* do nothing.  */
8178f7
@@ -5533,7 +5533,7 @@ sparc_flat_expand_prologue (void)
8178f7
     current_function_static_stack_size = size;
8178f7
 
8178f7
   if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
8178f7
-    sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
8178f7
+    sparc_emit_probe_stack_range (get_stack_check_protect (), size);
8178f7
 
8178f7
   if (sparc_save_local_in_regs_p)
8178f7
     emit_save_or_restore_local_in_regs (stack_pointer_rtx, SPARC_STACK_BIAS,
8178f7
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
8178f7
index 6b18a2724bc..eeef757bf5b 100644
8178f7
--- a/gcc/doc/tm.texi
8178f7
+++ b/gcc/doc/tm.texi
8178f7
@@ -3571,6 +3571,10 @@ GCC computed the default from the values of the above macros and you will
8178f7
 normally not need to override that default.
8178f7
 @end defmac
8178f7
 
8178f7
+@deftypefn {Target Hook} bool TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE (rtx @var{residual})
8178f7
+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.
8178f7
+@end deftypefn
8178f7
+
8178f7
 @need 2000
8178f7
 @node Frame Registers
8178f7
 @subsection Registers That Address the Stack Frame
8178f7
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
8178f7
index 7d0b3c73b2f..6707ca87236 100644
8178f7
--- a/gcc/doc/tm.texi.in
8178f7
+++ b/gcc/doc/tm.texi.in
8178f7
@@ -3539,6 +3539,8 @@ GCC computed the default from the values of the above macros and you will
8178f7
 normally not need to override that default.
8178f7
 @end defmac
8178f7
 
8178f7
+@hook TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE
8178f7
+
8178f7
 @need 2000
8178f7
 @node Frame Registers
8178f7
 @subsection Registers That Address the Stack Frame
8178f7
diff --git a/gcc/explow.c b/gcc/explow.c
8178f7
index 7da8bc75f19..2526e8513b7 100644
8178f7
--- a/gcc/explow.c
8178f7
+++ b/gcc/explow.c
8178f7
@@ -40,8 +40,11 @@ along with GCC; see the file COPYING3.  If not see
8178f7
 #include "target.h"
8178f7
 #include "common/common-target.h"
8178f7
 #include "output.h"
8178f7
+#include "params.h"
8178f7
+#include "dumpfile.h"
8178f7
 
8178f7
 static rtx break_out_memory_refs (rtx);
8178f7
+static void anti_adjust_stack_and_probe_stack_clash (rtx);
8178f7
 
8178f7
 
8178f7
 /* Truncate and perhaps sign-extend C as appropriate for MODE.  */
8178f7
@@ -1140,6 +1143,29 @@ update_nonlocal_goto_save_area (void)
8178f7
   emit_stack_save (SAVE_NONLOCAL, &r_save);
8178f7
 }
8178f7
 
8178f7
+/* Return the number of bytes to "protect" on the stack for -fstack-check.
8178f7
+
8178f7
+   "protect" in the context of -fstack-check means how many bytes we
8178f7
+   should always ensure are available on the stack.  More importantly
8178f7
+   this is how many bytes are skipped when probing the stack.
8178f7
+
8178f7
+   On some targets we want to reuse the -fstack-check prologue support
8178f7
+   to give a degree of protection against stack clashing style attacks.
8178f7
+
8178f7
+   In that scenario we do not want to skip bytes before probing as that
8178f7
+   would render the stack clash protections useless.
8178f7
+
8178f7
+   So we never use STACK_CHECK_PROTECT directly.  Instead we indirect though
8178f7
+   this helper which allows us to provide different values for
8178f7
+   -fstack-check and -fstack-clash-protection.  */
8178f7
+HOST_WIDE_INT
8178f7
+get_stack_check_protect (void)
8178f7
+{
8178f7
+  if (flag_stack_clash_protection)
8178f7
+    return 0;
8178f7
+ return STACK_CHECK_PROTECT;
8178f7
+}
8178f7
+
8178f7
 /* Return an rtx representing the address of an area of memory dynamically
8178f7
    pushed on the stack.
8178f7
 
8178f7
@@ -1393,7 +1419,7 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
8178f7
     probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE,
8178f7
 		       size);
8178f7
   else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
8178f7
-    probe_stack_range (STACK_CHECK_PROTECT, size);
8178f7
+    probe_stack_range (get_stack_check_protect (), size);
8178f7
 
8178f7
   /* Don't let anti_adjust_stack emit notes.  */
8178f7
   suppress_reg_args_size = true;
8178f7
@@ -1451,6 +1477,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
8178f7
 
8178f7
       if (flag_stack_check && STACK_CHECK_MOVING_SP)
8178f7
 	anti_adjust_stack_and_probe (size, false);
8178f7
+      else if (flag_stack_clash_protection)
8178f7
+	anti_adjust_stack_and_probe_stack_clash (size);
8178f7
       else
8178f7
 	anti_adjust_stack (size);
8178f7
 
8178f7
@@ -1712,6 +1740,219 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
8178f7
     }
8178f7
 }
8178f7
 
8178f7
+/* Compute parameters for stack clash probing a dynamic stack
8178f7
+   allocation of SIZE bytes.
8178f7
+
8178f7
+   We compute ROUNDED_SIZE, LAST_ADDR, RESIDUAL and PROBE_INTERVAL.
8178f7
+
8178f7
+   Additionally we conditionally dump the type of probing that will
8178f7
+   be needed given the values computed.  */
8178f7
+
8178f7
+void
8178f7
+compute_stack_clash_protection_loop_data (rtx *rounded_size, rtx *last_addr,
8178f7
+					  rtx *residual,
8178f7
+					  HOST_WIDE_INT *probe_interval,
8178f7
+					  rtx size)
8178f7
+{
8178f7
+  /* Round SIZE down to STACK_CLASH_PROTECTION_PROBE_INTERVAL */
8178f7
+  *probe_interval
8178f7
+    = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
8178f7
+  *rounded_size = simplify_gen_binary (AND, Pmode, size,
8178f7
+				        GEN_INT (-*probe_interval));
8178f7
+
8178f7
+  /* Compute the value of the stack pointer for the last iteration.
8178f7
+     It's just SP + ROUNDED_SIZE.  */
8178f7
+  rtx rounded_size_op = force_operand (*rounded_size, NULL_RTX);
8178f7
+  *last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
8178f7
+					      stack_pointer_rtx,
8178f7
+					      rounded_size_op),
8178f7
+			      NULL_RTX);
8178f7
+
8178f7
+  /* Compute any residuals not allocated by the loop above.  Residuals
8178f7
+     are just the ROUNDED_SIZE - SIZE.  */
8178f7
+  *residual = simplify_gen_binary (MINUS, Pmode, size, *rounded_size);
8178f7
+
8178f7
+  /* Dump key information to make writing tests easy.  */
8178f7
+  if (dump_file)
8178f7
+    {
8178f7
+      if (*rounded_size == CONST0_RTX (Pmode))
8178f7
+	fprintf (dump_file,
8178f7
+		 "Stack clash skipped dynamic allocation and probing loop.\n");
8178f7
+      else if (GET_CODE (*rounded_size) == CONST_INT
8178f7
+	       && INTVAL (*rounded_size) <= 4 * *probe_interval)
8178f7
+	fprintf (dump_file,
8178f7
+		 "Stack clash dynamic allocation and probing inline.\n");
8178f7
+      else if (GET_CODE (*rounded_size) == CONST_INT)
8178f7
+	fprintf (dump_file,
8178f7
+		 "Stack clash dynamic allocation and probing in "
8178f7
+		 "rotated loop.\n");
8178f7
+      else
8178f7
+	fprintf (dump_file,
8178f7
+		 "Stack clash dynamic allocation and probing in loop.\n");
8178f7
+
8178f7
+      if (*residual != CONST0_RTX (Pmode))
8178f7
+	fprintf (dump_file,
8178f7
+		 "Stack clash dynamic allocation and probing residuals.\n");
8178f7
+      else
8178f7
+	fprintf (dump_file,
8178f7
+		 "Stack clash skipped dynamic allocation and "
8178f7
+		 "probing residuals.\n");
8178f7
+    }
8178f7
+}
8178f7
+
8178f7
+/* Emit the start of an allocate/probe loop for stack
8178f7
+   clash protection.
8178f7
+
8178f7
+   LOOP_LAB and END_LAB are returned for use when we emit the
8178f7
+   end of the loop.
8178f7
+
8178f7
+   LAST addr is the value for SP which stops the loop.  */
8178f7
+void
8178f7
+emit_stack_clash_protection_probe_loop_start (rtx *loop_lab,
8178f7
+					      rtx *end_lab,
8178f7
+					      rtx last_addr,
8178f7
+					      bool rotated)
8178f7
+{
8178f7
+  /* Essentially we want to emit any setup code, the top of loop
8178f7
+     label and the comparison at the top of the loop.  */
8178f7
+  *loop_lab = gen_label_rtx ();
8178f7
+  *end_lab = gen_label_rtx ();
8178f7
+
8178f7
+  emit_label (*loop_lab);
8178f7
+  if (!rotated)
8178f7
+    emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX,
8178f7
+			     Pmode, 1, *end_lab);
8178f7
+}
8178f7
+
8178f7
+/* Emit the end of a stack clash probing loop.
8178f7
+
8178f7
+   This consists of just the jump back to LOOP_LAB and
8178f7
+   emitting END_LOOP after the loop.  */
8178f7
+
8178f7
+void
8178f7
+emit_stack_clash_protection_probe_loop_end (rtx loop_lab, rtx end_loop,
8178f7
+					    rtx last_addr, bool rotated)
8178f7
+{
8178f7
+  if (rotated)
8178f7
+    emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, NE, NULL_RTX,
8178f7
+			     Pmode, 1, loop_lab);
8178f7
+  else
8178f7
+    emit_jump (loop_lab);
8178f7
+
8178f7
+  emit_label (end_loop);
8178f7
+
8178f7
+}
8178f7
+
8178f7
+/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
8178f7
+   while probing it.  This pushes when SIZE is positive.  SIZE need not
8178f7
+   be constant.
8178f7
+
8178f7
+   This is subtly different than anti_adjust_stack_and_probe to try and
8178f7
+   prevent stack-clash attacks
8178f7
+
8178f7
+     1. It must assume no knowledge of the probing state, any allocation
8178f7
+	must probe.
8178f7
+
8178f7
+	Consider the case of a 1 byte alloca in a loop.  If the sum of the
8178f7
+	allocations is large, then this could be used to jump the guard if
8178f7
+	probes were not emitted.
8178f7
+
8178f7
+     2. It never skips probes, whereas anti_adjust_stack_and_probe will
8178f7
+	skip probes on the first couple PROBE_INTERVALs on the assumption
8178f7
+	they're done elsewhere.
8178f7
+
8178f7
+     3. It only allocates and probes SIZE bytes, it does not need to
8178f7
+	allocate/probe beyond that because this probing style does not
8178f7
+	guarantee signal handling capability if the guard is hit.  */
8178f7
+
8178f7
+static void
8178f7
+anti_adjust_stack_and_probe_stack_clash (rtx size)
8178f7
+{
8178f7
+  /* First ensure SIZE is Pmode.  */
8178f7
+  if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
8178f7
+    size = convert_to_mode (Pmode, size, 1);
8178f7
+
8178f7
+  /* We can get here with a constant size on some targets.  */
8178f7
+  rtx rounded_size, last_addr, residual;
8178f7
+  HOST_WIDE_INT probe_interval;
8178f7
+  compute_stack_clash_protection_loop_data (&rounded_size, &last_addr,
8178f7
+					    &residual, &probe_interval, size);
8178f7
+
8178f7
+  if (rounded_size != CONST0_RTX (Pmode))
8178f7
+    {
8178f7
+      if (INTVAL (rounded_size) <= 4 * probe_interval)
8178f7
+	{
8178f7
+	  for (HOST_WIDE_INT i = 0;
8178f7
+	       i < INTVAL (rounded_size);
8178f7
+	       i += probe_interval)
8178f7
+	    {
8178f7
+	      anti_adjust_stack (GEN_INT (probe_interval));
8178f7
+
8178f7
+	      /* The prologue does not probe residuals.  Thus the offset
8178f7
+		 here to probe just beyond what the prologue had already
8178f7
+		 allocated.  */
8178f7
+	      emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
8178f7
+					       (probe_interval
8178f7
+						- GET_MODE_SIZE (word_mode))));
8178f7
+	      emit_insn (gen_blockage ());
8178f7
+	    }
8178f7
+	}
8178f7
+      else
8178f7
+	{
8178f7
+	  rtx loop_lab, end_loop;
8178f7
+	  bool rotate_loop = GET_CODE (rounded_size) == CONST_INT;
8178f7
+	  emit_stack_clash_protection_probe_loop_start (&loop_lab, &end_loop,
8178f7
+							last_addr, rotate_loop);
8178f7
+
8178f7
+	  anti_adjust_stack (GEN_INT (probe_interval));
8178f7
+
8178f7
+	  /* The prologue does not probe residuals.  Thus the offset here
8178f7
+	     to probe just beyond what the prologue had already allocated.  */
8178f7
+	  emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
8178f7
+					   (probe_interval
8178f7
+					    - GET_MODE_SIZE (word_mode))));
8178f7
+
8178f7
+	  emit_stack_clash_protection_probe_loop_end (loop_lab, end_loop,
8178f7
+						      last_addr, rotate_loop);
8178f7
+	  emit_insn (gen_blockage ());
8178f7
+	}
8178f7
+    }
8178f7
+
8178f7
+  if (residual != CONST0_RTX (Pmode))
8178f7
+    {
8178f7
+      rtx x = force_reg (Pmode, plus_constant (Pmode, residual,
8178f7
+					       -GET_MODE_SIZE (word_mode)));
8178f7
+      anti_adjust_stack (residual);
8178f7
+      emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x));
8178f7
+      emit_insn (gen_blockage ());
8178f7
+    }
8178f7
+
8178f7
+  /* Some targets make optimistic assumptions in their prologues about
8178f7
+     how the caller may have probed the stack.  Make sure we honor
8178f7
+     those assumptions when needed.  */
8178f7
+  if (size != CONST0_RTX (Pmode)
8178f7
+      && targetm.stack_clash_protection_final_dynamic_probe (residual))
8178f7
+    {
8178f7
+      /* Ideally we would just probe at *sp.  However, if SIZE is not
8178f7
+	 a compile-time constant, but is zero at runtime, then *sp
8178f7
+	 might hold live data.  So probe at *sp if we know that
8178f7
+	 an allocation was made, otherwise probe into the red zone
8178f7
+	 which is obviously undesirable.  */
8178f7
+      if (GET_CODE (size) == CONST_INT)
8178f7
+	{
8178f7
+	  emit_stack_probe (stack_pointer_rtx);
8178f7
+	  emit_insn (gen_blockage ());
8178f7
+	}
8178f7
+      else
8178f7
+	{
8178f7
+	  emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
8178f7
+					   -GET_MODE_SIZE (word_mode)));
8178f7
+	  emit_insn (gen_blockage ());
8178f7
+	}
8178f7
+    }
8178f7
+}
8178f7
+
8178f7
+
8178f7
 /* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
8178f7
    while probing it.  This pushes when SIZE is positive.  SIZE need not
8178f7
    be constant.  If ADJUST_BACK is true, adjust back the stack pointer
8178f7
diff --git a/gcc/rtl.h b/gcc/rtl.h
8178f7
index 91f3387c701..ab8ec27418d 100644
8178f7
--- a/gcc/rtl.h
8178f7
+++ b/gcc/rtl.h
8178f7
@@ -1756,6 +1756,17 @@ extern int currently_expanding_to_rtl;
8178f7
 /* In explow.c */
8178f7
 extern HOST_WIDE_INT trunc_int_for_mode	(HOST_WIDE_INT, enum machine_mode);
8178f7
 extern rtx plus_constant (enum machine_mode, rtx, HOST_WIDE_INT);
8178f7
+extern HOST_WIDE_INT get_stack_check_protect (void);
8178f7
+
8178f7
+/* Support for building allocation/probing loops for stack-clash
8178f7
+   protection of dyamically allocated stack space.  */
8178f7
+extern void compute_stack_clash_protection_loop_data (rtx *, rtx *, rtx *,
8178f7
+						      HOST_WIDE_INT *, rtx);
8178f7
+extern void emit_stack_clash_protection_probe_loop_start (rtx *, rtx *,
8178f7
+							  rtx, bool);
8178f7
+extern void emit_stack_clash_protection_probe_loop_end (rtx, rtx,
8178f7
+							rtx, bool);
8178f7
+
8178f7
 
8178f7
 /* In rtl.c */
8178f7
 extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
8178f7
diff --git a/gcc/target.def b/gcc/target.def
8178f7
index 4d6081c3121..eb2bd46f7a1 100644
8178f7
--- a/gcc/target.def
8178f7
+++ b/gcc/target.def
8178f7
@@ -2580,6 +2580,13 @@ DEFHOOK
8178f7
  void, (void),
8178f7
  hook_void_void)
8178f7
 
8178f7
+DEFHOOK
8178f7
+(stack_clash_protection_final_dynamic_probe,
8178f7
+ "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.",
8178f7
+ bool, (rtx residual),
8178f7
+ default_stack_clash_protection_final_dynamic_probe)
8178f7
+
8178f7
+
8178f7
 /* Functions specific to the C family of frontends.  */
8178f7
 #undef HOOK_PREFIX
8178f7
 #define HOOK_PREFIX "TARGET_C_"
8178f7
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
8178f7
index f6aa9907225..be23875538d 100644
8178f7
--- a/gcc/targhooks.c
8178f7
+++ b/gcc/targhooks.c
8178f7
@@ -1557,4 +1557,10 @@ default_canonicalize_comparison (int *, rtx *, rtx *, bool)
8178f7
 {
8178f7
 }
8178f7
 
8178f7
+bool
8178f7
+default_stack_clash_protection_final_dynamic_probe (rtx residual ATTRIBUTE_UNUSED)
8178f7
+{
8178f7
+  return 0;
8178f7
+}
8178f7
+
8178f7
 #include "gt-targhooks.h"
8178f7
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
8178f7
index b64274d3ff9..4acf33fae08 100644
8178f7
--- a/gcc/targhooks.h
8178f7
+++ b/gcc/targhooks.h
8178f7
@@ -195,3 +195,4 @@ extern const char *default_pch_valid_p (const void *, size_t);
8178f7
 extern void default_asm_output_ident_directive (const char*);
8178f7
 
8178f7
 extern bool default_member_type_forces_blk (const_tree, enum machine_mode);
8178f7
+extern bool default_stack_clash_protection_final_dynamic_probe (rtx);
8178f7
diff --git a/gcc/testsuite/gcc.dg/stack-check-3.c b/gcc/testsuite/gcc.dg/stack-check-3.c
8178f7
new file mode 100644
8178f7
index 00000000000..58fb65649ee
8178f7
--- /dev/null
8178f7
+++ b/gcc/testsuite/gcc.dg/stack-check-3.c
8178f7
@@ -0,0 +1,86 @@
8178f7
+/* The goal here is to ensure that dynamic allocations via vlas or
8178f7
+   alloca calls receive probing.
8178f7
+
8178f7
+   Scanning the RTL or assembly code seems like insanity here as does
8178f7
+   checking for particular allocation sizes and probe offsets.  For
8178f7
+   now we just verify that there's an allocation + probe loop and
8178f7
+   residual allocation + probe for f?.  */
8178f7
+
8178f7
+/* { dg-do compile } */
8178f7
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-expand -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=4096 --param stack-clash-protection-guard-size=4096" } */
8178f7
+/* { dg-require-effective-target supports_stack_clash_protection } */
8178f7
+
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+foo (char *p)
8178f7
+{
8178f7
+  asm volatile ("" : : "r" (p) : "memory");
8178f7
+}
8178f7
+
8178f7
+/* Simple VLA, no other locals. */
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+f0 (int x)
8178f7
+{
8178f7
+  char vla[x];
8178f7
+  foo (vla);
8178f7
+}
8178f7
+
8178f7
+/* Simple VLA, small local frame.  */
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+f1 (int x)
8178f7
+{
8178f7
+  char locals[128];
8178f7
+  char vla[x];
8178f7
+  foo (vla);
8178f7
+}
8178f7
+
8178f7
+/* Small constant alloca, no other locals. */
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+f2 (int x)
8178f7
+{
8178f7
+  char *vla = __builtin_alloca (128);
8178f7
+  foo (vla);
8178f7
+}
8178f7
+
8178f7
+/* Big constant alloca, small local frame.  */
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+f3 (int x)
8178f7
+{
8178f7
+  char locals[128];
8178f7
+  char *vla = __builtin_alloca (16384);
8178f7
+  foo (vla);
8178f7
+}
8178f7
+
8178f7
+/* Big constant alloca, small local frame.  */
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+f3a (int x)
8178f7
+{
8178f7
+  char locals[128];
8178f7
+  char *vla = __builtin_alloca (32768);
8178f7
+  foo (vla);
8178f7
+}
8178f7
+
8178f7
+/* Nonconstant alloca, no other locals. */
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+f4 (int x)
8178f7
+{
8178f7
+  char *vla = __builtin_alloca (x);
8178f7
+  foo (vla);
8178f7
+}
8178f7
+
8178f7
+/* Nonconstant alloca, small local frame.  */
8178f7
+__attribute__((noinline, noclone)) void
8178f7
+f5 (int x)
8178f7
+{
8178f7
+  char locals[128];
8178f7
+  char *vla = __builtin_alloca (x);
8178f7
+  foo (vla);
8178f7
+}
8178f7
+
8178f7
+/* { dg-final { scan-rtl-dump-times "allocation and probing residuals" 7 "expand" } } */
8178f7
+
8178f7
+
8178f7
+/* { dg-final { scan-rtl-dump-times "allocation and probing in loop" 7 "expand" { target callee_realigns_stack } } } */
8178f7
+/* { dg-final { scan-rtl-dump-times "allocation and probing in loop" 4 "expand" { target { ! callee_realigns_stack } } } } */
8178f7
+/* { dg-final { scan-rtl-dump-times "allocation and probing in rotated loop" 1 "expand" { target { ! callee_realigns_stack } } } } */
8178f7
+/* { dg-final { scan-rtl-dump-times "allocation and probing inline" 1 "expand" { target { ! callee_realigns_stack } } } } */
8178f7
+/* { dg-final { scan-rtl-dump-times "skipped dynamic allocation and probing loop" 1 "expand" { target { ! callee_realigns_stack } } } } */