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>
|
2005-06-26 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||||
|
|
||||||
PR c/21911
|
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)
|
$(FLAGS_H) $(PARAMS_H)
|
||||||
targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_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 \
|
$(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) \
|
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 \
|
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) \
|
$(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) \
|
$(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 \
|
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) \
|
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) \
|
$(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) \
|
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) \
|
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) \
|
$(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) \
|
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) \
|
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 \
|
$(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) \
|
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-chrec.h $(srcdir)/tree-vect-generic.c \
|
||||||
$(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \
|
$(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \
|
||||||
$(srcdir)/tree-profile.c $(srcdir)/rtl-profile.c $(srcdir)/tree-nested.c \
|
$(srcdir)/tree-profile.c $(srcdir)/rtl-profile.c $(srcdir)/tree-nested.c \
|
||||||
$(out_file) \
|
$(srcdir)/targhooks.c $(out_file) \
|
||||||
@all_gtfiles@
|
@all_gtfiles@
|
||||||
|
|
||||||
GTFILES_FILES_LANGS = @all_gtfiles_files_langs@
|
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-ssanames.h gt-tree-iterator.h gt-gimplify.h \
|
||||||
gt-tree-phinodes.h gt-tree-nested.h \
|
gt-tree-phinodes.h gt-tree-nested.h \
|
||||||
gt-tree-ssa-operands.h gt-tree-ssa-propagate.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
|
gtyp-gen.h: s-gtyp-gen ; @true
|
||||||
s-gtyp-gen: Makefile
|
s-gtyp-gen: Makefile
|
||||||
|
@ -440,6 +440,12 @@ c_cpp_builtins (cpp_reader *pfile)
|
|||||||
if (targetm.handle_pragma_extern_prefix)
|
if (targetm.handle_pragma_extern_prefix)
|
||||||
cpp_define (pfile, "__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
|
/* A straightforward target hook doesn't work, because of problems
|
||||||
linking that hook's body when part of non-C front ends. */
|
linking that hook's body when part of non-C front ends. */
|
||||||
# define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM)
|
# 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 "flags.h"
|
||||||
#include "diagnostic.h"
|
#include "diagnostic.h"
|
||||||
#include "toplev.h"
|
#include "toplev.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
|
||||||
/* Verify that there is exactly single jump instruction since last and attach
|
/* Verify that there is exactly single jump instruction since last and attach
|
||||||
REG_BR_PROB note specifying probability.
|
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. */
|
(frame_offset+frame_phase) % PREFERRED_STACK_BOUNDARY == 0. */
|
||||||
static int frame_phase;
|
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
|
/* Discover the byte alignment to use for DECL. Ignore alignment
|
||||||
we can't do with expected alignment of the stack boundary. */
|
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. */
|
with that location. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
expand_stack_vars (void)
|
expand_stack_vars (bool (*pred) (tree))
|
||||||
{
|
{
|
||||||
size_t si, i, j, n = stack_vars_num;
|
size_t si, i, j, n = stack_vars_num;
|
||||||
|
|
||||||
@ -501,6 +510,16 @@ expand_stack_vars (void)
|
|||||||
if (stack_vars[i].representative != i)
|
if (stack_vars[i].representative != i)
|
||||||
continue;
|
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,
|
offset = alloc_stack_frame_space (stack_vars[i].size,
|
||||||
stack_vars[i].alignb);
|
stack_vars[i].alignb);
|
||||||
|
|
||||||
@ -620,6 +639,11 @@ expand_one_error_var (tree var)
|
|||||||
static bool
|
static bool
|
||||||
defer_stack_allocation (tree var, bool toplevel)
|
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
|
/* Variables in the outermost scope automatically conflict with
|
||||||
every other variable. The only reason to want to defer them
|
every other variable. The only reason to want to defer them
|
||||||
at all is that, after sorting, we can more efficiently pack
|
at all is that, after sorting, we can more efficiently pack
|
||||||
@ -725,6 +749,144 @@ clear_tree_used (tree block)
|
|||||||
clear_tree_used (t);
|
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. */
|
/* Expand all variables used in the function. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -746,6 +908,10 @@ expand_used_vars (void)
|
|||||||
/* Clear TREE_USED on all variables associated with a block scope. */
|
/* Clear TREE_USED on all variables associated with a block scope. */
|
||||||
clear_tree_used (outer_block);
|
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
|
/* At this point all variables on the unexpanded_var_list with TREE_USED
|
||||||
set are not associated with any block scope. Lay them out. */
|
set are not associated with any block scope. Lay them out. */
|
||||||
for (t = cfun->unexpanded_var_list; t; t = TREE_CHAIN (t))
|
for (t = cfun->unexpanded_var_list; t; t = TREE_CHAIN (t))
|
||||||
@ -794,14 +960,44 @@ expand_used_vars (void)
|
|||||||
reflect this. */
|
reflect this. */
|
||||||
add_alias_set_conflicts ();
|
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
|
/* Now that we have collected all stack variables, and have computed a
|
||||||
minimal interference graph, attempt to save some stack space. */
|
minimal interference graph, attempt to save some stack space. */
|
||||||
partition_stack_vars ();
|
partition_stack_vars ();
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
dump_stack_var_partition ();
|
dump_stack_var_partition ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Assign rtl to each variable based on these partitions. */
|
/* There are several conditions under which we should create a
|
||||||
expand_stack_vars ();
|
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. */
|
/* Free up stack variable graph data. */
|
||||||
XDELETEVEC (stack_vars);
|
XDELETEVEC (stack_vars);
|
||||||
@ -1288,6 +1484,16 @@ tree_expand_cfg (void)
|
|||||||
/* Expand the variables recorded during gimple lowering. */
|
/* Expand the variables recorded during gimple lowering. */
|
||||||
expand_used_vars ();
|
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. */
|
/* Set up parameters and prepare for return, for the function. */
|
||||||
expand_function_start (current_function_decl);
|
expand_function_start (current_function_decl);
|
||||||
|
|
||||||
@ -1298,6 +1504,11 @@ tree_expand_cfg (void)
|
|||||||
&& DECL_FILE_SCOPE_P (current_function_decl))
|
&& DECL_FILE_SCOPE_P (current_function_decl))
|
||||||
expand_main_function ();
|
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. */
|
/* Register rtl specific functions for cfg. */
|
||||||
rtl_register_cfg_hooks ();
|
rtl_register_cfg_hooks ();
|
||||||
|
|
||||||
|
@ -109,6 +109,10 @@ Wshadow
|
|||||||
Common Var(warn_shadow)
|
Common Var(warn_shadow)
|
||||||
Warn when one local variable shadows another
|
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
|
Wstrict-aliasing
|
||||||
Common
|
Common
|
||||||
Warn about code which might break strict aliasing rules
|
Warn about code which might break strict aliasing rules
|
||||||
@ -784,6 +788,14 @@ fstack-limit-symbol=
|
|||||||
Common RejectNegative Joined
|
Common RejectNegative Joined
|
||||||
-fstack-limit-symbol=<name> Trap if the stack goes past symbol <name>
|
-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
|
fstrength-reduce
|
||||||
Common Report Var(flag_strength_reduce)
|
Common Report Var(flag_strength_reduce)
|
||||||
Perform strength reduction optimizations
|
Perform strength reduction optimizations
|
||||||
|
@ -1081,6 +1081,9 @@ static void init_ext_80387_constants (void);
|
|||||||
#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
|
#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
|
||||||
#define TARGET_MANGLE_FUNDAMENTAL_TYPE ix86_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;
|
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@
|
|||||||
(UNSPEC_FLDCW 25)
|
(UNSPEC_FLDCW 25)
|
||||||
(UNSPEC_REP 26)
|
(UNSPEC_REP 26)
|
||||||
(UNSPEC_EH_RETURN 27)
|
(UNSPEC_EH_RETURN 27)
|
||||||
|
(UNSPEC_SP_SET 28)
|
||||||
|
(UNSPEC_SP_TEST 29)
|
||||||
|
|
||||||
; For SSE/MMX support:
|
; For SSE/MMX support:
|
||||||
(UNSPEC_FIX_NOTRUNC 30)
|
(UNSPEC_FIX_NOTRUNC 30)
|
||||||
@ -19436,53 +19438,16 @@
|
|||||||
"jmp\t*%%r11"
|
"jmp\t*%%r11"
|
||||||
[(set_attr "type" "callv")])
|
[(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"
|
(define_insn "trap"
|
||||||
[(trap_if (const_int 1) (const_int 5))]
|
[(trap_if (const_int 1) (const_int 6))]
|
||||||
""
|
""
|
||||||
"int\t$5")
|
"ud2"
|
||||||
|
[(set_attr "length" "2")])
|
||||||
;;; 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;
|
|
||||||
})
|
|
||||||
|
|
||||||
(define_expand "sse_prologue_save"
|
(define_expand "sse_prologue_save"
|
||||||
[(parallel [(set (match_operand:BLK 0 "" "")
|
[(parallel [(set (match_operand:BLK 0 "" "")
|
||||||
@ -19633,6 +19598,73 @@
|
|||||||
[(set_attr "type" "mmx")
|
[(set_attr "type" "mmx")
|
||||||
(set_attr "memory" "none")])
|
(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 "sse.md")
|
||||||
(include "mmx.md")
|
(include "mmx.md")
|
||||||
(include "sync.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
|
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.
|
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 table
|
||||||
|
|
||||||
@end ifset
|
@end ifset
|
||||||
|
@ -2716,6 +2716,7 @@ This describes the stack layout and calling conventions.
|
|||||||
* Function Entry::
|
* Function Entry::
|
||||||
* Profiling::
|
* Profiling::
|
||||||
* Tail Calls::
|
* Tail Calls::
|
||||||
|
* Stack Smashing Protection::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Frame Layout
|
@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.
|
may vary greatly between different architectures.
|
||||||
@end deftypefn
|
@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
|
@node Varargs
|
||||||
@section Implementing the Varargs Macros
|
@section Implementing the Varargs Macros
|
||||||
@cindex varargs implementation
|
@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 "target.h"
|
||||||
#include "cfglayout.h"
|
#include "cfglayout.h"
|
||||||
#include "tree-gimple.h"
|
#include "tree-gimple.h"
|
||||||
|
#include "predict.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef LOCAL_ALIGNMENT
|
#ifndef LOCAL_ALIGNMENT
|
||||||
#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) 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)
|
&& data->nominal_mode != data->passed_mode)
|
||||||
stack_parm = NULL;
|
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;
|
data->stack_parm = stack_parm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3921,6 +3931,97 @@ expand_main_function (void)
|
|||||||
#endif
|
#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
|
/* Start the RTL for a new function, and set variables used for
|
||||||
emitting RTL.
|
emitting RTL.
|
||||||
SUBR is the FUNCTION_DECL node.
|
SUBR is the FUNCTION_DECL node.
|
||||||
@ -4267,11 +4368,6 @@ expand_function_end (void)
|
|||||||
/* Output the label for the actual return from the function. */
|
/* Output the label for the actual return from the function. */
|
||||||
emit_label (return_label);
|
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
|
/* 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 value that got dumped to the stack, copy that to the hard
|
||||||
return register. */
|
return register. */
|
||||||
@ -4399,6 +4495,15 @@ expand_function_end (void)
|
|||||||
/* Output the label for the naked return from the function. */
|
/* Output the label for the naked return from the function. */
|
||||||
emit_label (naked_return_label);
|
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
|
/* If we had calls to alloca, and this machine needs
|
||||||
an accurate stack pointer to exit the function,
|
an accurate stack pointer to exit the function,
|
||||||
insert some code to save and restore the stack pointer. */
|
insert some code to save and restore the stack pointer. */
|
||||||
|
@ -368,6 +368,10 @@ struct function GTY(())
|
|||||||
|
|
||||||
const char *unlikely_text_section_name;
|
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. */
|
/* Collected bit flags. */
|
||||||
|
|
||||||
/* Nonzero if function being compiled needs to be given an address
|
/* Nonzero if function being compiled needs to be given an address
|
||||||
|
@ -252,3 +252,10 @@ GCC_4.0.0 {
|
|||||||
__mulxc3
|
__mulxc3
|
||||||
__multc3
|
__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
|
||||||
#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
|
#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
|
||||||
#endif /* L_ctors */
|
#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 __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
|
#ifndef HIDE_EXPORTS
|
||||||
#pragma GCC visibility pop
|
#pragma GCC visibility pop
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,7 +63,7 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
|
|||||||
_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
|
_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
|
||||||
_popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
|
_popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
|
||||||
_powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3
|
_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.
|
# Disable SHLIB_LINK if shared libgcc not enabled.
|
||||||
if [ "@enable_shared@" = "no" ]; then
|
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",
|
"Ratio between virtual mappings and virtual symbols to do full virtual renames",
|
||||||
3, 0, 0)
|
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:
|
Local variables:
|
||||||
mode:c
|
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_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_ARGS hook_bool_tree_false
|
||||||
#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_false
|
#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_false
|
||||||
#define TARGET_PROMOTE_PROTOTYPES 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_CALLING_CONVENTION, \
|
||||||
TARGET_DWARF_HANDLE_FRAME_UNSPEC, \
|
TARGET_DWARF_HANDLE_FRAME_UNSPEC, \
|
||||||
TARGET_STDARG_OPTIMIZE_HOOK, \
|
TARGET_STDARG_OPTIMIZE_HOOK, \
|
||||||
|
TARGET_STACK_PROTECT_GUARD, \
|
||||||
|
TARGET_STACK_PROTECT_FAIL, \
|
||||||
TARGET_INVALID_WITHIN_DOLOOP, \
|
TARGET_INVALID_WITHIN_DOLOOP, \
|
||||||
TARGET_CALLS, \
|
TARGET_CALLS, \
|
||||||
TARGET_CXX, \
|
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
|
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
|
is right hand side. Returns true if the statements doesn't need
|
||||||
to be checked for va_list references. */
|
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,
|
/* Returns NULL if target supports the insn within a doloop block,
|
||||||
otherwise it returns an error message. */
|
otherwise it returns an error message. */
|
||||||
|
@ -61,6 +61,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
|||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "tm_p.h"
|
#include "tm_p.h"
|
||||||
#include "target-def.h"
|
#include "target-def.h"
|
||||||
|
#include "ggc.h"
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -321,3 +322,86 @@ hook_invalid_arg_for_unprototyped_fn (
|
|||||||
{
|
{
|
||||||
return NULL;
|
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
|
extern unsigned HOST_WIDE_INT default_shift_truncation_mask
|
||||||
(enum machine_mode);
|
(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_guard_type (void);
|
||||||
extern tree default_cxx_get_cookie_size (tree);
|
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. */
|
/* With -fcx-limited-range, we do cheap and quick complex arithmetic. */
|
||||||
if (flag_cx_limited_range)
|
if (flag_cx_limited_range)
|
||||||
flag_complex_method = 0;
|
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. */
|
/* 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 dump_tree_statistics (void);
|
||||||
extern void expand_function_end (void);
|
extern void expand_function_end (void);
|
||||||
extern void expand_function_start (tree);
|
extern void expand_function_start (tree);
|
||||||
|
extern void stack_protect_prologue (void);
|
||||||
extern void recompute_tree_invarant_for_addr_expr (tree);
|
extern void recompute_tree_invarant_for_addr_expr (tree);
|
||||||
extern bool is_global_var (tree t);
|
extern bool is_global_var (tree t);
|
||||||
extern bool needs_to_live_in_memory (tree);
|
extern bool needs_to_live_in_memory (tree);
|
||||||
|
Loading…
Reference in New Issue
Block a user