c-cppbuiltin.c (c_cpp_builtins): Add __SSP_ALL__ and __SSP__.
authorRichard Henderson <rth@redhat.com>
Mon, 27 Jun 2005 07:41:16 +0000 (00:41 -0700)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 27 Jun 2005 07:41:16 +0000 (09:41 +0200)
* c-cppbuiltin.c (c_cpp_builtins): Add __SSP_ALL__ and __SSP__.
* cfgexpand.c: Include params.h.
(has_protected_decls, has_short_buffer): New.
(expand_stack_vars): Take a predicate to determine what to expand.
(defer_stack_allocation): True when flag_stack_protect on.
(SPCT_HAS_LARGE_CHAR_ARRAY, SPCT_HAS_SMALL_CHAR_ARRAY): New.
(SPCT_HAS_ARRAY, SPCT_HAS_AGGREGATE): New.
(stack_protect_classify_type, stack_protect_decl_phase): New.
(stack_protect_decl_phase_1, stack_protect_decl_phase_2): New.
(add_stack_protection_conflicts, create_stack_guard): New.
(expand_used_vars): Add stack protection logic.
(tree_expand_cfg): Likewise.
* common.opt (Wstack-protector): New.
(fstack-protector, fstack-protector-all): New.
* function.c: Include predict.h.
(assign_parm_adjust_stack_rtl): Zap stack_parm when stack protect
wants to copy the parameter into the stack frame.
(stack_protect_prologue, stack_protect_epilogue): New.
(expand_function_end): Call stack_protect_epilogue.  Do
sjlj_emit_function_exit_after after naked_return_label.
* function.h (struct function): Add stack_protect_guard.
* params.def (PARAM_SSP_BUFFER_SIZE): New.
* toplev.c (process_options): Disable flag_stack_protect and/or
warn_stack_protect based on FRAME_GROWS_DOWNWARD.
* tree.h (stack_protect_prologue): Declare.

* target-def.h (TARGET_STACK_PROTECT_GUARD): New.
(TARGET_STACK_PROTECT_FAIL): New.
(TARGET_INITIALIZER): Add them.
* target.h (struct gcc_target): Add stack_protect_guard and
stack_protect_fail.
* targhooks.c: Include ggc.h, gty header.
(stack_chk_guard_decl, default_stack_protect_guard): New.
(stack_chk_fail_decl, default_external_stack_protect_fail): New.
(default_hidden_stack_protect_fail): New.
* targhooks.h (default_stack_protect_guard): Declare.
(default_external_stack_protect_fail): Declare.
(default_hidden_stack_protect_fail): Declare.
* config/i386/i386.c (TARGET_STACK_PROTECT_FAIL): New.
* config/i386/i386.md (UNSPEC_SP_SET, UNSPEC_SP_TEST): New.
(trap): Use ud2.
(conditional_trap, conditional_trap_1): Remove.
(stack_protect_set, stack_protect_set_si, stack_protect_set_di): New.
(stack_protect_test, stack_protect_test_si, stack_protect_test_di): New.
* doc/md.texi (stack_protect_set, stack_protect_test): New.
* doc/tm.texi (TARGET_STACK_PROTECT_GUARD): New.
(TARGET_STACK_PROTECT_FAIL): New.

* libgcc-std.ver (GCC_4.1.0): New.
* libgcc.h (__stack_chk_guard): Declare.
(__stack_chk_fail, __stack_chk_fail_local): Declare.
* libgcc2.c (L_stack_chk, L_stack_chk_local): New.
* mklibgcc.in (lib2funcs): Add them.

From-SVN: r101348

22 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-cppbuiltin.c
gcc/cfgexpand.c
gcc/common.opt
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/doc/md.texi
gcc/doc/tm.texi
gcc/function.c
gcc/function.h
gcc/libgcc-std.ver
gcc/libgcc2.c
gcc/libgcc2.h
gcc/mklibgcc.in
gcc/params.def
gcc/target-def.h
gcc/target.h
gcc/targhooks.c
gcc/targhooks.h
gcc/toplev.c
gcc/tree.h

index 1ed245ebf92e9c37b13f71bf7e00cbba94816d9b..efa4b6e8fcab69aab527cca57e12fd7277dc11a2 100644 (file)
@@ -1,3 +1,59 @@
+2005-06-27  Richard Henderson  <rth@redhat.com>
+
+       * c-cppbuiltin.c (c_cpp_builtins): Add __SSP_ALL__ and __SSP__.
+       * cfgexpand.c: Include params.h.
+       (has_protected_decls, has_short_buffer): New.
+       (expand_stack_vars): Take a predicate to determine what to expand.
+       (defer_stack_allocation): True when flag_stack_protect on.
+       (SPCT_HAS_LARGE_CHAR_ARRAY, SPCT_HAS_SMALL_CHAR_ARRAY): New.
+       (SPCT_HAS_ARRAY, SPCT_HAS_AGGREGATE): New.
+       (stack_protect_classify_type, stack_protect_decl_phase): New.
+       (stack_protect_decl_phase_1, stack_protect_decl_phase_2): New.
+       (add_stack_protection_conflicts, create_stack_guard): New.
+       (expand_used_vars): Add stack protection logic.
+       (tree_expand_cfg): Likewise.
+       * common.opt (Wstack-protector): New.
+       (fstack-protector, fstack-protector-all): New.
+       * function.c: Include predict.h.
+       (assign_parm_adjust_stack_rtl): Zap stack_parm when stack protect
+       wants to copy the parameter into the stack frame.
+       (stack_protect_prologue, stack_protect_epilogue): New.
+       (expand_function_end): Call stack_protect_epilogue.  Do 
+       sjlj_emit_function_exit_after after naked_return_label.
+       * function.h (struct function): Add stack_protect_guard.
+       * params.def (PARAM_SSP_BUFFER_SIZE): New.
+       * toplev.c (process_options): Disable flag_stack_protect and/or
+       warn_stack_protect based on FRAME_GROWS_DOWNWARD.
+       * tree.h (stack_protect_prologue): Declare.
+
+       * target-def.h (TARGET_STACK_PROTECT_GUARD): New.
+       (TARGET_STACK_PROTECT_FAIL): New.
+       (TARGET_INITIALIZER): Add them.
+       * target.h (struct gcc_target): Add stack_protect_guard and
+       stack_protect_fail.
+       * targhooks.c: Include ggc.h, gty header.
+       (stack_chk_guard_decl, default_stack_protect_guard): New.
+       (stack_chk_fail_decl, default_external_stack_protect_fail): New.
+       (default_hidden_stack_protect_fail): New.
+       * targhooks.h (default_stack_protect_guard): Declare.
+       (default_external_stack_protect_fail): Declare.
+       (default_hidden_stack_protect_fail): Declare.
+       * config/i386/i386.c (TARGET_STACK_PROTECT_FAIL): New.
+       * config/i386/i386.md (UNSPEC_SP_SET, UNSPEC_SP_TEST): New.
+       (trap): Use ud2.
+       (conditional_trap, conditional_trap_1): Remove.
+       (stack_protect_set, stack_protect_set_si, stack_protect_set_di): New.
+       (stack_protect_test, stack_protect_test_si, stack_protect_test_di): New.
+       * doc/md.texi (stack_protect_set, stack_protect_test): New.
+       * doc/tm.texi (TARGET_STACK_PROTECT_GUARD): New.
+       (TARGET_STACK_PROTECT_FAIL): New.
+
+       * libgcc-std.ver (GCC_4.1.0): New.
+       * libgcc.h (__stack_chk_guard): Declare.
+       (__stack_chk_fail, __stack_chk_fail_local): Declare.
+       * libgcc2.c (L_stack_chk, L_stack_chk_local): New.
+       * mklibgcc.in (lib2funcs): Add them.
+
 2005-06-26  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        PR c/21911
