arm.c (use_return_insn): Not a single instruction, if there's a frame pointer.
authorRichard Earnshaw <rearnsha@arm.com>
Fri, 17 Oct 2003 14:45:47 +0000 (14:45 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Fri, 17 Oct 2003 14:45:47 +0000 (14:45 +0000)
* 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

gcc/ChangeLog
gcc/config/arm/arm.c

index 2b8fc81911ce3b0addee819e1275e5c6f5722295..912074a9ea10bc75edd934bbd6149ecd8bff5a3c 100644 (file)
@@ -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.
index dc8c536653609875962fc4c6792a689b10d9d9a4..70ea4cda89a8adaab09fb13a0f3b184f9cc64799 100644 (file)
@@ -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