diff mbox

[GCC/ARM] Fix PR77933: stack corruption on ARM when using high registers and lr

Message ID 34d1835c-9eea-1f86-0c93-30aeace74762@foss.arm.com
State New
Headers show

Commit Message

Thomas Preudhomme Nov. 2, 2016, 5:08 p.m. UTC
Hi,

When saving registers, function thumb1_expand_prologue () aims at minimizing the 
number of push instructions. One of the optimization it does is to push lr 
alongside high register(s) (after having moved them to low register(s)) when 
there is no low register to save. The way this is implemented is to add lr to 
the list of registers that can be pushed just before the push happens. This 
would then push lr and allows it to be used for further push if there was not 
enough registers to push all high registers to be pushed.

However, the logic that decides what register to move high registers to before 
being pushed only looks at low registers (see for loop initialization). This 
means not only that lr is not used for pushing high registers but also that lr 
is not removed from the list of registers to be pushed when it's not used. This 
extra lr push is not poped in epilogue leading in stack corruption.

This patch changes the loop to iterate over register r0 to lr so as to both fix 
the stack corruption and reuse lr to push some high register when possible.

ChangeLog entry are as follow:

*** gcc/ChangeLog ***

2016-11-01  Thomas Preud'homme  <thomas.preudhomme@arm.com>

         PR target/77933
         * config/arm/arm.c (thumb1_expand_prologue): Also check for lr being a
         pushable register.


*** gcc/testsuite/ChangeLog ***

2016-11-01  Thomas Preud'homme  <thomas.preudhomme@arm.com>

         PR target/77933
         * gcc.target/arm/pr77933.c: New test.


Testing: no regression on arm-none-eabi GCC cross-compiler targeting Cortex-M0

Is this ok for trunk?

Best regards,

Thomas
diff mbox

Patch

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index dd8d5e5db8ca50daab648e58df290969aa794862..22a20caf42389748fc64ee0a3f880c6bea4c8f49 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -24990,7 +24990,7 @@  thumb1_expand_prologue (void)
 	{
 	  unsigned long real_regs_mask = 0;
 
-	  for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
+	  for (regno = LR_REGNUM; regno >= 0; regno --)
 	    {
 	      if (pushable_regs & (1 << regno))
 		{
diff --git a/gcc/testsuite/gcc.target/arm/pr77933.c b/gcc/testsuite/gcc.target/arm/pr77933.c
new file mode 100644
index 0000000000000000000000000000000000000000..cba7e9bb9aa57c6755f79b5ec2ea1a8744e23599
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr77933.c
@@ -0,0 +1,9 @@ 
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+int
+main (void)
+{
+  __asm__ volatile ("" : : : "r8", "r9", "lr");
+  return 0;
+}