index fd6fbb0fb59beb83d379aa323cc5451dbd074f54..628d36ca4212018ef9c019c38b2168d11ee5db15 100644 (file)
@@ -1972,7 +1972,7 @@ opts.o : opts.c opts.h options.h toplev.h $(CONFIG_H) $(SYSTEM_H) \
    $(FLAGS_H) $(PARAMS_H)
 targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    $(EXPR_H) $(TM_H) $(RTL_H) $(TM_P_H) function.h output.h toplev.h \
-   $(MACHMODE_H) $(TARGET_DEF_H) $(TARGET_H)
+   $(MACHMODE_H) $(TARGET_DEF_H) $(TARGET_H) $(GGC_H) gt-targhooks.h
 
 toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    version.h $(RTL_H) function.h $(FLAGS_H) xcoffout.h input.h \
@@ -2025,7 +2025,7 @@ function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(CFGLAYOUT_H) $(TREE_GIMPLE_H) $(FLAGS_H) function.h $(EXPR_H) \
    $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \
    output.h toplev.h except.h $(HASHTAB_H) $(GGC_H) $(TM_P_H) langhooks.h \
-   gt-function.h $(TARGET_H) $(BASIC_BLOCK_H) $(INTEGRATE_H)
+   gt-function.h $(TARGET_H) $(BASIC_BLOCK_H) $(INTEGRATE_H) $(PREDICT_H)
 stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(FLAGS_H) function.h insn-config.h hard-reg-set.h $(EXPR_H) \
    libfuncs.h except.h $(RECOG_H) toplev.h output.h $(GGC_H) $(TM_P_H) \
@@ -2221,7 +2221,7 @@ cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
 cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) function.h $(TIMEVAR_H) $(TM_H) \
    coretypes.h $(TREE_DUMP_H) except.h langhooks.h tree-pass.h $(RTL_H) \
-   $(DIAGNOSTIC_H) toplev.h $(BASIC_BLOCK_H) $(FLAGS_H)
+   $(DIAGNOSTIC_H) toplev.h $(BASIC_BLOCK_H) $(FLAGS_H) $(PARAMS_H)
 cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \
    output.h toplev.h function.h except.h $(TM_P_H) insn-config.h $(EXPR_H) \
@@ -2675,7 +2675,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-chrec.h $(srcdir)/tree-vect-generic.c \
   $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \
   $(srcdir)/tree-profile.c $(srcdir)/rtl-profile.c $(srcdir)/tree-nested.c \
-  $(out_file) \
+  $(srcdir)/targhooks.c $(out_file) \
   @all_gtfiles@
 
 GTFILES_FILES_LANGS = @all_gtfiles_files_langs@
@@ -2696,7 +2696,7 @@ gt-tree-profile.h gt-tree-ssa-address.h \
 gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \
 gt-tree-phinodes.h gt-tree-nested.h \
 gt-tree-ssa-operands.h gt-tree-ssa-propagate.h \
-gt-stringpool.h : s-gtype ; @true
+gt-stringpool.h gt-targhooks.h : s-gtype ; @true
 
 gtyp-gen.h: s-gtyp-gen ; @true
 s-gtyp-gen: Makefile
index bf9885ea810e290f2f5a0d2d8b47e8150e39262d..44c7a3797ddb0305c559249e6ad72f4c3eb1cdd0 100644 (file)
@@ -440,6 +440,12 @@ c_cpp_builtins (cpp_reader *pfile)
   if (targetm.handle_pragma_extern_prefix)
     cpp_define (pfile, "__PRAGMA_EXTERN_PREFIX");
 
+  /* Make the choice of the stack protector runtime visible to source code.  */
+  if (flag_stack_protect == 2)
+    cpp_define (pfile, "__SSP_ALL__=2");
+  else if (flag_stack_protect == 1)
+    cpp_define (pfile, "__SSP__=1");
+
   /* A straightforward target hook doesn't work, because of problems
      linking that hook's body when part of non-C front ends.  */
 # define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM)
index 1747309010cf58b79a9de5566be08c9b913d047c..bb6ca4ac5622b80f83c72c6f53a1f6546e809e1d 100644 (file)
@@ -37,6 +37,8 @@ Boston, MA 02110-1301, USA.  */
 #include "flags.h"
 #include "diagnostic.h"
 #include "toplev.h"
+#include "params.h"
+
 
 /* Verify that there is exactly single jump instruction since last and attach
    REG_BR_PROB note specifying probability.
@@ -137,6 +139,13 @@ static size_t stack_vars_conflict_alloc;
    (frame_offset+frame_phase) % PREFERRED_STACK_BOUNDARY == 0.  */
 static int frame_phase;
 
+/* Used during expand_used_vars to remember if we saw any decls for
+   which we'd like to enable stack smashing protection.  */
+static bool has_protected_decls;
+
+/* Used during expand_used_vars.  Remember if we say a character buffer
+   smaller than our cutoff threshold.  Used for -Wstack-protector.  */
+static bool has_short_buffer;
 
 /* Discover the byte alignment to use for DECL.  Ignore alignment
    we can't do with expected alignment of the stack boundary.  */
@@ -487,7 +496,7 @@ expand_one_stack_var_at (tree decl, HOST_WIDE_INT offset)
    with that location.  */
 
 static void
