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:
parent
2bcf2e2bf1
commit
7d69de618e
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
217
gcc/cfgexpand.c
217
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 ();
|
||||
}
|
||||
|
||||
/* 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 ();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
115
gcc/function.c
115
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. */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
138
gcc/libgcc2.c
138
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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, \
|
||||
|
11
gcc/target.h
11
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. */
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
12
gcc/toplev.c
12
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. */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user