Submitted By: Robert Connolly (ashes) Date: 2004-10-28 Initial Package Version: 2.95.3 Upstream Status: Rejected Upstream Origin: http://www.research.ibm.com/trl/projects/security/ssp/ Description: Smashing Stack Protector - protector-2.95.3-29.tar.gz This patch is made specifically to work with the Glibc SSP patch. All guard functions have been removed. Developers are encouraged to check the differences between this patch, the original from ibm, and the Glibc patch. The gcc/libgcc2.c, gcc/config/t-linux, and gcc/Makefile.in LIB2FUNCS "_stack_smash_handler" hunks were not used. Equivilent to using -D_LIBC_PROVIDES_SSP_ (-DHAVE_SYSLOG is related). To set the version string do something like this: sed -e 's/2.95.3/2.95.3 ssp/' -i gcc/version.c && sed -e 's@http://gcc.gnu.org/bugs.html@http://bugs.linuxfromscratch.org/@' \ -i gcc/version.c This patch, and Glibc's patch, depends on erandom sysctl from: http://frandom.sourceforge.net/ Thanks to Eli Billauer. Also see: http://www.linuxfromscratch.org/hlfs/ http://www.linuxfromscratch.org/hints/downloads/files/ssp.txt http://www.linuxfromscratch.org/hints/downloads/files/entropy.txt diff -Naur gcc-2.95.3.orig/gcc/Makefile.in gcc-2.95.3.ssp/gcc/Makefile.in --- gcc-2.95.3.orig/gcc/Makefile.in 2001-01-25 14:02:58.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/Makefile.in 2004-10-29 00:27:29.228237072 +0000 @@ -683,7 +683,7 @@ insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \ insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \ profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \ - mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o + mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o protector.o # GEN files are listed separately, so they can be built before doing parallel # makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load @@ -1136,7 +1136,7 @@ if [ $${name}.asm = $${file} ]; then \ cp $${file} $${name}.s || exit 1; file=$${name}.s; \ else true; fi; \ - $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \ + $(GCC_FOR_TARGET) -fno-stack-protector $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${oname}$(objext); \ rm -f $${name}.s $${oname}$(objext); \ @@ -1463,7 +1463,7 @@ dwarf2out.h sdbout.h dbxout.h $(EXPR_H) $(BASIC_BLOCK_H) \ $(lang_options_files) $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \ - -DTARGET_NAME=\"$(target_alias)\" \ + -DTARGET_NAME=\"$(target_alias)\" @ENABLESSP@ \ -c `echo $(srcdir)/toplev.c | sed 's,^\./,,'` rtl.o : rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h diff -Naur gcc-2.95.3.orig/gcc/calls.c gcc-2.95.3.ssp/gcc/calls.c --- gcc-2.95.3.orig/gcc/calls.c 2001-01-25 14:03:00.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/calls.c 2004-10-29 00:22:36.592724432 +0000 @@ -1753,7 +1753,7 @@ /* This DECL is just something to feed to mark_addressable; it doesn't get pushed. */ d = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); - DECL_RTL (d) = assign_temp (TREE_TYPE (exp), 1, 0, 1); + DECL_RTL (d) = assign_temp (TREE_TYPE (exp), 5, 0, 1); mark_addressable (d); structure_value_addr = XEXP (DECL_RTL (d), 0); TREE_USED (d) = 1; diff -Naur gcc-2.95.3.orig/gcc/combine.c gcc-2.95.3.ssp/gcc/combine.c --- gcc-2.95.3.orig/gcc/combine.c 2001-01-25 14:03:01.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/combine.c 2004-10-29 00:22:36.710706496 +0000 @@ -3483,6 +3483,16 @@ 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') @@ -3953,6 +3963,11 @@ 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)), @@ -4045,7 +4060,10 @@ /* 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 -Naur gcc-2.95.3.orig/gcc/configure gcc-2.95.3.ssp/gcc/configure --- gcc-2.95.3.orig/gcc/configure 2001-03-16 14:13:48.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/configure 2004-10-29 00:22:36.763698440 +0000 @@ -67,6 +67,8 @@ ac_help="$ac_help --disable-nls do not use Native Language Support" ac_help="$ac_help + --enable-stack-protector force use stack protection as defaults" +ac_help="$ac_help --with-included-gettext use the GNU gettext library included here" ac_help="$ac_help --with-catgets use catgets functions if available" @@ -1258,6 +1260,16 @@ fi +# Determine whether or not stack protection is enabled. +# Check whether --enable-stack-protector was given. +if test "${enable_stack_protector+set}" = set; then + ENABLESSP="-DSTACK_PROTECTOR" + +else + ENABLESSP="" +fi; + + echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 echo "configure:1263: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` @@ -8772,6 +8784,7 @@ s%@build_os@%$build_os%g s%@CC@%$CC%g s%@stage1_warn_cflags@%$stage1_warn_cflags%g +s%@ENABLESSP@%$ENABLESSP%g s%@SET_MAKE@%$SET_MAKE%g s%@AWK@%$AWK%g s%@LEX@%$LEX%g diff -Naur gcc-2.95.3.orig/gcc/cse.c gcc-2.95.3.ssp/gcc/cse.c --- gcc-2.95.3.orig/gcc/cse.c 2001-01-25 14:03:03.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/cse.c 2004-10-29 00:22:36.820689776 +0000 @@ -4504,6 +4504,7 @@ int n_ops = 2, input_ops = 2, input_consts = 0, n_consts = 0; int first = 1, negate = 0, changed; int i, j; + HOST_WIDE_INT fp_offset = 0; bzero ((char *) ops, sizeof ops); @@ -4522,6 +4523,10 @@ switch (GET_CODE (ops[i])) { case PLUS: + if (flag_propolice_protection + && XEXP (ops[i], 0) == virtual_stack_vars_rtx + && GET_CODE (XEXP (ops[i], 1)) == CONST_INT) + fp_offset = INTVAL (XEXP (ops[i], 1)); case MINUS: if (n_ops == 7) return 0; @@ -4637,7 +4642,54 @@ j = negs[n_ops - 1], negs[n_ops - 1] = negs[i], negs[i] = j; } - /* Put a non-negated operand first. If there aren't any, make all + 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] == virtual_stack_vars_rtx) +#else + if (ops[i] == virtual_stack_vars_rtx + || ops[i] == frame_pointer_rtx) +#endif + { + if (GET_CODE (ops[n_ops - 1]) == CONST_INT) + { + HOST_WIDE_INT value = INTVAL (ops[n_ops - 1]); + if (n_ops < 3 || value >= fp_offset) + { + ops[i] = plus_constant (ops[i], value); + n_ops--; + } + else + { + if (n_ops+1 + n_consts > input_ops + || (n_ops+1 + n_consts == input_ops && n_consts <= input_consts)) + return 0; + ops[n_ops - 1] = GEN_INT (value-fp_offset); + ops[i] = plus_constant (ops[i], 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 0; +#ifndef FRAME_GROWS_DOWNWARD + /* + * For the case of buf[i], i: REG, buf: (plus fp 0), + */ + else if (fp_offset == 0) + return 0; +#endif + break; + } + } + +/* Put a non-negated operand first. If there aren't any, make all operands positive and negate the whole thing later. */ for (i = 0; i < n_ops && negs[i]; i++) ; @@ -5964,7 +6016,14 @@ 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 @@ -6483,6 +6542,13 @@ if (SET_DEST (x) == pc_rtx && GET_CODE (SET_SRC (x)) == LABEL_REF) ; + else if (x->volatil) { + rtx x1 = SET_DEST (x); + if (GET_CODE (x1) == SUBREG && GET_CODE (SUBREG_REG (x1)) == REG) + x1 = SUBREG_REG (x1); + make_new_qty (REGNO (x1)); + qty_mode[REG_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 -Naur gcc-2.95.3.orig/gcc/explow.c gcc-2.95.3.ssp/gcc/explow.c --- gcc-2.95.3.orig/gcc/explow.c 1999-04-17 17:14:48.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/explow.c 2004-10-29 00:22:36.825689016 +0000 @@ -52,7 +52,8 @@ register rtx tem; int all_constant = 0; - if (c == 0) + if (c == 0 + && !(flag_propolice_protection && x == virtual_stack_vars_rtx)) return x; restart: @@ -149,7 +150,8 @@ 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) @@ -473,6 +475,21 @@ 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 -Naur gcc-2.95.3.orig/gcc/expr.c gcc-2.95.3.ssp/gcc/expr.c --- gcc-2.95.3.orig/gcc/expr.c 2001-02-19 14:02:00.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/expr.c 2004-10-29 00:22:36.922674272 +0000 @@ -41,6 +41,7 @@ #include "typeclass.h" #include "defaults.h" #include "toplev.h" +#include "protector.h" #define CEIL(x,y) (((x) + (y) - 1) / (y)) @@ -1468,7 +1469,7 @@ 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; } @@ -1482,7 +1483,7 @@ 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; } @@ -1600,9 +1601,9 @@ MEM_IN_STRUCT_P (from1) = data->from_struct; if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0) - emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size))); + if (data->explicit_inc_to-- < -1) emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size))); if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0) - emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size))); + if (data->explicit_inc_from-- < -1) emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size))); emit_insn ((*genfun) (to1, from1)); if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0) @@ -2313,7 +2314,7 @@ 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; } @@ -2383,7 +2384,7 @@ MEM_IN_STRUCT_P (to1) = data->to_struct; if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0) - emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size))); + if (data->explicit_inc_to-- < -1) emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size))); emit_insn ((*genfun) (to1, const0_rtx)); if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0) @@ -5160,7 +5161,9 @@ && 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_binop (GET_MODE (value), binoptab, XEXP (XEXP (value, 0), 0), op2, @@ -7075,7 +7078,8 @@ /* 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 -Naur gcc-2.95.3.orig/gcc/flags.h gcc-2.95.3.ssp/gcc/flags.h --- gcc-2.95.3.orig/gcc/flags.h 1999-05-18 01:05:04.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/flags.h 2004-10-29 00:22:36.925673816 +0000 @@ -538,3 +538,12 @@ string identifying the compiler. */ extern int flag_no_ident; + +/* 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; diff -Naur gcc-2.95.3.orig/gcc/function.c gcc-2.95.3.ssp/gcc/function.c --- gcc-2.95.3.orig/gcc/function.c 2001-01-25 14:03:15.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/function.c 2004-10-29 00:22:36.941671384 +0000 @@ -58,6 +58,7 @@ #include "obstack.h" #include "toplev.h" #include "hash.h" +#include "protector.h" #ifndef TRAMPOLINE_ALIGNMENT #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY @@ -430,6 +431,8 @@ /* 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; }; /* List of all temporaries allocated, both available and in use. */ @@ -449,6 +452,11 @@ until no longer needed. CLEANUP_POINT_EXPRs define the lifetime of TARGET_EXPRs. */ int target_temp_slot_level; + +/* Current boundary mark for character arrays. */ + +int temp_boundary_mark; + /* This structure is used to record MEMs or pseudos used to replace VAR, any SUBREGs of VAR, and any MEMs containing VAR as an address. We need to @@ -917,7 +925,8 @@ with this flag. KEEP is 2 if we allocate a longer term temporary, 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). + 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. */ @@ -931,6 +940,8 @@ int align; int alias_set; struct temp_slot *p, *best_p = 0; + 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. */ @@ -963,7 +974,8 @@ && (!flag_strict_aliasing || (alias_set && p->alias_set == alias_set)) && (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) { @@ -1001,6 +1013,7 @@ p->align = best_p->align; p->address = 0; p->rtl_expr = 0; + p->boundary_mark = best_p->boundary_mark; p->next = temp_slots; temp_slots = p; @@ -1062,6 +1075,7 @@ 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; } @@ -1186,14 +1200,16 @@ 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; @@ -1702,7 +1718,7 @@ if (regno < max_parm_reg) new = parm_reg_stack_loc[regno]; if (new == 0) - new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0); + new = assign_stack_local_for_pseudo_reg (decl_mode, GET_MODE_SIZE (decl_mode), 0); } PUT_MODE (reg, decl_mode); @@ -3860,7 +3876,8 @@ 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 -Naur gcc-2.95.3.orig/gcc/gcse.c gcc-2.95.3.ssp/gcc/gcse.c --- gcc-2.95.3.orig/gcc/gcse.c 1999-10-16 21:20:32.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/gcse.c 2004-10-29 00:22:36.987664392 +0000 @@ -3718,7 +3718,7 @@ /* 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 -Naur gcc-2.95.3.orig/gcc/integrate.c gcc-2.95.3.ssp/gcc/integrate.c --- gcc-2.95.3.orig/gcc/integrate.c 1999-04-25 23:35:12.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/integrate.c 2004-10-29 00:22:36.995663176 +0000 @@ -2270,6 +2270,8 @@ } /* These args would always appear unused, if not for this. */ TREE_USED (d) = 1; + if (flag_propolice_protection && TREE_CODE (d) == VAR_DECL) + DECL_INLINE (d) = 1; if (DECL_LANG_SPECIFIC (d)) copy_lang_decl (d); @@ -2393,6 +2395,10 @@ seq = gen_sequence (); 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 -Naur gcc-2.95.3.orig/gcc/jump.c gcc-2.95.3.ssp/gcc/jump.c --- gcc-2.95.3.orig/gcc/jump.c 1999-10-21 06:24:03.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/jump.c 2004-10-29 00:22:37.007661352 +0000 @@ -65,6 +65,7 @@ #include "real.h" #include "except.h" #include "toplev.h" +#include "protector.h" /* ??? Eventually must record somehow the labels used by jumps from nested functions. */ @@ -2521,6 +2522,35 @@ insn = PREV_INSN (insn); } + /* If the NOTE_INSN_FUNCTION_END is generated by the stack protector, + skip to the label insn before protector's epilogue insns. */ + if (flag_propolice_protection + && insn != NULL_RTX + && GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END + && NOTE_SOURCE_FILE (insn) + && strcmp (NOTE_SOURCE_FILE (insn), SSP_DUMMY_FILE) == 0) + { + /* found ssp handler and skip to the call insn. */ + for (; insn != NULL_RTX; insn = PREV_INSN (insn)) + { + if (GET_CODE (insn) == CALL_INSN) + break; + } + + /* skip to the insn before jump insn. */ + for (; insn != NULL_RTX; insn = PREV_INSN (insn)) + { + if (GET_CODE (insn) == JUMP_INSN) + { + insn = PREV_INSN (insn); + return calculate_can_reach_end (insn, check_deleted, + delete_final_note); + } + } + return 0; + } + /* See if we backed up to the appropriate type of note. */ if (insn != NULL_RTX && GET_CODE (insn) == NOTE diff -Naur gcc-2.95.3.orig/gcc/loop.c gcc-2.95.3.ssp/gcc/loop.c --- gcc-2.95.3.orig/gcc/loop.c 2001-01-25 14:03:18.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/loop.c 2004-10-29 00:22:37.104646608 +0000 @@ -6201,6 +6201,14 @@ 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) { #ifdef ADDRESS_COST diff -Naur gcc-2.95.3.orig/gcc/optabs.c gcc-2.95.3.ssp/gcc/optabs.c --- gcc-2.95.3.orig/gcc/optabs.c 2001-01-25 14:03:19.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/optabs.c 2004-10-29 00:22:37.115644936 +0000 @@ -772,6 +772,25 @@ 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_operand_predicate[icode][0]) (temp, mode)) + 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 -Naur gcc-2.95.3.orig/gcc/protector.c gcc-2.95.3.ssp/gcc/protector.c --- gcc-2.95.3.orig/gcc/protector.c 1970-01-01 00:00:00.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/protector.c 2004-09-03 05:24:37.000000000 +0000 @@ -0,0 +1,2661 @@ +/* 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 GNU CC. + +GNU CC 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. + +GNU CC 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 GNU CC; 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 "protector.h" + + +rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int)); + + +/* 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; + +/* Nonzero if search_string_def finds a byte-pointer variable, + which may be assigned to alloca output. */ +static int may_have_alloca_pointer; + +static rtx guard_area, _guard; +static rtx function_first_insn, prologue_insert_point; +static rtx debuginsn; + +/* */ +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, int mark)); +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_in_operand PARAMS ((rtx x, rtx orig, rtx new, HOST_WIDE_INT size)); +static void expand_value_return PARAMS ((rtx val)); +static int replace_return_reg PARAMS ((rtx insn, rtx return_save)); +static void validate_insns_of_varrefs PARAMS ((rtx insn)); +static void validate_operand_of_varrefs PARAMS ((rtx insn, rtx *loc)); + +#ifndef SUSPICIOUS_BUF_SIZE +#define SUSPICIOUS_BUF_SIZE 8 +#endif + +#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)) + + + +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; + may_have_alloca_pointer = 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 + && may_have_alloca_pointer + && 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) + { + 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 (types) + && GET_CODE (DECL_RTL (types)) == MEM) + { + if (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 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 || + TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR) + current_function_defines_vsized_array = TRUE; + + if (TREE_TYPE (type) == char_type_node + || (TREE_TYPE (type) + && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE + && TYPE_PRECISION (TREE_TYPE (type)) == 8)) + { + /* Check if the string is a variable string */ + if (TYPE_DOMAIN (type) == 0 || + TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR) + return TRUE; + +#if SUSPICIOUS_BUF_SIZE > 0 + /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE */ + if (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: + /* Check if pointer variables, which may be a pointer assigned + by alloca function call, are declared. */ + if (TREE_TYPE (type) == char_type_node + || (TREE_TYPE (type) + && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE + && TYPE_PRECISION (TREE_TYPE (type)) == 8)) + may_have_alloca_pointer = TRUE; + break; + + 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 PLUS: + if (XEXP (x, 0) == virtual_stack_vars_rtx + && CONSTANT_P (XEXP (x, 1))) + return TRUE; + break; + + default: + return FALSE; + } + + /* 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: + /* I'm not sure whether OFFSET_TYPE needs this treatment, + so I'll play safe and return 1. */ + case OFFSET_TYPE: + if (TYPE_READONLY (TREE_TYPE (type))) + { + int funcp = search_func_pointer (TREE_TYPE (type), 1); + /* Un-mark the type as having been visited already */ + search_func_pointer (TREE_TYPE (type), 0); + return funcp; + } + return TRUE; + + default: + break; + } + + return FALSE; +} + + +static int +search_func_pointer (type, mark) + tree type; + int mark; +{ + tree tem; + + if (! type) + return FALSE; + + switch (TREE_CODE (type)) + { + case UNION_TYPE: + case QUAL_UNION_TYPE: + case RECORD_TYPE: + if (TREE_ASM_WRITTEN (type) != mark) + { + /* mark the type as having been visited already */ + TREE_ASM_WRITTEN (type) = mark; + + /* 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) == FIELD_DECL + && search_func_pointer (TREE_TYPE(tem), mark)) return TRUE; + } + } + break; + + case ARRAY_TYPE: + return search_func_pointer (TREE_TYPE(type), mark); + + 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: + return TREE_CODE (TREE_TYPE (type)) == FUNCTION_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) + { + types = BLOCK_VARS(block); + + while (types) + { + /* skip the declaration that refers an external variable and + also skip an global variable */ + if (! DECL_EXTERNAL (types)) + { + home = DECL_RTL (types); + if (home == 0) goto next; + + 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) + && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), "main") == 0 + && 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 + + prologue_insert_point = NEXT_INSN (insn); /* mark the next insn of FUNCTION_BEG insn */ + + start_sequence (); + + _guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard")); + emit_move_insn ( guard_area, _guard); + + _val = gen_sequence (); + end_sequence (); + + emit_insn_before (_val, prologue_insert_point); +} + +static void +rtl_epilogue (insn) + rtx insn; +{ + rtx if_false_label, end_label = 0; + rtx _val, dummyend; + rtx funcname; + tree funcstr; + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)), + return_save = 0; + 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 (return_reg + && ! (current_function_returns_struct + || current_function_returns_pcc_struct) + /* If scalar return value was NOT computed in a pseudo-reg */ + && ! (GET_CODE (return_reg) == REG + && REGNO (return_reg) >= FIRST_PSEUDO_REGISTER)) + { + return_save = GET_CODE (return_reg)==REG? + gen_reg_rtx (GET_MODE (return_reg)):return_reg; + + if (! replace_return_reg (prologue_insert_point, return_save)) + emit_move_insn (return_save, return_reg); + } + + compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, 0, 0); /* if (guard_area != _guard) */ + + if_false_label = gen_label_rtx (); /* { */ + emit_jump_insn ( gen_beq(if_false_label)); + + /* + In the function force_const_mem in varasm.c of egcs-1.1.2-30, there is a + failure to assign the guard_area variable to eax register, which destroys + the return value of the function. + + The BUG preceding comment is an apropriate processes. + When the bug is fixed, removes the comment + */ + + /* 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);/* = char_array_type_node;*/ + funcname = output_constant_def (funcstr); + + 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 (return_reg) + { + if (return_save) + expand_value_return (return_save); + + /* If returning a structure, arrange to return the address of the value + in a place where debuggers expect to find it. + + If returning a structure PCC style, + the caller also depends on this value. + And current_function_returns_pcc_struct is not necessarily set. */ + else if (current_function_returns_struct + || current_function_returns_pcc_struct) + { + rtx value_address = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); + tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); +#ifdef FUNCTION_OUTGOING_VALUE + rtx outgoing + = FUNCTION_OUTGOING_VALUE (build_pointer_type (type), + current_function_decl); +#else + rtx outgoing + = FUNCTION_VALUE (build_pointer_type (type), + current_function_decl); +#endif + + /* Mark this as a function return value so integrate will delete the + assignment and USE below when inlining this function. */ + REG_FUNCTION_VALUE_P (outgoing) = 1; + + emit_move_insn (outgoing, value_address); + use_variable (outgoing); + } + + else if (GET_CODE (return_reg) == REG + && REGNO (return_reg) >= FIRST_PSEUDO_REGISTER) { + /* If scalar return value was computed in a pseudo-reg, + copy that to the hard return register. */ + emit_move_insn (current_function_return_rtx, return_reg); + emit_insn (gen_rtx_USE (VOIDmode, current_function_return_rtx)); + } + + end_label = gen_label_rtx (); + emit_jump (end_label); + } + + /* Mark the end of the function body. + If control reaches this insn, the function can drop through + without returning a value. */ + dummyend = emit_note (SSP_DUMMY_FILE, NOTE_INSN_FUNCTION_END); + + if (end_label) + emit_label (end_label); + +#ifdef HAVE_return + if (HAVE_return && flag_have_return) + { + emit_jump_insn (gen_return ()); + emit_barrier (); + } +#endif + + _val = gen_sequence (); + end_sequence (); + + emit_insn_after (_val, insn); + + /* mark NOTE_FUNCTION_END as deleted not to be eliminated. */ + INSN_DELETED_P (dummyend) = 1; +} + + +static void +arrange_var_order (block) + tree block; +{ + tree types; + HOST_WIDE_INT offset; + + while (block) + { + /* arrange the location of character arrays in depth first. */ + arrange_var_order (BLOCK_SUBBLOCKS (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 (types) + && GET_CODE (DECL_RTL (types)) == MEM + && GET_MODE (DECL_RTL (types)) == BLKmode) + { + is_array = 0; + if (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); + + /* confirmed it is 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); + } + + block = BLOCK_CHAIN (block); + } +} + + +static void +copy_args_for_protection (void) +{ + tree parms = DECL_ARGUMENTS (current_function_decl); + rtx temp_rtx; + int idx; + + parms = DECL_ARGUMENTS (current_function_decl); + for (idx = 0; 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); + + start_sequence (); + + if (GET_CODE (DECL_RTL (parms)) == REG) + { + rtx movinsn; + rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms))); + + /* generate codes for copying the content */ + movinsn = emit_move_insn (safe, DECL_RTL (parms)); + PATTERN (movinsn)->volatil = 1; /* avoid register elimination in gcse.c (COPY-PROP)*/ + + change_arg_use_of_insns (prologue_insert_point, DECL_RTL (parms), safe, 0); + + /* 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)); + PATTERN (movinsn)->volatil = 1; /* avoid register elimination in gcse.c (COPY-PROP)*/ + + /* 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; + } + + else + { + /* declare temporary local variable DECL_NAME (parms) for it */ + 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)); + 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 */ + 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 */ + DECL_RTL (parms) = temp_rtx; + + /* change debugger info */ + DECL_INCOMING_RTL (parms) = temp_rtx; + } + + emit_insn_before (gen_sequence (), 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) + { + 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)) { + + home = DECL_RTL (types); + if (home == 0) goto next; + + /* 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, so 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, so 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); + } +} + + +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, so 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_insns_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 + /* + special 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: + sweep_string_use_of_insns (XEXP (x, 0), sweep_offset, sweep_size); + sweep_string_use_of_insns (XEXP (x, 1), sweep_offset, sweep_size); + sweep_string_use_of_insns (XEXP (x, 2), sweep_offset, sweep_size); + 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; +{ + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + change_arg_use_in_operand (PATTERN (insn), orig, new, size); + } +} + + +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 /* skip if orig is register variable in the optimization */ + && 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) = plus_constant (virtual_stack_vars_rtx, offset); + XEXP (x, 1)->used = 1; + + return; + } + } + break; + + case CALL_PLACEHOLDER: + change_arg_use_of_insns (XEXP (x, 0), orig, new, size); + change_arg_use_of_insns (XEXP (x, 1), orig, new, size); + change_arg_use_of_insns (XEXP (x, 2), orig, new, size); + 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) + { + 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) + { + XVECEXP (x, i, j) = new; + continue; + } + change_arg_use_in_operand (XVECEXP (x, i, j), orig, new, size); + } +} + +static int +replace_return_reg (first, return_save) + rtx first, return_save; +{ + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)); + rtx insn; + + /* comfirm that insn patterns are the expected order */ + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + + rtx prev; + + if (PREV_INSN (insn)) prev = PREV_INSN (insn); + + if (GET_CODE (PATTERN (insn)) == USE && XEXP (PATTERN (insn), 0) == return_reg) + if (!(prev && GET_CODE (PATTERN (prev)) == SET && XEXP (PATTERN (prev), 0) == return_reg)) + return FALSE; + } + } + + /* replace return register */ + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + rtx prev; + + if (PREV_INSN (insn)) prev = PREV_INSN (insn); + if (GET_CODE (PATTERN (insn)) == USE + && XEXP (PATTERN (insn), 0) == return_reg + && prev + && GET_CODE (PATTERN (prev)) == SET + && XEXP (PATTERN (prev), 0) == return_reg) + { + XEXP (PATTERN (prev), 0) = return_save; + + /* change use insn to NOTE_INSN_DELETED */ + PUT_CODE (insn, NOTE); + NOTE_SOURCE_FILE (insn) = 0; + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + } + } + } + + return TRUE; +} + + +/* + Generate RTL to return from the current function, with value VAL. + It is copied and modified based on expand_value_return function of stmt.c +*/ + +static void +expand_value_return (val) + rtx val; +{ + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)); + + /* Copy the value to the return location + unless it's already there. */ + + if (return_reg != val) + { +#ifdef PROMOTE_FUNCTION_RETURN + tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); + int unsignedp = TREE_UNSIGNED (type); + enum machine_mode mode + = promote_mode (type, DECL_MODE (DECL_RESULT (current_function_decl)), + &unsignedp, 1); + + if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) + convert_move (return_reg, val, unsignedp); + else +#endif + emit_move_insn (return_reg, val); + } + if (GET_CODE (return_reg) == REG + && REGNO (return_reg) < FIRST_PSEUDO_REGISTER) + emit_insn (gen_rtx_USE (VOIDmode, return_reg)); + /* Handle calls that return values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + else if (GET_CODE (return_reg) == PARALLEL) + { + int i; + + for (i = 0; i < XVECLEN (return_reg, 0); i++) + { + rtx x = XEXP (XVECEXP (return_reg, 0, i), 0); + + if (GET_CODE (x) == REG + && REGNO (x) < FIRST_PSEUDO_REGISTER) + emit_insn (gen_rtx_USE (VOIDmode, x)); + } + } +} + + +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 (); + /* temp = force_operand (x, NULL_RTX); */ + { /* 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_operand_mode[icode][2]; + 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_operand_predicate[icode][2]) (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_insns_before (seq, insn); + if (! validate_change (insn, loc, temp, 0)) + abort (); + return; + } + break; + + + case CALL_PLACEHOLDER: + validate_insns_of_varrefs (XEXP (x, 0)); + validate_insns_of_varrefs (XEXP (x, 1)); + validate_insns_of_varrefs (XEXP (x, 2)); + 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)); +} + + + + +/* + 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 || TREE_CODE (blocks) != BLOCK + || 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) + { + 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)) + { + + home = DECL_RTL (types); + if (home == 0) goto next; + + /* 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 *) alloca (max_reg_num () * sizeof (int)); + bzero ((char *) fp_equiv, 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) + { + insn_pushed = FALSE; debuginsn = insn; + push_frame_in_operand (insn, PATTERN (insn), push_size, boundary); + + if (insn_pushed) + { + rtx trial = insn; + rtx before = PREV_INSN (trial); + rtx after = NEXT_INSN (trial); + int has_barrier = 0; + rtx tem; + rtx seq = split_insns (PATTERN (insn), insn); + + /* If we are splitting a JUMP_INSN, it might be followed by a + BARRIER. We may need to handle this specially. */ + if (after && GET_CODE (after) == BARRIER) + { + has_barrier = 1; + after = NEXT_INSN (after); + } + + if (seq && GET_CODE (seq) == SEQUENCE) + { + if (XVECLEN (seq, 0) == 2) + { + rtx pattern = PATTERN (XVECEXP (seq, 0, 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); + + /* replace the pattern of the insn */ + add_insn_after (XVECEXP (seq, 0, 0), before); + delete_insn (trial); + goto next; + } + } + + /* excerpt from emit-rtl.c: L3320 */ + tem = emit_insn_after (seq, trial); + + delete_insn (trial); + if (has_barrier) + emit_barrier_after (tem); + + /* Recursively call try_split for each new insn created */ + for (tem = NEXT_INSN (before); tem != after; + tem = NEXT_INSN (tem)) + if (! INSN_DELETED_P (tem) + && GET_RTX_CLASS (GET_CODE(tem)) == 'i') + tem = try_split (PATTERN (tem), tem, 1); + } + } + + next: + /* 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); + } +} + + +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 -Naur gcc-2.95.3.orig/gcc/protector.h gcc-2.95.3.ssp/gcc/protector.h --- gcc-2.95.3.orig/gcc/protector.h 1970-01-01 00:00:00.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/protector.h 2004-09-03 05:24:37.000000000 +0000 @@ -0,0 +1,49 @@ +/* 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 GNU CC. + +GNU CC 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. + +GNU CC 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 GNU CC; 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)) +#define SSP_DUMMY_FILE "_ssp_" + +#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)); + +/* 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 -Naur gcc-2.95.3.orig/gcc/reload1.c gcc-2.95.3.ssp/gcc/reload1.c --- gcc-2.95.3.orig/gcc/reload1.c 2001-01-25 14:03:21.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/reload1.c 2004-10-29 00:22:37.201631864 +0000 @@ -39,6 +39,7 @@ #include "output.h" #include "real.h" #include "toplev.h" +#include "protector.h" #if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY #define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY @@ -2424,7 +2425,7 @@ 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 -Naur gcc-2.95.3.orig/gcc/toplev.c gcc-2.95.3.ssp/gcc/toplev.c --- gcc-2.95.3.orig/gcc/toplev.c 2001-01-25 14:03:23.000000000 +0000 +++ gcc-2.95.3.ssp/gcc/toplev.c 2004-10-29 00:22:37.214629888 +0000 @@ -772,6 +772,15 @@ int flag_no_ident = 0; +#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 struct { @@ -979,7 +988,11 @@ {"leading-underscore", &flag_leading_underscore, 1, "External symbols have a leading underscore" }, {"ident", &flag_no_ident, 0, - "Process #ident directives"} + "Process #ident directives"}, + {"stack-protector", &flag_propolice_protection, 1, + "Enables stack protection" }, + {"stack-protector-all", &flag_stack_protection, 1, + "Enables stack protection of every function" }, }; #define NUM_ELEM(a) (sizeof (a) / sizeof ((a)[0])) @@ -1258,7 +1271,9 @@ {"uninitialized", &warn_uninitialized, 1, "Warn about unitialized automatic variables"}, {"inline", &warn_inline, 1, - "Warn when an inlined function cannot be inlined"} + "Warn when an inlined function cannot be inlined"}, + {"stack-protector", &warn_stack_protector, 1, + "Warn when disabling stack protector for some reason"} }; /* Output files for assembler code (real compiler output) @@ -3608,6 +3623,10 @@ int failure = 0; int rebuild_label_notes_after_reload; + /* When processing delayed functions, init_function_start() won't + have been run to re-initialize it. */ + cse_not_expected = ! optimize; + /* If we are reconsidering an inline function at the end of compilation, skip the stuff for making it inline. */ @@ -3645,6 +3664,8 @@ insns = get_insns (); + if (flag_propolice_protection) prepare_stack_protection (inlinable); + /* Dump the rtl code if we are dumping rtl. */ if (rtl_dump) @@ -5447,6 +5468,13 @@ print_switch_values (stderr, 0, MAX_LINE, "", " ", "\n"); } + + /* 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; + compile_file (filename); #if !defined(OS2) && !defined(VMS) && (!defined(_WIN32) || defined (__CYGWIN__)) && !defined(__INTERIX)