-expand_stack_vars (void)
+expand_stack_vars (bool (*pred) (tree))
 {
   size_t si, i, j, n = stack_vars_num;
 
@@ -501,6 +510,16 @@ expand_stack_vars (void)
       if (stack_vars[i].representative != i)
        continue;
 
+      /* Skip variables that have already had rtl assigned.  See also
+        add_stack_var where we perpetrate this pc_rtx hack.  */
+      if (DECL_RTL (stack_vars[i].decl) != pc_rtx)
+       continue;
+
+      /* Check the predicate to see whether this variable should be 
+        allocated in this pass.  */
+      if (pred && !pred (stack_vars[i].decl))
+       continue;
+
       offset = alloc_stack_frame_space (stack_vars[i].size,
                                        stack_vars[i].alignb);
 
@@ -620,6 +639,11 @@ expand_one_error_var (tree var)
 static bool
 defer_stack_allocation (tree var, bool toplevel)
 {
+  /* If stack protection is enabled, *all* stack variables must be deferred,
+     so that we can re-order the strings to the top of the frame.  */
+  if (flag_stack_protect)
+    return true;
+
   /* Variables in the outermost scope automatically conflict with
      every other variable.  The only reason to want to defer them
      at all is that, after sorting, we can more efficiently pack
@@ -725,6 +749,144 @@ clear_tree_used (tree block)
     clear_tree_used (t);
 }
 
+/* Examine TYPE and determine a bit mask of the following features.  */
+
+#define SPCT_HAS_LARGE_CHAR_ARRAY      1
+#define SPCT_HAS_SMALL_CHAR_ARRAY      2
+#define SPCT_HAS_ARRAY                 4
+#define SPCT_HAS_AGGREGATE             8
+
+static unsigned int
+stack_protect_classify_type (tree type)
+{
+  unsigned int ret = 0;
+  tree t;
+
+  switch (TREE_CODE (type))
+    {
+    case ARRAY_TYPE:
+      t = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+      if (t == char_type_node
+         || t == signed_char_type_node
+         || t == unsigned_char_type_node)
+       {
+         HOST_WIDE_INT max = PARAM_VALUE (PARAM_SSP_BUFFER_SIZE);
+         HOST_WIDE_INT len;
+
+         if (!TYPE_DOMAIN (type)
+             || !TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+             || !host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 1))
+           len = max + 1;
+         else
+           len = tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 1);
+
+         if (len < max)
+           ret = SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_ARRAY;
+         else
+           ret = SPCT_HAS_LARGE_CHAR_ARRAY | SPCT_HAS_ARRAY;
+       }
+      else
+       ret = SPCT_HAS_ARRAY;
+      break;
+
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+    case RECORD_TYPE:
+      ret = SPCT_HAS_AGGREGATE;
+      for (t = TYPE_FIELDS (type); t ; t = TREE_CHAIN (t))
+       if (TREE_CODE (t) == FIELD_DECL)
+         ret |= stack_protect_classify_type (TREE_TYPE (t));
+      break;
+
+    default:
+      break;
+    }
+
+  return ret;
+}
+
+/* Return non-zero if DECL should be segregated into the "vulnerable" upper
+   part of the local stack frame.  Remember if we ever return non-zero for
+   any variable in this function.  The return value is the phase number in
+   which the variable should be allocated.  */
+
+static int
+stack_protect_decl_phase (tree decl)
+{
+  unsigned int bits = stack_protect_classify_type (TREE_TYPE (decl));
+  int ret = 0;
+
+  if (bits & SPCT_HAS_SMALL_CHAR_ARRAY)
+    has_short_buffer = true;
+
+  if (flag_stack_protect == 2)
+    {
+      if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY))
+         && !(bits & SPCT_HAS_AGGREGATE))
+       ret = 1;
+      else if (bits & SPCT_HAS_ARRAY)
+       ret = 2;
+    }
+  else
+    ret = (bits & SPCT_HAS_LARGE_CHAR_ARRAY) != 0;
+
+  if (ret)
+    has_protected_decls = true;
+
+  return ret;
+}
+
+/* Two helper routines that check for phase 1 and phase 2.  These are used
+   as callbacks for expand_stack_vars.  */
+
+static bool
+stack_protect_decl_phase_1 (tree decl)
+{
+  return stack_protect_decl_phase (decl) == 1;
+}
+
+static bool
+stack_protect_decl_phase_2 (tree decl)
+{
+  return stack_protect_decl_phase (decl) == 2;
+}
+
+/* Ensure that variables in different stack protection phases conflict
+   so that they are not merged and share the same stack slot.  */
+
+static void
+add_stack_protection_conflicts (void)
+{
+  size_t i, j, n = stack_vars_num;
+  unsigned char *phase;
+
+  phase = XNEWVEC (unsigned char, n);
+  for (i = 0; i < n; ++i)
+    phase[i] = stack_protect_decl_phase (stack_vars[i].decl);
+
+  for (i = 0; i < n; ++i)
+    {
+      unsigned char ph_i = phase[i];
+      for (j = 0; j < i; ++j)
+       if (ph_i != phase[j])
+         add_stack_var_conflict (i, j);
+    }
+
+  XDELETEVEC (phase);
+}
+
+/* Create a decl for the guard at the top of the stack frame.  */
+
+static void
+create_stack_guard (void)
+{
+  tree guard = build_decl (VAR_DECL, NULL, ptr_type_node);
+  TREE_THIS_VOLATILE (guard) = 1;
+  TREE_USED (guard) = 1;
+  expand_one_stack_var (guard);
+  cfun->stack_protect_guard = guard;
+}
+
 /* Expand all variables used in the function.  */
 
 static void
@@ -746,6 +908,10 @@ expand_used_vars (void)
   /* Clear TREE_USED on all variables associated with a block scope.  */
   clear_tree_used (outer_block);
 
+  /* Initialize local stack smashing state.  */
+  has_protected_decls = false;
+  has_short_buffer = false;
+
   /* At this point all variables on the unexpanded_var_list with TREE_USED
      set are not associated with any block scope.  Lay them out.  */
   for (t = cfun->unexpanded_var_list; t; t = TREE_CHAIN (t))
@@ -794,14 +960,44 @@ expand_used_vars (void)
         reflect this.  */
       add_alias_set_conflicts ();
 
+      /* If stack protection is enabled, we don't share space between 
+        vulnerable data and non-vulnerable data.  */
+      if (flag_stack_protect)
+       add_stack_protection_conflicts ();
+
       /* Now that we have collected all stack variables, and have computed a 
         minimal interference graph, attempt to save some stack space.  */
       partition_stack_vars ();
       if (dump_file)
        dump_stack_var_partition ();
+    }
+
+  /* There are several conditions under which we should create a
+     stack guard: protect-all, alloca used, protected decls present.  */
+  if (flag_stack_protect == 2
+      || (flag_stack_protect
+         && (current_function_calls_alloca || has_protected_decls)))
+    create_stack_guard ();
 
