summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiroaki Etoh <etoh@cvs.openbsd.org>2004-01-22 05:02:28 +0000
committerHiroaki Etoh <etoh@cvs.openbsd.org>2004-01-22 05:02:28 +0000
commitc36a2ee0746288226da0613af6633da315013b0e (patch)
tree4b42c9795a732f1786a6e1a0d44058fc630f25df
parentecfdbedbc0e3bb9a610b6da08829f45aa3233d10 (diff)
initial release of propolice gcc 3.3.2
-rw-r--r--gnu/usr.bin/gcc/gcc/Makefile.in9
-rw-r--r--gnu/usr.bin/gcc/gcc/calls.c2
-rw-r--r--gnu/usr.bin/gcc/gcc/combine.c22
-rw-r--r--gnu/usr.bin/gcc/gcc/cse.c17
-rw-r--r--gnu/usr.bin/gcc/gcc/explow.c21
-rw-r--r--gnu/usr.bin/gcc/gcc/expr.c29
-rw-r--r--gnu/usr.bin/gcc/gcc/flags.h9
-rw-r--r--gnu/usr.bin/gcc/gcc/function.c28
-rw-r--r--gnu/usr.bin/gcc/gcc/gcse.c2
-rw-r--r--gnu/usr.bin/gcc/gcc/integrate.c8
-rw-r--r--gnu/usr.bin/gcc/gcc/libgcc-std.ver4
-rw-r--r--gnu/usr.bin/gcc/gcc/loop.c8
-rw-r--r--gnu/usr.bin/gcc/gcc/optabs.c20
-rw-r--r--gnu/usr.bin/gcc/gcc/protector.c2633
-rw-r--r--gnu/usr.bin/gcc/gcc/protector.h53
-rw-r--r--gnu/usr.bin/gcc/gcc/reload1.c13
-rw-r--r--gnu/usr.bin/gcc/gcc/simplify-rtx.c61
-rw-r--r--gnu/usr.bin/gcc/gcc/toplev.c24
18 files changed, 2924 insertions, 39 deletions
diff --git a/gnu/usr.bin/gcc/gcc/Makefile.in b/gnu/usr.bin/gcc/gcc/Makefile.in
index 5326486d16b..a3e8fdc33aa 100644
--- a/gnu/usr.bin/gcc/gcc/Makefile.in
+++ b/gnu/usr.bin/gcc/gcc/Makefile.in
@@ -388,7 +388,7 @@ INSTALL_LIBGCC = install-libgcc
# Options to use when compiling libgcc2.a.
#
LIBGCC2_DEBUG_CFLAGS = -g
-LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED @inhibit_libc@
+LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED @inhibit_libc@ -fno-stack-protector
# Additional options to use when compiling libgcc2.a.
# Some targets override this to -isystem include
@@ -765,7 +765,7 @@ OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \
sibcall.o simplify-rtx.o ssa.o ssa-ccp.o ssa-dce.o stmt.o \
stor-layout.o stringpool.o timevar.o toplev.o tracer.o tree.o tree-dump.o \
tree-inline.o unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \
- et-forest.o $(GGC) $(out_object_file) $(EXTRA_OBJS)
+ et-forest.o protector.o $(GGC) $(out_object_file) $(EXTRA_OBJS)
BACKEND = main.o libbackend.a
@@ -799,7 +799,7 @@ LIB2FUNCS_1 = _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 _ffsdi2 _clz \
LIB2FUNCS_2 = _floatdixf _fixunsxfsi _fixtfdi _fixunstfdi _floatditf \
_clear_cache _trampoline __main _exit _absvsi2 _absvdi2 _addvsi3 \
- _addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
+ _addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors _stack_smash_handler
# Defined in libgcc2.c, included only in the static library.
LIB2FUNCS_ST = _eprintf _bb __gcc_bcmp
@@ -1410,7 +1410,7 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(RTL_H) function.h \
ssa.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \
langhooks.h insn-flags.h options.h cfglayout.h real.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
- -DTARGET_NAME=\"$(target_alias)\" \
+ -DSTACK_PROTECTOR -DTARGET_NAME=\"$(target_alias)\" \
-c $(srcdir)/toplev.c $(OUTPUT_OPTION)
main.o : main.c $(CONFIG_H) $(SYSTEM_H) toplev.h
@@ -1665,6 +1665,7 @@ ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) toplev.h \
output.h except.h $(TM_P_H) real.h
params.o : params.c $(CONFIG_H) $(SYSTEM_H) $(PARAMS_H) toplev.h
hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H) $(HOOKS_H)
+protector.o: protector.c $(CONFIG_H)
$(out_object_file): $(out_file) $(CONFIG_H) $(TREE_H) $(GGC_H) \
$(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h conditions.h \
diff --git a/gnu/usr.bin/gcc/gcc/calls.c b/gnu/usr.bin/gcc/gcc/calls.c
index 675674ec7f5..8c3ad6e837e 100644
--- a/gnu/usr.bin/gcc/gcc/calls.c
+++ b/gnu/usr.bin/gcc/gcc/calls.c
@@ -2331,7 +2331,7 @@ expand_call (exp, target, ignore)
/* For variable-sized objects, we must be called with a target
specified. If we were to allocate space on the stack here,
we would have no way of knowing when to free it. */
- rtx d = assign_temp (TREE_TYPE (exp), 1, 1, 1);
+ rtx d = assign_temp (TREE_TYPE (exp), 5, 1, 1);
mark_temp_addr_taken (d);
structure_value_addr = XEXP (d, 0);
diff --git a/gnu/usr.bin/gcc/gcc/combine.c b/gnu/usr.bin/gcc/gcc/combine.c
index cec5a29cf51..410c1eaab84 100644
--- a/gnu/usr.bin/gcc/gcc/combine.c
+++ b/gnu/usr.bin/gcc/gcc/combine.c
@@ -3889,7 +3889,17 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
rtx inner_op0 = XEXP (XEXP (x, 0), 1);
rtx inner_op1 = XEXP (x, 1);
rtx inner;
-
+
+#ifndef FRAME_GROWS_DOWNWARD
+ if (flag_propolice_protection
+ && code == PLUS
+ && other == frame_pointer_rtx
+ && GET_CODE (inner_op0) == CONST_INT
+ && GET_CODE (inner_op1) == CONST_INT
+ && INTVAL (inner_op0) > 0
+ && INTVAL (inner_op0) + INTVAL (inner_op1) <= 0)
+ return x;
+#endif
/* Make sure we pass the constant operand if any as the second
one if this is a commutative operation. */
if (CONSTANT_P (inner_op0) && GET_RTX_CLASS (code) == 'c')
@@ -4302,6 +4312,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
they are now checked elsewhere. */
if (GET_CODE (XEXP (x, 0)) == PLUS
&& CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
+#ifndef FRAME_GROWS_DOWNWARD
+ if (! (flag_propolice_protection
+ && XEXP (XEXP (x, 0), 0) == frame_pointer_rtx
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
+#endif
return gen_binary (PLUS, mode,
gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
XEXP (x, 1)),
@@ -4430,7 +4445,10 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
/* Canonicalize (minus A (plus B C)) to (minus (minus A B) C) for
integers. */
- if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
+ if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode)
+ && (! (flag_propolice_protection
+ && XEXP (XEXP (x, 1), 0) == frame_pointer_rtx
+ && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)))
return gen_binary (MINUS, mode,
gen_binary (MINUS, mode, XEXP (x, 0),
XEXP (XEXP (x, 1), 0)),
diff --git a/gnu/usr.bin/gcc/gcc/cse.c b/gnu/usr.bin/gcc/gcc/cse.c
index 9566865debe..1d685a62433 100644
--- a/gnu/usr.bin/gcc/gcc/cse.c
+++ b/gnu/usr.bin/gcc/gcc/cse.c
@@ -4288,7 +4288,14 @@ fold_rtx (x, insn)
if (new_const == 0)
break;
-
+#ifndef FRAME_GROWS_DOWNWARD
+ if (flag_propolice_protection
+ && GET_CODE (y) == PLUS
+ && XEXP (y, 0) == frame_pointer_rtx
+ && INTVAL (inner_const) > 0
+ && INTVAL (new_const) <= 0)
+ break;
+#endif
/* If we are associating shift operations, don't let this
produce a shift of the size of the object or larger.
This could occur when we follow a sign-extend by a right
@@ -4823,6 +4830,14 @@ cse_insn (insn, libcall_insn)
if (SET_DEST (x) == pc_rtx
&& GET_CODE (SET_SRC (x)) == LABEL_REF)
;
+ /* cut the reg propagation of stack-protected argument */
+ else if (x->volatil) {
+ rtx x1 = SET_DEST (x);
+ if (GET_CODE (x1) == SUBREG && GET_CODE (SUBREG_REG (x1)) == REG)
+ x1 = SUBREG_REG (x1);
+ if (! REGNO_QTY_VALID_P(REGNO (x1)))
+ make_new_qty (REGNO (x1), GET_MODE (x1));
+ }
/* Don't count call-insns, (set (reg 0) (call ...)), as a set.
The hard function value register is used only once, to copy to
diff --git a/gnu/usr.bin/gcc/gcc/explow.c b/gnu/usr.bin/gcc/gcc/explow.c
index 0d9139a466b..0665d5e19d9 100644
--- a/gnu/usr.bin/gcc/gcc/explow.c
+++ b/gnu/usr.bin/gcc/gcc/explow.c
@@ -86,7 +86,8 @@ plus_constant_wide (x, c)
rtx tem;
int all_constant = 0;
- if (c == 0)
+ if (c == 0
+ && !(flag_propolice_protection && x == virtual_stack_vars_rtx))
return x;
restart:
@@ -187,7 +188,8 @@ plus_constant_wide (x, c)
break;
}
- if (c != 0)
+ if (c != 0
+ || (flag_propolice_protection && x == virtual_stack_vars_rtx))
x = gen_rtx_PLUS (mode, x, GEN_INT (c));
if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
@@ -531,6 +533,21 @@ memory_address (mode, x)
in certain cases. This is not necessary since the code
below can handle all possible cases, but machine-dependent
transformations can make better code. */
+ if (flag_propolice_protection)
+ {
+#define FRAMEADDR_P(X) (GET_CODE (X) == PLUS \
+ && XEXP (X, 0) == virtual_stack_vars_rtx \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT)
+ rtx y;
+ if (FRAMEADDR_P (x)) goto win;
+ for (y=x; y!=0 && GET_CODE (y)==PLUS; y = XEXP (y, 0))
+ {
+ if (FRAMEADDR_P (XEXP (y, 0)))
+ XEXP (y, 0) = force_reg (GET_MODE (XEXP (y, 0)), XEXP (y, 0));
+ if (FRAMEADDR_P (XEXP (y, 1)))
+ XEXP (y, 1) = force_reg (GET_MODE (XEXP (y, 1)), XEXP (y, 1));
+ }
+ }
LEGITIMIZE_ADDRESS (x, oldx, mode, win);
/* PLUS and MULT can appear in special ways
diff --git a/gnu/usr.bin/gcc/gcc/expr.c b/gnu/usr.bin/gcc/gcc/expr.c
index 9f7c2847c58..dde2d993b94 100644
--- a/gnu/usr.bin/gcc/gcc/expr.c
+++ b/gnu/usr.bin/gcc/gcc/expr.c
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "langhooks.h"
#include "intl.h"
#include "tm_p.h"
+#include "protector.h"
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
@@ -1527,7 +1528,7 @@ move_by_pieces (to, from, len, align)
if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from)
{
- data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len));
+ data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len-GET_MODE_SIZE (mode)));
data.autinc_from = 1;
data.explicit_inc_from = -1;
}
@@ -1541,7 +1542,7 @@ move_by_pieces (to, from, len, align)
data.from_addr = copy_addr_to_reg (from_addr);
if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
{
- data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
+ data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len-GET_MODE_SIZE (mode)));
data.autinc_to = 1;
data.explicit_inc_to = -1;
}
@@ -1658,11 +1659,13 @@ move_by_pieces_1 (genfun, mode, data)
from1 = adjust_address (data->from, mode, data->offset);
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
- emit_insn (gen_add2_insn (data->to_addr,
- GEN_INT (-(HOST_WIDE_INT)size)));
+ if (data->explicit_inc_to < -1)
+ emit_insn (gen_add2_insn (data->to_addr,
+ GEN_INT (-(HOST_WIDE_INT)size)));
if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
- emit_insn (gen_add2_insn (data->from_addr,
- GEN_INT (-(HOST_WIDE_INT)size)));
+ if (data->explicit_inc_from < -1)
+ emit_insn (gen_add2_insn (data->from_addr,
+ GEN_INT (-(HOST_WIDE_INT)size)));
if (data->to)
emit_insn ((*genfun) (to1, from1));
@@ -2835,7 +2838,7 @@ store_by_pieces_1 (data, align)
if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
{
- data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
+ data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len-GET_MODE_SIZE (mode)));
data->autinc_to = 1;
data->explicit_inc_to = -1;
}
@@ -2906,8 +2909,9 @@ store_by_pieces_2 (genfun, mode, data)
to1 = adjust_address (data->to, mode, data->offset);
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
- emit_insn (gen_add2_insn (data->to_addr,
- GEN_INT (-(HOST_WIDE_INT) size)));
+ if (data->explicit_inc_to < -1)
+ emit_insn (gen_add2_insn (data->to_addr,
+ GEN_INT (-(HOST_WIDE_INT) size)));
cst = (*data->constfun) (data->constfundata, data->offset, mode);
emit_insn ((*genfun) (to1, cst));
@@ -5903,7 +5907,9 @@ force_operand (value, target)
&& GET_CODE (XEXP (value, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
&& REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
- && REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
+ && REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER
+ && (!flag_propolice_protection
+ || XEXP (XEXP (value, 0), 0) != virtual_stack_vars_rtx))
{
rtx temp = expand_simple_binop (GET_MODE (value), code,
XEXP (XEXP (value, 0), 0), op2,
@@ -8079,7 +8085,8 @@ expand_expr (exp, target, tmode, modifier)
/* If adding to a sum including a constant,
associate it to put the constant outside. */
if (GET_CODE (op1) == PLUS
- && CONSTANT_P (XEXP (op1, 1)))
+ && CONSTANT_P (XEXP (op1, 1))
+ && !(flag_propolice_protection && (contains_fp (op0) || contains_fp (op1))))
{
rtx constant_term = const0_rtx;
diff --git a/gnu/usr.bin/gcc/gcc/flags.h b/gnu/usr.bin/gcc/gcc/flags.h
index 0a8979d2dc9..7aa7c73b4ef 100644
--- a/gnu/usr.bin/gcc/gcc/flags.h
+++ b/gnu/usr.bin/gcc/gcc/flags.h
@@ -690,4 +690,13 @@ extern const char *flag_random_seed;
#define HONOR_SIGN_DEPENDENT_ROUNDING(MODE) \
(MODE_HAS_SIGN_DEPENDENT_ROUNDING (MODE) && !flag_unsafe_math_optimizations)
+/* Nonzero means use propolice as a stack protection method */
+
+extern int flag_propolice_protection;
+extern int flag_stack_protection;
+
+/* Warn when not issuing stack smashing protection for some reason */
+
+extern int warn_stack_protector;
+
#endif /* ! GCC_FLAGS_H */
diff --git a/gnu/usr.bin/gcc/gcc/function.c b/gnu/usr.bin/gcc/gcc/function.c
index e055375d860..4fb1151532d 100644
--- a/gnu/usr.bin/gcc/gcc/function.c
+++ b/gnu/usr.bin/gcc/gcc/function.c
@@ -59,6 +59,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tm_p.h"
#include "integrate.h"
#include "langhooks.h"
+#include "protector.h"
#ifndef TRAMPOLINE_ALIGNMENT
#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
@@ -142,6 +143,10 @@ static GTY(()) varray_type epilogue;
/* Array of INSN_UIDs to hold the INSN_UIDs for each sibcall epilogue
in this function. */
static GTY(()) varray_type sibcall_epilogue;
+
+/* Current boundary mark for character arrays. */
+int temp_boundary_mark = 0;
+
/* In order to evaluate some expressions, such as function calls returning
structures in memory, we need to temporarily allocate stack locations.
@@ -195,6 +200,8 @@ struct temp_slot GTY(())
/* The size of the slot, including extra space for alignment. This
info is for combine_temp_slots. */
HOST_WIDE_INT full_size;
+ /* Boundary mark of a character array and the others. This info is for propolice */
+ int boundary_mark;
};
/* This structure is used to record MEMs or pseudos used to replace VAR, any
@@ -629,6 +636,7 @@ assign_stack_local (mode, size, align)
whose lifetime is controlled by CLEANUP_POINT_EXPRs. KEEP is 3
if we are to allocate something at an inner level to be treated as
a variable in the block (e.g., a SAVE_EXPR).
+ KEEP is 5 if we allocate a place to return structure.
TYPE is the type that will be used for the stack slot. */
@@ -642,6 +650,8 @@ assign_stack_temp_for_type (mode, size, keep, type)
unsigned int align;
struct temp_slot *p, *best_p = 0;
rtx slot;
+ int char_array = (flag_propolice_protection
+ && keep == 1 && search_string_def (type));
/* If SIZE is -1 it means that somebody tried to allocate a temporary
of a variable size. */
@@ -667,7 +677,8 @@ assign_stack_temp_for_type (mode, size, keep, type)
&& ! p->in_use
&& objects_must_conflict_p (p->type, type)
&& (best_p == 0 || best_p->size > p->size
- || (best_p->size == p->size && best_p->align > p->align)))
+ || (best_p->size == p->size && best_p->align > p->align))
+ && (! char_array || p->boundary_mark != 0))
{
if (p->align == align && p->size == size)
{
@@ -702,6 +713,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
p->address = 0;
p->rtl_expr = 0;
p->type = best_p->type;
+ p->boundary_mark = best_p->boundary_mark;
p->next = temp_slots;
temp_slots = p;
@@ -762,6 +774,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
p->full_size = frame_offset - frame_offset_old;
#endif
p->address = 0;
+ p->boundary_mark = char_array?++temp_boundary_mark:0;
p->next = temp_slots;
temp_slots = p;
}
@@ -932,14 +945,16 @@ combine_temp_slots ()
int delete_q = 0;
if (! q->in_use && GET_MODE (q->slot) == BLKmode)
{
- if (p->base_offset + p->full_size == q->base_offset)
+ if (p->base_offset + p->full_size == q->base_offset &&
+ p->boundary_mark == q->boundary_mark)
{
/* Q comes after P; combine Q into P. */
p->size += q->size;
p->full_size += q->full_size;
delete_q = 1;
}
- else if (q->base_offset + q->full_size == p->base_offset)
+ else if (q->base_offset + q->full_size == p->base_offset &&
+ p->boundary_mark == q->boundary_mark)
{
/* P comes after Q; combine P into Q. */
q->size += p->size;
@@ -1499,7 +1514,9 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
new = func->x_parm_reg_stack_loc[regno];
if (new == 0)
- new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func);
+ new = function ?
+ assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func):
+ assign_stack_local_for_pseudo_reg (decl_mode, GET_MODE_SIZE (decl_mode), 0);
PUT_CODE (reg, MEM);
PUT_MODE (reg, decl_mode);
@@ -3963,7 +3980,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
constant with that register. */
temp = gen_reg_rtx (Pmode);
XEXP (x, 0) = new;
- if (validate_change (object, &XEXP (x, 1), temp, 0))
+ if (validate_change (object, &XEXP (x, 1), temp, 0)
+ && ! flag_propolice_protection)
emit_insn_before (gen_move_insn (temp, new_offset), object);
else
{
diff --git a/gnu/usr.bin/gcc/gcc/gcse.c b/gnu/usr.bin/gcc/gcc/gcse.c
index 241357e9760..de8386094e7 100644
--- a/gnu/usr.bin/gcc/gcc/gcse.c
+++ b/gnu/usr.bin/gcc/gcc/gcse.c
@@ -4211,7 +4211,7 @@ cprop_insn (insn, alter_jumps)
/* Find an assignment that sets reg_used and is available
at the start of the block. */
set = find_avail_set (regno, insn);
- if (! set)
+ if (! set || set->expr->volatil)
continue;
pat = set->expr;
diff --git a/gnu/usr.bin/gcc/gcc/integrate.c b/gnu/usr.bin/gcc/gcc/integrate.c
index 7e36070f7ea..dc49bd09804 100644
--- a/gnu/usr.bin/gcc/gcc/integrate.c
+++ b/gnu/usr.bin/gcc/gcc/integrate.c
@@ -401,6 +401,10 @@ copy_decl_for_inlining (decl, from_fn, to_fn)
/* These args would always appear unused, if not for this. */
TREE_USED (copy) = 1;
+ /* The inlined variable is marked as INLINE not to sweep by propolice */
+ if (flag_propolice_protection && TREE_CODE (copy) == VAR_DECL)
+ DECL_INLINE (copy) = 1;
+
/* Set the context for the new declaration. */
if (!DECL_CONTEXT (decl))
/* Globals stay global. */
@@ -1965,6 +1969,10 @@ copy_rtx_and_substitute (orig, map, for_lhs)
seq = get_insns ();
end_sequence ();
+#ifdef FRAME_GROWS_DOWNWARD
+ if (flag_propolice_protection && GET_CODE (seq) == SET)
+ RTX_INTEGRATED_P (SET_SRC (seq)) = 1;
+#endif
emit_insn_after (seq, map->insns_at_start);
return temp;
}
diff --git a/gnu/usr.bin/gcc/gcc/libgcc-std.ver b/gnu/usr.bin/gcc/gcc/libgcc-std.ver
index 79e79fb512e..3cf6b1394c6 100644
--- a/gnu/usr.bin/gcc/gcc/libgcc-std.ver
+++ b/gnu/usr.bin/gcc/gcc/libgcc-std.ver
@@ -174,6 +174,10 @@ GCC_3.0 {
_Unwind_SjLj_RaiseException
_Unwind_SjLj_ForcedUnwind
_Unwind_SjLj_Resume
+
+ # stack smash handler symbols
+ __guard
+ __stack_smash_handler
}
%inherit GCC_3.3 GCC_3.0
diff --git a/gnu/usr.bin/gcc/gcc/loop.c b/gnu/usr.bin/gcc/gcc/loop.c
index c0888fa6ce2..6b397ea7b0e 100644
--- a/gnu/usr.bin/gcc/gcc/loop.c
+++ b/gnu/usr.bin/gcc/gcc/loop.c
@@ -6543,6 +6543,14 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
if (GET_CODE (*mult_val) == USE)
*mult_val = XEXP (*mult_val, 0);
+#ifndef FRAME_GROWS_DOWNWARD
+ if (flag_propolice_protection
+ && GET_CODE (*add_val) == PLUS
+ && (XEXP (*add_val, 0) == frame_pointer_rtx
+ || XEXP (*add_val, 1) == frame_pointer_rtx))
+ return 0;
+#endif
+
if (is_addr)
*pbenefit += address_cost (orig_x, addr_mode) - reg_address_cost;
else
diff --git a/gnu/usr.bin/gcc/gcc/optabs.c b/gnu/usr.bin/gcc/gcc/optabs.c
index d4eb640a71c..ecd32caa7e1 100644
--- a/gnu/usr.bin/gcc/gcc/optabs.c
+++ b/gnu/usr.bin/gcc/gcc/optabs.c
@@ -703,6 +703,26 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (target)
target = protect_from_queue (target, 1);
+ if (flag_propolice_protection
+ && binoptab->code == PLUS
+ && op0 == virtual_stack_vars_rtx
+ && GET_CODE(op1) == CONST_INT)
+ {
+ int icode = (int) binoptab->handlers[(int) mode].insn_code;
+ if (target)
+ temp = target;
+ else
+ temp = gen_reg_rtx (mode);
+
+ if (! (*insn_data[icode].operand[0].predicate) (temp, mode)
+ || GET_CODE (temp) != REG)
+ temp = gen_reg_rtx (mode);
+
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ gen_rtx_PLUS (GET_MODE (op0), op0, op1)));
+ return temp;
+ }
+
if (flag_force_mem)
{
op0 = force_not_mem (op0);
diff --git a/gnu/usr.bin/gcc/gcc/protector.c b/gnu/usr.bin/gcc/gcc/protector.c
new file mode 100644
index 00000000000..a78857bfc82
--- /dev/null
+++ b/gnu/usr.bin/gcc/gcc/protector.c
@@ -0,0 +1,2633 @@
+/* RTL buffer overflow protection function for GNU C compiler
+ Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "machmode.h"
+
+#include "rtl.h"
+#include "tree.h"
+#include "regs.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "insn-flags.h"
+#include "expr.h"
+#include "output.h"
+#include "recog.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+#include "conditions.h"
+#include "insn-attr.h"
+#include "c-tree.h"
+#include "optabs.h"
+#include "reload.h"
+#include "protector.h"
+
+
+/* Warn when not issuing stack smashing protection for some reason */
+int warn_stack_protector;
+
+/* Round a value to the lowest integer less than it that is a multiple of
+ the required alignment. Avoid using division in case the value is
+ negative. Assume the alignment is a power of two. */
+#define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1))
+
+/* Similar, but round to the next highest integer that meets the
+ alignment. */
+#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
+
+
+/* Nonzero means use propolice as a stack protection method */
+extern int flag_propolice_protection;
+
+/* This file contains several memory arrangement functions to protect
+ the return address and the frame pointer of the stack
+ from a stack-smashing attack. It also
+ provides the function that protects pointer variables. */
+
+/* Nonzero if function being compiled can define string buffers that may be
+ damaged by the stack-smash attack */
+static int current_function_defines_vulnerable_string;
+static int current_function_defines_short_string;
+static int current_function_has_variable_string;
+static int current_function_defines_vsized_array;
+static int current_function_is_inlinable;
+static int is_array;
+
+static rtx guard_area, _guard;
+static rtx function_first_insn, prologue_insert_point;
+
+/* */
+static HOST_WIDE_INT sweep_frame_offset;
+static HOST_WIDE_INT push_allocated_offset = 0;
+static HOST_WIDE_INT push_frame_offset = 0;
+static int saved_cse_not_expected = 0;
+
+static int search_string_from_argsandvars PARAMS ((int caller));
+static int search_string_from_local_vars PARAMS ((tree block));
+static int search_pointer_def PARAMS ((tree names));
+static int search_func_pointer PARAMS ((tree type));
+static void reset_used_flags_for_insns PARAMS ((rtx insn));
+static void reset_used_flags_for_decls PARAMS ((tree block));
+static void reset_used_flags_of_plus PARAMS ((rtx x));
+static void rtl_prologue PARAMS ((rtx insn));
+static void rtl_epilogue PARAMS ((rtx fnlastinsn));
+static void arrange_var_order PARAMS ((tree blocks));
+static void copy_args_for_protection PARAMS ((void));
+static void sweep_string_variable
+ PARAMS ((rtx sweep_var, HOST_WIDE_INT var_size));
+static void sweep_string_in_decls
+ PARAMS ((tree block, HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size));
+static void sweep_string_in_args
+ PARAMS ((tree parms, HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size));
+static void sweep_string_use_of_insns
+ PARAMS ((rtx insn, HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size));
+static void sweep_string_in_operand
+ PARAMS ((rtx insn, rtx *loc,
+ HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size));
+static void move_arg_location
+ PARAMS ((rtx insn, rtx orig, rtx new, HOST_WIDE_INT var_size));
+static void change_arg_use_of_insns
+ PARAMS ((rtx insn, rtx orig, rtx *new, HOST_WIDE_INT size));
+static void change_arg_use_of_insns_2
+ PARAMS ((rtx insn, rtx orig, rtx *new, HOST_WIDE_INT size));
+static void change_arg_use_in_operand
+ PARAMS ((rtx x, rtx orig, rtx *new, HOST_WIDE_INT size));
+static void validate_insns_of_varrefs PARAMS ((rtx insn));
+static void validate_operand_of_varrefs PARAMS ((rtx insn, rtx *loc));
+
+#define SUSPICIOUS_BUF_SIZE 0
+
+#define AUTO_BASEPTR(X) \
+ (GET_CODE (X) == PLUS ? XEXP (X, 0) : X)
+#define AUTO_OFFSET(X) \
+ (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0)
+#undef PARM_PASSED_IN_MEMORY
+#define PARM_PASSED_IN_MEMORY(PARM) \
+ (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM)
+#define VIRTUAL_STACK_VARS_P(X) \
+ ((X) == virtual_stack_vars_rtx || (GET_CODE (X) == REG && (X)->used))
+#define TREE_VISITED(NODE) ((NODE)->common.unused_0)
+
+
+
+void
+prepare_stack_protection (inlinable)
+ int inlinable;
+{
+ tree blocks = DECL_INITIAL (current_function_decl);
+ current_function_is_inlinable = inlinable && !flag_no_inline;
+ push_frame_offset = push_allocated_offset = 0;
+ saved_cse_not_expected = 0;
+
+ /*
+ skip the protection if the function has no block
+ or it is an inline function
+ */
+ if (current_function_is_inlinable) validate_insns_of_varrefs (get_insns ());
+ if (! blocks || current_function_is_inlinable) return;
+
+ current_function_defines_vulnerable_string
+ = search_string_from_argsandvars (0);
+
+ if (current_function_defines_vulnerable_string
+ || flag_stack_protection)
+ {
+ HOST_WIDE_INT offset;
+ function_first_insn = get_insns ();
+
+ if (current_function_contains_functions) {
+ if (warn_stack_protector)
+ warning ("not protecting function: it contains functions");
+ return;
+ }
+
+ /* Initialize recognition, indicating that volatile is OK. */
+ init_recog ();
+
+ sweep_frame_offset = 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+ /*
+ frame_offset: offset to end of allocated area of stack frame.
+ It is defined in the function.c
+ */
+
+ /* the location must be before buffers */
+ guard_area = assign_stack_local (BLKmode, UNITS_PER_GUARD, -1);
+ PUT_MODE (guard_area, GUARD_m);
+ MEM_VOLATILE_P (guard_area) = 1;
+
+#ifndef FRAME_GROWS_DOWNWARD
+ sweep_frame_offset = frame_offset;
+#endif
+
+ /* For making room for guard value, scan all insns and fix the offset
+ address of the variable that is based on frame pointer.
+ Scan all declarations of variables and fix the offset address
+ of the variable that is based on the frame pointer */
+ sweep_string_variable (guard_area, UNITS_PER_GUARD);
+
+
+ /* the location of guard area moves to the beginning of stack frame */
+ if ((offset = AUTO_OFFSET(XEXP (guard_area, 0))))
+ XEXP (XEXP (guard_area, 0), 1)
+ = gen_rtx_CONST_INT (VOIDmode, sweep_frame_offset);
+
+
+ /* Insert prologue rtl instructions */
+ rtl_prologue (function_first_insn);
+
+ if (! current_function_has_variable_string)
+ {
+ /* Generate argument saving instruction */
+ copy_args_for_protection ();
+
+#ifndef FRAME_GROWS_DOWNWARD
+ /* If frame grows upward, character string copied from an arg
+ stays top of the guard variable.
+ So sweep the guard variable again */
+ sweep_frame_offset = CEIL_ROUND (frame_offset,
+ BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+ sweep_string_variable (guard_area, UNITS_PER_GUARD);
+#endif
+ }
+ else if (warn_stack_protector)
+ warning ("not protecting variables: it has a variable length buffer");
+#endif
+#ifndef FRAME_GROWS_DOWNWARD
+ if (STARTING_FRAME_OFFSET == 0)
+ {
+ /* this may be only for alpha */
+ push_allocated_offset = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ assign_stack_local (BLKmode, push_allocated_offset, -1);
+ sweep_frame_offset = frame_offset;
+ sweep_string_variable (const0_rtx, -push_allocated_offset);
+ sweep_frame_offset = AUTO_OFFSET (XEXP (guard_area, 0));
+ }
+#endif
+
+ /* Arrange the order of local variables */
+ arrange_var_order (blocks);
+
+#ifdef STACK_GROWS_DOWNWARD
+ /* Insert epilogue rtl instructions */
+ rtl_epilogue (get_last_insn ());
+#endif
+ init_recog_no_volatile ();
+ }
+ else if (current_function_defines_short_string
+ && warn_stack_protector)
+ warning ("not protecting function: buffer is less than %d bytes long",
+ SUSPICIOUS_BUF_SIZE);
+}
+
+/*
+ search string from arguments and local variables
+ caller: 0 means call from protector_stack_protection
+ 1 means call from push_frame
+*/
+static int
+search_string_from_argsandvars (caller)
+ int caller;
+{
+ tree blocks, parms;
+ int string_p;
+
+ /* saves a latest search result as a cached infomation */
+ static tree __latest_search_decl = 0;
+ static int __latest_search_result = FALSE;
+
+ if (__latest_search_decl == current_function_decl)
+ return __latest_search_result;
+ else if (caller) return FALSE;
+ __latest_search_decl = current_function_decl;
+ __latest_search_result = TRUE;
+
+ current_function_defines_short_string = FALSE;
+ current_function_has_variable_string = FALSE;
+ current_function_defines_vsized_array = FALSE;
+
+ /*
+ search a string variable from local variables
+ */
+ blocks = DECL_INITIAL (current_function_decl);
+ string_p = search_string_from_local_vars (blocks);
+
+ if (!current_function_defines_vsized_array && current_function_calls_alloca)
+ {
+ current_function_has_variable_string = TRUE;
+ return TRUE;
+ }
+
+ if (string_p) return TRUE;
+
+#ifdef STACK_GROWS_DOWNWARD
+ /*
+ search a string variable from arguments
+ */
+ parms = DECL_ARGUMENTS (current_function_decl);
+
+ for (; parms; parms = TREE_CHAIN (parms))
+ if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
+ {
+ if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
+ {
+ string_p = search_string_def (TREE_TYPE(parms));
+ if (string_p) return TRUE;
+ }
+ }
+#endif
+
+ __latest_search_result = FALSE;
+ return FALSE;
+}
+
+
+static int
+search_string_from_local_vars (block)
+ tree block;
+{
+ tree types;
+ int found = FALSE;
+
+ while (block && TREE_CODE(block)==BLOCK)
+ {
+ types = BLOCK_VARS(block);
+
+ while (types)
+ {
+ /* skip the declaration that refers an external variable */
+ /* name: types.decl.name.identifier.id */
+ if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
+ && TREE_CODE (types) == VAR_DECL
+ && ! DECL_ARTIFICIAL (types)
+ && DECL_RTL_SET_P (types)
+ && GET_CODE (DECL_RTL (types)) == MEM
+
+ && search_string_def (TREE_TYPE (types)))
+ {
+ rtx home = DECL_RTL (types);
+
+ if (GET_CODE (home) == MEM
+ && (GET_CODE (XEXP (home, 0)) == MEM
+ ||
+ (GET_CODE (XEXP (home, 0)) == REG
+ && XEXP (home, 0) != virtual_stack_vars_rtx
+ && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
+ && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
+#endif
+ )))
+ /* If the value is indirect by memory or by a register
+ that isn't the frame pointer then it means the object is
+ variable-sized and address through
+ that register or stack slot.
+ The protection has no way to hide pointer variables
+ behind the array, so all we can do is staying
+ the order of variables and arguments. */
+ {
+ current_function_has_variable_string = TRUE;
+ }
+
+ /* found character array */
+ found = TRUE;
+ }
+
+ types = TREE_CHAIN(types);
+ }
+
+ if (search_string_from_local_vars (BLOCK_SUBBLOCKS (block)))
+ {
+ found = TRUE;
+ }
+
+ block = BLOCK_CHAIN (block);
+ }
+
+ return found;
+}
+
+
+/*
+ * search a character array from the specified type tree
+ */
+int
+search_string_def (type)
+ tree type;
+{
+ tree tem;
+
+ if (! type)
+ return FALSE;
+
+ switch (TREE_CODE (type))
+ {
+ case ARRAY_TYPE:
+ /* Check if the array is a variable-sized array */
+ if (TYPE_DOMAIN (type) == 0
+ || (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0
+ && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR))
+ current_function_defines_vsized_array = TRUE;
+
+ /* TREE_CODE( TREE_TYPE(type) ) == INTEGER_TYPE */
+ if (TYPE_MAIN_VARIANT (TREE_TYPE(type)) == char_type_node
+ || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == signed_char_type_node
+ || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == unsigned_char_type_node)
+ {
+ /* Check if the string is a variable string */
+ if (TYPE_DOMAIN (type) == 0
+ ||
+ (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0
+ && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR))
+ return TRUE;
+
+ /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE */
+#if SUSPICIOUS_BUF_SIZE > 0
+ if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0
+ &&
+ TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type)))+1
+ >= SUSPICIOUS_BUF_SIZE)
+ return TRUE;
+
+ current_function_defines_short_string = TRUE;
+#else
+ return TRUE;
+#endif
+ }
+
+ /* to protect every functions, sweep any arrays to the frame top */
+ is_array = TRUE;
+
+ return search_string_def(TREE_TYPE(type));
+
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case RECORD_TYPE:
+ /* Output the name, type, position (in bits), size (in bits) of each
+ field. */
+ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
+ {
+ /* Omit here local type decls until we know how to support them. */
+ if ((TREE_CODE (tem) == TYPE_DECL)
+ || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
+ continue;
+
+ if (search_string_def(TREE_TYPE(tem))) return TRUE;
+ }
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ /* I'm not sure whether OFFSET_TYPE needs this treatment,
+ so I'll play safe and return 1. */
+ case OFFSET_TYPE:
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/*
+ * examine whether the input contains frame pointer addressing
+ */
+int
+contains_fp (op)
+ rtx op;
+{
+ register enum rtx_code code;
+ rtx x;
+ int i, j;
+ const char *fmt;
+
+ x = op;
+ if (x == 0)
+ return FALSE;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case REG:
+ case ADDRESSOF:
+ return FALSE;
+
+ case PLUS:
+ if (XEXP (x, 0) == virtual_stack_vars_rtx
+ && CONSTANT_P (XEXP (x, 1)))
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ if (*fmt == 'e')
+ {
+ if (contains_fp (XEXP (x, i))) return TRUE;
+ }
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (contains_fp (XVECEXP (x, i, j))) return TRUE;
+
+ return FALSE;
+}
+
+
+static int
+search_pointer_def (type)
+ tree type;
+{
+ tree tem;
+
+ if (! type)
+ return FALSE;
+
+ switch (TREE_CODE (type))
+ {
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case RECORD_TYPE:
+ /* Output the name, type, position (in bits), size (in bits) of each
+ field. */
+ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
+ {
+ /* Omit here local type decls until we know how to support them. */
+ if ((TREE_CODE (tem) == TYPE_DECL)
+ || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
+ continue;
+
+ if (search_pointer_def (TREE_TYPE(tem))) return TRUE;
+ }
+ break;
+
+ case ARRAY_TYPE:
+ return search_pointer_def (TREE_TYPE(type));
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case OFFSET_TYPE:
+ if (TYPE_READONLY (TREE_TYPE (type)))
+ {
+ /* unless this pointer contains function pointer,
+ it should be protected */
+ return search_func_pointer (TREE_TYPE (type));
+ }
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static int
+search_func_pointer (type)
+ tree type;
+{
+ tree tem;
+
+ if (! type)
+ return FALSE;
+
+ switch (TREE_CODE (type))
+ {
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case RECORD_TYPE:
+ if (! TREE_VISITED (type))
+ {
+ /* mark the type as having been visited already */
+ TREE_VISITED (type) = 1;
+
+ /* Output the name, type, position (in bits), size (in bits) of
+ each field. */
+ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
+ {
+ if (TREE_CODE (tem) == FIELD_DECL
+ && search_func_pointer (TREE_TYPE(tem))) {
+ TREE_VISITED (type) = 0;
+ return TRUE;
+ }
+ }
+
+ TREE_VISITED (type) = 0;
+ }
+ break;
+
+ case ARRAY_TYPE:
+ return search_func_pointer (TREE_TYPE(type));
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ /* I'm not sure whether OFFSET_TYPE needs this treatment,
+ so I'll play safe and return 1. */
+ case OFFSET_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ return TRUE;
+ return search_func_pointer (TREE_TYPE(type));
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static void
+reset_used_flags_for_insns (insn)
+ rtx insn;
+{
+ register int i, j;
+ register enum rtx_code code;
+ register const char *format_ptr;
+
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)
+ {
+ code = GET_CODE (insn);
+ insn->used = 0;
+ format_ptr = GET_RTX_FORMAT (code);
+
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ {
+ switch (*format_ptr++) {
+ case 'e':
+ reset_used_flags_of_plus (XEXP (insn, i));
+ break;
+
+ case 'E':
+ for (j = 0; j < XVECLEN (insn, i); j++)
+ reset_used_flags_of_plus (XVECEXP (insn, i, j));
+ break;
+ }
+ }
+ }
+}
+
+static void
+reset_used_flags_for_decls (block)
+ tree block;
+{
+ tree types;
+ rtx home;
+
+ while (block && TREE_CODE(block)==BLOCK)
+ {
+ types = BLOCK_VARS(block);
+
+ while (types)
+ {
+ /* skip the declaration that refers an external variable and
+ also skip an global variable */
+ if (! DECL_EXTERNAL (types))
+ {
+ if (!DECL_RTL_SET_P (types)) goto next;
+ home = DECL_RTL (types);
+
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
+ {
+ XEXP (home, 0)->used = 0;
+ }
+ }
+ next:
+ types = TREE_CHAIN(types);
+ }
+
+ reset_used_flags_for_decls (BLOCK_SUBBLOCKS (block));
+
+ block = BLOCK_CHAIN (block);
+ }
+}
+
+/* Clear the USED bits only of type PLUS in X */
+
+static void
+reset_used_flags_of_plus (x)
+ rtx x;
+{
+ register int i, j;
+ register enum rtx_code code;
+ register const char *format_ptr;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ /* These types may be freely shared so we needn't do any resetting
+ for them. */
+
+ switch (code)
+ {
+ case REG:
+ case QUEUED:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ return;
+
+ case INSN:
+ case JUMP_INSN:
+ case CALL_INSN:
+ case NOTE:
+ case LABEL_REF:
+ case BARRIER:
+ /* The chain of insns is not being copied. */
+ return;
+
+ case PLUS:
+ x->used = 0;
+ break;
+
+ case CALL_PLACEHOLDER:
+ reset_used_flags_for_insns (XEXP (x, 0));
+ reset_used_flags_for_insns (XEXP (x, 1));
+ reset_used_flags_for_insns (XEXP (x, 2));
+ break;
+
+ default:
+ break;
+ }
+
+ format_ptr = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ reset_used_flags_of_plus (XEXP (x, i));
+ break;
+
+ case 'E':
+ for (j = 0; j < XVECLEN (x, i); j++)
+ reset_used_flags_of_plus (XVECEXP (x, i, j));
+ break;
+ }
+ }
+}
+
+
+static void
+rtl_prologue (insn)
+ rtx insn;
+{
+#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
+#undef HAS_INIT_SECTION
+#define HAS_INIT_SECTION
+#endif
+
+ rtx _val;
+
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
+ break;
+
+#if !defined (HAS_INIT_SECTION)
+ /* If this function is `main', skip a call to `__main'
+ to run guard instruments after global initializers, etc. */
+ if (DECL_NAME (current_function_decl)
+ && MAIN_NAME_P (DECL_NAME (current_function_decl))
+ && DECL_CONTEXT (current_function_decl) == NULL_TREE)
+ {
+ rtx fbinsn = insn;
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
+ break;
+ if (insn == 0) insn = fbinsn;
+ }
+#endif
+
+ /* mark the next insn of FUNCTION_BEG insn */
+ prologue_insert_point = NEXT_INSN (insn);
+
+ start_sequence ();
+
+ _guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard"));
+ emit_move_insn ( guard_area, _guard);
+
+ _val = get_insns ();
+ end_sequence ();
+
+ emit_insn_before (_val, prologue_insert_point);
+}
+
+static void
+rtl_epilogue (insn)
+ rtx insn;
+{
+ rtx if_false_label;
+ rtx _val;
+ rtx funcname;
+ tree funcstr;
+ int flag_have_return = FALSE;
+
+ start_sequence ();
+
+#ifdef HAVE_return
+ if (HAVE_return)
+ {
+ rtx insn;
+ return_label = gen_label_rtx ();
+
+ for (insn = prologue_insert_point; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (PATTERN (insn)) == RETURN
+ && GET_MODE (PATTERN (insn)) == VOIDmode)
+ {
+ rtx pat = gen_rtx_SET (VOIDmode,
+ pc_rtx,
+ gen_rtx_LABEL_REF (VOIDmode,
+ return_label));
+ PATTERN (insn) = pat;
+ flag_have_return = TRUE;
+ }
+
+
+ emit_label (return_label);
+ }
+#endif
+
+ /* if (guard_area != _guard) */
+ compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, NULL_RTX);
+
+ if_false_label = gen_label_rtx (); /* { */
+ emit_jump_insn ( gen_beq(if_false_label));
+
+ /* generate string for the current function name */
+ funcstr = build_string (strlen(current_function_name)+1,
+ current_function_name);
+ TREE_TYPE (funcstr) = build_array_type (char_type_node, 0);
+ funcname = output_constant_def (funcstr, 1);
+
+ emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__stack_smash_handler"),
+ 0, VOIDmode, 2,
+ XEXP (funcname, 0), Pmode, guard_area, GUARD_m);
+
+ /* generate RTL to return from the current function */
+
+ emit_barrier (); /* } */
+ emit_label (if_false_label);
+
+ /* generate RTL to return from the current function */
+ if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
+ use_return_register ();
+
+#ifdef HAVE_return
+ if (HAVE_return && flag_have_return)
+ {
+ emit_jump_insn (gen_return ());
+ emit_barrier ();
+ }
+#endif
+
+ _val = get_insns ();
+ end_sequence ();
+
+ emit_insn_after (_val, insn);
+}
+
+
+static void
+arrange_var_order (block)
+ tree block;
+{
+ tree types;
+ HOST_WIDE_INT offset;
+
+ while (block && TREE_CODE(block)==BLOCK)
+ {
+ types = BLOCK_VARS (block);
+
+ while (types)
+ {
+ /* skip the declaration that refers an external variable */
+ /* name: types.decl.assembler_name.id */
+ if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
+ && TREE_CODE (types) == VAR_DECL
+ && ! DECL_ARTIFICIAL (types)
+ && ! DECL_INLINE (types) /* don't sweep inlined string */
+ && DECL_RTL_SET_P (types)
+ && GET_CODE (DECL_RTL (types)) == MEM
+
+ && (is_array=0, search_string_def (TREE_TYPE (types))
+ || (! current_function_defines_vulnerable_string
+ && is_array)))
+ {
+ rtx home = DECL_RTL (types);
+
+ if (!(GET_CODE (home) == MEM
+ && (GET_CODE (XEXP (home, 0)) == MEM
+ ||
+ (GET_CODE (XEXP (home, 0)) == REG
+ && XEXP (home, 0) != virtual_stack_vars_rtx
+ && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
+ && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
+#endif
+ ))))
+ {
+ /* found a string variable */
+ HOST_WIDE_INT var_size =
+ ((TREE_INT_CST_LOW (DECL_SIZE (types)) + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT);
+
+ if (GET_MODE (DECL_RTL (types)) == BLKmode)
+ {
+ int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ var_size = CEIL_ROUND (var_size, alignment);
+ }
+
+ /* skip the variable if it is top of the region
+ specified by sweep_frame_offset */
+ offset = AUTO_OFFSET (XEXP (DECL_RTL (types), 0));
+ if (offset == sweep_frame_offset - var_size)
+ sweep_frame_offset -= var_size;
+
+ else if (offset < sweep_frame_offset - var_size)
+ sweep_string_variable (DECL_RTL (types), var_size);
+ }
+ }
+
+ types = TREE_CHAIN(types);
+ }
+
+ arrange_var_order (BLOCK_SUBBLOCKS (block));
+
+ block = BLOCK_CHAIN (block);
+ }
+}
+
+
+static void
+copy_args_for_protection ()
+{
+ tree parms = DECL_ARGUMENTS (current_function_decl);
+ rtx temp_rtx;
+
+ parms = DECL_ARGUMENTS (current_function_decl);
+ for (; parms; parms = TREE_CHAIN (parms))
+ if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
+ {
+ if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
+ {
+ int string_p;
+
+ /*
+ skip arguemnt protection if the last argument is used
+ for the variable argument
+ */
+ /*
+ tree fntype;
+ if (TREE_CHAIN (parms) == 0)
+ {
+ fntype = TREE_TYPE (current_function_decl);
+
+ if ((TYPE_ARG_TYPES (fntype) != 0
+ && TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+ != void_type_node)
+ || current_function_varargs)
+ continue;
+ }
+ */
+
+ string_p = search_string_def (TREE_TYPE(parms));
+
+ /* check if it is a candidate to move */
+ if (string_p || search_pointer_def (TREE_TYPE (parms)))
+ {
+ int arg_size
+ = ((TREE_INT_CST_LOW (DECL_SIZE (parms)) + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT);
+ tree passed_type = DECL_ARG_TYPE (parms);
+ tree nominal_type = TREE_TYPE (parms);
+
+ start_sequence ();
+
+ if (GET_CODE (DECL_RTL (parms)) == REG)
+ {
+ rtx safe = 0;
+
+ change_arg_use_of_insns (prologue_insert_point,
+ DECL_RTL (parms), &safe, 0);
+ if (safe)
+ {
+ /* generate codes for copying the content */
+ rtx movinsn = emit_move_insn (safe, DECL_RTL (parms));
+
+ /* avoid register elimination in gcse.c (COPY-PROP)*/
+ PATTERN (movinsn)->volatil = 1;
+
+ /* save debugger info */
+ DECL_INCOMING_RTL (parms) = safe;
+ }
+ }
+ else if (GET_CODE (DECL_RTL (parms)) == MEM
+ && GET_CODE (XEXP (DECL_RTL (parms), 0)) == ADDRESSOF)
+ {
+ rtx movinsn;
+ rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms)));
+
+ /* generate codes for copying the content */
+ movinsn = emit_move_insn (safe, DECL_INCOMING_RTL (parms));
+ /* avoid register elimination in gcse.c (COPY-PROP)*/
+ PATTERN (movinsn)->volatil = 1;
+
+ /* change the addressof information to the newly
+ allocated pseudo register */
+ emit_move_insn (DECL_RTL (parms), safe);
+
+ /* save debugger info */
+ DECL_INCOMING_RTL (parms) = safe;
+ }
+
+ /* See if the frontend wants to pass this by invisible
+ reference. */
+ else if (passed_type != nominal_type
+ && POINTER_TYPE_P (passed_type)
+ && TREE_TYPE (passed_type) == nominal_type)
+ {
+ rtx safe = 0, orig = XEXP (DECL_RTL (parms), 0);
+
+ change_arg_use_of_insns (prologue_insert_point,
+ orig, &safe, 0);
+ if (safe)
+ {
+ /* generate codes for copying the content */
+ rtx movinsn = emit_move_insn (safe, orig);
+
+ /* avoid register elimination in gcse.c (COPY-PROP)*/
+ PATTERN (movinsn)->volatil = 1;
+
+ /* save debugger info */
+ DECL_INCOMING_RTL (parms) = safe;
+ }
+ }
+
+ else
+ {
+ /* declare temporary local variable DECL_NAME (parms) */
+ temp_rtx
+ = assign_stack_local (DECL_MODE (parms), arg_size,
+ DECL_MODE (parms) == BLKmode ?
+ -1 : 0);
+
+ MEM_IN_STRUCT_P (temp_rtx)
+ = AGGREGATE_TYPE_P (TREE_TYPE (parms));
+ set_mem_alias_set (temp_rtx, get_alias_set (parms));
+
+ /* move_arg_location may change the contents of
+ DECL_RTL (parms). to avoid this, copies the contents */
+ /* SET_DECL_RTL (parms, copy_rtx (DECL_RTL (parms))); */
+
+ /* generate codes for copying the content */
+ store_expr (parms, temp_rtx, 0);
+
+ /* change the reference for each instructions */
+ move_arg_location (prologue_insert_point, DECL_RTL (parms),
+ temp_rtx, arg_size);
+
+ /* change the location of parms variable */
+ SET_DECL_RTL (parms, temp_rtx);
+
+ /* change debugger info */
+ DECL_INCOMING_RTL (parms) = temp_rtx;
+ }
+
+ emit_insn_before (get_insns (), prologue_insert_point);
+ end_sequence ();
+
+#ifdef FRAME_GROWS_DOWNWARD
+ /* process the string argument */
+ if (string_p && DECL_MODE (parms) == BLKmode)
+ {
+ int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ arg_size = CEIL_ROUND (arg_size, alignment);
+
+ /* change the reference for each instructions */
+ sweep_string_variable (DECL_RTL (parms), arg_size);
+ }
+#endif
+ }
+ }
+ }
+}
+
+
+/*
+ sweep a string variable to the local variable addressed
+ by sweep_frame_offset, that is a last position of string variables.
+*/
+static void
+sweep_string_variable (sweep_var, var_size)
+ rtx sweep_var;
+ HOST_WIDE_INT var_size;
+{
+ HOST_WIDE_INT sweep_offset;
+
+ switch (GET_CODE (sweep_var))
+ {
+ case MEM:
+ if (GET_CODE (XEXP (sweep_var, 0)) == ADDRESSOF
+ && GET_CODE (XEXP (XEXP (sweep_var, 0), 0)) == REG)
+ return;
+ sweep_offset = AUTO_OFFSET(XEXP (sweep_var, 0));
+ break;
+ case CONST_INT:
+ sweep_offset = INTVAL (sweep_var);
+ break;
+ default:
+ abort ();
+ }
+
+ /* scan all declarations of variables and fix the offset address of
+ the variable based on the frame pointer */
+ sweep_string_in_decls (DECL_INITIAL (current_function_decl),
+ sweep_offset, var_size);
+
+ /* scan all argument variable and fix the offset address based on
+ the frame pointer */
+ sweep_string_in_args (DECL_ARGUMENTS (current_function_decl),
+ sweep_offset, var_size);
+
+ /* For making room for sweep variable, scan all insns and
+ fix the offset address of the variable that is based on frame pointer */
+ sweep_string_use_of_insns (function_first_insn, sweep_offset, var_size);
+
+
+ /* Clear all the USED bits in operands of all insns and declarations of
+ local vars */
+ reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
+ reset_used_flags_for_insns (function_first_insn);
+
+ sweep_frame_offset -= var_size;
+}
+
+
+
+/*
+ move an argument to the local variable addressed by frame_offset
+*/
+static void
+move_arg_location (insn, orig, new, var_size)
+ rtx insn, orig, new;
+ HOST_WIDE_INT var_size;
+{
+ /* For making room for sweep variable, scan all insns and
+ fix the offset address of the variable that is based on frame pointer */
+ change_arg_use_of_insns (insn, orig, &new, var_size);
+
+
+ /* Clear all the USED bits in operands of all insns and declarations
+ of local vars */
+ reset_used_flags_for_insns (insn);
+}
+
+
+static void
+sweep_string_in_decls (block, sweep_offset, sweep_size)
+ tree block;
+ HOST_WIDE_INT sweep_offset, sweep_size;
+{
+ tree types;
+ HOST_WIDE_INT offset;
+ rtx home;
+
+ while (block && TREE_CODE(block)==BLOCK)
+ {
+ types = BLOCK_VARS(block);
+
+ while (types)
+ {
+ /* skip the declaration that refers an external variable and
+ also skip an global variable */
+ if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) {
+
+ if (!DECL_RTL_SET_P (types)) goto next;
+ home = DECL_RTL (types);
+
+ /* process for static local variable */
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
+ goto next;
+
+ if (GET_CODE (home) == MEM
+ && XEXP (home, 0) == virtual_stack_vars_rtx)
+ {
+ offset = 0;
+
+ /* the operand related to the sweep variable */
+ if (sweep_offset <= offset
+ && offset < sweep_offset + sweep_size)
+ {
+ offset = sweep_frame_offset - sweep_size - sweep_offset;
+
+ XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx,
+ offset);
+ XEXP (home, 0)->used = 1;
+ }
+ else if (sweep_offset <= offset
+ && offset < sweep_frame_offset)
+ {
+ /* the rest of variables under sweep_frame_offset,
+ shift the location */
+ XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx,
+ -sweep_size);
+ XEXP (home, 0)->used = 1;
+ }
+ }
+
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == MEM)
+ {
+ /* process for dynamically allocated aray */
+ home = XEXP (home, 0);
+ }
+
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == PLUS
+ && XEXP (XEXP (home, 0), 0) == virtual_stack_vars_rtx
+ && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
+ {
+ if (! XEXP (home, 0)->used)
+ {
+ offset = AUTO_OFFSET(XEXP (home, 0));
+
+ /* the operand related to the sweep variable */
+ if (sweep_offset <= offset
+ && offset < sweep_offset + sweep_size)
+ {
+
+ offset
+ += sweep_frame_offset - sweep_size - sweep_offset;
+ XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode,
+ offset);
+
+ /* mark */
+ XEXP (home, 0)->used = 1;
+ }
+ else if (sweep_offset <= offset
+ && offset < sweep_frame_offset)
+ { /* the rest of variables under sweep_frame_offset,
+ so shift the location */
+
+ XEXP (XEXP (home, 0), 1)
+ = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
+
+ /* mark */
+ XEXP (home, 0)->used = 1;
+ }
+ }
+ }
+
+ }
+ next:
+ types = TREE_CHAIN(types);
+ }
+
+ sweep_string_in_decls (BLOCK_SUBBLOCKS (block),
+ sweep_offset, sweep_size);
+ block = BLOCK_CHAIN (block);
+ }
+}
+
+
+static void
+sweep_string_in_args (parms, sweep_offset, sweep_size)
+ tree parms;
+ HOST_WIDE_INT sweep_offset, sweep_size;
+{
+ rtx home;
+ HOST_WIDE_INT offset;
+
+ for (; parms; parms = TREE_CHAIN (parms))
+ if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
+ {
+ if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
+ {
+ home = DECL_INCOMING_RTL (parms);
+
+ if (XEXP (home, 0)->used) continue;
+
+ offset = AUTO_OFFSET(XEXP (home, 0));
+
+ /* the operand related to the sweep variable */
+ if (AUTO_BASEPTR (XEXP (home, 0)) == virtual_stack_vars_rtx)
+ {
+ if (sweep_offset <= offset
+ && offset < sweep_offset + sweep_size)
+ {
+ offset += sweep_frame_offset - sweep_size - sweep_offset;
+ XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode,
+ offset);
+
+ /* mark */
+ XEXP (home, 0)->used = 1;
+ }
+ else if (sweep_offset <= offset
+ && offset < sweep_frame_offset)
+ {
+ /* the rest of variables under sweep_frame_offset,
+ shift the location */
+ XEXP (XEXP (home, 0), 1)
+ = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
+
+ /* mark */
+ XEXP (home, 0)->used = 1;
+ }
+ }
+ }
+ }
+}
+
+
+static int has_virtual_reg;
+
+static void
+sweep_string_use_of_insns (insn, sweep_offset, sweep_size)
+ rtx insn;
+ HOST_WIDE_INT sweep_offset, sweep_size;
+{
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)
+ {
+ has_virtual_reg = FALSE;
+ sweep_string_in_operand (insn, &PATTERN (insn),
+ sweep_offset, sweep_size);
+ sweep_string_in_operand (insn, &REG_NOTES (insn),
+ sweep_offset, sweep_size);
+ }
+}
+
+
+static void
+sweep_string_in_operand (insn, loc, sweep_offset, sweep_size)
+ rtx insn, *loc;
+ HOST_WIDE_INT sweep_offset, sweep_size;
+{
+ register rtx x = *loc;
+ register enum rtx_code code;
+ int i, j, k = 0;
+ HOST_WIDE_INT offset;
+ const char *fmt;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case ASM_INPUT:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case RETURN:
+ case ADDRESSOF:
+ return;
+
+ case REG:
+ if (x == virtual_incoming_args_rtx
+ || x == virtual_stack_vars_rtx
+ || x == virtual_stack_dynamic_rtx
+ || x == virtual_outgoing_args_rtx
+ || x == virtual_cfa_rtx)
+ has_virtual_reg = TRUE;
+ return;
+
+ case SET:
+ /*
+ skip setjmp setup insn and setjmp restore insn
+ Example:
+ (set (MEM (reg:SI xx)) (virtual_stack_vars_rtx)))
+ (set (virtual_stack_vars_rtx) (REG))
+ */
+ if (GET_CODE (XEXP (x, 0)) == MEM
+ && XEXP (x, 1) == virtual_stack_vars_rtx)
+ return;
+ if (XEXP (x, 0) == virtual_stack_vars_rtx
+ && GET_CODE (XEXP (x, 1)) == REG)
+ return;
+ break;
+
+ case PLUS:
+ /* Handle typical case of frame register plus constant. */
+ if (XEXP (x, 0) == virtual_stack_vars_rtx
+ && CONSTANT_P (XEXP (x, 1)))
+ {
+ if (x->used) goto single_use_of_virtual_reg;
+
+ offset = AUTO_OFFSET(x);
+ if (RTX_INTEGRATED_P (x)) k = -1; /* for inline base ptr */
+
+ /* the operand related to the sweep variable */
+ if (sweep_offset <= offset + k
+ && offset + k < sweep_offset + sweep_size)
+ {
+ offset += sweep_frame_offset - sweep_size - sweep_offset;
+
+ XEXP (x, 0) = virtual_stack_vars_rtx;
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
+ x->used = 1;
+ }
+ else if (sweep_offset <= offset + k
+ && offset + k < sweep_frame_offset)
+ {
+ /* the rest of variables under sweep_frame_offset,
+ shift the location */
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
+ x->used = 1;
+ }
+
+ single_use_of_virtual_reg:
+ if (has_virtual_reg) {
+ /* excerpt from insn_invalid_p in recog.c */
+ int icode = recog_memoized (insn);
+
+ if (icode < 0 && asm_noperands (PATTERN (insn)) < 0)
+ {
+ rtx temp, seq;
+
+ start_sequence ();
+ temp = force_operand (x, NULL_RTX);
+ seq = get_insns ();
+ end_sequence ();
+
+ emit_insn_before (seq, insn);
+ if (! validate_change (insn, loc, temp, 0)
+ && ! validate_replace_rtx (x, temp, insn))
+ fatal_insn ("sweep_string_in_operand", insn);
+ }
+ }
+
+ has_virtual_reg = TRUE;
+ return;
+ }
+
+#ifdef FRAME_GROWS_DOWNWARD
+ /*
+ alert the case of frame register plus constant given by reg.
+ */
+ else if (XEXP (x, 0) == virtual_stack_vars_rtx
+ && GET_CODE (XEXP (x, 1)) == REG)
+ fatal_insn ("sweep_string_in_operand: unknown addressing", insn);
+#endif
+
+ /*
+ process further subtree:
+ Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
+ (const_int 5))
+ */
+ break;
+
+ case CALL_PLACEHOLDER:
+ for (i = 0; i < 3; i++)
+ {
+ rtx seq = XEXP (x, i);
+ if (seq)
+ {
+ push_to_sequence (seq);
+ sweep_string_use_of_insns (XEXP (x, i),
+ sweep_offset, sweep_size);
+ XEXP (x, i) = get_insns ();
+ end_sequence ();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ if (*fmt == 'e')
+ {
+ /*
+ virtual_stack_vars_rtx without offset
+ Example:
+ (set (reg:SI xx) (reg:SI 78))
+ (set (reg:SI xx) (MEM (reg:SI 78)))
+ */
+ if (XEXP (x, i) == virtual_stack_vars_rtx)
+ fatal_insn ("sweep_string_in_operand: unknown fp usage", insn);
+ sweep_string_in_operand (insn, &XEXP (x, i), sweep_offset, sweep_size);
+ }
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ sweep_string_in_operand (insn, &XVECEXP (x, i, j), sweep_offset, sweep_size);
+}
+
+
+/*
+ change a argument variable to the local variable addressed
+ by the "new" variable.
+*/
+static void
+change_arg_use_of_insns (insn, orig, new, size)
+ rtx insn, orig, *new;
+ HOST_WIDE_INT size;
+{
+ change_arg_use_of_insns_2 (insn, orig, new, size);
+}
+
+static void
+change_arg_use_of_insns_2 (insn, orig, new, size)
+ rtx insn, orig, *new;
+ HOST_WIDE_INT size;
+{
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)
+ {
+ rtx seq;
+
+ start_sequence ();
+ change_arg_use_in_operand (PATTERN (insn), orig, new, size);
+
+ seq = get_insns ();
+ end_sequence ();
+ emit_insn_before (seq, insn);
+ }
+}
+
+
+
+static void
+change_arg_use_in_operand (x, orig, new, size)
+ rtx x, orig, *new;
+ HOST_WIDE_INT size;
+{
+ register enum rtx_code code;
+ int i, j;
+ HOST_WIDE_INT offset;
+ const char *fmt;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case ASM_INPUT:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case RETURN:
+ case REG:
+ case ADDRESSOF:
+ return;
+
+ case MEM:
+ /* Handle special case of MEM (incoming_args) */
+ if (GET_CODE (orig) == MEM
+ && XEXP (x, 0) == virtual_incoming_args_rtx)
+ {
+ offset = 0;
+
+ /* the operand related to the sweep variable */
+ if (AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
+ offset < AUTO_OFFSET(XEXP (orig, 0)) + size) {
+
+ offset = AUTO_OFFSET(XEXP (*new, 0))
+ + (offset - AUTO_OFFSET(XEXP (orig, 0)));
+
+ XEXP (x, 0) = plus_constant (virtual_stack_vars_rtx, offset);
+ XEXP (x, 0)->used = 1;
+
+ return;
+ }
+ }
+ break;
+
+ case PLUS:
+ /* Handle special case of frame register plus constant. */
+ if (GET_CODE (orig) == MEM
+ && XEXP (x, 0) == virtual_incoming_args_rtx
+ && CONSTANT_P (XEXP (x, 1))
+ && ! x->used)
+ {
+ offset = AUTO_OFFSET(x);
+
+ /* the operand related to the sweep variable */
+ if (AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
+ offset < AUTO_OFFSET(XEXP (orig, 0)) + size) {
+
+ offset = AUTO_OFFSET(XEXP (*new, 0))
+ + (offset - AUTO_OFFSET(XEXP (orig, 0)));
+
+ XEXP (x, 0) = virtual_stack_vars_rtx;
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
+ x->used = 1;
+
+ return;
+ }
+
+ /*
+ process further subtree:
+ Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
+ (const_int 5))
+ */
+ }
+ break;
+
+ case SET:
+ /* Handle special case of "set (REG or MEM) (incoming_args)".
+ It means that the the address of the 1st argument is stored. */
+ if (GET_CODE (orig) == MEM
+ && XEXP (x, 1) == virtual_incoming_args_rtx)
+ {
+ offset = 0;
+
+ /* the operand related to the sweep variable */
+ if (AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
+ offset < AUTO_OFFSET(XEXP (orig, 0)) + size) {
+
+ offset = AUTO_OFFSET(XEXP (*new, 0))
+ + (offset - AUTO_OFFSET(XEXP (orig, 0)));
+
+ XEXP (x, 1) = force_operand (plus_constant (virtual_stack_vars_rtx,
+ offset), NULL_RTX);
+ XEXP (x, 1)->used = 1;
+
+ return;
+ }
+ }
+ break;
+
+ case CALL_PLACEHOLDER:
+ for (i = 0; i < 3; i++)
+ {
+ rtx seq = XEXP (x, i);
+ if (seq)
+ {
+ push_to_sequence (seq);
+ change_arg_use_of_insns_2 (XEXP (x, i), orig, new, size);
+ XEXP (x, i) = get_insns ();
+ end_sequence ();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ if (*fmt == 'e')
+ {
+ if (XEXP (x, i) == orig)
+ {
+ if (*new == 0) *new = gen_reg_rtx (GET_MODE (orig));
+ XEXP (x, i) = *new;
+ continue;
+ }
+ change_arg_use_in_operand (XEXP (x, i), orig, new, size);
+ }
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+
+ if (XVECEXP (x, i, j) == orig)
+ {
+ if (*new == 0) *new = gen_reg_rtx (GET_MODE (orig));
+ XVECEXP (x, i, j) = *new;
+ continue;
+ }
+ change_arg_use_in_operand (XVECEXP (x, i, j), orig, new, size);
+ }
+}
+
+
+static void
+validate_insns_of_varrefs (insn)
+ rtx insn;
+{
+ rtx next;
+
+ /* Initialize recognition, indicating that volatile is OK. */
+ init_recog ();
+
+ for (; insn; insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)
+ {
+ /* excerpt from insn_invalid_p in recog.c */
+ int icode = recog_memoized (insn);
+
+ if (icode < 0 && asm_noperands (PATTERN (insn)) < 0)
+ validate_operand_of_varrefs (insn, &PATTERN (insn));
+ }
+ }
+
+ init_recog_no_volatile ();
+}
+
+
+static void
+validate_operand_of_varrefs (insn, loc)
+ rtx insn, *loc;
+{
+ register enum rtx_code code;
+ rtx x, temp, seq;
+ int i, j;
+ const char *fmt;
+
+ x = *loc;
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case USE:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case ASM_INPUT:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case RETURN:
+ case REG:
+ case ADDRESSOF:
+ return;
+
+ case PLUS:
+ /* validate insn of frame register plus constant. */
+ if (GET_CODE (x) == PLUS
+ && XEXP (x, 0) == virtual_stack_vars_rtx
+ && CONSTANT_P (XEXP (x, 1)))
+ {
+ start_sequence ();
+
+ { /* excerpt from expand_binop in optabs.c */
+ optab binoptab = add_optab;
+ enum machine_mode mode = GET_MODE (x);
+ int icode = (int) binoptab->handlers[(int) mode].insn_code;
+ enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+ rtx pat;
+ rtx xop0 = XEXP (x, 0), xop1 = XEXP (x, 1);
+ temp = gen_reg_rtx (mode);
+
+ /* Now, if insn's predicates don't allow offset operands,
+ put them into pseudo regs. */
+
+ if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
+ && mode1 != VOIDmode)
+ xop1 = copy_to_mode_reg (mode1, xop1);
+
+ pat = GEN_FCN (icode) (temp, xop0, xop1);
+ if (pat)
+ emit_insn (pat);
+ }
+ seq = get_insns ();
+ end_sequence ();
+
+ emit_insn_before (seq, insn);
+ if (! validate_change (insn, loc, temp, 0))
+ abort ();
+ return;
+ }
+ break;
+
+
+ case CALL_PLACEHOLDER:
+ for (i = 0; i < 3; i++)
+ {
+ rtx seq = XEXP (x, i);
+ if (seq)
+ {
+ push_to_sequence (seq);
+ validate_insns_of_varrefs (XEXP (x, i));
+ XEXP (x, i) = get_insns ();
+ end_sequence ();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ if (*fmt == 'e')
+ validate_operand_of_varrefs (insn, &XEXP (x, i));
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ validate_operand_of_varrefs (insn, &XVECEXP (x, i, j));
+}
+
+
+
+/* Return size that is not allocated for stack frame. It will be allocated
+ to modify the home of pseudo registers called from global_alloc. */
+
+HOST_WIDE_INT
+get_frame_free_size ()
+{
+ if (! flag_propolice_protection)
+ return 0;
+
+ return push_allocated_offset - push_frame_offset;
+}
+
+
+/*
+ The following codes are invoked after the instantiation of pseuso registers.
+
+ Reorder local variables to place a peudo register after buffers to avoid
+ the corruption of local variables that could be used to further corrupt
+ arbitrary memory locations.
+*/
+#if !defined(FRAME_GROWS_DOWNWARD) && defined(STACK_GROWS_DOWNWARD)
+static void push_frame
+ PARAMS ((HOST_WIDE_INT var_size, HOST_WIDE_INT boundary));
+static void push_frame_in_decls
+ PARAMS ((tree block, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary));
+static void push_frame_in_args
+ PARAMS ((tree parms, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary));
+static void push_frame_of_insns
+ PARAMS ((rtx insn, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary));
+static void push_frame_in_operand
+ PARAMS ((rtx insn, rtx orig,
+ HOST_WIDE_INT push_size, HOST_WIDE_INT boundary));
+static void push_frame_of_reg_equiv_memory_loc
+ PARAMS ((HOST_WIDE_INT push_size, HOST_WIDE_INT boundary));
+static void push_frame_of_reg_equiv_constant
+ PARAMS ((HOST_WIDE_INT push_size, HOST_WIDE_INT boundary));
+static void reset_used_flags_for_push_frame PARAMS ((void));
+static int check_out_of_frame_access
+ PARAMS ((rtx insn, HOST_WIDE_INT boundary));
+static int check_out_of_frame_access_in_operand
+ PARAMS ((rtx, HOST_WIDE_INT boundary));
+#endif
+
+rtx
+assign_stack_local_for_pseudo_reg (mode, size, align)
+ enum machine_mode mode;
+ HOST_WIDE_INT size;
+ int align;
+{
+#if defined(FRAME_GROWS_DOWNWARD) || !defined(STACK_GROWS_DOWNWARD)
+ return assign_stack_local (mode, size, align);
+#else
+ tree blocks = DECL_INITIAL (current_function_decl);
+ rtx new;
+ HOST_WIDE_INT saved_frame_offset, units_per_push, starting_frame;
+ int first_call_from_purge_addressof, first_call_from_global_alloc;
+
+ if (! flag_propolice_protection
+ || size == 0
+ || ! blocks
+ || current_function_is_inlinable
+ || ! search_string_from_argsandvars (1)
+ || current_function_contains_functions)
+ return assign_stack_local (mode, size, align);
+
+ first_call_from_purge_addressof = !push_frame_offset && !cse_not_expected;
+ first_call_from_global_alloc = !saved_cse_not_expected && cse_not_expected;
+ saved_cse_not_expected = cse_not_expected;
+
+ starting_frame = (STARTING_FRAME_OFFSET)?
+ STARTING_FRAME_OFFSET:BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ units_per_push = MAX(BIGGEST_ALIGNMENT / BITS_PER_UNIT,
+ GET_MODE_SIZE (mode));
+
+ if (first_call_from_purge_addressof)
+ {
+ push_frame_offset = push_allocated_offset;
+ if (check_out_of_frame_access (get_insns (), starting_frame))
+ {
+ /* if there is an access beyond frame, push dummy region to seperate
+ the address of instantiated variables */
+ push_frame (GET_MODE_SIZE (DImode), 0);
+ assign_stack_local (BLKmode, GET_MODE_SIZE (DImode), -1);
+ }
+ }
+
+ if (first_call_from_global_alloc)
+ {
+ push_frame_offset = push_allocated_offset = 0;
+ if (check_out_of_frame_access (get_insns (), starting_frame))
+ {
+ if (STARTING_FRAME_OFFSET)
+ {
+ /* if there is an access beyond frame, push dummy region
+ to seperate the address of instantiated variables */
+ push_frame (GET_MODE_SIZE (DImode), 0);
+ assign_stack_local (BLKmode, GET_MODE_SIZE (DImode), -1);
+ }
+ else
+ push_allocated_offset = starting_frame;
+ }
+ }
+
+ saved_frame_offset = frame_offset;
+ frame_offset = push_frame_offset;
+
+ new = assign_stack_local (mode, size, align);
+
+ push_frame_offset = frame_offset;
+ frame_offset = saved_frame_offset;
+
+ if (push_frame_offset > push_allocated_offset)
+ {
+ push_frame (units_per_push,
+ push_allocated_offset + STARTING_FRAME_OFFSET);
+
+ assign_stack_local (BLKmode, units_per_push, -1);
+ push_allocated_offset += units_per_push;
+ }
+
+ /* At the second call from global alloc, alpha push frame and assign
+ a local variable to the top of the stack */
+ if (first_call_from_global_alloc && STARTING_FRAME_OFFSET == 0)
+ push_frame_offset = push_allocated_offset = 0;
+
+ return new;
+#endif
+}
+
+
+#if !defined(FRAME_GROWS_DOWNWARD) && defined(STACK_GROWS_DOWNWARD)
+/*
+ push frame infomation for instantiating pseudo register at the top of stack.
+ This is only for the "frame grows upward", it means FRAME_GROWS_DOWNWARD is
+ not defined.
+
+ It is called by purge_addressof function and global_alloc (or reload)
+ function.
+*/
+static void
+push_frame (var_size, boundary)
+ HOST_WIDE_INT var_size, boundary;
+{
+ reset_used_flags_for_push_frame();
+
+ /* scan all declarations of variables and fix the offset address of
+ the variable based on the frame pointer */
+ push_frame_in_decls (DECL_INITIAL (current_function_decl),
+ var_size, boundary);
+
+ /* scan all argument variable and fix the offset address based on
+ the frame pointer */
+ push_frame_in_args (DECL_ARGUMENTS (current_function_decl),
+ var_size, boundary);
+
+ /* scan all operands of all insns and fix the offset address
+ based on the frame pointer */
+ push_frame_of_insns (get_insns (), var_size, boundary);
+
+ /* scan all reg_equiv_memory_loc and reg_equiv_constant*/
+ push_frame_of_reg_equiv_memory_loc (var_size, boundary);
+ push_frame_of_reg_equiv_constant (var_size, boundary);
+
+ reset_used_flags_for_push_frame();
+}
+
+static void
+reset_used_flags_for_push_frame()
+{
+ int i;
+ extern rtx *reg_equiv_memory_loc;
+ extern rtx *reg_equiv_constant;
+
+ /* Clear all the USED bits in operands of all insns and declarations of
+ local vars */
+ reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
+ reset_used_flags_for_insns (get_insns ());
+
+
+ /* The following codes are processed if the push_frame is called from
+ global_alloc (or reload) function */
+ if (reg_equiv_memory_loc == 0) return;
+
+ for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
+ if (reg_equiv_memory_loc[i])
+ {
+ rtx x = reg_equiv_memory_loc[i];
+
+ if (GET_CODE (x) == MEM
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && AUTO_BASEPTR (XEXP (x, 0)) == frame_pointer_rtx)
+ {
+ /* reset */
+ XEXP (x, 0)->used = 0;
+ }
+ }
+
+
+ if (reg_equiv_constant == 0) return;
+
+ for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
+ if (reg_equiv_constant[i])
+ {
+ rtx x = reg_equiv_constant[i];
+
+ if (GET_CODE (x) == PLUS
+ && AUTO_BASEPTR (x) == frame_pointer_rtx)
+ {
+ /* reset */
+ x->used = 0;
+ }
+ }
+}
+
+static void
+push_frame_in_decls (block, push_size, boundary)
+ tree block;
+ HOST_WIDE_INT push_size, boundary;
+{
+ tree types;
+ HOST_WIDE_INT offset;
+ rtx home;
+
+ while (block && TREE_CODE(block)==BLOCK)
+ {
+ types = BLOCK_VARS(block);
+
+ while (types)
+ {
+ /* skip the declaration that refers an external variable and
+ also skip an global variable */
+ if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types))
+ {
+
+ if (!DECL_RTL_SET_P (types)) goto next;
+ home = DECL_RTL (types);
+
+ /* process for static local variable */
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
+ goto next;
+
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == REG)
+ {
+ if (XEXP (home, 0) != frame_pointer_rtx
+ || boundary != 0)
+ goto next;
+
+ XEXP (home, 0) = plus_constant (frame_pointer_rtx,
+ push_size);
+
+ /* mark */
+ XEXP (home, 0)->used = 1;
+ }
+
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == MEM)
+ {
+
+ /* process for dynamically allocated aray */
+ home = XEXP (home, 0);
+ }
+
+ if (GET_CODE (home) == MEM
+ && GET_CODE (XEXP (home, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
+ {
+ offset = AUTO_OFFSET(XEXP (home, 0));
+
+ if (! XEXP (home, 0)->used
+ && offset >= boundary)
+ {
+ offset += push_size;
+ XEXP (XEXP (home, 0), 1)
+ = gen_rtx_CONST_INT (VOIDmode, offset);
+
+ /* mark */
+ XEXP (home, 0)->used = 1;
+ }
+ }
+
+ }
+ next:
+ types = TREE_CHAIN(types);
+ }
+
+ push_frame_in_decls (BLOCK_SUBBLOCKS (block), push_size, boundary);
+ block = BLOCK_CHAIN (block);
+ }
+}
+
+
+static void
+push_frame_in_args (parms, push_size, boundary)
+ tree parms;
+ HOST_WIDE_INT push_size, boundary;
+{
+ rtx home;
+ HOST_WIDE_INT offset;
+
+ for (; parms; parms = TREE_CHAIN (parms))
+ if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
+ {
+ if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
+ {
+ home = DECL_INCOMING_RTL (parms);
+ offset = AUTO_OFFSET(XEXP (home, 0));
+
+ if (XEXP (home, 0)->used || offset < boundary) continue;
+
+ /* the operand related to the sweep variable */
+ if (AUTO_BASEPTR (XEXP (home, 0)) == frame_pointer_rtx)
+ {
+ if (XEXP (home, 0) == frame_pointer_rtx)
+ XEXP (home, 0) = plus_constant (frame_pointer_rtx,
+ push_size);
+ else {
+ offset += push_size;
+ XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode,
+ offset);
+ }
+
+ /* mark */
+ XEXP (home, 0)->used = 1;
+ }
+ }
+ }
+}
+
+
+static int insn_pushed;
+static int *fp_equiv = 0;
+
+static void
+push_frame_of_insns (insn, push_size, boundary)
+ rtx insn;
+ HOST_WIDE_INT push_size, boundary;
+{
+ /* init fp_equiv */
+ fp_equiv = (int *) xcalloc (max_reg_num (), sizeof (int));
+
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)
+ {
+ rtx last;
+
+ insn_pushed = FALSE;
+
+ /* push frame in INSN operation */
+ push_frame_in_operand (insn, PATTERN (insn), push_size, boundary);
+
+ /* push frame in NOTE */
+ push_frame_in_operand (insn, REG_NOTES (insn), push_size, boundary);
+
+ /* push frame in CALL EXPR_LIST */
+ if (GET_CODE (insn) == CALL_INSN)
+ push_frame_in_operand (insn, CALL_INSN_FUNCTION_USAGE (insn),
+ push_size, boundary);
+
+ if (insn_pushed
+ && (last = try_split (PATTERN (insn), insn, 1)) != insn)
+ {
+ rtx first = NEXT_INSN (insn);
+ rtx trial = NEXT_INSN (first);
+ rtx pattern = PATTERN (trial);
+ rtx set;
+
+ /* update REG_EQUIV info to the first splitted insn */
+ if ((set = single_set (insn))
+ && find_reg_note (insn, REG_EQUIV, SET_SRC (set))
+ && GET_CODE (PATTERN (first)) == SET)
+ {
+ REG_NOTES (first)
+ = gen_rtx_EXPR_LIST (REG_EQUIV,
+ SET_SRC (PATTERN (first)),
+ REG_NOTES (first));
+ }
+
+ /* copy the first insn of splitted insns to the original insn and
+ delete the first insn,
+ because the original insn is pointed from records:
+ insn_chain, reg_equiv_init, used for global_alloc. */
+ if (cse_not_expected)
+ {
+ add_insn_before (insn, first);
+
+ /* Copy the various flags, and other information. */
+ memcpy (insn, first, sizeof (struct rtx_def) - sizeof (rtunion));
+ PATTERN (insn) = PATTERN (first);
+ REG_NOTES (insn) = REG_NOTES (first);
+
+ /* then remove the first insn of splitted insns. */
+ remove_insn (first);
+ INSN_DELETED_P (first) = 1;
+ }
+
+ if (GET_CODE (pattern) == SET
+ && GET_CODE (XEXP (pattern, 0)) == REG
+ && GET_CODE (XEXP (pattern, 1)) == PLUS
+ && XEXP (pattern, 0) == XEXP (XEXP (pattern, 1), 0)
+ && CONSTANT_P (XEXP (XEXP (pattern, 1), 1)))
+ {
+ rtx offset = XEXP (XEXP (pattern, 1), 1);
+ fp_equiv[REGNO (XEXP (pattern, 0))] = INTVAL (offset);
+
+ delete_insn (trial);
+ }
+
+ insn = last;
+ }
+ }
+
+ /* Clean up. */
+ free (fp_equiv);
+}
+
+
+static void
+push_frame_in_operand (insn, orig, push_size, boundary)
+ rtx insn, orig;
+ HOST_WIDE_INT push_size, boundary;
+{
+ register rtx x = orig;
+ register enum rtx_code code;
+ int i, j;
+ HOST_WIDE_INT offset;
+ const char *fmt;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case ASM_INPUT:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case RETURN:
+ case REG:
+ case ADDRESSOF:
+ case USE:
+ return;
+
+ case SET:
+ /*
+ skip setjmp setup insn and setjmp restore insn
+ alpha case:
+ (set (MEM (reg:SI xx)) (frame_pointer_rtx)))
+ (set (frame_pointer_rtx) (REG))
+ */
+ if (GET_CODE (XEXP (x, 0)) == MEM
+ && XEXP (x, 1) == frame_pointer_rtx)
+ return;
+ if (XEXP (x, 0) == frame_pointer_rtx
+ && GET_CODE (XEXP (x, 1)) == REG)
+ return;
+
+ /*
+ powerpc case: restores setjmp address
+ (set (frame_pointer_rtx) (plus frame_pointer_rtx const_int -n))
+ or
+ (set (reg) (plus frame_pointer_rtx const_int -n))
+ (set (frame_pointer_rtx) (reg))
+ */
+ if (GET_CODE (XEXP (x, 0)) == REG
+ && GET_CODE (XEXP (x, 1)) == PLUS
+ && XEXP (XEXP (x, 1), 0) == frame_pointer_rtx
+ && CONSTANT_P (XEXP (XEXP (x, 1), 1))
+ && INTVAL (XEXP (XEXP (x, 1), 1)) < 0)
+ {
+ x = XEXP (x, 1);
+ offset = AUTO_OFFSET(x);
+ if (x->used || abs (offset) < boundary)
+ return;
+
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - push_size);
+ x->used = 1; insn_pushed = TRUE;
+ return;
+ }
+
+ /* reset fp_equiv register */
+ else if (GET_CODE (XEXP (x, 0)) == REG
+ && fp_equiv[REGNO (XEXP (x, 0))])
+ fp_equiv[REGNO (XEXP (x, 0))] = 0;
+
+ /* propagete fp_equiv register */
+ else if (GET_CODE (XEXP (x, 0)) == REG
+ && GET_CODE (XEXP (x, 1)) == REG
+ && fp_equiv[REGNO (XEXP (x, 1))])
+ if (REGNO (XEXP (x, 0)) <= LAST_VIRTUAL_REGISTER
+ || reg_renumber[REGNO (XEXP (x, 0))] > 0)
+ fp_equiv[REGNO (XEXP (x, 0))] = fp_equiv[REGNO (XEXP (x, 1))];
+ break;
+
+ case MEM:
+ if (XEXP (x, 0) == frame_pointer_rtx
+ && boundary == 0)
+ {
+ XEXP (x, 0) = plus_constant (frame_pointer_rtx, push_size);
+ XEXP (x, 0)->used = 1; insn_pushed = TRUE;
+ return;
+ }
+ break;
+
+ case PLUS:
+ offset = AUTO_OFFSET(x);
+
+ /* Handle special case of frame register plus constant. */
+ if (CONSTANT_P (XEXP (x, 1))
+ && XEXP (x, 0) == frame_pointer_rtx)
+ {
+ if (x->used || offset < boundary)
+ return;
+
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset + push_size);
+ x->used = 1; insn_pushed = TRUE;
+
+ return;
+ }
+ /*
+ Handle alpha case:
+ (plus:SI (subreg:SI (reg:DI 63 FP) 0) (const_int 64 [0x40]))
+ */
+ if (CONSTANT_P (XEXP (x, 1))
+ && GET_CODE (XEXP (x, 0)) == SUBREG
+ && SUBREG_REG (XEXP (x, 0)) == frame_pointer_rtx)
+ {
+ if (x->used || offset < boundary)
+ return;
+
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset + push_size);
+ x->used = 1; insn_pushed = TRUE;
+
+ return;
+ }
+ /*
+ Handle powerpc case:
+ (set (reg x) (plus fp const))
+ (set (.....) (... (plus (reg x) (const B))))
+ */
+ else if (CONSTANT_P (XEXP (x, 1))
+ && GET_CODE (XEXP (x, 0)) == REG
+ && fp_equiv[REGNO (XEXP (x, 0))])
+ {
+ if (x->used) return;
+
+ offset += fp_equiv[REGNO (XEXP (x, 0))];
+
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
+ x->used = 1; insn_pushed = TRUE;
+
+ return;
+ }
+ /*
+ Handle special case of frame register plus reg (constant).
+ (set (reg x) (const B))
+ (set (....) (...(plus fp (reg x))))
+ */
+ else if (XEXP (x, 0) == frame_pointer_rtx
+ && GET_CODE (XEXP (x, 1)) == REG
+ && PREV_INSN (insn)
+ && PATTERN (PREV_INSN (insn))
+ && SET_DEST (PATTERN (PREV_INSN (insn))) == XEXP (x, 1)
+ && CONSTANT_P (SET_SRC (PATTERN (PREV_INSN (insn)))))
+ {
+ HOST_WIDE_INT offset = INTVAL (SET_SRC (PATTERN (PREV_INSN (insn))));
+
+ if (x->used || offset < boundary)
+ return;
+
+ SET_SRC (PATTERN (PREV_INSN (insn)))
+ = gen_rtx_CONST_INT (VOIDmode, offset + push_size);
+ x->used = 1;
+ XEXP (x, 1)->used = 1;
+
+ return;
+ }
+ /* Handle special case of frame register plus reg (used). */
+ else if (XEXP (x, 0) == frame_pointer_rtx
+ && XEXP (x, 1)->used)
+ {
+ x->used = 1;
+ return;
+ }
+ /*
+ process further subtree:
+ Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
+ (const_int 5))
+ */
+ break;
+
+ case CALL_PLACEHOLDER:
+ push_frame_of_insns (XEXP (x, 0), push_size, boundary);
+ push_frame_of_insns (XEXP (x, 1), push_size, boundary);
+ push_frame_of_insns (XEXP (x, 2), push_size, boundary);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ if (*fmt == 'e')
+ {
+ if (XEXP (x, i) == frame_pointer_rtx && boundary == 0)
+ fatal_insn ("push_frame_in_operand", insn);
+ push_frame_in_operand (insn, XEXP (x, i), push_size, boundary);
+ }
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ push_frame_in_operand (insn, XVECEXP (x, i, j), push_size, boundary);
+}
+
+static void
+push_frame_of_reg_equiv_memory_loc (push_size, boundary)
+ HOST_WIDE_INT push_size, boundary;
+{
+ int i;
+ extern rtx *reg_equiv_memory_loc;
+
+ /* This function is processed if the push_frame is called from
+ global_alloc (or reload) function */
+ if (reg_equiv_memory_loc == 0) return;
+
+ for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
+ if (reg_equiv_memory_loc[i])
+ {
+ rtx x = reg_equiv_memory_loc[i];
+ int offset;
+
+ if (GET_CODE (x) == MEM
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && XEXP (XEXP (x, 0), 0) == frame_pointer_rtx)
+ {
+ offset = AUTO_OFFSET(XEXP (x, 0));
+
+ if (! XEXP (x, 0)->used
+ && offset >= boundary)
+ {
+ offset += push_size;
+ XEXP (XEXP (x, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);
+
+ /* mark */
+ XEXP (x, 0)->used = 1;
+ }
+ }
+ else if (GET_CODE (x) == MEM
+ && XEXP (x, 0) == frame_pointer_rtx
+ && boundary == 0)
+ {
+ XEXP (x, 0) = plus_constant (frame_pointer_rtx, push_size);
+ XEXP (x, 0)->used = 1; insn_pushed = TRUE;
+ }
+ }
+}
+
+static void
+push_frame_of_reg_equiv_constant (push_size, boundary)
+ HOST_WIDE_INT push_size, boundary;
+{
+ int i;
+ extern rtx *reg_equiv_constant;
+
+ /* This function is processed if the push_frame is called from
+ global_alloc (or reload) function */
+ if (reg_equiv_constant == 0) return;
+
+ for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
+ if (reg_equiv_constant[i])
+ {
+ rtx x = reg_equiv_constant[i];
+ int offset;
+
+ if (GET_CODE (x) == PLUS
+ && XEXP (x, 0) == frame_pointer_rtx)
+ {
+ offset = AUTO_OFFSET(x);
+
+ if (! x->used
+ && offset >= boundary)
+ {
+ offset += push_size;
+ XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
+
+ /* mark */
+ x->used = 1;
+ }
+ }
+ else if (x == frame_pointer_rtx
+ && boundary == 0)
+ {
+ reg_equiv_constant[i]
+ = plus_constant (frame_pointer_rtx, push_size);
+ reg_equiv_constant[i]->used = 1; insn_pushed = TRUE;
+ }
+ }
+}
+
+static int
+check_out_of_frame_access (insn, boundary)
+ rtx insn;
+ HOST_WIDE_INT boundary;
+{
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)
+ {
+ if (check_out_of_frame_access_in_operand (PATTERN (insn), boundary))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static int
+check_out_of_frame_access_in_operand (orig, boundary)
+ rtx orig;
+ HOST_WIDE_INT boundary;
+{
+ register rtx x = orig;
+ register enum rtx_code code;
+ int i, j;
+ const char *fmt;
+
+ if (x == 0)
+ return FALSE;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case ASM_INPUT:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case RETURN:
+ case REG:
+ case ADDRESSOF:
+ return FALSE;
+
+ case MEM:
+ if (XEXP (x, 0) == frame_pointer_rtx)
+ if (0 < boundary) return TRUE;
+ break;
+
+ case PLUS:
+ /* Handle special case of frame register plus constant. */
+ if (CONSTANT_P (XEXP (x, 1))
+ && XEXP (x, 0) == frame_pointer_rtx)
+ {
+ if (0 <= AUTO_OFFSET(x)
+ && AUTO_OFFSET(x) < boundary) return TRUE;
+ return FALSE;
+ }
+ /*
+ process further subtree:
+ Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
+ (const_int 5))
+ */
+ break;
+
+ case CALL_PLACEHOLDER:
+ if (check_out_of_frame_access (XEXP (x, 0), boundary)) return TRUE;
+ if (check_out_of_frame_access (XEXP (x, 1), boundary)) return TRUE;
+ if (check_out_of_frame_access (XEXP (x, 2), boundary)) return TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ if (*fmt == 'e')
+ {
+ if (check_out_of_frame_access_in_operand (XEXP (x, i), boundary))
+ return TRUE;
+ }
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (check_out_of_frame_access_in_operand (XVECEXP (x, i, j), boundary))
+ return TRUE;
+
+ return FALSE;
+}
+#endif
diff --git a/gnu/usr.bin/gcc/gcc/protector.h b/gnu/usr.bin/gcc/gcc/protector.h
new file mode 100644
index 00000000000..7b47789503c
--- /dev/null
+++ b/gnu/usr.bin/gcc/gcc/protector.h
@@ -0,0 +1,53 @@
+/* RTL buffer overflow protection function for GNU C compiler
+ Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+
+/* declaration of GUARD variable */
+#define GUARD_m Pmode
+#define UNITS_PER_GUARD MAX(BIGGEST_ALIGNMENT / BITS_PER_UNIT, GET_MODE_SIZE (GUARD_m))
+
+#ifndef L_stack_smash_handler
+
+/* insert a guard variable before a character buffer and change the order
+ of pointer variables, character buffers and pointer arguments */
+
+extern void prepare_stack_protection PARAMS ((int inlinable));
+
+#ifdef TREE_CODE
+/* search a character array from the specified type tree */
+
+extern int search_string_def PARAMS ((tree names));
+#endif
+
+/* examine whether the input contains frame pointer addressing */
+
+extern int contains_fp PARAMS ((rtx op));
+
+/* Return size that is not allocated for stack frame. It will be allocated
+ to modify the home of pseudo registers called from global_alloc. */
+
+extern HOST_WIDE_INT get_frame_free_size PARAMS ((void));
+
+/* allocate a local variable in the stack area before character buffers
+ to avoid the corruption of it */
+
+extern rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int));
+
+#endif
diff --git a/gnu/usr.bin/gcc/gcc/reload1.c b/gnu/usr.bin/gcc/gcc/reload1.c
index 3000f617398..bfe7ae4b8d3 100644
--- a/gnu/usr.bin/gcc/gcc/reload1.c
+++ b/gnu/usr.bin/gcc/gcc/reload1.c
@@ -42,6 +42,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "toplev.h"
#include "except.h"
#include "tree.h"
+#include "protector.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
@@ -925,7 +926,7 @@ reload (first, global)
if (cfun->stack_alignment_needed)
assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed);
- starting_frame_size = get_frame_size ();
+ starting_frame_size = get_frame_size () - get_frame_free_size ();
set_initial_elim_offsets ();
set_initial_label_offsets ();
@@ -989,7 +990,7 @@ reload (first, global)
setup_save_areas ();
/* If we allocated another stack slot, redo elimination bookkeeping. */
- if (starting_frame_size != get_frame_size ())
+ if (starting_frame_size != get_frame_size () - get_frame_free_size ())
continue;
if (caller_save_needed)
@@ -1008,7 +1009,7 @@ reload (first, global)
/* If we allocated any new memory locations, make another pass
since it might have changed elimination offsets. */
- if (starting_frame_size != get_frame_size ())
+ if (starting_frame_size != get_frame_size () - get_frame_free_size ())
something_changed = 1;
{
@@ -1100,11 +1101,11 @@ reload (first, global)
if (insns_need_reload != 0 || something_needs_elimination
|| something_needs_operands_changed)
{
- HOST_WIDE_INT old_frame_size = get_frame_size ();
+ HOST_WIDE_INT old_frame_size = get_frame_size () - get_frame_free_size ();
reload_as_needed (global);
- if (old_frame_size != get_frame_size ())
+ if (old_frame_size != get_frame_size () - get_frame_free_size ())
abort ();
if (num_eliminable)
@@ -1992,7 +1993,7 @@ alter_reg (i, from_reg)
if (from_reg == -1)
{
/* No known place to spill from => no slot to reuse. */
- x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
+ x = assign_stack_local_for_pseudo_reg (GET_MODE (regno_reg_rtx[i]), total_size,
inherent_size == total_size ? 0 : -1);
if (BYTES_BIG_ENDIAN)
/* Cancel the big-endian correction done in assign_stack_local.
diff --git a/gnu/usr.bin/gcc/gcc/simplify-rtx.c b/gnu/usr.bin/gcc/gcc/simplify-rtx.c
index eca29457a8c..1217d00f481 100644
--- a/gnu/usr.bin/gcc/gcc/simplify-rtx.c
+++ b/gnu/usr.bin/gcc/gcc/simplify-rtx.c
@@ -1670,7 +1670,8 @@ simplify_plus_minus (code, mode, op0, op1, force)
int n_ops = 2, input_ops = 2, input_consts = 0, n_consts;
int first, negate, changed;
int i, j;
-
+ HOST_WIDE_INT fp_offset = 0;
+
memset ((char *) ops, 0, sizeof ops);
/* Set up the two operands and then expand them until nothing has been
@@ -1695,6 +1696,10 @@ simplify_plus_minus (code, mode, op0, op1, force)
switch (this_code)
{
case PLUS:
+ if (flag_propolice_protection
+ && XEXP (this_op, 0) == virtual_stack_vars_rtx
+ && GET_CODE (XEXP (this_op, 1)) == CONST_INT)
+ fp_offset = INTVAL (XEXP (this_op, 1));
case MINUS:
if (n_ops == 7)
return NULL_RTX;
@@ -1849,10 +1854,10 @@ simplify_plus_minus (code, mode, op0, op1, force)
&& GET_CODE (ops[n_ops - 1].op) == CONST_INT
&& CONSTANT_P (ops[n_ops - 2].op))
{
- rtx value = ops[n_ops - 1].op;
+ int value = INTVAL (ops[n_ops - 1].op);
if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg)
- value = neg_const_int (mode, value);
- ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value));
+ value = -value;
+ ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, value);
n_ops--;
}
@@ -1871,6 +1876,54 @@ simplify_plus_minus (code, mode, op0, op1, force)
|| (n_ops + n_consts == input_ops && n_consts <= input_consts)))
return NULL_RTX;
+ if (flag_propolice_protection)
+ {
+ /* keep the addressing style of local variables
+ as (plus (virtual_stack_vars_rtx) (CONST_int x))
+ (1) inline function is expanded, (+ (+VFP c1) -c2)=>(+ VFP c1-c2)
+ (2) the case ary[r-1], (+ (+VFP c1) (+r -1))=>(+ R (+r -1))
+ */
+ for (i = 0; i < n_ops; i++)
+#ifdef FRAME_GROWS_DOWNWARD
+ if (ops[i].op == virtual_stack_vars_rtx)
+#else
+ if (ops[i].op == virtual_stack_vars_rtx
+ || ops[i].op == frame_pointer_rtx)
+#endif
+ {
+ if (GET_CODE (ops[n_ops - 1].op) == CONST_INT)
+ {
+ HOST_WIDE_INT value = INTVAL (ops[n_ops - 1].op);
+ if (n_ops < 3 || value >= fp_offset)
+ {
+ ops[i].op = plus_constant (ops[i].op, value);
+ n_ops--;
+ }
+ else
+ {
+ if (!force
+ && (n_ops+1 + n_consts > input_ops
+ || (n_ops+1 + n_consts == input_ops && n_consts <= input_consts)))
+ return NULL_RTX;
+ ops[n_ops - 1].op = GEN_INT (value-fp_offset);
+ ops[i].op = plus_constant (ops[i].op, fp_offset);
+ }
+ }
+ /* buf[BUFSIZE]: buf is the first local variable (+ (+ fp -S) S)
+ or (+ (fp 0) r) ==> ((+ (+fp 1) r) -1) */
+ else if (fp_offset != 0)
+ return NULL_RTX;
+#ifndef FRAME_GROWS_DOWNWARD
+ /*
+ * For the case of buf[i], i: REG, buf: (plus fp 0),
+ */
+ else if (fp_offset == 0)
+ return NULL_RTX;
+#endif
+ break;
+ }
+ }
+
/* Put a non-negated operand first. If there aren't any, make all
operands positive and negate the whole thing later. */
diff --git a/gnu/usr.bin/gcc/gcc/toplev.c b/gnu/usr.bin/gcc/gcc/toplev.c
index e3b5ac5d010..d0d2a3483e6 100644
--- a/gnu/usr.bin/gcc/gcc/toplev.c
+++ b/gnu/usr.bin/gcc/gcc/toplev.c
@@ -908,8 +908,14 @@ int align_functions_log;
minimum function alignment. Zero means no alignment is forced. */
int force_align_functions_log;
-/* Fake StackProtector option, does nothing. */
+#if defined(STACK_PROTECTOR) && defined(STACK_GROWS_DOWNWARD)
+/* Nonzero means use propolice as a stack protection method */
+int flag_propolice_protection = 1;
+int flag_stack_protection = 0;
+#else
int flag_propolice_protection = 0;
+int flag_stack_protection = 0;
+#endif
/* Table of supported debugging formats. */
static const struct
@@ -1197,6 +1203,10 @@ static const lang_independent_options f_options[] =
N_("Fake disable stack protection") },
{ "new-ra", &flag_new_regalloc, 1,
N_("Use graph coloring register allocation.") },
+ {"stack-protector", &flag_propolice_protection, 1,
+ N_("Enables stack protection") },
+ {"stack-protector-all", &flag_stack_protection, 1,
+ N_("Enables stack protection of every function") } ,
};
/* Table of language-specific options. */
@@ -1559,7 +1569,9 @@ static const lang_independent_options W_options[] =
{"missing-noreturn", &warn_missing_noreturn, 1,
N_("Warn about functions which might be candidates for attribute noreturn") },
{"strict-aliasing", &warn_strict_aliasing, 1,
- N_ ("Warn about code which might break the strict aliasing rules") }
+ N_ ("Warn about code which might break the strict aliasing rules") },
+ {"stack-protector", &warn_stack_protector, 1,
+ N_("Warn when disabling stack protector for some reason")}
};
void
@@ -2461,6 +2473,8 @@ rest_of_compilation (decl)
insns = get_insns ();
+ if (flag_propolice_protection) prepare_stack_protection (inlinable);
+
/* Dump the rtl code if we are dumping rtl. */
if (open_dump_file (DFI_rtl, decl))
@@ -5230,6 +5244,12 @@ process_options ()
/* The presence of IEEE signaling NaNs, implies all math can trap. */
if (flag_signaling_nans)
flag_trapping_math = 1;
+
+ /* This combination makes optimized frame addressings and causes
+ a internal compilation error at prepare_stack_protection.
+ so don't allow it. */
+ if (flag_stack_protection && !flag_propolice_protection)
+ flag_propolice_protection = TRUE;
}
/* Initialize the compiler back end. */