This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[ARM PATCH] Protect stack pointer
- From: Nathan Sidwell <nathan at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 17 Oct 2003 15:50:53 +0100
- Subject: [ARM PATCH] Protect stack pointer
- Organization: Codesourcery LLC
I've installed this patch which fixes a problem with the ARM epilogue
code.
ARM can use a load multiple to pop the registers, including the caller's
stack pointer, off the stack. This is a restartable instruction, and when
interrupted will ensure the base register is restored correctly, but not
any registers which are loaded. If this instruction is interrupted, the SP
might have been restored, but then it would be pointer above the stack
frame being unwound -- this violates the ABI and can lead to stack
corruption. The patch makes sure that the SP is used as a base register,
and so is restored on an interrupt.
built and tested with an cross compiler to arm-unknown-linux. Approved
by Richard Earnshaw.
nathan
--
Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC
The voices in my head said this was stupid too
nathan@codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk
2003-09-22 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.
Index: config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.291
diff -c -3 -p -r1.291 arm.c
*** config/arm/arm.c 4 Sep 2003 03:17:52 -0000 1.291
--- config/arm/arm.c 22 Sep 2003 14:50:33 -0000
*************** use_return_insn (int iscond)
*** 987,993 ****
/* Never use a return instruction before reload has run. */
if (!reload_completed)
return 0;
!
func_type = arm_current_func_type ();
/* Naked functions and volatile functions need special
--- 987,997 ----
/* 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
*************** arm_output_epilogue (int really_return)
*** 8482,8489 ****
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);
if (IS_INTERRUPT (func_type))
/* Interrupt handlers will have pushed the
--- 8486,8503 ----
saved_regs_mask &= ~ (1 << LR_REGNUM);
else
saved_regs_mask &= ~ (1 << PC_REGNUM);
!
! /* 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