-      /* Assign rtl to each variable based on these partitions.  */
-      expand_stack_vars ();
+  /* Assign rtl to each variable based on these partitions.  */
+  if (stack_vars_num > 0)
+    {
+      /* Reorder decls to be protected by iterating over the variables
+        array multiple times, and allocating out of each phase in turn.  */
+      /* ??? We could probably integrate this into the qsort we did 
+        earlier, such that we naturally see these variables first,
+        and thus naturally allocate things in the right order.  */
+      if (has_protected_decls)
+       {
+         /* Phase 1 contains only character arrays.  */
+         expand_stack_vars (stack_protect_decl_phase_1);
+
+         /* Phase 2 contains other kinds of arrays.  */
+         if (flag_stack_protect == 2)
+           expand_stack_vars (stack_protect_decl_phase_2);
+       }
+
+      expand_stack_vars (NULL);
 
       /* Free up stack variable graph data.  */
       XDELETEVEC (stack_vars);
@@ -1288,6 +1484,16 @@ tree_expand_cfg (void)
   /* Expand the variables recorded during gimple lowering.  */
   expand_used_vars ();
 
+  /* Honor stack protection warnings.  */
+  if (warn_stack_protect)
+    {
+      if (current_function_calls_alloca)
+       warning (0, "not protecting local variables: variable length buffer");
+      if (has_short_buffer && !cfun->stack_protect_guard)
+       warning (0, "not protecting function: no buffer at least %d bytes long",
+                (int) PARAM_VALUE (PARAM_SSP_BUFFER_SIZE));
+    }
+
   /* Set up parameters and prepare for return, for the function.  */
   expand_function_start (current_function_decl);
 
@@ -1298,6 +1504,11 @@ tree_expand_cfg (void)
       && DECL_FILE_SCOPE_P (current_function_decl))
     expand_main_function ();
 
+  /* Initialize the stack_protect_guard field.  This must happen after the
+     call to __main (if any) so that the external decl is initialized.  */
+  if (cfun->stack_protect_guard)
+    stack_protect_prologue ();
+
   /* Register rtl specific functions for cfg.  */
   rtl_register_cfg_hooks ();
 
index 7b6aee109243a74dc3ccb06276af72015ca60f9d..4d097c78fc33e490a028ca198bc2aa0832cd3100 100644 (file)
@@ -109,6 +109,10 @@ Wshadow
 Common Var(warn_shadow)
 Warn when one local variable shadows another
 
+Wstack-protector
+Common Var(warn_stack_protect)
+Warn when not issuing stack smashing protection for some reason
+
 Wstrict-aliasing
 Common
 Warn about code which might break strict aliasing rules
@@ -784,6 +788,14 @@ fstack-limit-symbol=
 Common RejectNegative Joined
 -fstack-limit-symbol=<name>    Trap if the stack goes past symbol <name>
 
+fstack-protector
+Common Report Var(flag_stack_protect, 1)
+Use propolice as a stack protection method
+
+fstack-protector-all
+Common Report RejectNegative Var(flag_stack_protect, 2) VarExists
+Use a stack protection method for every function
+
 fstrength-reduce
 Common Report Var(flag_strength_reduce)
 Perform strength reduction optimizations
index 5a1af7ac88425d809446d6917f731ba09f6c3141..0f487c47f921be62beb3a359a3e0214ee76117c8 100644 (file)
@@ -1081,6 +1081,9 @@ static void init_ext_80387_constants (void);
 #undef TARGET_MANGLE_FUNDAMENTAL_TYPE
 #define TARGET_MANGLE_FUNDAMENTAL_TYPE ix86_mangle_fundamental_type
 
+#undef TARGET_STACK_PROTECT_FAIL
+#define TARGET_STACK_PROTECT_FAIL default_hidden_stack_protect_fail
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 \f
index 46fe51e5662928ebbb7a1200d635f84593c64d29..8aaad7b817dd702128747c74a52b7b7db52935cd 100644 (file)
@@ -81,6 +81,8 @@
    (UNSPEC_FLDCW               25)
    (UNSPEC_REP                 26)
    (UNSPEC_EH_RETURN           27)
+   (UNSPEC_SP_SET              28)
+   (UNSPEC_SP_TEST             29)
 
    ; For SSE/MMX support:
    (UNSPEC_FIX_NOTRUNC         30)
   "jmp\t*%%r11"
   [(set_attr "type" "callv")])
 \f
