diff options
-rw-r--r-- | gcc/ChangeLog | 34 | ||||
-rw-r--r-- | gcc/config/i386/linux.h | 3 | ||||
-rw-r--r-- | gcc/config/i386/linux64.h | 3 | ||||
-rw-r--r-- | gcc/doc/md.texi | 18 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 20 | ||||
-rw-r--r-- | gcc/explow.c | 340 | ||||
-rw-r--r-- | gcc/expr.h | 20 | ||||
-rw-r--r-- | gcc/ira.c | 3 | ||||
-rw-r--r-- | gcc/rtlanal.c | 5 | ||||
-rw-r--r-- | gcc/system.h | 2 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/stack_check1.adb | 38 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/stack_check2.adb | 43 | ||||
-rw-r--r-- | gcc/tree.c | 3 | ||||
-rw-r--r-- | gcc/unwind-dw2.c | 8 |
15 files changed, 442 insertions, 103 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0da48a4..ce89099 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2009-11-03 Eric Botcazou <ebotcazou@adacore.com> + + PR target/10127 + PR ada/20548 + * expr.h (STACK_CHECK_PROBE_INTERVAL): Delete. + (STACK_CHECK_PROBE_INTERVAL_EXP): New macro. + (STACK_CHECK_MOVING_SP): Likewise. + * system.h (STACK_CHECK_PROBE_INTERVAL): Poison it. + * doc/tm.texi (Stack Checking): Delete STACK_CHECK_PROBE_INTERVAL. + Document STACK_CHECK_PROBE_INTERVAL_EXP and STACK_CHECK_MOVING_SP. + * doc/md.texi (Standard Pattern Names): Tweak entry of CHECK_STACK. + Document PROBE_STACK. + * explow.c (anti_adjust_stack_and_probe): New function. + (allocate_dynamic_stack_space): Do not directly allocate space if + STACK_CHECK_MOVING_SP, instead invoke above function. + (emit_stack_probe): Handle probe_stack insn. + (PROBE_INTERVAL): New macro. + (STACK_GROW_OPTAB): Likewise. + (STACK_GROW_OFF): Likewise. + (probe_stack_range): Use Pmode and memory_address consistently. Fix + loop condition in the small constant case. Rewrite in the general + case to be immune to wraparounds. Make sure the address of probes + is valid. Try to use [base + disp] addressing mode if possible. + * ira.c (setup_eliminable_regset): Set frame_pointer_needed if stack + checking is enabled and STACK_CHECK_MOVING_SP. + * rtlanal.c (may_trap_p_1) <MEM>: If stack checking is enabled, + return 1 for volatile references to the stack pointer. + * tree.c (build_common_builtin_nodes): Do not set ECF_NOTHROW on + __builtin_alloca if stack checking is enabled. + * unwind-dw2.c (uw_identify_context): Take into account whether the + context is that of a signal frame or not. + * config/i386/linux.h (STACK_CHECK_MOVING_SP): Define to 1. + * config/i386/linux64.h (STACK_CHECK_MOVING_SP): Likewise. + 2009-11-03 Jakub Jelinek <jakub@redhat.com> PR rtl-optimization/41917 diff --git a/gcc/config/i386/linux.h b/gcc/config/i386/linux.h index 5e2e013..5d8e5ad 100644 --- a/gcc/config/i386/linux.h +++ b/gcc/config/i386/linux.h @@ -207,6 +207,9 @@ along with GCC; see the file COPYING3. If not see #define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h" +/* The stack pointer needs to be moved while checking the stack. */ +#define STACK_CHECK_MOVING_SP 1 + /* This macro may be overridden in i386/k*bsd-gnu.h. */ #define REG_NAME(reg) reg diff --git a/gcc/config/i386/linux64.h b/gcc/config/i386/linux64.h index cfa3f49..d07547a 100644 --- a/gcc/config/i386/linux64.h +++ b/gcc/config/i386/linux64.h @@ -110,6 +110,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h" +/* The stack pointer needs to be moved while checking the stack. */ +#define STACK_CHECK_MOVING_SP 1 + /* This macro may be overridden in i386/k*bsd-gnu.h. */ #define REG_NAME(reg) reg diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index dcfba92..2974dcf 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5037,11 +5037,19 @@ operations in addition to updating the stack pointer. @item @samp{check_stack} If stack checking cannot be done on your system by probing the stack with a load or store instruction (@pxref{Stack Checking}), define this pattern -to perform the needed check and signaling an error if the stack -has overflowed. The single operand is the location in the stack furthest -from the current stack pointer that you need to validate. Normally, -on machines where this pattern is needed, you would obtain the stack -limit from a global or thread-specific variable or register. +to perform the needed check and signal an error if the stack has overflowed. +The single operand is the address in the stack furthest from the current +stack pointer that you need to validate. Normally, on machines where this +pattern is needed, you would obtain the stack limit from a global or +thread-specific variable or register. + +@cindex @code{probe_stack} instruction pattern +@item @samp{probe_stack} +If stack checking can be done on your system by probing the stack but doing +it with a load or store instruction is not optimal (@pxref{Stack Checking}), +define this pattern to do the probing differently and signal an error if +the stack has overflowed. The single operand is the memory location in the +stack that needs to be probed. @cindex @code{nonlocal_goto} instruction pattern @item @samp{nonlocal_goto} diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 984bbd7..c69ef0c 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3556,11 +3556,12 @@ like to do static stack checking in some more efficient way than the generic approach. The default value of this macro is zero. @end defmac -@defmac STACK_CHECK_PROBE_INTERVAL -An integer representing the interval at which GCC must generate stack -probe instructions. You will normally define this macro to be no larger -than the size of the ``guard pages'' at the end of a stack area. The -default value of 4096 is suitable for most systems. +@defmac STACK_CHECK_PROBE_INTERVAL_EXP +An integer specifying the interval at which GCC must generate stack probe +instructions, defined as 2 raised to this integer. You will normally +define this macro so that the interval be no larger than the size of +the ``guard pages'' at the end of a stack area. The default value +of 12 (4096-byte interval) is suitable for most systems. @end defmac @defmac STACK_CHECK_PROBE_LOAD @@ -3569,6 +3570,15 @@ as a load instruction and zero if GCC should use a store instruction. The default is zero, which is the most efficient choice on most systems. @end defmac +@defmac STACK_CHECK_MOVING_SP +An integer which is nonzero if GCC should move the stack pointer page by page +when doing probes. This can be necessary on systems where the stack pointer +contains the bottom address of the memory area accessible to the executing +thread at any point in time. In this situation an alternate signal stack +is required in order to be able to recover from a stack overflow. The +default value of this macro is zero. +@end defmac + @defmac STACK_CHECK_PROTECT The number of bytes of stack needed to recover from a stack overflow, for languages where such a recovery is supported. The default value of diff --git a/gcc/explow.c b/gcc/explow.c index c38682d..0bbbc00 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see static rtx break_out_memory_refs (rtx); static void emit_stack_probe (rtx); +static void anti_adjust_stack_and_probe (rtx); /* Truncate and perhaps sign-extend C as appropriate for MODE. */ @@ -1233,9 +1234,11 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align) gcc_assert (!(stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT))); - /* If needed, check that we have the required amount of stack. - Take into account what has already been checked. */ - if (flag_stack_check == GENERIC_STACK_CHECK) + /* If needed, check that we have the required amount of stack. Take into + account what has already been checked. */ + if (STACK_CHECK_MOVING_SP) + ; + else if (flag_stack_check == GENERIC_STACK_CHECK) probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE, size); else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK) @@ -1304,7 +1307,10 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align) emit_label (space_available); } - anti_adjust_stack (size); + if (flag_stack_check && STACK_CHECK_MOVING_SP) + anti_adjust_stack_and_probe (size); + else + anti_adjust_stack (size); #ifdef STACK_GROWS_DOWNWARD emit_move_insn (target, virtual_stack_dynamic_rtx); @@ -1355,6 +1361,12 @@ emit_stack_probe (rtx address) MEM_VOLATILE_P (memref) = 1; + /* See if we have an insn to probe the stack. */ +#ifdef HAVE_probe_stack + if (HAVE_probe_stack) + emit_insn (gen_probe_stack (memref)); + else +#endif if (STACK_CHECK_PROBE_LOAD) emit_move_insn (gen_reg_rtx (word_mode), memref); else @@ -1362,15 +1374,20 @@ emit_stack_probe (rtx address) } /* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive. - FIRST is a constant and size is a Pmode RTX. These are offsets from the - current stack pointer. STACK_GROWS_DOWNWARD says whether to add or - subtract from the stack. If SIZE is constant, this is done - with a fixed number of probes. Otherwise, we must make a loop. */ + FIRST is a constant and size is a Pmode RTX. These are offsets from + the current stack pointer. STACK_GROWS_DOWNWARD says whether to add + or subtract them from the stack pointer. */ + +#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP) #ifdef STACK_GROWS_DOWNWARD #define STACK_GROW_OP MINUS +#define STACK_GROW_OPTAB sub_optab +#define STACK_GROW_OFF(off) -(off) #else #define STACK_GROW_OP PLUS +#define STACK_GROW_OPTAB add_optab +#define STACK_GROW_OFF(off) (off) #endif void @@ -1380,113 +1397,272 @@ probe_stack_range (HOST_WIDE_INT first, rtx size) if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode) size = convert_to_mode (Pmode, size, 1); - /* Next see if the front end has set up a function for us to call to - check the stack. */ - if (stack_check_libfunc != 0) + /* Next see if we have a function to check the stack. */ + if (stack_check_libfunc) { - rtx addr = memory_address (QImode, + rtx addr = memory_address (Pmode, gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, stack_pointer_rtx, plus_constant (size, first))); - - addr = convert_memory_address (ptr_mode, addr); - emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr, - ptr_mode); + emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr); } - /* Next see if we have an insn to check the stack. Use it if so. */ + /* Next see if we have an insn to check the stack. */ #ifdef HAVE_check_stack else if (HAVE_check_stack) { - insn_operand_predicate_fn pred; - rtx last_addr - = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - plus_constant (size, first)), - NULL_RTX); - - pred = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate; - if (pred && ! ((*pred) (last_addr, Pmode))) - last_addr = copy_to_mode_reg (Pmode, last_addr); + rtx addr = memory_address (Pmode, + gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + stack_pointer_rtx, + plus_constant (size, first))); + insn_operand_predicate_fn pred + = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate; + if (pred && !((*pred) (addr, Pmode))) + addr = copy_to_mode_reg (Pmode, addr); - emit_insn (gen_check_stack (last_addr)); + emit_insn (gen_check_stack (addr)); } #endif - /* If we have to generate explicit probes, see if we have a constant - small number of them to generate. If so, that's the easy case. */ - else if (CONST_INT_P (size) - && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL) + /* Otherwise we have to generate explicit probes. If we have a constant + small number of them to generate, that's the easy case. */ + else if (CONST_INT_P (size) && INTVAL (size) < 7 * PROBE_INTERVAL) { - HOST_WIDE_INT offset; - - /* Start probing at FIRST + N * STACK_CHECK_PROBE_INTERVAL - for values of N from 1 until it exceeds LAST. If only one - probe is needed, this will not generate any code. Then probe - at LAST. */ - for (offset = first + STACK_CHECK_PROBE_INTERVAL; - offset < INTVAL (size); - offset = offset + STACK_CHECK_PROBE_INTERVAL) - emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - GEN_INT (offset))); - - emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - plus_constant (size, first))); + HOST_WIDE_INT isize = INTVAL (size), i; + rtx addr; + + /* Probe at FIRST + N * PROBE_INTERVAL for values of N from 1 until + it exceeds SIZE. If only one probe is needed, this will not + generate any code. Then probe at FIRST + SIZE. */ + for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL) + { + addr = memory_address (Pmode, + plus_constant (stack_pointer_rtx, + STACK_GROW_OFF (first + i))); + emit_stack_probe (addr); + } + + addr = memory_address (Pmode, + plus_constant (stack_pointer_rtx, + STACK_GROW_OFF (first + isize))); + emit_stack_probe (addr); } - /* In the variable case, do the same as above, but in a loop. We emit loop - notes so that loop optimization can be done. */ + /* In the variable case, do the same as above, but in a loop. Note that we + must be extra careful with variables wrapping around because we might be + at the very top (or the very bottom) of the address space and we have to + be able to handle this case properly; in particular, we use an equality + test for the loop condition. */ else { - rtx test_addr - = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - GEN_INT (first + STACK_CHECK_PROBE_INTERVAL)), - NULL_RTX); - rtx last_addr - = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - plus_constant (size, first)), - NULL_RTX); - rtx incr = GEN_INT (STACK_CHECK_PROBE_INTERVAL); + rtx rounded_size, rounded_size_op, test_addr, last_addr, temp; rtx loop_lab = gen_label_rtx (); - rtx test_lab = gen_label_rtx (); rtx end_lab = gen_label_rtx (); - rtx temp; - if (!REG_P (test_addr) - || REGNO (test_addr) < FIRST_PSEUDO_REGISTER) - test_addr = force_reg (Pmode, test_addr); - emit_jump (test_lab); + /* Step 1: round SIZE to the previous multiple of the interval. */ + + /* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */ + rounded_size + = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL)); + rounded_size_op = force_operand (rounded_size, NULL_RTX); + + + /* Step 2: compute initial and final value of the loop counter. */ + + /* TEST_ADDR = SP + FIRST. */ + test_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + stack_pointer_rtx, + GEN_INT (first)), NULL_RTX); + + /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */ + last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + test_addr, + rounded_size_op), NULL_RTX); + + + /* Step 3: the loop + + while (TEST_ADDR != LAST_ADDR) + { + TEST_ADDR = TEST_ADDR + PROBE_INTERVAL + probe at TEST_ADDR + } + + probes at FIRST + N * PROBE_INTERVAL for values of N from 1 + until it is equal to ROUNDED_SIZE. */ emit_label (loop_lab); - emit_stack_probe (test_addr); -#ifdef STACK_GROWS_DOWNWARD -#define CMP_OPCODE GTU - temp = expand_binop (Pmode, sub_optab, test_addr, incr, test_addr, - 1, OPTAB_WIDEN); -#else -#define CMP_OPCODE LTU - temp = expand_binop (Pmode, add_optab, test_addr, incr, test_addr, + /* Jump to END_LAB if TEST_ADDR == LAST_ADDR. */ + emit_cmp_and_jump_insns (test_addr, last_addr, EQ, NULL_RTX, Pmode, 1, + end_lab); + + /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */ + temp = expand_binop (Pmode, STACK_GROW_OPTAB, test_addr, + GEN_INT (PROBE_INTERVAL), test_addr, 1, OPTAB_WIDEN); -#endif gcc_assert (temp == test_addr); - emit_label (test_lab); - emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE, - NULL_RTX, Pmode, 1, loop_lab); - emit_jump (end_lab); + /* Probe at TEST_ADDR. */ + emit_stack_probe (test_addr); + + emit_jump (loop_lab); + emit_label (end_lab); - emit_stack_probe (last_addr); + + /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time + that SIZE is equal to ROUNDED_SIZE. */ + + /* TEMP = SIZE - ROUNDED_SIZE. */ + temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size); + if (temp != const0_rtx) + { + rtx addr; + + if (GET_CODE (temp) == CONST_INT) + { + /* Use [base + disp} addressing mode if supported. */ + HOST_WIDE_INT offset = INTVAL (temp); + addr = memory_address (Pmode, + plus_constant (last_addr, + STACK_GROW_OFF (offset))); + } + else + { + /* Manual CSE if the difference is not known at compile-time. */ + temp = gen_rtx_MINUS (Pmode, size, rounded_size_op); + addr = memory_address (Pmode, + gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + last_addr, temp)); + } + + emit_stack_probe (addr); + } } } - + +/* Adjust the stack by SIZE bytes while probing it. Note that we skip the + probe for the first interval + a small dope of 4 words and instead probe + that many bytes past the specified size to maintain a protection area. */ + +static void +anti_adjust_stack_and_probe (rtx size) +{ + const int dope = 4 * UNITS_PER_WORD; + + /* First ensure SIZE is Pmode. */ + if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode) + size = convert_to_mode (Pmode, size, 1); + + /* If we have a constant small number of probes to generate, that's the + easy case. */ + if (GET_CODE (size) == CONST_INT && INTVAL (size) < 7 * PROBE_INTERVAL) + { + HOST_WIDE_INT isize = INTVAL (size), i; + bool first_probe = true; + + /* Adjust SP and probe to PROBE_INTERVAL + N * PROBE_INTERVAL for + values of N from 1 until it exceeds SIZE. If only one probe is + needed, this will not generate any code. Then adjust and probe + to PROBE_INTERVAL + SIZE. */ + for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL) + { + if (first_probe) + { + anti_adjust_stack (GEN_INT (2 * PROBE_INTERVAL + dope)); + first_probe = false; + } + else + anti_adjust_stack (GEN_INT (PROBE_INTERVAL)); + emit_stack_probe (stack_pointer_rtx); + } + + if (first_probe) + anti_adjust_stack (plus_constant (size, PROBE_INTERVAL + dope)); + else + anti_adjust_stack (plus_constant (size, PROBE_INTERVAL - i)); + emit_stack_probe (stack_pointer_rtx); + } + + /* In the variable case, do the same as above, but in a loop. Note that we + must be extra careful with variables wrapping around because we might be + at the very top (or the very bottom) of the address space and we have to + be able to handle this case properly; in particular, we use an equality + test for the loop condition. */ + else + { + rtx rounded_size, rounded_size_op, last_addr, temp; + rtx loop_lab = gen_label_rtx (); + rtx end_lab = gen_label_rtx (); + + + /* Step 1: round SIZE to the previous multiple of the interval. */ + + /* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */ + rounded_size + = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL)); + rounded_size_op = force_operand (rounded_size, NULL_RTX); + + + /* Step 2: compute initial and final value of the loop counter. */ + + /* SP = SP_0 + PROBE_INTERVAL. */ + anti_adjust_stack (GEN_INT (PROBE_INTERVAL + dope)); + + /* LAST_ADDR = SP_0 + PROBE_INTERVAL + ROUNDED_SIZE. */ + last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + stack_pointer_rtx, + rounded_size_op), NULL_RTX); + + + /* Step 3: the loop + + while (SP != LAST_ADDR) + { + SP = SP + PROBE_INTERVAL + probe at SP + } + + adjusts SP and probes to PROBE_INTERVAL + N * PROBE_INTERVAL for + values of N from 1 until it is equal to ROUNDED_SIZE. */ + + emit_label (loop_lab); + + /* Jump to END_LAB if SP == LAST_ADDR. */ + emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX, + Pmode, 1, end_lab); + + /* SP = SP + PROBE_INTERVAL and probe at SP. */ + anti_adjust_stack (GEN_INT (PROBE_INTERVAL)); + emit_stack_probe (stack_pointer_rtx); + + emit_jump (loop_lab); + + emit_label (end_lab); + + + /* Step 4: adjust SP and probe to PROBE_INTERVAL + SIZE if we cannot + assert at compile-time that SIZE is equal to ROUNDED_SIZE. */ + + /* TEMP = SIZE - ROUNDED_SIZE. */ + temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size); + if (temp != const0_rtx) + { + /* Manual CSE if the difference is not known at compile-time. */ + if (GET_CODE (temp) != CONST_INT) + temp = gen_rtx_MINUS (Pmode, size, rounded_size_op); + anti_adjust_stack (temp); + emit_stack_probe (stack_pointer_rtx); + } + } + + /* Adjust back to account for the additional first interval. */ + adjust_stack (GEN_INT (PROBE_INTERVAL + dope)); +} + /* Return an rtx representing the register or memory location in which a scalar value of data type VALTYPE was returned by a function call to function FUNC. @@ -218,9 +218,9 @@ do { \ #define STACK_CHECK_STATIC_BUILTIN 0 #endif -/* The default interval is one page. */ -#ifndef STACK_CHECK_PROBE_INTERVAL -#define STACK_CHECK_PROBE_INTERVAL 4096 +/* The default interval is one page (4096 bytes). */ +#ifndef STACK_CHECK_PROBE_INTERVAL_EXP +#define STACK_CHECK_PROBE_INTERVAL_EXP 12 #endif /* The default is to do a store into the stack. */ @@ -228,6 +228,11 @@ do { \ #define STACK_CHECK_PROBE_LOAD 0 #endif +/* The default is not to move the stack pointer. */ +#ifndef STACK_CHECK_MOVING_SP +#define STACK_CHECK_MOVING_SP 0 +#endif + /* This is a kludge to try to capture the discrepancy between the old mechanism (generic stack checking) and the new mechanism (static builtin stack checking). STACK_CHECK_PROTECT needs to be bumped @@ -252,7 +257,7 @@ do { \ one probe per function. */ #ifndef STACK_CHECK_MAX_FRAME_SIZE #define STACK_CHECK_MAX_FRAME_SIZE \ - (STACK_CHECK_PROBE_INTERVAL - UNITS_PER_WORD) + ((1 << STACK_CHECK_PROBE_INTERVAL_EXP) - UNITS_PER_WORD) #endif /* This is arbitrary, but should be large enough everywhere. */ @@ -779,10 +784,9 @@ extern void update_nonlocal_goto_save_area (void); extern rtx allocate_dynamic_stack_space (rtx, rtx, int); /* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive. - FIRST is a constant and size is a Pmode RTX. These are offsets from the - current stack pointer. STACK_GROWS_DOWNWARD says whether to add or - subtract from the stack. If SIZE is constant, this is done - with a fixed number of probes. Otherwise, we must make a loop. */ + FIRST is a constant and size is a Pmode RTX. These are offsets from + the current stack pointer. STACK_GROWS_DOWNWARD says whether to add + or subtract them from the stack pointer. */ extern void probe_stack_range (HOST_WIDE_INT, rtx); /* Return an rtx that refers to the value returned by a library call @@ -1442,6 +1442,9 @@ ira_setup_eliminable_regset (void) int need_fp = (! flag_omit_frame_pointer || (cfun->calls_alloca && EXIT_IGNORE_STACK) + /* We need the frame pointer to catch stack overflow exceptions + if the stack pointer is moving. */ + || (flag_stack_check && STACK_CHECK_MOVING_SP) || crtl->accesses_prior_frames || crtl->stack_realign_needed || targetm.frame_pointer_required ()); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 120d37a..ab88f23 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -2252,6 +2252,11 @@ may_trap_p_1 (const_rtx x, unsigned flags) /* Memory ref can trap unless it's a static var or a stack slot. */ case MEM: + /* Recognize specific pattern of stack checking probes. */ + if (flag_stack_check + && MEM_VOLATILE_P (x) + && XEXP (x, 0) == stack_pointer_rtx) + return 1; if (/* MEM_NOTRAP_P only relates to the actual position of the memory reference; moving it out of context such as when moving code when optimizing, might cause its address to become invalid. */ diff --git a/gcc/system.h b/gcc/system.h index 0c846cf..03910d0 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -761,7 +761,7 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; TARGET_ASM_EXCEPTION_SECTION TARGET_ASM_EH_FRAME_SECTION \ SMALL_ARG_MAX ASM_OUTPUT_SHARED_BSS ASM_OUTPUT_SHARED_COMMON \ ASM_OUTPUT_SHARED_LOCAL UNALIGNED_WORD_ASM_OP \ - ASM_MAKE_LABEL_LINKONCE + ASM_MAKE_LABEL_LINKONCE STACK_CHECK_PROBE_INTERVAL /* Hooks that are no longer used. */ #pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE \ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 220a4c3..4a499e2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-11-03 Eric Botcazou <ebotcazou@adacore.com> + + * gnat.dg/stack_check.adb1: New test. + * gnat.dg/stack_check.adb2: Likewise. + 2009-11-03 Jakub Jelinek <jakub@redhat.com> PR rtl-optimization/41917 diff --git a/gcc/testsuite/gnat.dg/stack_check1.adb b/gcc/testsuite/gnat.dg/stack_check1.adb new file mode 100644 index 0000000..51ee1a6 --- /dev/null +++ b/gcc/testsuite/gnat.dg/stack_check1.adb @@ -0,0 +1,38 @@ +-- { dg-do run } +-- { dg-options "-fstack-check" } + +-- This test requires architecture- and OS-specific support code for unwinding +-- through signal frames (typically located in *-unwind.h) to pass. Feel free +-- to disable it if this code hasn't been implemented yet. + +procedure Stack_Check1 is + + type A is Array (1..2048) of Integer; + + procedure Consume_Stack (N : Integer) is + My_A : A; -- 8 KB static + begin + My_A (1) := 0; + if N <= 0 then + return; + end if; + Consume_Stack (N-1); + end; + + Task T; + + Task body T is + begin + begin + Consume_Stack (Integer'Last); + raise Program_Error; + exception + when Storage_Error => null; + end; + + Consume_Stack (128); + end; + +begin + null; +end; diff --git a/gcc/testsuite/gnat.dg/stack_check2.adb b/gcc/testsuite/gnat.dg/stack_check2.adb new file mode 100644 index 0000000..4a3008b --- /dev/null +++ b/gcc/testsuite/gnat.dg/stack_check2.adb @@ -0,0 +1,43 @@ +-- { dg-do run } +-- { dg-options "-fstack-check" } + +-- This test requires architecture- and OS-specific support code for unwinding +-- through signal frames (typically located in *-unwind.h) to pass. Feel free +-- to disable it if this code hasn't been implemented yet. + +procedure Stack_Check2 is + + function UB return Integer is + begin + return 2048; + end; + + type A is Array (Positive range <>) of Integer; + + procedure Consume_Stack (N : Integer) is + My_A : A (1..UB); -- 8 KB dynamic + begin + My_A (1) := 0; + if N <= 0 then + return; + end if; + Consume_Stack (N-1); + end; + + Task T; + + Task body T is + begin + begin + Consume_Stack (Integer'Last); + raise Program_Error; + exception + when Storage_Error => null; + end; + + Consume_Stack (128); + end; + +begin + null; +end; @@ -9009,7 +9009,8 @@ build_common_builtin_nodes (void) tmp = tree_cons (NULL_TREE, size_type_node, void_list_node); ftype = build_function_type (ptr_type_node, tmp); local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA, - "alloca", ECF_NOTHROW | ECF_MALLOC); + "alloca", + ECF_MALLOC | (flag_stack_check ? 0 : ECF_NOTHROW)); } tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c index 82958b0..2208f17 100644 --- a/gcc/unwind-dw2.c +++ b/gcc/unwind-dw2.c @@ -1559,7 +1559,13 @@ uw_install_context_1 (struct _Unwind_Context *current, static inline _Unwind_Ptr uw_identify_context (struct _Unwind_Context *context) { - return _Unwind_GetCFA (context); + /* The CFA is not sufficient to disambiguate the context of a function + interrupted by a signal before establishing its frame and the context + of the signal itself. */ + if (STACK_GROWS_DOWNWARD) + return _Unwind_GetCFA (context) - _Unwind_IsSignalFrame (context); + else + return _Unwind_GetCFA (context) + _Unwind_IsSignalFrame (context); } |