c-cppbuiltin.c (c_cpp_builtins): Add __SSP_ALL__ and __SSP__.

* 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
This commit is contained in:
Richard Henderson 2005-06-27 00:41:16 -07:00 committed by Jakub Jelinek
parent 2bcf2e2bf1
commit 7d69de618e
22 changed files with 809 additions and 60 deletions

View 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

View 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

View 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)

View 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 ();
}
/* 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);
@ -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 ();

View 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

View 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;

View 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)
@ -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")

View 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

View 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

View 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
}
/* 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. */

View 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

View 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
}

View 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 */
#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 */

View 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

View 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

View 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

View 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, \

View 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. */

View 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"

View 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);

View 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. */

View 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);