+;; We used to use "int $5", in honor of #BR which maps to interrupt vector 5.
+;; That, however, is usually mapped by the OS to SIGSEGV, which is often 
+;; caught for use by garbage collectors and the like.  Using an insn that
+;; maps to SIGILL makes it more likely the program will rightfully die.
+;; Keeping with tradition, "6" is in honor of #UD.
 (define_insn "trap"
-  [(trap_if (const_int 1) (const_int 5))]
+  [(trap_if (const_int 1) (const_int 6))]
   ""
-  "int\t$5")
-
-;;; ix86 doesn't have conditional trap instructions, but we fake them
-;;; for the sake of bounds checking.  By emitting bounds checks as
-;;; conditional traps rather than as conditional jumps around
-;;; unconditional traps we avoid introducing spurious basic-block
-;;; boundaries and facilitate elimination of redundant checks.  In
-;;; honor of the too-inflexible-for-BPs `bound' instruction, we use
-;;; interrupt 5.
-;;; 
-;;; FIXME: Static branch prediction rules for ix86 are such that
-;;; forward conditional branches predict as untaken.  As implemented
-;;; below, pseudo conditional traps violate that rule.  We should use
-;;; .pushsection/.popsection to place all of the `int 5's in a special
-;;; section loaded at the end of the text segment and branch forward
-;;; there on bounds-failure, and then jump back immediately (in case
-;;; the system chooses to ignore bounds violations, or to report
-;;; violations and continue execution).
-
-(define_expand "conditional_trap"
-  [(trap_if (match_operator 0 "comparison_operator"
-            [(match_dup 2) (const_int 0)])
-           (match_operand 1 "const_int_operand" ""))]
-  ""
-{
-  emit_insn (gen_rtx_TRAP_IF (VOIDmode,
-                             ix86_expand_compare (GET_CODE (operands[0]),
-                                                  NULL, NULL),
-                             operands[1]));
-  DONE;
-})
-
-(define_insn "*conditional_trap_1"
-  [(trap_if (match_operator 0 "comparison_operator"
-            [(reg FLAGS_REG) (const_int 0)])
-           (match_operand 1 "const_int_operand" ""))]
-  ""
-{
-  operands[2] = gen_label_rtx ();
-  output_asm_insn ("j%c0\t%l2\; int\t%1", operands);
-  (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                            CODE_LABEL_NUMBER (operands[2]));
-  RET;
-})
+  "ud2"
+  [(set_attr "length" "2")])
 
 (define_expand "sse_prologue_save"
   [(parallel [(set (match_operand:BLK 0 "" "")
   [(set_attr "type" "mmx")
    (set_attr "memory" "none")])
 
+(define_expand "stack_protect_set"
+  [(match_operand 0 "memory_operand" "")
+   (match_operand 1 "memory_operand" "")]
+  ""
+{
+  if (TARGET_64BIT)
+    emit_insn (gen_stack_protect_set_di (operands[0], operands[1]));
+  else
+    emit_insn (gen_stack_protect_set_si (operands[0], operands[1]));
+  DONE;
+})
+
+(define_insn "stack_protect_set_si"
+  [(set (match_operand:SI 0 "memory_operand" "=m")
+       (unspec:SI [(match_operand:SI 1 "memory_operand" "m")] UNSPEC_SP_SET))
+   (clobber (match_scratch:SI 2 "=r"))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "mov{l}\t{%1, %2|%2, %1}\;mov{l}\t{%2, %0|%0, %2}\;xor{l}\t%2, %2"
+  [(set_attr "type" "multi")])
+
+(define_insn "stack_protect_set_di"
+  [(set (match_operand:DI 0 "memory_operand" "=m")
+       (unspec:DI [(match_operand:DI 1 "memory_operand" "m")] UNSPEC_SP_SET))
+   (clobber (match_scratch:DI 2 "=r"))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "mov{q}\t{%1, %2|%2, %1}\;mov{q}\t{%2, %0|%0, %2}\;xor{l}\t%2, %2"
+  [(set_attr "type" "multi")])
+
+(define_expand "stack_protect_test"
+  [(match_operand 0 "memory_operand" "")
+   (match_operand 1 "memory_operand" "")]
+  ""
+{
+  rtx flags = gen_rtx_REG (CCZmode, FLAGS_REG);
+  ix86_compare_op0 = operands[0];
+  ix86_compare_op1 = operands[1];
+  ix86_compare_emitted = flags;
+
+  if (TARGET_64BIT)
+    emit_insn (gen_stack_protect_test_di (flags, operands[0], operands[1]));
+  else
+    emit_insn (gen_stack_protect_test_si (flags, operands[0], operands[1]));
+  DONE;
+})
+
+(define_insn "stack_protect_test_si"
+  [(set (match_operand:CCZ 0 "flags_reg_operand" "")
+       (unspec:CCZ [(match_operand:SI 1 "memory_operand" "m")
+                    (match_operand:SI 2 "memory_operand" "m")]
+                   UNSPEC_SP_TEST))
+   (clobber (match_scratch:SI 3 "=r"))]
+  ""
+  "mov{l}\t{%1, %3|%3, %1}\;xor{l}\t{%2, %3|%3, %2}"
+  [(set_attr "type" "multi")])
+
+(define_insn "stack_protect_test_di"
+  [(set (match_operand:CCZ 0 "flags_reg_operand" "")
+       (unspec:CCZ [(match_operand:DI 1 "memory_operand" "m")
+                    (match_operand:DI 2 "memory_operand" "m")]
+                   UNSPEC_SP_TEST))
+   (clobber (match_scratch:DI 3 "=r"))]
+  "TARGET_64BIT"
+  "mov{q}\t{%1, %3|%3, %1}\;xor{q}\t{%2, %3|%3, %2}"
+  [(set_attr "type" "multi")])
+
 (include "sse.md")
 (include "mmx.md")
 (include "sync.md")
index 6a3b76e3fde9ced9551a39cb9ebdd265e927f1c8..ed07a2fd88c360ba05bbf18cb167569327df6745 100644 (file)
@@ -4094,6 +4094,30 @@ released only after all previous memory operations have completed.
 If this pattern is not defined, then a @code{memory_barrier} pattern
 will be emitted, followed by a store of the value to the memory operand.
 
+@cindex @code{stack_protect_set} instruction pattern
+@item @samp{stack_protect_set}
+
+This pattern, if defined, moves a @code{Pmode} value from the memory
+in operand 1 to the memory in operand 0 without leaving the value in
+a register afterward.  This is to avoid leaking the value some place
+that an attacker might use to rewrite the stack guard slot after 
+having clobbered it.
+
+If this pattern is not defined, then a plain move pattern is generated.
+
+@cindex @code{stack_protect_test} instruction pattern
+@item @samp{stack_protect_test}
+
+This pattern, if defined, compares a @code{Pmode} value from the
+memory in operand 1 with the memory in operand 0 without leaving the
+value in a register afterward.  Further, it initializes the data
+structures in the target as if the normal @code{cmp@var{mode}} 
+pattern had been emitted.  If the pattern does not @code{FAIL}, then
+the rtl expanders will be invoking either the @code{beq} or @code{bne}
+pattern to make use of the comparison.
+
+If this pattern is not defined, then a plain compare pattern is used.
+
 @end table
 
 @end ifset
index fbf5cd1bf85a800a1dcb243e63ad68630bb486c7..cd2bf87a032c03d468e0040a584c1ee0bc2ed62c 100644 (file)
@@ -2716,6 +2716,7 @@ This describes the stack layout and calling conventions.
 * Function Entry::
 * Profiling::
 * Tail Calls::
+* Stack Smashing Protection::
 @end menu
 
 @node Frame Layout
@@ -4379,6 +4380,31 @@ as the @code{sibcall} md pattern can not fail, or fall over to a
 may vary greatly between different architectures.
 @end deftypefn
 
+@node Stack Smashing Protection
+@subsection Stack smashing protection
+@cindex stack smashing protection
+
+@deftypefn {Target Hook} tree TARGET_STACK_PROTECT_GUARD (void)
+This hook returns a @code{DECL} node for the external variable to use
+for the stack protection guard.  This variable is initialized by the 
+runtime to some random value and is used to initialize the guard value
+that is placed at the top of the local stack frame.  The type of this
+variable must be @code{ptr_type_node}.
+
+The default version of this hook creates a variable called
+@samp{__stack_chk_guard}, which is normally defined in @file{libgcc2.c}.
+@end deftypefn
+
+@deftypefn {Target Hook} tree TARGET_STACK_PROTECT_FAIL (void)
+This hook returns a tree expression that alerts the runtime that the
+stack protect guard variable has been modified.  This expression should
+involve a call to a @code{noreturn} function.
+
+The default version of this hook invokes a function called
+@samp{__stack_chk_fail}, taking no arguments.  This function is 
+normally defined in @file{libgcc2.c}.
+@end deftypefn
+
 @node Varargs
 @section Implementing the Varargs Macros
 @cindex varargs implementation
index c5c8dd80dfd4556c91e4fc11d668bc9046dd22ff..7ab698bd9858618469d19ee53e6b5c557dc422cc 100644 (file)
@@ -61,6 +61,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "target.h"
 #include "cfglayout.h"
 #include "tree-gimple.h"
+#include "predict.h"
+
 
 #ifndef LOCAL_ALIGNMENT
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
@@ -2334,6 +2336,14 @@ assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
           && data->nominal_mode != data->passed_mode)
     stack_parm = NULL;
 
+  /* If stack protection is in effect for this function, don't leave any
+     pointers in their passed stack slots.  */
+  else if (cfun->stack_protect_guard
+          && (flag_stack_protect == 2
+              || data->passed_pointer
+              || POINTER_TYPE_P (data->nominal_type)))
+    stack_parm = NULL;
+
   data->stack_parm = stack_parm;
 }
 
@@ -3921,6 +3931,97 @@ expand_main_function (void)
 #endif
 }
 \f
+/* Expand code to initialize the stack_protect_guard.  This is invoked at
+   the beginning of a function to be protected.  */
+
+#ifndef HAVE_stack_protect_set
+# define HAVE_stack_protect_set                0
+# define gen_stack_protect_set(x,y)    (gcc_unreachable (), NULL_RTX)
+#endif
+
+void
+stack_protect_prologue (void)
+{
+  tree guard_decl = targetm.stack_protect_guard ();
+  rtx x, y;
+
+  /* Avoid expand_expr here, because we don't want guard_decl pulled
+     into registers unless absolutely necessary.  And we know that
+     cfun->stack_protect_guard is a local stack slot, so this skips
+     all the fluff.  */
+  x = validize_mem (DECL_RTL (cfun->stack_protect_guard));
+  y = validize_mem (DECL_RTL (guard_decl));
+
+  /* Allow the target to copy from Y to X without leaking Y into a
+     register.  */
+  if (HAVE_stack_protect_set)
+    {
+      rtx insn = gen_stack_protect_set (x, y);
+      if (insn)
+       {
+         emit_insn (insn);
+         return;
+       }
+    }
+
+  /* Otherwise do a straight move.  */
+  emit_move_insn (x, y);
+}
+
+/* Expand code to verify the stack_protect_guard.  This is invoked at
+   the end of a function to be protected.  */
+
+#ifndef HAVE_stack_protect_test
+# define HAVE_stack_protect_test       0
+# define gen_stack_protect_test(x, y)  (gcc_unreachable (), NULL_RTX)
+#endif
+
+static void
+stack_protect_epilogue (void)
+{
+  tree guard_decl = targetm.stack_protect_guard ();
+  rtx label = gen_label_rtx ();
+  rtx x, y, tmp;
+
+  /* Avoid expand_expr here, because we don't want guard_decl pulled
+     into registers unless absolutely necessary.  And we know that
+     cfun->stack_protect_guard is a local stack slot, so this skips
+     all the fluff.  */
+  x = validize_mem (DECL_RTL (cfun->stack_protect_guard));
+  y = validize_mem (DECL_RTL (guard_decl));
+
+  /* Allow the target to compare Y with X without leaking either into
+     a register.  */
+  switch (HAVE_stack_protect_test != 0)
+    {
+    case 1:
+      tmp = gen_stack_protect_test (x, y);
+      if (tmp)
+       {
+         emit_insn (tmp);
+         emit_jump_insn (bcc_gen_fctn[EQ] (label));
+         break;
+       }
+      /* FALLTHRU */
+
+    default:
+      emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);
+      break;
+    }
+
+  /* The noreturn predictor has been moved to the tree level.  The rtl-level
+     predictors estimate this branch about 20%, which isn't enough to get
+     things moved out of line.  Since this is the only extant case of adding
+     a noreturn function at the rtl level, it doesn't seem worth doing ought
+     except adding the prediction by hand.  */
+  tmp = get_last_insn ();
+  if (JUMP_P (tmp))
+    predict_insn_def (tmp, PRED_NORETURN, TAKEN);
+
+  expand_expr_stmt (targetm.stack_protect_fail ());
+  emit_label (label);
+}
+\f
 /* Start the RTL for a new function, and set variables used for
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
@@ -4267,11 +4368,6 @@ expand_function_end (void)
   /* Output the label for the actual return from the function.  */
   emit_label (return_label);
 
-  /* Let except.c know where it should emit the call to unregister
-     the function context for sjlj exceptions.  */
-  if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
-    sjlj_emit_function_exit_after (get_last_insn ());
-
   /* If scalar return value was computed in a pseudo-reg, or was a named
      return value that got dumped to the stack, copy that to the hard
      return register.  */
@@ -4399,6 +4495,15 @@ expand_function_end (void)
   /* Output the label for the naked return from the function.  */
   emit_label (naked_return_label);
 
+  /* Let except.c know where it should emit the call to unregister
+     the function context for sjlj exceptions.  */
+  if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
+    sjlj_emit_function_exit_after (get_last_insn ());
+
+  /* If stack protection is enabled for this function, check the guard.  */
+  if (cfun->stack_protect_guard)
+    stack_protect_epilogue ();
+
   /* If we had calls to alloca, and this machine needs
      an accurate stack pointer to exit the function,
      insert some code to save and restore the stack pointer.  */
index f935e2e11757700133891852b4fa780e1b13336a..2d59d235141f2c4166a9c64a3e8ee0024d512010 100644 (file)
@@ -368,6 +368,10 @@ struct function GTY(())
 
   const char *unlikely_text_section_name;
 
+  /* A variable living at the top of the frame that holds a known value.
+     Used for detecting stack clobbers.  */
+  tree stack_protect_guard;
+
   /* Collected bit flags.  */
 
   /* Nonzero if function being compiled needs to be given an address
index 341cf7a481bc27029905899882fe3e2db11ef4c0..d6c182130a7a769bbf52c0f4766aaf7603448ea7 100644 (file)
@@ -252,3 +252,10 @@ GCC_4.0.0 {
   __mulxc3
   __multc3
 }
+
+%inherit GCC_4.1.0 GCC_4.0.0
+GCC_4.1.0 {
+  # stack smash handler symbols
+  __stack_chk_guard
+  __stack_chk_fail
+}
index 3108bff6729e2d0f1aee0f5f1473a074dcee0f47..a49c8c128f9d581211affbf8a5e5358a4ae2a2d2 100644 (file)
@@ -2015,3 +2015,141 @@ func_ptr __DTOR_LIST__[2];
 #endif
 #endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
 #endif /* L_ctors */
+\f
+#ifdef L_stack_chk
+#ifndef TARGET_LIBC_PROVIDES_SSP
+
+#ifndef inhibit_libc
+# include <string.h>
+# include <unistd.h>
+# include <fcntl.h>
+# ifdef HAVE_PATHS_H
+#  include <paths.h>
+# endif
+# ifndef _PATH_TTY
+#  define _PATH_TTY "/dev/tty"
+# endif
+# ifdef HAVE_SYSLOG_H
+#  include <syslog.h>
+# endif
+#endif
+
+void *__stack_chk_guard = 0;
+
+static void __attribute__ ((constructor))
+__guard_setup (void)
+{
+  unsigned char *p;
+
+  if (__stack_chk_guard != 0)
+    return;
+
+#ifndef inhibit_libc
+  {
+    int fd = open ("/dev/urandom", O_RDONLY);
+    if (fd != -1)
+      {
+       ssize_t size = read (fd, &__stack_chk_guard,
+                            sizeof (__stack_chk_guard));
+       close (fd);
+       if (size == sizeof(__stack_chk_guard))
+         return;
+      }
+  }
+#endif
+
+  /* If a random generator can't be used, the protector switches the guard
+     to the "terminator canary".  */
+  p = (unsigned char *)&__stack_chk_guard;
+  p[sizeof(__stack_chk_guard)-1] = 255;
+  p[sizeof(__stack_chk_guard)-2] = '\n';
+  p[0] = 0;
+}
+
+void
+__stack_chk_fail (void)
+{
+#ifndef inhibit_libc
+# ifdef __GNU_LIBRARY__
+  extern char * __progname;
+# else
+  static const char __progname[] = "";
+# endif
+
+  int fd;
+
+  /* Print error message directly to the tty.  This avoids Bad Things
+     happening if stderr is redirected.  */
+  fd = open (_PATH_TTY, O_WRONLY);
+  if (fd != -1)
+    {
+      static const char msg1[] = "*** stack smashing detected ***: ";
+      static const char msg2[] = " terminated\n";
+      size_t progname_len, len;
+      char *buf, *p;
+
+      progname_len = strlen (__progname);
+      len = sizeof(msg1)-1 + progname_len + sizeof(msg2)-1 + 1;
+      p = buf = alloca (len);
+
+      memcpy (p, msg1, sizeof(msg1)-1);
+      p += sizeof(msg1)-1;
+      memcpy (p, __progname, progname_len);
+      p += progname_len;
+      memcpy (p, msg2, sizeof(msg2));
+
+      while (len > 0)
+       {
+         ssize_t wrote = write (fd, buf, len);
+         if (wrote < 0)
+           break;
+         len -= wrote;
+       }
+      close (fd);
+    }
+
+# ifdef HAVE_SYSLOG_H
+  /* Only send the error to syslog if there was no tty available.  */
+  else
+    syslog (LOG_CRIT, "stack smashing detected: terminated");
+# endif /* HAVE_SYSLOG_H */
+#endif /* inhibit_libc */
+
+  /* Try very hard to exit.  Note that signals may be blocked preventing
+     the first two options from working.  The use of volatile is here to
+     prevent optimizers from "knowing" that __builtin_trap is called first,
+     and that it doesn't return, and so "obviously" the rest of the code
+     is dead.  */
+  {
+    volatile int state;
+    for (state = 0; ; state++)
+      switch (state)
+       {
+       case 0:
+         __builtin_trap ();
+         break;
+       case 1:
+         *(volatile int *)-1L = 0;
+         break;
+       case 2:
+         _exit (127);
+         break;
+       }
+  }
+}
+#endif /* TARGET_LIBC_PROVIDES_SSP */
+#endif /* L_stack_chk */
+\f
+#ifdef L_stack_chk_local
+#ifndef TARGET_LIBC_PROVIDES_SSP
+/* Some targets can avoid loading a GP for calls to hidden functions.
+   Using this entry point may avoid the load of a GP entirely for the
+   function, making the overall code smaller.  */
+
+void
+__stack_chk_fail_local (void)
+{
+  __stack_chk_fail ();
+}
+#endif /* TARGET_LIBC_PROVIDES_SSP */
+#endif /* L_stack_chk_local */
index 05901d89215ece31bb7a283a2bd4b378797cc8fb..cd1e47e11377b30d2b0919ab12c01d3601902d88 100644 (file)
@@ -390,6 +390,11 @@ extern int __parityDI2 (UDWtype);
 
 extern void __enable_execute_stack (void *);
 
+extern void *__stack_chk_guard;
+extern void __stack_chk_fail (void) __attribute__ ((__noreturn__));
+extern void __stack_chk_fail_local (void)
+       __attribute__ ((__noreturn__)) ATTRIBUTE_HIDDEN;
+
 #ifndef HIDE_EXPORTS
 #pragma GCC visibility pop
 #endif
index aa61d41f4339a6f7394d74ddc04f7f8b1ef25744..d2581d55b1e9f8922cfbed9f13eec2a6c40fabbe 100644 (file)
@@ -63,7 +63,7 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
        _ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
        _popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
        _powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3
-       _divxc3 _divtc3'
+       _divxc3 _divtc3 _stack_chk _stack_chk_local'
 
 # Disable SHLIB_LINK if shared libgcc not enabled.
 if [ "@enable_shared@" = "no" ]; then
index c17b54ee4fc7362f271e1b8e3e2bdce448c51b5e..0948c40d0c540321936229f129c8c5d9efea8266 100644 (file)
@@ -467,6 +467,11 @@ DEFPARAM (PARAM_VIRTUAL_MAPPINGS_TO_SYMS_RATIO,
          "Ratio between virtual mappings and virtual symbols to do full virtual renames",
          3, 0, 0)
 
+DEFPARAM (PARAM_SSP_BUFFER_SIZE,
+         "ssp-buffer-size",
+         "The lower bound for a buffer to be considered for stack smashing protection",
+         8, 1, 0)
+
 /*
 Local variables:
 mode:c
index 91cb6d3d5148932e73d34cc8fd6e6fd45d005e31..cdaf3d368ae1e331bca97b9bceaf5cb423f7a021 100644 (file)
@@ -398,6 +398,9 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
 #define TARGET_STDARG_OPTIMIZE_HOOK 0
 
+#define TARGET_STACK_PROTECT_GUARD  default_stack_protect_guard
+#define TARGET_STACK_PROTECT_FAIL   default_external_stack_protect_fail
+
 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_false
 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_false
 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_false
@@ -564,6 +567,8 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   TARGET_DWARF_CALLING_CONVENTION,              \
   TARGET_DWARF_HANDLE_FRAME_UNSPEC,            \
   TARGET_STDARG_OPTIMIZE_HOOK,                 \
+  TARGET_STACK_PROTECT_GUARD,                  \
+  TARGET_STACK_PROTECT_FAIL,                   \
   TARGET_INVALID_WITHIN_DOLOOP,                        \
   TARGET_CALLS,                                        \
   TARGET_CXX,                                  \
index 9c39f03df650c548c57e9ba771c86376c1391744..87e644b02acf4fdb2cc65e6323a91f7c39e16f19 100644 (file)
@@ -526,7 +526,16 @@ struct gcc_target
      from VA_ARG_EXPR.  LHS is left hand side of MODIFY_EXPR, RHS
      is right hand side.  Returns true if the statements doesn't need
      to be checked for va_list references.  */
-  bool (*stdarg_optimize_hook) (struct stdarg_info *ai, tree lhs, tree rhs);
+  bool (* stdarg_optimize_hook) (struct stdarg_info *ai, tree lhs, tree rhs);
+
+  /* This target hook allows the operating system to override the DECL
+     that represents the external variable that contains the stack
+     protection guard variable.  The type of this DECL is ptr_type_node.  */
+  tree (* stack_protect_guard) (void);
+
+  /* This target hook allows the operating system to override the CALL_EXPR
+     that is invoked when a check vs the guard variable fails.  */
+  tree (* stack_protect_fail) (void);
 
   /* Returns NULL if target supports the insn within a doloop block,
      otherwise it returns an error message.  */
index 31aa0dd595ee46839093763c90db85b05a31b944..ec374c6593a51e3ad327ca2c2dc10bcc428ce3ae 100644 (file)
@@ -61,6 +61,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "target.h"
 #include "tm_p.h"
 #include "target-def.h"
+#include "ggc.h"
 
 
 void
@@ -321,3 +322,86 @@ hook_invalid_arg_for_unprototyped_fn (
 {
   return NULL;
 }
+
+/* Initialize the stack protection decls.  */
+
+/* Stack protection related decls living in libgcc.  */
+static GTY(()) tree stack_chk_guard_decl;
+
+tree
+default_stack_protect_guard (void)
+{
+  tree t = stack_chk_guard_decl;
+
+  if (t == NULL)
+    {
+      t = build_decl (VAR_DECL, get_identifier ("__stack_chk_guard"),
+                     ptr_type_node);
+      TREE_STATIC (t) = 1;
+      TREE_PUBLIC (t) = 1;
+      DECL_EXTERNAL (t) = 1;
+      TREE_USED (t) = 1;
+      TREE_THIS_VOLATILE (t) = 1;
+      DECL_ARTIFICIAL (t) = 1;
+      DECL_IGNORED_P (t) = 1;
+
+      stack_chk_guard_decl = t;
+    }
+
+  return t;
+}
+
+static GTY(()) tree stack_chk_fail_decl;
+
+tree 
+default_external_stack_protect_fail (void)
+{
+  tree t = stack_chk_fail_decl;
+
+  if (t == NULL_TREE)
+    {
+      t = build_function_type_list (void_type_node, NULL_TREE);
+      t = build_decl (FUNCTION_DECL, get_identifier ("__stack_chk_fail"), t);
+      TREE_STATIC (t) = 1;
+      TREE_PUBLIC (t) = 1;
+      DECL_EXTERNAL (t) = 1;
+      TREE_USED (t) = 1;
+      TREE_THIS_VOLATILE (t) = 1;
+      TREE_NOTHROW (t) = 1;
+      DECL_ARTIFICIAL (t) = 1;
+      DECL_IGNORED_P (t) = 1;
+
+      stack_chk_fail_decl = t;
+    }
+
+  return build_function_call_expr (t, NULL_TREE);
+}
+
+tree
+default_hidden_stack_protect_fail (void)
+{
+  tree t = stack_chk_fail_decl;
+
+  if (stack_chk_fail_decl == NULL_TREE)
+    {
+      t = build_function_type_list (void_type_node, NULL_TREE);
+      t = build_decl (FUNCTION_DECL,
+                     get_identifier ("__stack_chk_fail_local"), t);
+      TREE_STATIC (t) = 1;
+      TREE_PUBLIC (t) = 1;
+      DECL_EXTERNAL (t) = 1;
+      TREE_USED (t) = 1;
+      TREE_THIS_VOLATILE (t) = 1;
+      TREE_NOTHROW (t) = 1;
+      DECL_ARTIFICIAL (t) = 1;
+      DECL_IGNORED_P (t) = 1;
+      DECL_VISIBILITY_SPECIFIED (t) = 1;
+      DECL_VISIBILITY (t) = VISIBILITY_HIDDEN;
+
+      stack_chk_fail_decl = t;
+    }
+
+  return build_function_call_expr (t, NULL_TREE);
+}
+
+#include "gt-targhooks.h"
index 99aeb5b8d1f0703e5c26fa0d0bb78943e858746e..80c49c8764b27a399f8fb2cc60532ac13434c5b8 100644 (file)
@@ -34,6 +34,10 @@ extern enum machine_mode default_eh_return_filter_mode (void);
 extern unsigned HOST_WIDE_INT default_shift_truncation_mask
   (enum machine_mode);
 
+extern tree default_stack_protect_guard (void);
+extern tree default_external_stack_protect_fail (void);
+extern tree default_hidden_stack_protect_fail (void);
+
 extern tree default_cxx_guard_type (void);
 extern tree default_cxx_get_cookie_size (tree);
 
index 709d63e8a7313fdaffc14d67ac935e75556162a4..495e104dd6a4882b6d12cf9b3dcc0d2ad0f8ec49 100644 (file)
@@ -1747,6 +1747,18 @@ process_options (void)
   /* With -fcx-limited-range, we do cheap and quick complex arithmetic.  */
   if (flag_cx_limited_range)
     flag_complex_method = 0;
+
+#ifndef FRAME_GROWS_DOWNWARD
+  /* Targets must be able to place spill slots at lower addresses.  If the
+     target already uses a soft frame pointer, the transition is trivial.  */
+  if (flag_stack_protect)
+    {
+      warning (0, "-fstack-protector not supported for this target");
+      flag_stack_protect = 0;
+    }
+#endif
+  if (!flag_stack_protect)
+    warn_stack_protect = 0;
 }
 
 /* Initialize the compiler back end.  */
index 09e0d63545e6826112933569467c4b82eee66425..1c0a4be2fcb9f24c8669fed5ac1548a27ffbb4b7 100644 (file)
@@ -3659,6 +3659,7 @@ extern int simple_cst_list_equal (tree, tree);
 extern void dump_tree_statistics (void);
 extern void expand_function_end (void);
 extern void expand_function_start (tree);
+extern void stack_protect_prologue (void);
 extern void recompute_tree_invarant_for_addr_expr (tree);
 extern bool is_global_var (tree t);
 extern bool needs_to_live_in_memory (tree);