* 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. Index: gcc/Makefile.in =================================================================== RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v retrieving revision 1.1484 diff -u -p -d -r1.1484 Makefile.in --- gcc/Makefile.in 11 May 2005 16:25:24 -0000 1.1484 +++ gcc/Makefile.in 12 May 2005 23:56:05 -0000 @@ -1893,7 +1893,7 @@ opts.o : opts.c opts.h options.h toplev. $(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 \ @@ -1946,7 +1946,7 @@ function.o : function.c $(CONFIG_H) $(SY $(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) \ @@ -2132,7 +2132,7 @@ cfghooks.o: cfghooks.c $(CONFIG_H) $(SYS 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) \ @@ -2585,7 +2585,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/co $(srcdir)/tree-chrec.h $(srcdir)/tree-complex.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@ @@ -2606,7 +2606,7 @@ gt-tree-profile.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: gcc/c-cppbuiltin.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-cppbuiltin.c,v retrieving revision 1.30 diff -u -p -d -r1.30 c-cppbuiltin.c --- gcc/c-cppbuiltin.c 1 May 2005 20:30:26 -0000 1.30 +++ gcc/c-cppbuiltin.c 12 May 2005 23:56:05 -0000 @@ -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: gcc/cfgexpand.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cfgexpand.c,v retrieving revision 2.38 diff -u -p -d -r2.38 cfgexpand.c --- gcc/cfgexpand.c 28 Apr 2005 05:02:59 -0000 2.38 +++ gcc/cfgexpand.c 12 May 2005 23:56:05 -0000 @@ -37,6 +37,8 @@ Boston, MA 02111-1307, 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. @@ -144,6 +146,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. */ @@ -494,7 +503,7 @@ expand_one_stack_var_at (tree decl, HOST with that location. */ static void -expand_stack_vars (void) +expand_stack_vars (bool (*pred) (tree)) { size_t si, i, j, n = stack_vars_num; @@ -508,6 +517,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); @@ -627,6 +646,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 @@ -732,6 +756,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 @@ -753,6 +915,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)) @@ -801,14 +967,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 (); + } - /* Assign rtl to each variable based on these partitions. */ - expand_stack_vars (); + /* 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. */ + 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); @@ -1285,6 +1481,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); @@ -1295,6 +1501,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: gcc/common.opt =================================================================== RCS file: /cvs/gcc/gcc/gcc/common.opt,v retrieving revision 1.70 diff -u -p -d -r1.70 common.opt --- gcc/common.opt 4 May 2005 01:36:09 -0000 1.70 +++ gcc/common.opt 12 May 2005 23:56:05 -0000 @@ -105,6 +105,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 @@ -777,6 +781,14 @@ fstack-limit-symbol= Common RejectNegative Joined -fstack-limit-symbol= Trap if the stack goes past symbol +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: gcc/function.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/function.c,v retrieving revision 1.622 diff -u -p -d -r1.622 function.c --- gcc/function.c 12 May 2005 23:52:37 -0000 1.622 +++ gcc/function.c 12 May 2005 23:56:06 -0000 @@ -61,6 +61,8 @@ Software Foundation, 59 Temple Place - S #include "target.h" #include "cfglayout.h" #include "tree-gimple.h" +#include "predict.h" + #ifndef LOCAL_ALIGNMENT #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT @@ -2329,6 +2331,14 @@ assign_parm_adjust_stack_rtl (struct ass && 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; } @@ -3914,6 +3924,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. @@ -4260,11 +4361,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. */ @@ -4392,6 +4488,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: gcc/function.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/function.h,v retrieving revision 1.150 diff -u -p -d -r1.150 function.h --- gcc/function.h 12 May 2005 19:29:19 -0000 1.150 +++ gcc/function.h 12 May 2005 23:56:07 -0000 @@ -356,17 +356,19 @@ struct function GTY(()) /* Assembly labels for the hot and cold text sections, to be used by debugger functions for determining the size of text sections. */ - - const char * hot_section_label; - const char * cold_section_label; - const char * hot_section_end_label; - const char * cold_section_end_label; + const char *hot_section_label; + const char *cold_section_label; + const char *hot_section_end_label; + const char *cold_section_end_label; /* String to be used for name of cold text sections, via targetm.asm_out.named_section. */ - 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: gcc/libgcc-std.ver =================================================================== RCS file: /cvs/gcc/gcc/gcc/libgcc-std.ver,v retrieving revision 1.29 diff -u -p -d -r1.29 libgcc-std.ver --- gcc/libgcc-std.ver 12 Feb 2005 00:26:51 -0000 1.29 +++ gcc/libgcc-std.ver 12 May 2005 23:56:07 -0000 @@ -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: gcc/libgcc2.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/libgcc2.c,v retrieving revision 1.190 diff -u -p -d -r1.190 libgcc2.c --- gcc/libgcc2.c 8 May 2005 10:13:17 -0000 1.190 +++ gcc/libgcc2.c 12 May 2005 23:56:07 -0000 @@ -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 +# include +# include +# ifdef HAVE_PATHS_H +# include +# endif +# ifndef _PATH_TTY +# define _PATH_TTY "/dev/tty" +# endif +# ifdef HAVE_SYSLOG_H +# include +# 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 */ Index: gcc/libgcc2.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/libgcc2.h,v retrieving revision 1.40 diff -u -p -d -r1.40 libgcc2.h --- gcc/libgcc2.h 30 Mar 2005 20:59:21 -0000 1.40 +++ gcc/libgcc2.h 12 May 2005 23:56:07 -0000 @@ -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: gcc/mklibgcc.in =================================================================== RCS file: /cvs/gcc/gcc/gcc/mklibgcc.in,v retrieving revision 1.87 diff -u -p -d -r1.87 mklibgcc.in --- gcc/mklibgcc.in 19 Apr 2005 19:53:26 -0000 1.87 +++ gcc/mklibgcc.in 12 May 2005 23:56:07 -0000 @@ -63,7 +63,7 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ash _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: gcc/params.def =================================================================== RCS file: /cvs/gcc/gcc/gcc/params.def,v retrieving revision 1.59 diff -u -p -d -r1.59 params.def --- gcc/params.def 23 Apr 2005 00:59:23 -0000 1.59 +++ gcc/params.def 12 May 2005 23:56:07 -0000 @@ -467,6 +467,11 @@ DEFPARAM (PARAM_VIRTUAL_MAPPINGS_TO_SYMS "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: gcc/target-def.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/target-def.h,v retrieving revision 1.121 diff -u -p -d -r1.121 target-def.h --- gcc/target-def.h 2 May 2005 16:02:22 -0000 1.121 +++ gcc/target-def.h 12 May 2005 23:56:07 -0000 @@ -388,6 +388,9 @@ Foundation, 59 Temple Place - Suite 330, #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 @@ -553,6 +556,8 @@ Foundation, 59 Temple Place - Suite 330, TARGET_DWARF_CALLING_CONVENTION, \ TARGET_DWARF_HANDLE_FRAME_UNSPEC, \ TARGET_STDARG_OPTIMIZE_HOOK, \ + TARGET_STACK_PROTECT_GUARD, \ + TARGET_STACK_PROTECT_FAIL, \ TARGET_CALLS, \ TARGET_CXX, \ TARGET_HAVE_NAMED_SECTIONS, \ Index: gcc/target.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/target.h,v retrieving revision 1.133 diff -u -p -d -r1.133 target.h --- gcc/target.h 2 May 2005 16:02:23 -0000 1.133 +++ gcc/target.h 12 May 2005 23:56:08 -0000 @@ -518,7 +518,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); /* Functions relating to calls - argument passing, returns, etc. */ struct calls { Index: gcc/targhooks.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/targhooks.c,v retrieving revision 2.38 diff -u -p -d -r2.38 targhooks.c --- gcc/targhooks.c 12 Mar 2005 00:34:04 -0000 2.38 +++ gcc/targhooks.c 12 May 2005 23:56:08 -0000 @@ -61,6 +61,7 @@ Software Foundation, 59 Temple Place - S #include "target.h" #include "tm_p.h" #include "target-def.h" +#include "ggc.h" void @@ -297,3 +298,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: gcc/targhooks.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/targhooks.h,v retrieving revision 2.27 diff -u -p -d -r2.27 targhooks.h --- gcc/targhooks.h 8 Mar 2005 21:01:42 -0000 2.27 +++ gcc/targhooks.h 12 May 2005 23:56:08 -0000 @@ -34,6 +34,10 @@ extern enum machine_mode default_eh_retu 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: gcc/toplev.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/toplev.c,v retrieving revision 1.954 diff -u -p -d -r1.954 toplev.c --- gcc/toplev.c 3 May 2005 17:55:38 -0000 1.954 +++ gcc/toplev.c 12 May 2005 23:56:08 -0000 @@ -1967,6 +1967,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: gcc/tree.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/tree.h,v retrieving revision 1.727 diff -u -p -d -r1.727 tree.h --- gcc/tree.h 11 May 2005 16:25:30 -0000 1.727 +++ gcc/tree.h 12 May 2005 23:56:09 -0000 @@ -3634,6 +3634,7 @@ extern int simple_cst_list_equal (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); Index: gcc/config/i386/i386.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v retrieving revision 1.820 diff -u -p -d -r1.820 i386.c --- gcc/config/i386/i386.c 7 May 2005 14:43:53 -0000 1.820 +++ gcc/config/i386/i386.c 12 May 2005 23:56:12 -0000 @@ -1095,6 +1095,9 @@ static void init_ext_80387_constants (vo #define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES #endif +#undef TARGET_STACK_PROTECT_FAIL +#define TARGET_STACK_PROTECT_FAIL default_hidden_stack_protect_fail + struct gcc_target targetm = TARGET_INITIALIZER; Index: gcc/config/i386/i386.md =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v retrieving revision 1.632 diff -u -p -d -r1.632 i386.md --- gcc/config/i386/i386.md 1 May 2005 00:47:57 -0000 1.632 +++ gcc/config/i386/i386.md 12 May 2005 23:56:16 -0000 @@ -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) @@ -19523,53 +19525,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))] - "" - "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" ""))] + [(trap_if (const_int 1) (const_int 6))] "" -{ - 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 "" "") @@ -19720,6 +19685,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") Index: gcc/doc/md.texi =================================================================== RCS file: /cvs/gcc/gcc/gcc/doc/md.texi,v retrieving revision 1.133 diff -u -p -d -r1.133 md.texi --- gcc/doc/md.texi 10 May 2005 22:40:37 -0000 1.133 +++ gcc/doc/md.texi 12 May 2005 23:56:17 -0000 @@ -4083,6 +4083,30 @@ released only after all previous memory 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: gcc/doc/tm.texi =================================================================== RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v retrieving revision 1.427 diff -u -p -d -r1.427 tm.texi --- gcc/doc/tm.texi 4 May 2005 16:27:21 -0000 1.427 +++ gcc/doc/tm.texi 12 May 2005 23:56:20 -0000 @@ -2863,6 +2863,7 @@ This describes the stack layout and call * Function Entry:: * Profiling:: * Tail Calls:: +* Stack Smashing Protection:: @end menu @node Frame Layout @@ -4526,6 +4527,31 @@ as the @code{sibcall} md pattern can not 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