aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2003-10-17 14:45:47 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2003-10-17 14:45:47 +0000
commitefc2515b4913b2b8870b041475542277520aa002 (patch)
tree431e646419600f7ff50a09192331f97028048699
parent51a785a03619403e4dec65d83553edb5bdff0f75 (diff)
downloadgcc-efc2515b4913b2b8870b041475542277520aa002.zip
gcc-efc2515b4913b2b8870b041475542277520aa002.tar.gz
gcc-efc2515b4913b2b8870b041475542277520aa002.tar.bz2
arm.c (use_return_insn): Not a single instruction, if there's a frame pointer.
* config/arm/arm.c (use_return_insn): Not a single instruction, if there's a frame pointer. (arm_output_epilogue): Protect stack pointer from being corrupted on interrupt. Co-Authored-By: Nathan Sidwell <nathan@codesourcery.com> From-SVN: r72606
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/arm/arm.c20
2 files changed, 25 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2b8fc81..912074a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2003-10-17 Richard Earnshaw <rearnsha@arm.com>
+ Nathan Sidwell <nathan@codesourcery.com>
+
+ * config/arm/arm.c (use_return_insn): Not a single instruction, if
+ there's a frame pointer.
+ (arm_output_epilogue): Protect stack pointer from being corrupted
+ on interrupt.
+
2003-10-17 Ulrich Weigand <uweigand@de.ibm.com>
* ifcvt.c (noce_try_addcc): Handle ifs with 'else' case.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index dc8c536..70ea4cd 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -986,7 +986,11 @@ use_return_insn (int iscond)
/* Never use a return instruction before reload has run. */
if (!reload_completed)
return 0;
-
+
+ /* We need two instructions when there's a frame pointer. */
+ if (frame_pointer_needed)
+ return 0;
+
func_type = arm_current_func_type ();
/* Naked functions and volatile functions need special
@@ -8500,8 +8504,18 @@ arm_output_epilogue (int really_return)
saved_regs_mask &= ~ (1 << LR_REGNUM);
else
saved_regs_mask &= ~ (1 << PC_REGNUM);
-
- print_multi_reg (f, "ldmea\t%r", FP_REGNUM, saved_regs_mask);
+
+ /* We must use SP as the base register, because SP is one of the
+ registers being restored. If an interrupt or page fault
+ happens in the ldm instruction, the SP might or might not
+ have been restored. That would be bad, as then SP will no
+ longer indicate the safe area of stack, and we can get stack
+ corruption. Using SP as the base register means that it will
+ be reset correctly to the original value, should an interrupt
+ occur. */
+ asm_fprintf (f, "\tsub\t%r,%r,#%d\n", SP_REGNUM, FP_REGNUM,
+ 4 * bit_count (saved_regs_mask));
+ print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
if (IS_INTERRUPT (func_type))
/* Interrupt handlers will have pushed the