aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog56
-rw-r--r--gcc/Makefile.in10
-rw-r--r--gcc/c-cppbuiltin.c6
-rw-r--r--gcc/cfgexpand.c217
-rw-r--r--gcc/common.opt12
-rw-r--r--gcc/config/i386/i386.c3
-rw-r--r--gcc/config/i386/i386.md122
-rw-r--r--gcc/doc/md.texi24
-rw-r--r--gcc/doc/tm.texi26
-rw-r--r--gcc/function.c115
-rw-r--r--gcc/function.h4
-rw-r--r--gcc/libgcc-std.ver7
-rw-r--r--gcc/libgcc2.c138
-rw-r--r--gcc/libgcc2.h5
-rw-r--r--gcc/mklibgcc.in2
-rw-r--r--gcc/params.def5
-rw-r--r--gcc/target-def.h5
-rw-r--r--gcc/target.h11
-rw-r--r--gcc/targhooks.c84
-rw-r--r--gcc/targhooks.h4
-rw-r--r--gcc/toplev.c12
-rw-r--r--gcc/tree.h1
22 files changed, 809 insertions, 60 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1ed245e..efa4b6e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index fd6fbb0..628d36c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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
diff --git a/gcc/c-cppbuiltin.c b/gcc/c-cppbuiltin.c
index bf9885e..44c7a37 100644
--- a/gcc/c-cppbuiltin.c
+++ b/gcc/c-cppbuiltin.c
@@ -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)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 1747309..bb6ca4a 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -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 ();
diff --git a/gcc/common.opt b/gcc/common.opt
index 7b6aee1..4d097c7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -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
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 5a1af7a..0f487c4 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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;
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 46fe51e..8aaad7b 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -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)
@@ -19436,53 +19438,16 @@
"jmp\t*%%r11"
[(set_attr "type" "callv")])
+;; 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 "" "")
@@ -19633,6 +19598,73 @@
[(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")
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 6a3b76e..ed07a2f 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -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
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index fbf5cd1..cd2bf87 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -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
diff --git a/gcc/function.c b/gcc/function.c
index c5c8dd8..7ab698b 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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
}
+/* 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);
+}
+
/* 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. */
diff --git a/gcc/function.h b/gcc/function.h
index f935e2e..2d59d23 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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
diff --git a/gcc/libgcc-std.ver b/gcc/libgcc-std.ver
index 341cf7a..d6c1821 100644
--- a/gcc/libgcc-std.ver
+++ b/gcc/libgcc-std.ver
@@ -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
+}
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index 3108bff..a49c8c1 100644
--- a/gcc/libgcc2.c
+++ b/gcc/libgcc2.c
@@ -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 */
+
+#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 */
+
+#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 */
diff --git a/gcc/libgcc2.h b/gcc/libgcc2.h
index 05901d8..cd1e47e 100644
--- a/gcc/libgcc2.h
+++ b/gcc/libgcc2.h
@@ -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
diff --git a/gcc/mklibgcc.in b/gcc/mklibgcc.in
index aa61d41..d2581d5 100644
--- a/gcc/mklibgcc.in
+++ b/gcc/mklibgcc.in
@@ -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
diff --git a/gcc/params.def b/gcc/params.def
index c17b54e..0948c40 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -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
diff --git a/gcc/target-def.h b/gcc/target-def.h
index 91cb6d3..cdaf3d3 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -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, \
diff --git a/gcc/target.h b/gcc/target.h
index 9c39f03..87e644b 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -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. */
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 31aa0dd..ec374c6 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -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"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 99aeb5b..80c49c8 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -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);
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 709d63e..495e104 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 09e0d63..1c0a4be 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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);