diff -uNr gcc-3.4.3.orig/gcc/calls.c gcc-3.4.3/gcc/calls.c --- gcc-3.4.3.orig/gcc/calls.c 2004-06-24 09:26:50.000000000 +0200 +++ gcc-3.4.3/gcc/calls.c 2004-11-24 18:35:31.000000000 +0100 @@ -2321,8 +2321,12 @@ { /* For variable-sized objects, we must be called with a target specified. If we were to allocate space on the stack here, - we would have no way of knowing when to free it. */ - rtx d = assign_temp (TREE_TYPE (exp), 1, 1, 1); + we would have no way of knowing when to free it. + + This is the structure of a function return object and it isn't + a character array for the stack protection, so it is + marked using the assignment of the KEEP argument to 5. */ + rtx d = assign_temp (TREE_TYPE (exp), 5, 1, 1); mark_temp_addr_taken (d); structure_value_addr = XEXP (d, 0); diff -uNr gcc-3.4.3.orig/gcc/c-cppbuiltin.c gcc-3.4.3/gcc/c-cppbuiltin.c --- gcc-3.4.3.orig/gcc/c-cppbuiltin.c 2004-03-04 11:24:54.000000000 +0100 +++ gcc-3.4.3/gcc/c-cppbuiltin.c 2004-11-24 18:35:31.000000000 +0100 @@ -408,6 +408,12 @@ if (c_dialect_objc () && flag_next_runtime) cpp_define (pfile, "__NEXT_RUNTIME__"); + /* Make the choice of the stack protector runtime visible to source code. */ + if (flag_propolice_protection) + cpp_define (pfile, "__SSP__=1"); + if (flag_stack_protection) + cpp_define (pfile, "__SSP_ALL__=2"); + /* A straightforward target hook doesn't work, because of problems linking that hook's body when part of non-C front ends. */ # define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM) diff -uNr gcc-3.4.3.orig/gcc/combine.c gcc-3.4.3/gcc/combine.c --- gcc-3.4.3.orig/gcc/combine.c 2004-10-13 01:35:29.000000000 +0200 +++ gcc-3.4.3/gcc/combine.c 2004-11-24 18:35:31.000000000 +0100 @@ -1401,6 +1401,10 @@ && ! fixed_regs[REGNO (dest)] && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (dest)))))) return 1; + /* Never combine loads and stores protecting argument that use set insn + with used flag on. */ + if (SET_VOLATILE_P (set)) + return 1; return 0; } @@ -3781,7 +3785,20 @@ rtx inner_op0 = XEXP (XEXP (x, 0), 1); rtx inner_op1 = XEXP (x, 1); rtx inner; - + +#ifndef FRAME_GROWS_DOWNWARD + /* For the case where the frame grows upward, + the stack protector keeps the offset of the frame pointer + positive integer. */ + 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') @@ -4146,6 +4163,13 @@ they are now checked elsewhere. */ if (GET_CODE (XEXP (x, 0)) == PLUS && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1))) +#ifndef FRAME_GROWS_DOWNWARD + /* The stack protector keeps the addressing style of a local variable + to be able to change its stack position. */ + 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)), @@ -4273,8 +4297,14 @@ } /* 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)) + integers. + + The stack protector keeps the addressing style of + a local variable. */ + 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 -uNr gcc-3.4.3.orig/gcc/common.opt gcc-3.4.3/gcc/common.opt --- gcc-3.4.3.orig/gcc/common.opt 2004-11-24 18:04:19.000000000 +0100 +++ gcc-3.4.3/gcc/common.opt 2004-11-24 18:35:31.000000000 +0100 @@ -152,6 +152,10 @@ Common Warn when a variable is unused +Wstack-protector +Common +Warn when not issuing stack smashing protection for some reason + aux-info Common Separate -aux-info Emit declaration information into @@ -743,6 +747,14 @@ Common Put zero initialized data in the bss section +fstack-protector +Common +Enables stack protection + +fstack-protector-all +Common +Enables stack protection of every function + g Common JoinedOrMissing Generate debug information in default format diff -uNr gcc-3.4.3.orig/gcc/config/arm/arm.md gcc-3.4.3/gcc/config/arm/arm.md --- gcc-3.4.3.orig/gcc/config/arm/arm.md 2004-08-25 17:46:19.000000000 +0200 +++ gcc-3.4.3/gcc/config/arm/arm.md 2004-11-24 18:35:31.000000000 +0100 @@ -3840,7 +3840,13 @@ (match_operand:DI 1 "general_operand" ""))] "TARGET_EITHER" " - if (TARGET_THUMB) + if (TARGET_ARM) + { + /* Everything except mem = const or mem = mem can be done easily */ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DImode, operands[1]); + } + else /* TARGET_THUMB.... */ { if (!no_new_pseudos) { diff -uNr gcc-3.4.3.orig/gcc/config/t-linux gcc-3.4.3/gcc/config/t-linux --- gcc-3.4.3.orig/gcc/config/t-linux 2003-09-23 20:55:57.000000000 +0200 +++ gcc-3.4.3/gcc/config/t-linux 2004-11-24 18:35:31.000000000 +0100 @@ -1,7 +1,7 @@ # Compile crtbeginS.o and crtendS.o with pic. CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC # Compile libgcc2.a with pic. -TARGET_LIBGCC2_CFLAGS = -fPIC +TARGET_LIBGCC2_CFLAGS = -fPIC -DHAVE_SYSLOG # Override t-slibgcc-elf-ver to export some libgcc symbols with # the symbol versions that glibc used. diff -uNr gcc-3.4.3.orig/gcc/configure gcc-3.4.3/gcc/configure --- gcc-3.4.3.orig/gcc/configure 2004-11-05 05:14:05.000000000 +0100 +++ gcc-3.4.3/gcc/configure 2004-11-24 18:44:13.000000000 +0100 @@ -4809,6 +4809,9 @@ fi; +ENABLESSP="" + + # ------------------------- # Checks for other programs # ------------------------- @@ -13036,6 +13039,7 @@ s,@TARGET_SYSTEM_ROOT_DEFINE@,$TARGET_SYSTEM_ROOT_DEFINE,;t t s,@CROSS_SYSTEM_HEADER_DIR@,$CROSS_SYSTEM_HEADER_DIR,;t t s,@onestep@,$onestep,;t t +s,@ENABLESSP@,$ENABLESSP,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@AWK@,$AWK,;t t s,@LN@,$LN,;t t diff -uNr gcc-3.4.3.orig/gcc/configure.ac gcc-3.4.3/gcc/configure.ac --- gcc-3.4.3.orig/gcc/configure.ac 2004-11-24 18:04:19.000000000 +0100 +++ gcc-3.4.3/gcc/configure.ac 2004-11-24 18:46:57.000000000 +0100 @@ -613,6 +613,9 @@ [onestep=""]) AC_SUBST(onestep) +ENABLESSP="" +AC_SUBST(ENABLESSP) + # ------------------------- # Checks for other programs # ------------------------- diff -uNr gcc-3.4.3.orig/gcc/cse.c gcc-3.4.3/gcc/cse.c --- gcc-3.4.3.orig/gcc/cse.c 2004-10-26 20:05:42.000000000 +0200 +++ gcc-3.4.3/gcc/cse.c 2004-11-24 18:35:31.000000000 +0100 @@ -4212,7 +4212,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 @@ -4744,6 +4751,14 @@ if (SET_DEST (x) == pc_rtx && GET_CODE (SET_SRC (x)) == LABEL_REF) ; + /* cut the reg propagation of stack-protected argument. */ + else if (SET_VOLATILE_P (x)) { + rtx x1 = SET_DEST (x); + if (GET_CODE (x1) == SUBREG && GET_CODE (SUBREG_REG (x1)) == REG) + x1 = SUBREG_REG (x1); + if (! REGNO_QTY_VALID_P(REGNO (x1))) + make_new_qty (REGNO (x1), GET_MODE (x1)); + } /* Don't count call-insns, (set (reg 0) (call ...)), as a set. The hard function value register is used only once, to copy to diff -uNr gcc-3.4.3.orig/gcc/doc/invoke.texi gcc-3.4.3/gcc/doc/invoke.texi --- gcc-3.4.3.orig/gcc/doc/invoke.texi 2004-11-24 18:04:19.000000000 +0100 +++ gcc-3.4.3/gcc/doc/invoke.texi 2004-11-24 18:35:32.000000000 +0100 @@ -228,7 +228,7 @@ -Wno-multichar -Wnonnull -Wpacked -Wpadded @gol -Wparentheses -Wpointer-arith -Wredundant-decls @gol -Wreturn-type -Wsequence-point -Wshadow @gol --Wsign-compare -Wstrict-aliasing @gol +-Wsign-compare -Wstack-protector -Wstrict-aliasing @gol -Wswitch -Wswitch-default -Wswitch-enum @gol -Wsystem-headers -Wtrigraphs -Wundef -Wuninitialized @gol -Wunknown-pragmas -Wunreachable-code @gol @@ -673,6 +673,7 @@ -fshort-double -fshort-wchar @gol -fverbose-asm -fpack-struct -fstack-check @gol -fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol +-fstack-protector -fstack-protector-all @gol -fargument-alias -fargument-noalias @gol -fargument-noalias-global -fleading-underscore @gol -ftls-model=@var{model} @gol @@ -3006,6 +3007,10 @@ complex; GCC will refuse to optimize programs when the optimization itself is likely to take inordinate amounts of time. +@item -Wstack-protector +@opindex Wstack-protector +Warn when not issuing stack smashing protection for some reason. + @item -Werror @opindex Werror Make all warnings into errors. @@ -11202,6 +11207,24 @@ @option{-Wl,--defsym,__stack_limit=0x7ffe0000} to enforce a stack limit of 128KB@. Note that this may only work with the GNU linker. +@item -fstack-protector +@item -fstack-protector-all +@opindex fstack-protector +@opindex fstack-protector-all +@opindex fno-stack-protector +Generate code to protect an application from a stack smashing +attack. The features are (1) the insertion of random value next to the +frame pointer to detect the integrity of the stack, (2) the reordering +of local variables to place buffers after pointers to avoid the +corruption of pointers that could be used to further corrupt arbitrary +memory locations, (3) the copying of pointers in function arguments to +an area preceding local variable buffers to prevent the corruption of +pointers that could be used to further corrupt arbitrary memory +locations, and the (4) omission of instrumentation code from some +functions to decrease the performance overhead. If the integrity +would be broken, the program is aborted. If stack-protector-all is +specified, instrumentation codes are generated at every functions. + @cindex aliasing of parameters @cindex parameters, aliased @item -fargument-alias diff -uNr gcc-3.4.3.orig/gcc/explow.c gcc-3.4.3/gcc/explow.c --- gcc-3.4.3.orig/gcc/explow.c 2004-04-03 01:05:26.000000000 +0200 +++ gcc-3.4.3/gcc/explow.c 2004-11-24 18:35:31.000000000 +0100 @@ -84,7 +84,8 @@ rtx tem; int all_constant = 0; - if (c == 0) + if (c == 0 + && ! (flag_propolice_protection && x == virtual_stack_vars_rtx)) return x; restart: @@ -185,7 +186,10 @@ break; } - if (c != 0) + /* For the use of stack protection, keep the frame and offset pattern + even if the offset is zero. */ + 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) @@ -474,6 +478,26 @@ if (memory_address_p (mode, oldx)) goto win2; + /* The stack protector keeps the addressing style of a local variable. + LEGITIMIZE_ADDRESS changes the addressing to the machine-dependent + style, so the protector split the frame address to a register using + force_reg. */ + 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)); + } + } /* Perform machine-dependent transformations on X in certain cases. This is not necessary since the code below can handle all possible cases, but machine-dependent diff -uNr gcc-3.4.3.orig/gcc/expr.c gcc-3.4.3/gcc/expr.c --- gcc-3.4.3.orig/gcc/expr.c 2004-05-27 21:35:17.000000000 +0200 +++ gcc-3.4.3/gcc/expr.c 2004-11-24 18:35:31.000000000 +0100 @@ -48,6 +48,7 @@ #include "intl.h" #include "tm_p.h" #include "target.h" +#include "protector.h" /* Decide whether a function's arguments should be processed from first to last or from last to first. @@ -1060,7 +1061,11 @@ If ENDP is 0 return to, if ENDP is 1 return memory at the end ala mempcpy, and if ENDP is 2 return memory the end minus one byte ala - stpcpy. */ + stpcpy. + + When the stack protector is used at the reverse move, it starts the move + instruction from the address within the region of a variable. + So it eliminates the first address decrement instruction. */ rtx move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, @@ -1123,6 +1128,8 @@ if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from) { + if (flag_propolice_protection) + len = len - GET_MODE_SIZE (mode); data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len)); data.autinc_from = 1; data.explicit_inc_from = -1; @@ -1137,6 +1144,8 @@ data.from_addr = copy_addr_to_reg (from_addr); if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to) { + if (flag_propolice_protection) + len = len - GET_MODE_SIZE (mode); data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); data.autinc_to = 1; data.explicit_inc_to = -1; @@ -1280,11 +1289,15 @@ from1 = adjust_address (data->from, mode, data->offset); if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0) - emit_insn (gen_add2_insn (data->to_addr, - GEN_INT (-(HOST_WIDE_INT)size))); + /* The stack protector skips the first address decrement instruction + at the reverse move. */ + if (!flag_propolice_protection || data->explicit_inc_to < -1) + emit_insn (gen_add2_insn (data->to_addr, + GEN_INT (-(HOST_WIDE_INT)size))); if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0) - emit_insn (gen_add2_insn (data->from_addr, - GEN_INT (-(HOST_WIDE_INT)size))); + if (!flag_propolice_protection || data->explicit_inc_from < -1) + emit_insn (gen_add2_insn (data->from_addr, + GEN_INT (-(HOST_WIDE_INT)size))); if (data->to) emit_insn ((*genfun) (to1, from1)); @@ -2475,7 +2488,12 @@ if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to) { - data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len)); + int len = data->len; + /* The stack protector starts the store instruction from + the address within the region of a variable. */ + if (flag_propolice_protection) + len -= GET_MODE_SIZE (mode); + data->to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); data->autinc_to = 1; data->explicit_inc_to = -1; } @@ -2544,8 +2562,11 @@ to1 = adjust_address (data->to, mode, data->offset); if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0) - emit_insn (gen_add2_insn (data->to_addr, - GEN_INT (-(HOST_WIDE_INT) size))); + /* The stack protector skips the first address decrement instruction + at the reverse store. */ + if (!flag_propolice_protection || data->explicit_inc_to < -1) + emit_insn (gen_add2_insn (data->to_addr, + GEN_INT (-(HOST_WIDE_INT) size))); cst = (*data->constfun) (data->constfundata, data->offset, mode); emit_insn ((*genfun) (to1, cst)); @@ -5701,7 +5722,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_simple_binop (GET_MODE (value), code, XEXP (XEXP (value, 0), 0), op2, diff -uNr gcc-3.4.3.orig/gcc/flags.h gcc-3.4.3/gcc/flags.h --- gcc-3.4.3.orig/gcc/flags.h 2004-11-24 18:04:19.000000000 +0100 +++ gcc-3.4.3/gcc/flags.h 2004-11-24 18:35:31.492689688 +0100 @@ -210,6 +210,10 @@ extern bool warn_strict_aliasing; +/* Warn when not issuing stack smashing protection for some reason. */ + +extern bool warn_stack_protector; + /* Nonzero if generating code to do profiling. */ extern int profile_flag; @@ -795,4 +799,12 @@ #define HONOR_SIGN_DEPENDENT_ROUNDING(MODE) \ (MODE_HAS_SIGN_DEPENDENT_ROUNDING (MODE) && flag_rounding_math) +/* Nonzero means use propolice as a stack protection method. */ + +extern int flag_propolice_protection; + +/* Nonzero means use a stack protection method for every function. */ + +extern int flag_stack_protection; + #endif /* ! GCC_FLAGS_H */ diff -uNr gcc-3.4.3.orig/gcc/function.c gcc-3.4.3/gcc/function.c --- gcc-3.4.3.orig/gcc/function.c 2004-10-14 01:18:13.000000000 +0200 +++ gcc-3.4.3/gcc/function.c 2004-11-24 18:35:31.542682088 +0100 @@ -63,6 +63,7 @@ #include "integrate.h" #include "langhooks.h" #include "target.h" +#include "protector.h" #ifndef TRAMPOLINE_ALIGNMENT #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY @@ -155,6 +156,10 @@ /* Array of INSN_UIDs to hold the INSN_UIDs for each sibcall epilogue in this function. */ static GTY(()) varray_type sibcall_epilogue; + +/* Current boundary mark for character arrays. */ +static int temp_boundary_mark = 0; + /* In order to evaluate some expressions, such as function calls returning structures in memory, we need to temporarily allocate stack locations. @@ -208,6 +213,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; }; /* This structure is used to record MEMs or pseudos used to replace VAR, any @@ -638,6 +645,7 @@ whose lifetime is controlled by CLEANUP_POINT_EXPRs. KEEP is 3 if we are to allocate something at an inner level to be treated as a variable in the block (e.g., a SAVE_EXPR). + KEEP is 5 if we allocate a place to return structure. TYPE is the type that will be used for the stack slot. */ @@ -648,6 +656,8 @@ unsigned int align; struct temp_slot *p, *best_p = 0; rtx slot; + int char_array = (flag_propolice_protection + && keep == 1 && search_string_def (type)); /* If SIZE is -1 it means that somebody tried to allocate a temporary of a variable size. */ @@ -673,7 +683,8 @@ && ! p->in_use && objects_must_conflict_p (p->type, type) && (best_p == 0 || best_p->size > p->size - || (best_p->size == p->size && best_p->align > p->align))) + || (best_p->size == p->size && best_p->align > p->align)) + && (! char_array || p->boundary_mark != 0)) { if (p->align == align && p->size == size) { @@ -708,6 +719,7 @@ p->address = 0; p->rtl_expr = 0; p->type = best_p->type; + p->boundary_mark = best_p->boundary_mark; p->next = temp_slots; temp_slots = p; @@ -768,6 +780,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; } @@ -932,14 +945,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; @@ -1449,7 +1464,9 @@ } if (new == 0) - new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func); + new = function ? + assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func) + : assign_stack_local_for_pseudo_reg (decl_mode, GET_MODE_SIZE (decl_mode), 0); PUT_CODE (reg, MEM); PUT_MODE (reg, decl_mode); @@ -3937,10 +3954,13 @@ } /* Otherwise copy the new constant into a register and replace - constant with that register. */ + constant with that register. + At the use of stack protection, stop to replace the frame + offset with a 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 -uNr gcc-3.4.3.orig/gcc/gcse.c gcc-3.4.3/gcc/gcse.c --- gcc-3.4.3.orig/gcc/gcse.c 2004-10-30 20:02:53.000000000 +0200 +++ gcc-3.4.3/gcc/gcse.c 2004-11-24 18:35:31.583675856 +0100 @@ -4176,9 +4176,13 @@ continue; /* Find an assignment that sets reg_used and is available - at the start of the block. */ + at the start of the block. + + Skip the copy propagation not to eliminate the register that is + the duplicated pointer of a function argument. It is used for + the function argument protection. */ set = find_avail_set (regno, insn); - if (! set) + if (! set || SET_VOLATILE_P (set->expr)) continue; pat = set->expr; diff -uNr gcc-3.4.3.orig/gcc/integrate.c gcc-3.4.3/gcc/integrate.c --- gcc-3.4.3.orig/gcc/integrate.c 2004-01-24 00:36:00.000000000 +0100 +++ gcc-3.4.3/gcc/integrate.c 2004-11-24 18:35:31.603672816 +0100 @@ -393,6 +393,11 @@ /* These args would always appear unused, if not for this. */ TREE_USED (copy) = 1; + /* The inlined variable is marked as INLINE not to change the location + by stack protector. */ + if (flag_propolice_protection && TREE_CODE (copy) == VAR_DECL) + DECL_COPIED (copy) = 1; + /* Set the context for the new declaration. */ if (!DECL_CONTEXT (decl)) /* Globals stay global. */ @@ -1970,6 +1975,12 @@ seq = get_insns (); end_sequence (); +#ifdef ARGS_GROWS_DOWNWARD + /* Mark this pointer as the top of the argument + block. The pointer minus one is in the block. */ + 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 -uNr gcc-3.4.3.orig/gcc/libgcc2.c gcc-3.4.3/gcc/libgcc2.c --- gcc-3.4.3.orig/gcc/libgcc2.c 2004-09-26 22:47:14.000000000 +0200 +++ gcc-3.4.3/gcc/libgcc2.c 2004-11-24 18:35:31.627669168 +0100 @@ -1678,3 +1678,124 @@ #endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */ #endif /* L_ctors */ + +#ifdef L_stack_smash_handler +#ifndef _LIBC_PROVIDES_SSP_ +#include +#include +#include +#include + +#ifdef _POSIX_SOURCE +#include +#endif + +#if defined(HAVE_SYSLOG) +#include +#include +#include + +#include +#ifndef _PATH_LOG +#define _PATH_LOG "/dev/log" +#endif +#endif + +long __guard[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +static void __guard_setup (void) __attribute__ ((constructor)); + +static void +__guard_setup (void) +{ + int fd; + if (__guard[0] != 0) + return; + fd = open ("/dev/urandom", 0); + if (fd != -1) { + ssize_t size = read (fd, (char*)&__guard, sizeof(__guard)); + close (fd) ; + if (size == sizeof(__guard)) + return; + } + /* If a random generator can't be used, the protector switches the guard + to the "terminator canary". */ + ((char*)__guard)[0] = 0; + ((char*)__guard)[1] = 0; + ((char*)__guard)[2] = '\n'; + ((char*)__guard)[3] = 255; +} + +extern void __stack_smash_handler (char func[], ATTRIBUTE_UNUSED int damaged); +void +__stack_smash_handler (char func[], ATTRIBUTE_UNUSED int damaged) +{ +#if defined (__GNU_LIBRARY__) + extern char * __progname; +#endif + const char message[] = ": stack smashing attack in function "; + int bufsz = 256, len; + char buf[bufsz]; +#if defined(HAVE_SYSLOG) + int log_file; + struct sockaddr_un sys_log_addr; /* AF_UNIX address of local logger. */ +#endif +#ifdef _POSIX_SOURCE + { + sigset_t mask; + sigfillset (&mask); + /* Block all signal handlers except SIGABRT. */ + sigdelset (&mask, SIGABRT); + sigprocmask (SIG_BLOCK, &mask, NULL); + } +#endif + + /* send LOG_CRIT. */ + strcpy (buf, "<2>"); len=3; +#if defined (__GNU_LIBRARY__) + strncat (buf, __progname, bufsz - len - 1); + len = strlen (buf); +#endif + if (bufsz > len) + { + strncat (buf, message, bufsz - len - 1); + len = strlen (buf); + } + if (bufsz > len) + { + strncat (buf, func, bufsz - len - 1); + len = strlen (buf); + } + + /* Print error message. */ + write (STDERR_FILENO, buf + 3, len - 3); +#if defined(HAVE_SYSLOG) + if ((log_file = socket (AF_UNIX, SOCK_DGRAM, 0)) != -1) + { + + /* Send "found" message to the "/dev/log" path. */ + sys_log_addr.sun_family = AF_UNIX; + (void)strncpy (sys_log_addr.sun_path, _PATH_LOG, + sizeof (sys_log_addr.sun_path) - 1); + sys_log_addr.sun_path[sizeof (sys_log_addr.sun_path) - 1] = '\0'; + sendto(log_file, buf, len, 0, (struct sockaddr *)&sys_log_addr, + sizeof (sys_log_addr)); + } +#endif + +#ifdef _POSIX_SOURCE + { + /* Make sure the default handler is associated with SIGABRT. */ + struct sigaction sa; + + memset (&sa, 0, sizeof(struct sigaction)); + sigfillset (&sa.sa_mask); /* Block all signals. */ + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigaction (SIGABRT, &sa, NULL); + (void)kill (getpid(), SIGABRT); + } +#endif + _exit (127); +} +#endif /* _LIBC_PROVIDES_SSP_ */ +#endif /* L_stack_smash_handler */ diff -uNr gcc-3.4.3.orig/gcc/libgcc-std.ver gcc-3.4.3/gcc/libgcc-std.ver --- gcc-3.4.3.orig/gcc/libgcc-std.ver 2004-09-01 21:14:33.000000000 +0200 +++ gcc-3.4.3/gcc/libgcc-std.ver 2004-11-24 18:35:31.620670232 +0100 @@ -174,6 +174,12 @@ _Unwind_SjLj_RaiseException _Unwind_SjLj_ForcedUnwind _Unwind_SjLj_Resume + +%if !defined(_LIBC_PROVIDES_SSP_) + # stack smash handler symbols + __guard + __stack_smash_handler +%endif } %inherit GCC_3.3 GCC_3.0 diff -uNr gcc-3.4.3.orig/gcc/loop.c gcc-3.4.3/gcc/loop.c --- gcc-3.4.3.orig/gcc/loop.c 2004-07-13 17:29:08.000000000 +0200 +++ gcc-3.4.3/gcc/loop.c 2004-11-24 18:35:31.680661112 +0100 @@ -6514,6 +6514,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) *pbenefit += address_cost (orig_x, addr_mode) - reg_address_cost; else diff -uNr gcc-3.4.3.orig/gcc/Makefile.in gcc-3.4.3/gcc/Makefile.in --- gcc-3.4.3.orig/gcc/Makefile.in 2004-11-24 18:04:18.000000000 +0100 +++ gcc-3.4.3/gcc/Makefile.in 2004-11-24 18:35:31.038758696 +0100 @@ -867,7 +867,7 @@ sibcall.o simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o \ targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o \ varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \ - et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o + et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o protector.o OBJS-md = $(out_object_file) OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \ @@ -1549,7 +1549,7 @@ langhooks.h insn-flags.h cfglayout.h real.h cfgloop.h \ hosthooks.h $(LANGHOOKS_DEF_H) cgraph.h $(COVERAGE_H) alloc-pool.h $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - -DTARGET_NAME=\"$(target_noncanonical)\" \ + -DTARGET_NAME=\"$(target_noncanonical)\" @ENABLESSP@ \ -c $(srcdir)/toplev.c $(OUTPUT_OPTION) main.o : main.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h @@ -1852,6 +1852,10 @@ params.o : params.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(PARAMS_H) toplev.h hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(HOOKS_H) pretty-print.o: $(CONFIG_H) $(SYSTEM_H) pretty-print.c $(PRETTY_PRINT_H) +protector.o : protector.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ + flags.h function.h $(EXPR_H) $(OPTABS_H) $(REGS_H) toplev.h hard-reg-set.h \ + insn-config.h insn-flags.h $(RECOG_H) output.h toplev.h except.h reload.h \ + $(TM_P_H) conditions.h $(INSN_ATTR_H) real.h protector.h $(out_object_file): $(out_file) $(CONFIG_H) coretypes.h $(TM_H) $(TREE_H) $(GGC_H) \ $(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h conditions.h \ diff -uNr gcc-3.4.3.orig/gcc/mklibgcc.in gcc-3.4.3/gcc/mklibgcc.in --- gcc-3.4.3.orig/gcc/mklibgcc.in 2004-10-18 18:00:43.000000000 +0200 +++ gcc-3.4.3/gcc/mklibgcc.in 2004-11-24 18:35:31.699658224 +0100 @@ -57,7 +57,7 @@ _enable_execute_stack _trampoline __main _absvsi2 _absvdi2 _addvsi3 _addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors _ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab - _popcountsi2 _popcountdi2 _paritysi2 _paritydi2' + _popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _stack_smash_handler' # Disable SHLIB_LINK if shared libgcc not enabled. if [ "@enable_shared@" = "no" ]; then diff -uNr gcc-3.4.3.orig/gcc/optabs.c gcc-3.4.3/gcc/optabs.c --- gcc-3.4.3.orig/gcc/optabs.c 2004-03-03 01:45:01.000000000 +0100 +++ gcc-3.4.3/gcc/optabs.c 2004-11-24 18:35:31.739652144 +0100 @@ -678,6 +678,27 @@ if (target) target = protect_from_queue (target, 1); + /* Keep the frame and offset pattern at the use of stack protection. */ + if (flag_propolice_protection + && binoptab->code == PLUS + && op0 == virtual_stack_vars_rtx + && GET_CODE(op1) == CONST_INT) + { + int icode = (int) binoptab->handlers[(int) mode].insn_code; + if (target) + temp = target; + else + temp = gen_reg_rtx (mode); + + if (! (*insn_data[icode].operand[0].predicate) (temp, mode) + || GET_CODE (temp) != REG) + temp = gen_reg_rtx (mode); + + emit_insn (gen_rtx_SET (VOIDmode, temp, + gen_rtx_PLUS (GET_MODE (op0), op0, op1))); + return temp; + } + if (flag_force_mem) { /* Load duplicate non-volatile operands once. */ diff -uNr gcc-3.4.3.orig/gcc/opts.c gcc-3.4.3/gcc/opts.c --- gcc-3.4.3.orig/gcc/opts.c 2004-11-24 18:04:19.000000000 +0100 +++ gcc-3.4.3/gcc/opts.c 2004-11-24 18:35:31.762648648 +0100 @@ -125,6 +125,9 @@ bool warn_unused_variable; bool warn_unused_value; +/* Warn when not issuing stack smashing protection for some reason */ +bool warn_stack_protector; + /* Hack for cooperation between set_Wunused and set_Wextra. */ static bool maybe_warn_unused_parameter; @@ -804,6 +807,10 @@ warn_unused_variable = value; break; + case OPT_Wstack_protector: + warn_stack_protector = value; + break; + case OPT_aux_info: case OPT_aux_info_: aux_info_file_name = arg; @@ -1367,6 +1374,14 @@ stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (arg)); break; + case OPT_fstack_protector: + flag_propolice_protection = value; + break; + + case OPT_fstack_protector_all: + flag_stack_protection = value; + break; + case OPT_fstrength_reduce: flag_strength_reduce = value; break; diff -uNr gcc-3.4.3.orig/gcc/protector.c gcc-3.4.3/gcc/protector.c --- gcc-3.4.3.orig/gcc/protector.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-3.4.3/gcc/protector.c 2004-09-02 11:36:11.000000000 +0200 @@ -0,0 +1,2730 @@ +/* RTL buffer overflow protection function for GNU C compiler + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* 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. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "machmode.h" +#include "real.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 "except.h" +#include "function.h" +#include "toplev.h" +#include "tm_p.h" +#include "conditions.h" +#include "insn-attr.h" +#include "optabs.h" +#include "reload.h" +#include "protector.h" + + +/* 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 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; + +/* Nonzero if search_string_def finds the variable which contains an array. */ +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; + +/* Offset to end of sweeped area for gathering character arrays. */ +static HOST_WIDE_INT sweep_frame_offset; + +/* Offset to end of allocated area for instantiating pseudo registers. */ +static HOST_WIDE_INT push_allocated_offset = 0; + +/* Offset to end of assigned area for instantiating pseudo registers. */ +static HOST_WIDE_INT push_frame_offset = 0; + +/* Set to 1 after cse_not_expected becomes nonzero. it is used to identify + which stage assign_stack_local_for_pseudo_reg is called from. */ +static int saved_cse_not_expected = 0; + +static int search_string_from_argsandvars (int); +static int search_string_from_local_vars (tree); +static int search_pointer_def (tree); +static int search_func_pointer (tree); +static int check_used_flag (rtx); +static void reset_used_flags_for_insns (rtx); +static void reset_used_flags_for_decls (tree); +static void reset_used_flags_of_plus (rtx); +static void rtl_prologue (rtx); +static void rtl_epilogue (rtx); +static void arrange_var_order (tree); +static void copy_args_for_protection (void); +static void sweep_string_variable (rtx, HOST_WIDE_INT); +static void sweep_string_in_decls (tree, HOST_WIDE_INT, HOST_WIDE_INT); +static void sweep_string_in_args (tree, HOST_WIDE_INT, HOST_WIDE_INT); +static void sweep_string_use_of_insns (rtx, HOST_WIDE_INT, HOST_WIDE_INT); +static void sweep_string_in_operand (rtx, rtx *, HOST_WIDE_INT, HOST_WIDE_INT); +static void move_arg_location (rtx, rtx, rtx, HOST_WIDE_INT); +static void change_arg_use_of_insns (rtx, rtx, rtx *, HOST_WIDE_INT); +static void change_arg_use_in_operand (rtx, rtx, rtx, rtx *, HOST_WIDE_INT); +static void validate_insns_of_varrefs (rtx); +static void validate_operand_of_varrefs (rtx, rtx *); + +/* Specify which size of buffers should be protected from a stack smashing + attack. Because small buffers are not used in situations which may + overflow buffer, the default size sets to the size of 64 bit register. */ +#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 TREE_VISITED(NODE) ((NODE)->common.unused_0) + +/* Argument values for calling search_string_from_argsandvars. */ +#define CALL_FROM_PREPARE_STACK_PROTECTION 0 +#define CALL_FROM_PUSH_FRAME 1 + + +/* Prepare several stack protection instruments for the current function + if the function has an array as a local variable, which may be vulnerable + from a stack smashing attack, and it is not inlinable. + + The overall steps are as follows; + (1)search an array, + (2)insert guard_area on the stack, + (3)duplicate pointer arguments into local variables, and + (4)arrange the location of local variables. */ +void +prepare_stack_protection (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 (CALL_FROM_PREPARE_STACK_PROTECTION); + + if (current_function_defines_vulnerable_string + || flag_stack_protection) + { + 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 (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 arrays for protecting args + may copy to the 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 + } + /* Variable can't be protected from the overflow of variable length + buffer. But variable reordering is still effective against + the overflow of fixed size character arrays. */ + 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 part 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: CALL_FROM_PREPARE_STACK_PROTECTION (0) + CALL_FROM_PUSH_FRAME (1) +*/ +static int +search_string_from_argsandvars (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 == CALL_FROM_PUSH_FRAME) + 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)) + { + string_p = search_string_def (TREE_TYPE(parms)); + if (string_p) + return TRUE; + } + } +#endif + + __latest_search_result = FALSE; + return FALSE; +} + + +/* Search string from local variables in the specified scope. */ +static int +search_string_from_local_vars (tree block) +{ + tree types; + int found = FALSE; + + while (block && TREE_CODE(block)==BLOCK) + { + for (types = BLOCK_VARS(block); types; types = TREE_CHAIN(types)) + { + /* Skip the declaration that refers an external variable. */ + /* name: types.decl.name.identifier.id */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types) + && TREE_CODE (types) == VAR_DECL + && ! DECL_ARTIFICIAL (types) + && DECL_RTL_SET_P (types) + && GET_CODE (DECL_RTL (types)) == MEM + + && search_string_def (TREE_TYPE (types))) + { + rtx home = DECL_RTL (types); + + if (GET_CODE (home) == MEM + && (GET_CODE (XEXP (home, 0)) == MEM + || (GET_CODE (XEXP (home, 0)) == REG + && XEXP (home, 0) != virtual_stack_vars_rtx + && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM +#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM +#endif + ))) + /* If the value is indirect by memory or by a register + that isn't the frame pointer then it means the object is + variable-sized and address through + that register or stack slot. + The protection has no way to hide pointer variables + behind the array, so all we can do is staying + the order of variables and arguments. */ + { + current_function_has_variable_string = TRUE; + } + + /* Found character array. */ + found = TRUE; + } + } + + 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 (tree type) +{ + tree tem; + + if (! type) + return FALSE; + + switch (TREE_CODE (type)) + { + case ARRAY_TYPE: + /* Check if the array is a variable-sized array. */ + if (TYPE_DOMAIN (type) == 0 + || (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0 + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR)) + current_function_defines_vsized_array = TRUE; + + /* Check if the array is related to char array. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE(type)) == char_type_node + || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == signed_char_type_node + || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == unsigned_char_type_node) + { + /* Check if the string is a variable string. */ + if (TYPE_DOMAIN (type) == 0 + || (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0 + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR)) + return TRUE; + + /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE. */ + if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0 + && (TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type)))+1 + >= SUSPICIOUS_BUF_SIZE)) + return TRUE; + + current_function_defines_short_string = TRUE; + } + + /* 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: + /* Check if each field has character arrays. */ + 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 (TYPE_MAIN_VARIANT (TREE_TYPE(type)) == char_type_node + || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == signed_char_type_node + || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == unsigned_char_type_node) + may_have_alloca_pointer = TRUE; + break; + + case REFERENCE_TYPE: + case OFFSET_TYPE: + default: + break; + } + + return FALSE; +} + + +/* Examine whether the input contains frame pointer addressing. */ +int +contains_fp (rtx op) +{ + enum rtx_code code; + rtx x; + int i, j; + const char *fmt; + + x = op; + if (x == 0) + return FALSE; + + code = GET_CODE (x); + + switch (code) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST: + case SYMBOL_REF: + case CODE_LABEL: + case REG: + case ADDRESSOF: + return FALSE; + + case MEM: + /* This case is not generated at the stack protection. + see plus_constant_wide and simplify_plus_minus function. */ + if (XEXP (x, 0) == virtual_stack_vars_rtx) + abort (); + + case PLUS: + if (XEXP (x, 0) == virtual_stack_vars_rtx + && GET_CODE (XEXP (x, 1)) == CONST_INT) + return TRUE; + + default: + break; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + { + if (contains_fp (XEXP (x, i))) + return TRUE; + } + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + if (contains_fp (XVECEXP (x, i, j))) + return TRUE; + + return FALSE; +} + + +/* Examine whether the input contains any pointer. */ +static int +search_pointer_def (tree type) +{ + tree tem; + + if (! type) + return FALSE; + + switch (TREE_CODE (type)) + { + case UNION_TYPE: + case QUAL_UNION_TYPE: + case RECORD_TYPE: + /* Check if each field has a pointer. */ + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + { + if ((TREE_CODE (tem) == TYPE_DECL) + || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem))) + continue; + + if (search_pointer_def (TREE_TYPE(tem))) + return TRUE; + } + break; + + case ARRAY_TYPE: + return search_pointer_def (TREE_TYPE(type)); + + case POINTER_TYPE: + case REFERENCE_TYPE: + case OFFSET_TYPE: + if (TYPE_READONLY (TREE_TYPE (type))) + { + /* If this pointer contains function pointer, + it should be protected. */ + return search_func_pointer (TREE_TYPE (type)); + } + return TRUE; + + default: + break; + } + + return FALSE; +} + + +/* Examine whether the input contains function pointer. */ +static int +search_func_pointer (tree type) +{ + tree tem; + + if (! type) + return FALSE; + + switch (TREE_CODE (type)) + { + case UNION_TYPE: + case QUAL_UNION_TYPE: + case RECORD_TYPE: + if (! TREE_VISITED (type)) + { + /* Mark the type as having been visited already. */ + TREE_VISITED (type) = 1; + + /* Check if each field has a function pointer. */ + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + { + if (TREE_CODE (tem) == FIELD_DECL + && search_func_pointer (TREE_TYPE(tem))) + { + TREE_VISITED (type) = 0; + return TRUE; + } + } + + TREE_VISITED (type) = 0; + } + break; + + case ARRAY_TYPE: + return search_func_pointer (TREE_TYPE(type)); + + case POINTER_TYPE: + case REFERENCE_TYPE: + case OFFSET_TYPE: + if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + return TRUE; + return search_func_pointer (TREE_TYPE(type)); + + default: + break; + } + + return FALSE; +} + + +/* Check whether the specified rtx contains PLUS rtx with used flag. */ +static int +check_used_flag (rtx x) +{ + register int i, j; + register enum rtx_code code; + register const char *format_ptr; + + if (x == 0) + return FALSE; + + code = GET_CODE (x); + + switch (code) + { + case REG: + case QUEUED: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + return FALSE; + + case PLUS: + if (x->used) + return TRUE; + + default: + break; + } + + format_ptr = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*format_ptr++) + { + case 'e': + if (check_used_flag (XEXP (x, i))) + return TRUE; + break; + + case 'E': + for (j = 0; j < XVECLEN (x, i); j++) + if (check_used_flag (XVECEXP (x, i, j))) + return TRUE; + break; + } + } + + return FALSE; +} + + +/* Reset used flag of every insns after the spcecified insn. */ +static void +reset_used_flags_for_insns (rtx insn) +{ + int i, j; + enum rtx_code code; + 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; + } + } + } +} + + +/* Reset used flag of every variables in the specified block. */ +static void +reset_used_flags_for_decls (tree block) +{ + tree types; + rtx home; + + while (block && TREE_CODE(block)==BLOCK) + { + types = BLOCK_VARS(block); + + for (types= BLOCK_VARS(block); types; types = TREE_CHAIN(types)) + { + /* Skip the declaration that refers an external variable and + also skip an global variable. */ + if (! DECL_EXTERNAL (types)) + { + if (! DECL_RTL_SET_P (types)) + continue; + home = DECL_RTL (types); + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == PLUS + && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) + { + XEXP (home, 0)->used = 0; + } + } + } + + reset_used_flags_for_decls (BLOCK_SUBBLOCKS (block)); + + block = BLOCK_CHAIN (block); + } +} + + +/* Reset the used flag of every PLUS rtx derived from the specified rtx. */ +static void +reset_used_flags_of_plus (rtx x) +{ + int i, j; + enum rtx_code code; + const char *format_ptr; + + if (x == 0) + return; + + code = GET_CODE (x); + + switch (code) + { + /* These types may be freely shared so we needn't do any resetting + for them. */ + 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; + } + } +} + + +/* Generate the prologue insns of the protector into the specified insn. */ +static void +rtl_prologue (rtx insn) +{ +#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main) +#undef HAS_INIT_SECTION +#define HAS_INIT_SECTION +#endif + + rtx _val; + + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) + break; + +#if !defined (HAS_INIT_SECTION) + /* If this function is `main', skip a call to `__main' + to run guard instruments after global initializers, etc. */ + if (DECL_NAME (current_function_decl) + && MAIN_NAME_P (DECL_NAME (current_function_decl)) + && DECL_CONTEXT (current_function_decl) == NULL_TREE) + { + rtx fbinsn = insn; + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG) + break; + if (insn == 0) + insn = fbinsn; + } +#endif + + /* Mark the next insn of FUNCTION_BEG insn. */ + prologue_insert_point = NEXT_INSN (insn); + + start_sequence (); + + _guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard")); + emit_move_insn ( guard_area, _guard); + + _val = get_insns (); + end_sequence (); + + emit_insn_before (_val, prologue_insert_point); +} + + +/* Generate the epilogue insns of the protector into the specified insn. */ +static void +rtl_epilogue (rtx insn) +{ + rtx if_false_label; + rtx _val; + rtx funcname; + tree funcstr; + int flag_have_return = FALSE; + + start_sequence (); + +#ifdef HAVE_return + if (HAVE_return) + { + rtx insn; + return_label = gen_label_rtx (); + + for (insn = prologue_insert_point; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == JUMP_INSN + && GET_CODE (PATTERN (insn)) == RETURN + && GET_MODE (PATTERN (insn)) == VOIDmode) + { + rtx pat = gen_rtx_SET (VOIDmode, + pc_rtx, + gen_rtx_LABEL_REF (VOIDmode, + return_label)); + PATTERN (insn) = pat; + flag_have_return = TRUE; + } + + + emit_label (return_label); + } +#endif + + /* if (guard_area != _guard) */ + compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, NULL_RTX); + + if_false_label = gen_label_rtx (); /* { */ + emit_jump_insn ( gen_beq(if_false_label)); + + /* generate string for the current function name */ + funcstr = build_string (strlen(current_function_name ())+1, + current_function_name ()); + TREE_TYPE (funcstr) = build_array_type (char_type_node, 0); + funcname = output_constant_def (funcstr, 1); + + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__stack_smash_handler"), + 0, VOIDmode, 2, + XEXP (funcname, 0), Pmode, guard_area, GUARD_m); + + /* generate RTL to return from the current function */ + + emit_barrier (); /* } */ + emit_label (if_false_label); + + /* generate RTL to return from the current function */ + if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl))) + use_return_register (); + +#ifdef HAVE_return + if (HAVE_return && flag_have_return) + { + emit_jump_insn (gen_return ()); + emit_barrier (); + } +#endif + + _val = get_insns (); + end_sequence (); + + emit_insn_after (_val, insn); +} + + +/* For every variable which type is character array, moves its location + in the stack frame to the sweep_frame_offset position. */ +static void +arrange_var_order (tree block) +{ + tree types; + HOST_WIDE_INT offset; + + while (block && TREE_CODE(block)==BLOCK) + { + /* arrange the location of character arrays in depth first. */ + arrange_var_order (BLOCK_SUBBLOCKS (block)); + + for (types = BLOCK_VARS (block); types; types = TREE_CHAIN(types)) + { + /* Skip the declaration that refers an external variable. */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types) + && TREE_CODE (types) == VAR_DECL + && ! DECL_ARTIFICIAL (types) + && DECL_RTL_SET_P (types) + && GET_CODE (DECL_RTL (types)) == MEM + && GET_MODE (DECL_RTL (types)) == BLKmode + + && (is_array=0, + search_string_def (TREE_TYPE (types)) + || (! current_function_defines_vulnerable_string && is_array))) + { + rtx home = DECL_RTL (types); + + if (!(GET_CODE (home) == MEM + && (GET_CODE (XEXP (home, 0)) == MEM + || (GET_CODE (XEXP (home, 0)) == REG + && XEXP (home, 0) != virtual_stack_vars_rtx + && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM +#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM +#endif + )))) + { + /* Found a string variable. */ + HOST_WIDE_INT var_size = + ((TREE_INT_CST_LOW (DECL_SIZE (types)) + BITS_PER_UNIT - 1) + / BITS_PER_UNIT); + + /* 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); + } + } + } + + block = BLOCK_CHAIN (block); + } +} + + +/* To protect every pointer argument and move character arrays in the argument, + Copy those variables to the top of the stack frame and move the location of + character arrays to the posion of sweep_frame_offset. */ +static void +copy_args_for_protection (void) +{ + tree parms = DECL_ARGUMENTS (current_function_decl); + rtx temp_rtx; + + parms = DECL_ARGUMENTS (current_function_decl); + for (; parms; parms = TREE_CHAIN (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) + { + int string_p; + rtx seq; + + string_p = search_string_def (TREE_TYPE(parms)); + + /* Check if it is a candidate to move. */ + if (string_p || search_pointer_def (TREE_TYPE (parms))) + { + int arg_size + = ((TREE_INT_CST_LOW (DECL_SIZE (parms)) + BITS_PER_UNIT - 1) + / BITS_PER_UNIT); + tree passed_type = DECL_ARG_TYPE (parms); + tree nominal_type = TREE_TYPE (parms); + + start_sequence (); + + if (GET_CODE (DECL_RTL (parms)) == REG) + { + rtx safe = 0; + + change_arg_use_of_insns (prologue_insert_point, + DECL_RTL (parms), &safe, 0); + if (safe) + { + /* Generate codes for copying the content. */ + rtx movinsn = emit_move_insn (safe, DECL_RTL (parms)); + + /* Avoid register elimination in gcse.c. */ + PATTERN (movinsn)->volatil = 1; + + /* Save debugger info. */ + SET_DECL_RTL (parms, safe); + } + } + else if (GET_CODE (DECL_RTL (parms)) == MEM + && GET_CODE (XEXP (DECL_RTL (parms), 0)) == ADDRESSOF) + { + rtx movinsn; + rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms))); + + /* Generate codes for copying the content. */ + movinsn = emit_move_insn (safe, DECL_INCOMING_RTL (parms)); + /* Avoid register elimination in gcse.c. */ + PATTERN (movinsn)->volatil = 1; + + /* Change the addressof information to the newly + allocated pseudo register. */ + emit_move_insn (DECL_RTL (parms), safe); + + /* Save debugger info. */ + SET_DECL_RTL (parms, safe); + } + + /* See if the frontend wants to pass this by invisible + reference. */ + else if (passed_type != nominal_type + && POINTER_TYPE_P (passed_type) + && TREE_TYPE (passed_type) == nominal_type) + { + rtx safe = 0, orig = XEXP (DECL_RTL (parms), 0); + + change_arg_use_of_insns (prologue_insert_point, + orig, &safe, 0); + if (safe) + { + /* Generate codes for copying the content. */ + rtx movinsn = emit_move_insn (safe, orig); + + /* Avoid register elimination in gcse.c */ + PATTERN (movinsn)->volatil = 1; + + /* Save debugger info. */ + SET_DECL_RTL (parms, safe); + } + } + + else + { + /* Declare temporary local variable for parms. */ + temp_rtx + = assign_stack_local (DECL_MODE (parms), arg_size, + DECL_MODE (parms) == BLKmode ? + -1 : 0); + + MEM_IN_STRUCT_P (temp_rtx) + = AGGREGATE_TYPE_P (TREE_TYPE (parms)); + set_mem_alias_set (temp_rtx, get_alias_set (parms)); + + /* Generate codes for copying the content. */ + store_expr (parms, temp_rtx, 0); + + /* Change the reference for each instructions. */ + move_arg_location (prologue_insert_point, DECL_RTL (parms), + temp_rtx, arg_size); + + /* Change the location of parms variable. */ + SET_DECL_RTL (parms, temp_rtx); + } + + seq = get_insns (); + end_sequence (); + emit_insn_before (seq, prologue_insert_point); + +#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 positon of sweep_frame_offset in the + stack frame, that is a last position of string variables. */ +static void +sweep_string_variable (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 variables. */ + 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 (rtx insn, rtx orig, rtx 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 variables. */ + reset_used_flags_for_insns (insn); +} + + +/* Sweep character arrays declared as local variable. */ +static void +sweep_string_in_decls (tree block, HOST_WIDE_INT sweep_offset, + HOST_WIDE_INT sweep_size) +{ + tree types; + HOST_WIDE_INT offset; + rtx home; + + while (block && TREE_CODE(block)==BLOCK) + { + for (types = BLOCK_VARS(block); types; types = TREE_CHAIN(types)) + { + /* Skip the declaration that refers an external variable and + also skip an global variable. */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) { + + if (! DECL_RTL_SET_P (types)) + continue; + + home = DECL_RTL (types); + + /* Process for static local variable. */ + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) + continue; + + if (GET_CODE (home) == MEM + && XEXP (home, 0) == virtual_stack_vars_rtx) + { + offset = 0; + + /* the operand related to the sweep variable. */ + if (sweep_offset <= offset + && offset < sweep_offset + sweep_size) + { + offset = sweep_frame_offset - sweep_size - sweep_offset; + + XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx, + offset); + XEXP (home, 0)->used = 1; + } + else if (sweep_offset <= offset + && offset < sweep_frame_offset) + { + /* the rest of variables under sweep_frame_offset, + shift the location. */ + XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx, + -sweep_size); + XEXP (home, 0)->used = 1; + } + } + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == MEM) + { + /* Process for dynamically allocated array. */ + 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; + } + } + } + } + } + + sweep_string_in_decls (BLOCK_SUBBLOCKS (block), + sweep_offset, sweep_size); + + block = BLOCK_CHAIN (block); + } +} + + +/* Sweep character arrays declared as argument. */ +static void +sweep_string_in_args (tree parms, HOST_WIDE_INT sweep_offset, + HOST_WIDE_INT sweep_size) +{ + rtx home; + HOST_WIDE_INT offset; + + for (; parms; parms = TREE_CHAIN (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) + { + home = DECL_INCOMING_RTL (parms); + + if (XEXP (home, 0)->used) + continue; + + offset = AUTO_OFFSET(XEXP (home, 0)); + + /* the operand related to the sweep variable. */ + if (AUTO_BASEPTR (XEXP (home, 0)) == virtual_stack_vars_rtx) + { + if (sweep_offset <= offset + && offset < sweep_offset + sweep_size) + { + offset += sweep_frame_offset - sweep_size - sweep_offset; + XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, + offset); + + /* mark */ + XEXP (home, 0)->used = 1; + } + else if (sweep_offset <= offset + && offset < sweep_frame_offset) + { + /* the rest of variables under sweep_frame_offset, + shift the location. */ + XEXP (XEXP (home, 0), 1) + = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); + + /* mark */ + XEXP (home, 0)->used = 1; + } + } + } + } +} + + +/* Set to 1 when the instruction contains virtual registers. */ +static int has_virtual_reg; + +/* Sweep the specified character array for every insns. The array starts from + the sweep_offset and its size is sweep_size. */ +static void +sweep_string_use_of_insns (rtx insn, HOST_WIDE_INT sweep_offset, + HOST_WIDE_INT sweep_size) +{ + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + has_virtual_reg = FALSE; + sweep_string_in_operand (insn, &PATTERN (insn), + sweep_offset, sweep_size); + sweep_string_in_operand (insn, ®_NOTES (insn), + sweep_offset, sweep_size); + } +} + + +/* Sweep the specified character array, which starts from the sweep_offset and + its size is sweep_size. + + When a pointer is given, + if it points the address higher than the array, it stays. + if it points the address inside the array, it changes to point inside + the sweeped array. + if it points the address lower than the array, it shifts higher address by + the sweep_size. */ +static void +sweep_string_in_operand (rtx insn, rtx *loc, + HOST_WIDE_INT sweep_offset, HOST_WIDE_INT sweep_size) +{ + rtx x = *loc; + 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 + && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + if (x->used) + goto single_use_of_virtual_reg; + + offset = AUTO_OFFSET(x); + + /* When arguments grow downward, the virtual incoming + args pointer points to the top of the argument block, + so block is identified by the pointer - 1. + The flag is set at the copy_rtx_and_substitute in integrate.c */ + if (RTX_INTEGRATED_P (x)) + k = -1; + + /* the operand related to the sweep variable. */ + if (sweep_offset <= offset + k + && offset + k < sweep_offset + sweep_size) + { + offset += sweep_frame_offset - sweep_size - sweep_offset; + + XEXP (x, 0) = virtual_stack_vars_rtx; + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); + x->used = 1; + } + else if (sweep_offset <= offset + k + && offset + k < sweep_frame_offset) + { + /* the rest of variables under sweep_frame_offset, + shift the location. */ + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); + x->used = 1; + } + + single_use_of_virtual_reg: + if (has_virtual_reg) { + /* excerpt from insn_invalid_p in recog.c */ + int icode = recog_memoized (insn); + + if (icode < 0 && asm_noperands (PATTERN (insn)) < 0) + { + rtx temp, seq; + + start_sequence (); + temp = force_operand (x, NULL_RTX); + seq = get_insns (); + end_sequence (); + + emit_insn_before (seq, insn); + if (! validate_change (insn, loc, temp, 0) + && !validate_replace_rtx (x, temp, insn)) + fatal_insn ("sweep_string_in_operand", insn); + } + } + + has_virtual_reg = TRUE; + return; + } + +#ifdef FRAME_GROWS_DOWNWARD + /* Alert the case of frame register plus constant given by reg. */ + else if (XEXP (x, 0) == virtual_stack_vars_rtx + && GET_CODE (XEXP (x, 1)) == REG) + fatal_insn ("sweep_string_in_operand: unknown addressing", insn); +#endif + + /* + process further subtree: + Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) + (const_int 5)) + */ + break; + + case CALL_PLACEHOLDER: + for (i = 0; i < 3; i++) + { + rtx seq = XEXP (x, i); + if (seq) + { + push_to_sequence (seq); + sweep_string_use_of_insns (XEXP (x, i), + sweep_offset, sweep_size); + XEXP (x, i) = get_insns (); + end_sequence (); + } + } + break; + + default: + break; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + { + /* + virtual_stack_vars_rtx without offset + Example: + (set (reg:SI xx) (reg:SI 78)) + (set (reg:SI xx) (MEM (reg:SI 78))) + */ + if (XEXP (x, i) == virtual_stack_vars_rtx) + fatal_insn ("sweep_string_in_operand: unknown fp usage", insn); + sweep_string_in_operand (insn, &XEXP (x, i), sweep_offset, sweep_size); + } + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + sweep_string_in_operand (insn, &XVECEXP (x, i, j), sweep_offset, sweep_size); +} + + +/* Change the use of an argument to the use of the duplicated variable for + every insns, The variable is addressed by new rtx. */ +static void +change_arg_use_of_insns (rtx insn, rtx orig, rtx *new, HOST_WIDE_INT size) +{ + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + rtx seq; + + start_sequence (); + change_arg_use_in_operand (insn, PATTERN (insn), orig, new, size); + + seq = get_insns (); + end_sequence (); + emit_insn_before (seq, insn); + + /* load_multiple insn from virtual_incoming_args_rtx have several + load insns. If every insn change the load address of arg + to frame region, those insns are moved before the PARALLEL insn + and remove the PARALLEL insn. */ + if (GET_CODE (PATTERN (insn)) == PARALLEL + && XVECLEN (PATTERN (insn), 0) == 0) + delete_insn (insn); + } +} + + +/* Change the use of an argument to the use of the duplicated variable for + every rtx derived from the x. */ +static void +change_arg_use_in_operand (rtx insn, rtx x, rtx orig, rtx *new, HOST_WIDE_INT size) +{ + enum rtx_code code; + int i, j; + HOST_WIDE_INT offset; + const char *fmt; + + if (x == 0) + return; + + code = GET_CODE (x); + + switch (code) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + case ASM_INPUT: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case RETURN: + case REG: + case ADDRESSOF: + return; + + case MEM: + /* Handle special case of MEM (incoming_args). */ + if (GET_CODE (orig) == MEM + && XEXP (x, 0) == virtual_incoming_args_rtx) + { + offset = 0; + + /* the operand related to the sweep variable. */ + if (AUTO_OFFSET(XEXP (orig, 0)) <= offset && + offset < AUTO_OFFSET(XEXP (orig, 0)) + size) { + + offset = AUTO_OFFSET(XEXP (*new, 0)) + + (offset - AUTO_OFFSET(XEXP (orig, 0))); + + XEXP (x, 0) = plus_constant (virtual_stack_vars_rtx, offset); + XEXP (x, 0)->used = 1; + + return; + } + } + break; + + case PLUS: + /* Handle special case of frame register plus constant. */ + if (GET_CODE (orig) == MEM + && XEXP (x, 0) == virtual_incoming_args_rtx + && GET_CODE (XEXP (x, 1)) == CONST_INT + && ! x->used) + { + offset = AUTO_OFFSET(x); + + /* the operand related to the sweep variable. */ + if (AUTO_OFFSET(XEXP (orig, 0)) <= offset && + offset < AUTO_OFFSET(XEXP (orig, 0)) + size) + { + + offset = (AUTO_OFFSET(XEXP (*new, 0)) + + (offset - AUTO_OFFSET(XEXP (orig, 0)))); + + XEXP (x, 0) = virtual_stack_vars_rtx; + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); + x->used = 1; + + return; + } + + /* + process further subtree: + Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) + (const_int 5)) + */ + } + break; + + case SET: + /* Handle special case of "set (REG or MEM) (incoming_args)". + It means that the the address of the 1st argument is stored. */ + if (GET_CODE (orig) == MEM + && XEXP (x, 1) == virtual_incoming_args_rtx) + { + offset = 0; + + /* the operand related to the sweep variable. */ + if (AUTO_OFFSET(XEXP (orig, 0)) <= offset && + offset < AUTO_OFFSET(XEXP (orig, 0)) + size) + { + offset = (AUTO_OFFSET(XEXP (*new, 0)) + + (offset - AUTO_OFFSET(XEXP (orig, 0)))); + + XEXP (x, 1) = force_operand (plus_constant (virtual_stack_vars_rtx, + offset), NULL_RTX); + XEXP (x, 1)->used = 1; + + return; + } + } + break; + + case CALL_PLACEHOLDER: + for (i = 0; i < 3; i++) + { + rtx seq = XEXP (x, i); + if (seq) + { + push_to_sequence (seq); + change_arg_use_of_insns (XEXP (x, i), orig, new, size); + XEXP (x, i) = get_insns (); + end_sequence (); + } + } + break; + + case PARALLEL: + for (j = 0; j < XVECLEN (x, 0); j++) + { + change_arg_use_in_operand (insn, XVECEXP (x, 0, j), orig, new, size); + } + if (recog_memoized (insn) < 0) + { + for (i = 0, j = 0; j < XVECLEN (x, 0); j++) + { + /* if parallel insn has a insn used virtual_incoming_args_rtx, + the insn is removed from this PARALLEL insn. */ + if (check_used_flag (XVECEXP (x, 0, j))) + { + emit_insn (XVECEXP (x, 0, j)); + XVECEXP (x, 0, j) = NULL; + } + else + XVECEXP (x, 0, i++) = XVECEXP (x, 0, j); + } + PUT_NUM_ELEM (XVEC (x, 0), i); + } + return; + + default: + break; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + { + if (XEXP (x, i) == orig) + { + if (*new == 0) + *new = gen_reg_rtx (GET_MODE (orig)); + XEXP (x, i) = *new; + continue; + } + change_arg_use_in_operand (insn, XEXP (x, i), orig, new, size); + } + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + { + if (XVECEXP (x, i, j) == orig) + { + if (*new == 0) + *new = gen_reg_rtx (GET_MODE (orig)); + XVECEXP (x, i, j) = *new; + continue; + } + change_arg_use_in_operand (insn, XVECEXP (x, i, j), orig, new, size); + } +} + + +/* Validate every instructions from the specified instruction. + + The stack protector prohibits to generate machine specific frame addressing + for the first rtl generation. The prepare_stack_protection must convert + machine independent frame addressing to machine specific frame addressing, + so instructions for inline functions, which skip the conversion of + the stack protection, validate every instructions. */ +static void +validate_insns_of_varrefs (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 (); +} + + +/* Validate frame addressing of the rtx and covert it to machine specific one. */ +static void +validate_operand_of_varrefs (rtx insn, rtx *loc) +{ + 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 + && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + start_sequence (); + + { /* excerpt from expand_binop in optabs.c */ + optab binoptab = add_optab; + enum machine_mode mode = GET_MODE (x); + int icode = (int) binoptab->handlers[(int) mode].insn_code; + enum machine_mode mode1 = insn_data[icode].operand[2].mode; + rtx pat; + rtx xop0 = XEXP (x, 0), xop1 = XEXP (x, 1); + temp = gen_reg_rtx (mode); + + /* Now, if insn's predicates don't allow offset operands, + put them into pseudo regs. */ + + if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1) + && mode1 != VOIDmode) + xop1 = copy_to_mode_reg (mode1, xop1); + + pat = GEN_FCN (icode) (temp, xop0, xop1); + if (pat) + emit_insn (pat); + else + abort (); /* there must be add_optab handler. */ + } + seq = get_insns (); + end_sequence (); + + emit_insn_before (seq, insn); + if (! validate_change (insn, loc, temp, 0)) + abort (); + return; + } + break; + + + case CALL_PLACEHOLDER: + for (i = 0; i < 3; i++) + { + rtx seq = XEXP (x, i); + if (seq) + { + push_to_sequence (seq); + validate_insns_of_varrefs (XEXP (x, i)); + XEXP (x, i) = get_insns (); + end_sequence (); + } + } + break; + + default: + break; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + validate_operand_of_varrefs (insn, &XEXP (x, i)); + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + validate_operand_of_varrefs (insn, &XVECEXP (x, i, j)); +} + + + +/* Return size that is not allocated for stack frame. It will be allocated + to modify the home of pseudo registers called from global_alloc. */ +HOST_WIDE_INT +get_frame_free_size (void) +{ + if (! flag_propolice_protection) + return 0; + + return push_allocated_offset - push_frame_offset; +} + + +/* The following codes are invoked after the instantiation of pseudo 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 (HOST_WIDE_INT, HOST_WIDE_INT); +static void push_frame_in_decls (tree, HOST_WIDE_INT, HOST_WIDE_INT); +static void push_frame_in_args (tree, HOST_WIDE_INT, HOST_WIDE_INT); +static void push_frame_of_insns (rtx, HOST_WIDE_INT, HOST_WIDE_INT); +static void push_frame_in_operand (rtx, rtx, HOST_WIDE_INT, HOST_WIDE_INT); +static void push_frame_of_reg_equiv_memory_loc (HOST_WIDE_INT, HOST_WIDE_INT); +static void push_frame_of_reg_equiv_constant (HOST_WIDE_INT, HOST_WIDE_INT); +static void reset_used_flags_for_push_frame (void); +static int check_out_of_frame_access (rtx, HOST_WIDE_INT); +static int check_out_of_frame_access_in_operand (rtx, HOST_WIDE_INT); +#endif + + +/* Assign stack local at the stage of register allocater. if a pseudo reg is + spilled out from such an allocation, it is allocated on the stack. + The protector keep the location be lower stack region than the location of + sweeped arrays. */ +rtx +assign_stack_local_for_pseudo_reg (enum machine_mode mode, + HOST_WIDE_INT size, int align) +{ +#if defined(FRAME_GROWS_DOWNWARD) || !defined(STACK_GROWS_DOWNWARD) + return assign_stack_local (mode, size, align); +#else + tree blocks = DECL_INITIAL (current_function_decl); + rtx new; + HOST_WIDE_INT saved_frame_offset, units_per_push, starting_frame; + int first_call_from_purge_addressof, first_call_from_global_alloc; + + if (! flag_propolice_protection + || size == 0 + || ! blocks + || current_function_is_inlinable + || ! search_string_from_argsandvars (CALL_FROM_PUSH_FRAME) + || 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)) + { + /* After the purge_addressof stage, there may be an instruction which + have the pointer less than the starting_frame. + if there is an access below 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 below 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 (HOST_WIDE_INT var_size, HOST_WIDE_INT 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(); +} + + +/* Reset used flag of every insns, reg_equiv_memory_loc, + and reg_equiv_constant. */ +static void +reset_used_flags_for_push_frame(void) +{ + 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; + } + } +} + + +/* Push every variables declared as a local variable and make a room for + instantiated register. */ +static void +push_frame_in_decls (tree block, HOST_WIDE_INT push_size, + HOST_WIDE_INT boundary) +{ + tree types; + HOST_WIDE_INT offset; + rtx home; + + while (block && TREE_CODE(block)==BLOCK) + { + for (types = BLOCK_VARS(block); types; types = TREE_CHAIN(types)) + { + /* Skip the declaration that refers an external variable and + also skip an global variable. */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) + { + if (! DECL_RTL_SET_P (types)) + continue; + + home = DECL_RTL (types); + + /* Process for static local variable. */ + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) + continue; + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == REG) + { + if (XEXP (home, 0) != frame_pointer_rtx + || boundary != 0) + continue; + + 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 array. */ + 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; + } + } + } + } + + push_frame_in_decls (BLOCK_SUBBLOCKS (block), push_size, boundary); + block = BLOCK_CHAIN (block); + } +} + + +/* Push every variables declared as an argument and make a room for + instantiated register. */ +static void +push_frame_in_args (tree parms, HOST_WIDE_INT push_size, + HOST_WIDE_INT 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)) + { + 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; + } + } + } +} + + +/* Set to 1 when the instruction has the reference to be pushed. */ +static int insn_pushed; + +/* Tables of equivalent registers with frame pointer. */ +static int *fp_equiv = 0; + + +/* Push the frame region to make a room for allocated local variable. */ +static void +push_frame_of_insns (rtx insn, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary) +{ + /* init fp_equiv */ + fp_equiv = (int *) xcalloc (max_reg_num (), sizeof (int)); + + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + rtx last; + + insn_pushed = FALSE; + + /* Push frame in INSN operation. */ + push_frame_in_operand (insn, PATTERN (insn), push_size, boundary); + + /* Push frame in NOTE. */ + push_frame_in_operand (insn, REG_NOTES (insn), push_size, boundary); + + /* Push frame in CALL EXPR_LIST. */ + if (GET_CODE (insn) == CALL_INSN) + push_frame_in_operand (insn, CALL_INSN_FUNCTION_USAGE (insn), + push_size, boundary); + + /* Pushed frame addressing style may not be machine specific one. + so the instruction should be converted to use the machine specific + frame addressing. */ + if (insn_pushed + && (last = try_split (PATTERN (insn), insn, 1)) != insn) + { + rtx first = NEXT_INSN (insn); + rtx trial = NEXT_INSN (first); + rtx pattern = PATTERN (trial); + rtx set; + + /* Update REG_EQUIV info to the first splitted insn. */ + if ((set = single_set (insn)) + && find_reg_note (insn, REG_EQUIV, SET_SRC (set)) + && GET_CODE (PATTERN (first)) == SET) + { + REG_NOTES (first) + = gen_rtx_EXPR_LIST (REG_EQUIV, + SET_SRC (PATTERN (first)), + REG_NOTES (first)); + } + + /* copy the first insn of splitted insns to the original insn and + delete the first insn, + because the original insn is pointed from records: + insn_chain, reg_equiv_init, used for global_alloc. */ + if (cse_not_expected) + { + add_insn_before (insn, first); + + /* Copy the various flags, and other information. */ + memcpy (insn, first, sizeof (struct rtx_def) - sizeof (rtunion)); + PATTERN (insn) = PATTERN (first); + INSN_CODE (insn) = INSN_CODE (first); + LOG_LINKS (insn) = LOG_LINKS (first); + REG_NOTES (insn) = REG_NOTES (first); + + /* then remove the first insn of splitted insns. */ + remove_insn (first); + INSN_DELETED_P (first) = 1; + } + + if (GET_CODE (pattern) == SET + && GET_CODE (XEXP (pattern, 0)) == REG + && GET_CODE (XEXP (pattern, 1)) == PLUS + && XEXP (pattern, 0) == XEXP (XEXP (pattern, 1), 0) + && GET_CODE (XEXP (XEXP (pattern, 1), 1)) == CONST_INT) + { + rtx offset = XEXP (XEXP (pattern, 1), 1); + fp_equiv[REGNO (XEXP (pattern, 0))] = INTVAL (offset); + + delete_insn (trial); + } + + insn = last; + } + } + + /* Clean up. */ + free (fp_equiv); +} + + +/* Push the frame region by changing the operand that points the frame. */ +static void +push_frame_in_operand (rtx insn, rtx orig, + HOST_WIDE_INT push_size, HOST_WIDE_INT boundary) +{ + rtx x = orig; + 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 + && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 1), 1)) < 0) + { + x = XEXP (x, 1); + offset = AUTO_OFFSET(x); + if (x->used || -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: + /* Handle special case of frame register plus constant. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && XEXP (x, 0) == frame_pointer_rtx) + { + offset = AUTO_OFFSET(x); + + 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 (GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == SUBREG + && SUBREG_REG (XEXP (x, 0)) == frame_pointer_rtx) + { + offset = AUTO_OFFSET(x); + + 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 (GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == REG + && fp_equiv[REGNO (XEXP (x, 0))]) + { + offset = AUTO_OFFSET(x); + + 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) + && GET_CODE (SET_SRC (PATTERN (PREV_INSN (insn)))) == CONST_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). + The register already have a pushed offset, just mark this frame + addressing. + */ + 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 (FP) (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); +} + + +/* Change the location pointed in reg_equiv_memory_loc. */ +static void +push_frame_of_reg_equiv_memory_loc (HOST_WIDE_INT push_size, + HOST_WIDE_INT 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; + } + } +} + + +/* Change the location pointed in reg_equiv_constant. */ +static void +push_frame_of_reg_equiv_constant (HOST_WIDE_INT push_size, + HOST_WIDE_INT 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; + } + } +} + + +/* Check every instructions if insn's memory reference is out of frame. */ +static int +check_out_of_frame_access (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; +} + + +/* Check every operands if the reference is out of frame. */ +static int +check_out_of_frame_access_in_operand (rtx orig, HOST_WIDE_INT boundary) +{ + rtx x = orig; + 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 (GET_CODE (XEXP (x, 1)) == CONST_INT + && 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 -uNr gcc-3.4.3.orig/gcc/protector.h gcc-3.4.3/gcc/protector.h --- gcc-3.4.3.orig/gcc/protector.h 1970-01-01 01:00:00.000000000 +0100 +++ gcc-3.4.3/gcc/protector.h 2004-01-20 03:01:39.000000000 +0100 @@ -0,0 +1,55 @@ +/* RTL buffer overflow protection function for GNU C compiler + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +/* Declare GUARD variable. */ +#define GUARD_m Pmode +#define UNITS_PER_GUARD \ + MAX(BIGGEST_ALIGNMENT / BITS_PER_UNIT, GET_MODE_SIZE (GUARD_m)) + +#ifndef L_stack_smash_handler + +/* Insert a guard variable before a character buffer and change the order + of pointer variables, character buffers and pointer arguments. */ + +extern void prepare_stack_protection (int); + +#ifdef TREE_CODE +/* Search a character array from the specified type tree. */ + +extern int search_string_def (tree); +#endif + +/* Examine whether the input contains frame pointer addressing. */ + +extern int contains_fp (rtx); + +/* Return size that is not allocated for stack frame. It will be allocated + to modify the home of pseudo registers called from global_alloc. */ + +extern HOST_WIDE_INT get_frame_free_size (void); + +/* Allocate a local variable in the stack area before character buffers + to avoid the corruption of it. */ + +extern rtx assign_stack_local_for_pseudo_reg (enum machine_mode, + HOST_WIDE_INT, int); + +#endif diff -uNr gcc-3.4.3.orig/gcc/reload1.c gcc-3.4.3/gcc/reload1.c --- gcc-3.4.3.orig/gcc/reload1.c 2004-05-02 14:37:17.000000000 +0200 +++ gcc-3.4.3/gcc/reload1.c 2004-11-24 18:35:31.812641048 +0100 @@ -43,6 +43,7 @@ #include "toplev.h" #include "except.h" #include "tree.h" +#include "protector.h" /* This file contains the reload pass of the compiler, which is run after register allocation has been done. It checks that @@ -891,7 +892,7 @@ if (cfun->stack_alignment_needed) assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed); - starting_frame_size = get_frame_size (); + starting_frame_size = get_frame_size () - get_frame_free_size (); set_initial_elim_offsets (); set_initial_label_offsets (); @@ -955,7 +956,7 @@ setup_save_areas (); /* If we allocated another stack slot, redo elimination bookkeeping. */ - if (starting_frame_size != get_frame_size ()) + if (starting_frame_size != get_frame_size () - get_frame_free_size ()) continue; if (caller_save_needed) @@ -974,7 +975,7 @@ /* If we allocated any new memory locations, make another pass since it might have changed elimination offsets. */ - if (starting_frame_size != get_frame_size ()) + if (starting_frame_size != get_frame_size () - get_frame_free_size ()) something_changed = 1; { @@ -1066,11 +1067,11 @@ if (insns_need_reload != 0 || something_needs_elimination || something_needs_operands_changed) { - HOST_WIDE_INT old_frame_size = get_frame_size (); + HOST_WIDE_INT old_frame_size = get_frame_size () - get_frame_free_size (); reload_as_needed (global); - if (old_frame_size != get_frame_size ()) + if (old_frame_size != get_frame_size () - get_frame_free_size ()) abort (); if (num_eliminable) @@ -1957,8 +1958,10 @@ inherent space, and no less total space, then the previous slot. */ 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, + /* No known place to spill from => no slot to reuse. + For the stack protection, an allocated slot should be placed in + the safe region from the stack smaching attack. */ + 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 -uNr gcc-3.4.3.orig/gcc/rtl.h gcc-3.4.3/gcc/rtl.h --- gcc-3.4.3.orig/gcc/rtl.h 2004-10-13 01:35:32.000000000 +0200 +++ gcc-3.4.3/gcc/rtl.h 2004-11-24 18:35:31.830638312 +0100 @@ -473,6 +473,18 @@ __FUNCTION__); \ _rtx; }) +#define RTL_FLAG_CHECK9(NAME, RTX, C1, C2, C3, C4, C5, C6, C7, C8, C9) \ + __extension__ \ +({ rtx const _rtx = (RTX); \ + if (GET_CODE(_rtx) != C1 && GET_CODE(_rtx) != C2 \ + && GET_CODE(_rtx) != C3 && GET_CODE(_rtx) != C4 \ + && GET_CODE(_rtx) != C5 && GET_CODE(_rtx) != C6 \ + && GET_CODE(_rtx) != C7 && GET_CODE(_rtx) != C8 \ + && GET_CODE(_rtx) != C9) \ + rtl_check_failed_flag (NAME, _rtx, __FILE__, __LINE__, \ + __FUNCTION__); \ + _rtx; }) + extern void rtl_check_failed_flag (const char *, rtx, const char *, int, const char *) ATTRIBUTE_NORETURN @@ -488,6 +500,7 @@ #define RTL_FLAG_CHECK6(NAME, RTX, C1, C2, C3, C4, C5, C6) (RTX) #define RTL_FLAG_CHECK7(NAME, RTX, C1, C2, C3, C4, C5, C6, C7) (RTX) #define RTL_FLAG_CHECK8(NAME, RTX, C1, C2, C3, C4, C5, C6, C7, C8) (RTX) +#define RTL_FLAG_CHECK9(NAME, RTX, C1, C2, C3, C4, C5, C6, C7, C8, C9) (RTX) #endif #define CLEAR_RTX_FLAGS(RTX) \ @@ -583,9 +596,9 @@ #define LOG_LINKS(INSN) XEXP(INSN, 7) #define RTX_INTEGRATED_P(RTX) \ - (RTL_FLAG_CHECK8("RTX_INTEGRATED_P", (RTX), INSN, CALL_INSN, \ + (RTL_FLAG_CHECK9("RTX_INTEGRATED_P", (RTX), INSN, CALL_INSN, \ JUMP_INSN, INSN_LIST, BARRIER, CODE_LABEL, CONST, \ - NOTE)->integrated) + PLUS, NOTE)->integrated) #define RTX_UNCHANGING_P(RTX) \ (RTL_FLAG_CHECK3("RTX_UNCHANGING_P", (RTX), REG, MEM, CONCAT)->unchanging) #define RTX_FRAME_RELATED_P(RTX) \ @@ -1125,6 +1138,10 @@ (RTL_FLAG_CHECK3("MEM_VOLATILE_P", (RTX), MEM, ASM_OPERANDS, \ ASM_INPUT)->volatil) +/* 1 if RTX is an SET rtx that is not eliminated for the stack protection. */ +#define SET_VOLATILE_P(RTX) \ + (RTL_FLAG_CHECK1("SET_VOLATILE_P", (RTX), SET)->volatil) + /* 1 if RTX is a mem that refers to an aggregate, either to the aggregate itself of to a field of the aggregate. If zero, RTX may or may not be such a reference. */ diff -uNr gcc-3.4.3.orig/gcc/simplify-rtx.c gcc-3.4.3/gcc/simplify-rtx.c --- gcc-3.4.3.orig/gcc/simplify-rtx.c 2004-10-10 23:53:35.000000000 +0200 +++ gcc-3.4.3/gcc/simplify-rtx.c 2004-11-24 18:35:31.858634056 +0100 @@ -2287,6 +2287,7 @@ int n_ops = 2, input_ops = 2, input_consts = 0, n_consts; int first, changed; int i, j; + HOST_WIDE_INT fp_offset = 0; memset (ops, 0, sizeof ops); @@ -2312,6 +2313,10 @@ switch (this_code) { case PLUS: + if (flag_propolice_protection + && XEXP (this_op, 0) == virtual_stack_vars_rtx + && GET_CODE (XEXP (this_op, 1)) == CONST_INT) + fp_offset = INTVAL (XEXP (this_op, 1)); case MINUS: if (n_ops == 7) return NULL_RTX; @@ -2473,11 +2478,24 @@ && GET_CODE (ops[n_ops - 1].op) == CONST_INT && CONSTANT_P (ops[n_ops - 2].op)) { - rtx value = ops[n_ops - 1].op; - if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg) - value = neg_const_int (mode, value); - ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value)); - n_ops--; + if (!flag_propolice_protection) + { + rtx value = ops[n_ops - 1].op; + if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg) + value = neg_const_int (mode, value); + ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value)); + n_ops--; + } + /* The stack protector keeps the addressing style of a local variable, + so it doesn't use neg_const_int function not to change + the offset value. */ + else { + HOST_WIDE_INT value = INTVAL (ops[n_ops - 1].op); + if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg) + value = -value; + ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, value); + n_ops--; + } } /* Count the number of CONSTs that we generated. */ @@ -2495,6 +2513,59 @@ || (n_ops + n_consts == input_ops && n_consts <= input_consts))) return NULL_RTX; + if (flag_propolice_protection) + { + /* keep the addressing style of local variables + as (plus (virtual_stack_vars_rtx) (CONST_int x)). + For the case array[r-1], + converts from (+ (+VFP c1) (+r -1)) to (SET R (+VFP c1)) (+ R (+r -1)). + + This loop finds ops[i] which is the register for the frame + addressing, Then, makes the frame addressing using the register and + the constant of ops[n_ops - 1]. */ + for (i = 0; i < n_ops; i++) +#ifdef FRAME_GROWS_DOWNWARD + if (ops[i].op == virtual_stack_vars_rtx) +#else + if (ops[i].op == virtual_stack_vars_rtx + || ops[i].op == frame_pointer_rtx) +#endif + { + if (GET_CODE (ops[n_ops - 1].op) == CONST_INT) + { + HOST_WIDE_INT value = INTVAL (ops[n_ops - 1].op); + if (value >= fp_offset) + { + ops[i].op = plus_constant (ops[i].op, value); + n_ops--; + } + else + { + if (!force + && (n_ops + 1 + n_consts > input_ops + || (n_ops + 1 + n_consts == input_ops + && n_consts <= input_consts))) + return NULL_RTX; + ops[n_ops - 1].op = GEN_INT (value-fp_offset); + ops[i].op = plus_constant (ops[i].op, fp_offset); + } + } + /* keep the following address pattern; + (1) buf[BUFSIZE] is the first assigned variable. + (+ (+ fp -BUFSIZE) BUFSIZE) + (2) ((+ (+ fp 1) r) -1). */ + else if (fp_offset != 0) + return NULL_RTX; + /* keep the (+ fp 0) pattern for the following case; + (1) buf[i]: i: REG, buf: (+ fp 0) in !FRAME_GROWS_DOWNWARD + (2) argument: the address is (+ fp 0). */ + else if (fp_offset == 0) + return NULL_RTX; + + break; + } + } + /* Put a non-negated operand first, if possible. */ for (i = 0; i < n_ops && ops[i].neg; i++) diff -uNr gcc-3.4.3.orig/gcc/testsuite/gcc.dg/ssp-warn.c gcc-3.4.3/gcc/testsuite/gcc.dg/ssp-warn.c --- gcc-3.4.3.orig/gcc/testsuite/gcc.dg/ssp-warn.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-3.4.3/gcc/testsuite/gcc.dg/ssp-warn.c 2003-11-21 09:41:19.000000000 +0100 @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-fstack-protector" } */ +void +test1() +{ + void intest1(int *a) + { + *a ++; + } + + char buf[80]; + + buf[0] = 0; +} /* { dg-bogus "not protecting function: it contains functions" } */ + +void +test2(int n) +{ + char buf[80]; + char vbuf[n]; + + buf[0] = 0; + vbuf[0] = 0; +} /* { dg-bogus "not protecting variables: it has a variable length buffer" } */ + +void +test3() +{ + char buf[5]; + + buf[0] = 0; +} /* { dg-bogus "not protecting function: buffer is less than 8 bytes long" } */ diff -uNr gcc-3.4.3.orig/gcc/testsuite/gcc.misc-tests/ssp-execute1.c gcc-3.4.3/gcc/testsuite/gcc.misc-tests/ssp-execute1.c --- gcc-3.4.3.orig/gcc/testsuite/gcc.misc-tests/ssp-execute1.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-3.4.3/gcc/testsuite/gcc.misc-tests/ssp-execute1.c 2004-02-16 06:15:39.000000000 +0100 @@ -0,0 +1,54 @@ +/* Test location changes of character array. */ + +void +test(int i) +{ + int ibuf1[10]; + char buf[50]; + int ibuf2[10]; + char buf2[50000]; + int ibuf3[10]; + char *p; + + /* c1: the frame offset of buf[0] + c2: the frame offset of buf2[0] + */ + p= &buf[0]; *p=1; /* expected rtl: (+ fp -c1) */ + if (*p != buf[0]) + abort(); + p= &buf[5]; *p=2; /* expected rtl: (+ fp -c1+5) */ + if (*p != buf[5]) + abort(); + p= &buf[-1]; *p=3; /* expected rtl: (+ (+ fp -c1) -1) */ + if (*p != buf[-1]) + abort(); + p= &buf[49]; *p=4; /* expected rtl: (+ fp -c1+49) */ + if (*p != buf[49]) + abort(); + p = &buf[i+5]; *p=5; /* expected rtl: (+ (+ fp -c1) (+ i 5)) */ + if (*p != buf[i+5]) + abort (); + p = buf - 1; *p=6; /* expected rtl: (+ (+ fp -c1) -1) */ + if (*p != buf[-1]) + abort (); + p = 1 + buf; *p=7; /* expected rtl: (+ (+ fp -c1) 1) */ + if (*p != buf[1]) + abort (); + p = &buf[1] - 1; *p=8; /* expected rtl: (+ (+ fp -c1+1) -1) */ + if (*p != buf[0]) + abort (); + + /* test big offset which is greater than the max value of signed 16 bit integer. */ + p = &buf2[45555]; *p=9; /* expected rtl: (+ fp -c2+45555) */ + if (*p != buf2[45555]) + abort (); +} + +int main() +{ + test(10); + exit(0); +} + + + diff -uNr gcc-3.4.3.orig/gcc/testsuite/gcc.misc-tests/ssp-execute2.c gcc-3.4.3/gcc/testsuite/gcc.misc-tests/ssp-execute2.c --- gcc-3.4.3.orig/gcc/testsuite/gcc.misc-tests/ssp-execute2.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-3.4.3/gcc/testsuite/gcc.misc-tests/ssp-execute2.c 2003-11-22 09:44:33.000000000 +0100 @@ -0,0 +1,49 @@ +void +test(int i, char *j, int k) +{ + int a[10]; + char b; + int c; + long *d; + char buf[50]; + long e[10]; + int n; + + a[0] = 4; + b = 5; + c = 6; + d = (long*)7; + e[0] = 8; + + /* overflow buffer */ + for (n = 0; n < 120; n++) + buf[n] = 0; + + if (j == 0 || *j != 2) + abort (); + if (a[0] == 0) + abort (); + if (b == 0) + abort (); + if (c == 0) + abort (); + if (d == 0) + abort (); + if (e[0] == 0) + abort (); + + exit (0); +} + +int main() +{ + int i, k; + int j[40]; + i = 1; + j[39] = 2; + k = 3; + test(i, &j[39], k); +} + + + diff -uNr gcc-3.4.3.orig/gcc/testsuite/gcc.misc-tests/ssp-execute.exp gcc-3.4.3/gcc/testsuite/gcc.misc-tests/ssp-execute.exp --- gcc-3.4.3.orig/gcc/testsuite/gcc.misc-tests/ssp-execute.exp 1970-01-01 01:00:00.000000000 +0100 +++ gcc-3.4.3/gcc/testsuite/gcc.misc-tests/ssp-execute.exp 2004-06-02 13:23:36.000000000 +0200 @@ -0,0 +1,35 @@ +# Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +if $tracelevel then { + strace $tracelevel +} + +# Load support procs. +load_lib c-torture.exp + +# +# main test loop +# + +foreach src [lsort [glob -nocomplain $srcdir/$subdir/ssp-execute*.c]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $src] then { + continue + } + + c-torture-execute $src -fstack-protector +} diff -uNr gcc-3.4.3.orig/gcc/toplev.c gcc-3.4.3/gcc/toplev.c --- gcc-3.4.3.orig/gcc/toplev.c 2004-07-26 16:42:11.000000000 +0200 +++ gcc-3.4.3/gcc/toplev.c 2004-11-24 18:35:31.000000000 +0100 @@ -79,6 +79,7 @@ #include "coverage.h" #include "value-prof.h" #include "alloc-pool.h" +#include "protector.h" #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) #include "dwarf2out.h" @@ -97,6 +98,10 @@ declarations for e.g. AIX 4.x. */ #endif +#ifdef STACK_PROTECTOR +#include "protector.h" +#endif + #ifndef HAVE_conditional_execution #define HAVE_conditional_execution 0 #endif @@ -979,6 +984,15 @@ minimum function alignment. Zero means no alignment is forced. */ int force_align_functions_log; +#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 + typedef struct { const char *const string; @@ -1154,7 +1168,9 @@ {"mem-report", &mem_report, 1 }, { "trapv", &flag_trapv, 1 }, { "wrapv", &flag_wrapv, 1 }, - { "new-ra", &flag_new_regalloc, 1 } + { "new-ra", &flag_new_regalloc, 1 }, + {"stack-protector", &flag_propolice_protection, 1 }, + {"stack-protector-all", &flag_stack_protection, 1 } }; /* Here is a table, controlled by the tm.h file, listing each -m switch @@ -2686,6 +2702,9 @@ insns = get_insns (); + if (flag_propolice_protection) + prepare_stack_protection (inlinable); + /* Dump the rtl code if we are dumping rtl. */ if (open_dump_file (DFI_rtl, decl)) @@ -4483,6 +4502,12 @@ /* The presence of IEEE signaling NaNs, implies all math can trap. */ if (flag_signaling_nans) flag_trapping_math = 1; + + /* This combination makes optimized frame addressings and causes + a internal compilation error at prepare_stack_protection. + so don't allow it. */ + if (flag_stack_protection && !flag_propolice_protection) + flag_propolice_protection = TRUE; } /* Initialize the compiler back end. */ diff -uNr gcc-3.4.3.orig/gcc/tree.h gcc-3.4.3/gcc/tree.h --- gcc-3.4.3.orig/gcc/tree.h 2004-11-24 18:04:19.000000000 +0100 +++ gcc-3.4.3/gcc/tree.h 2004-11-24 18:35:31.000000000 +0100 @@ -1489,6 +1489,10 @@ where it is called. */ #define DECL_INLINE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.inline_flag) +/* In a VAR_DECL, nonzero if the declaration is copied for inlining. + The stack protector should keep its location in the stack. */ +#define DECL_COPIED(NODE) (VAR_DECL_CHECK (NODE)->decl.inline_flag) + /* Nonzero in a FUNCTION_DECL means that this function was declared inline, such as via the `inline' keyword in C/C++. This flag controls the linkage semantics of 'inline'; whether or not the function is inlined is