aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorThomas Preud'homme <thomas.preudhomme@arm.com>2016-11-17 20:12:13 +0000
committerThomas Preud'homme <thopre01@gcc.gnu.org>2016-11-17 20:12:13 +0000
commit77b384c53f2229b05513fb4b297d4c93da04f01a (patch)
tree57d72e555ae16df422d83d7d1b6434b8123f1ac1 /gcc
parentd9df71be907c93848f4ab31b280080da59cf5b5a (diff)
downloadgcc-77b384c53f2229b05513fb4b297d4c93da04f01a.zip
gcc-77b384c53f2229b05513fb4b297d4c93da04f01a.tar.gz
gcc-77b384c53f2229b05513fb4b297d4c93da04f01a.tar.bz2
Fix PR77933: stack corruption on ARM when using high registers and LR
2016-11-17 Thomas Preud'homme <thomas.preudhomme@arm.com> gcc/ PR target/77933 * config/arm/arm.c (thumb1_expand_prologue): Distinguish between lr being live in the function and lr needing to be saved. Distinguish between already saved pushable registers and registers to push. Check for LR being an available pushable register. gcc/testsuite/ PR target/77933 * gcc.target/arm/pr77933-1.c: New test. * gcc.target/arm/pr77933-2.c: Likewise. From-SVN: r242559
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/arm/arm.c29
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.target/arm/pr77933-1.c46
-rw-r--r--gcc/testsuite/gcc.target/arm/pr77933-2.c47
5 files changed, 124 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 86c664b..1cf436d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2016-11-17 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ PR target/77933
+ * config/arm/arm.c (thumb1_expand_prologue): Distinguish between lr
+ being live in the function and lr needing to be saved. Distinguish
+ between already saved pushable registers and registers to push.
+ Check for LR being an available pushable register.
+
2016-11-17 Aaron Sawdey <acsawdey@linux.vnet.ibm.com>
* config/i386/i386.md (cmpstrnsi): New test to bail out if neither
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 239117f..d7ce87c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -23593,6 +23593,7 @@ thumb1_expand_prologue (void)
unsigned long live_regs_mask;
unsigned long l_mask;
unsigned high_regs_pushed = 0;
+ bool lr_needs_saving;
func_type = arm_current_func_type ();
@@ -23615,6 +23616,7 @@ thumb1_expand_prologue (void)
offsets = arm_get_frame_offsets ();
live_regs_mask = offsets->saved_regs_mask;
+ lr_needs_saving = live_regs_mask & (1 << LR_REGNUM);
/* Extract a mask of the ones we can give to the Thumb's push instruction. */
l_mask = live_regs_mask & 0x40ff;
@@ -23681,6 +23683,7 @@ thumb1_expand_prologue (void)
{
insn = thumb1_emit_multi_reg_push (l_mask, l_mask);
RTX_FRAME_RELATED_P (insn) = 1;
+ lr_needs_saving = false;
offset = bit_count (l_mask) * UNITS_PER_WORD;
}
@@ -23745,12 +23748,13 @@ thumb1_expand_prologue (void)
be a push of LR and we can combine it with the push of the first high
register. */
else if ((l_mask & 0xff) != 0
- || (high_regs_pushed == 0 && l_mask))
+ || (high_regs_pushed == 0 && lr_needs_saving))
{
unsigned long mask = l_mask;
mask |= (1 << thumb1_extra_regs_pushed (offsets, true)) - 1;
insn = thumb1_emit_multi_reg_push (mask, mask);
RTX_FRAME_RELATED_P (insn) = 1;
+ lr_needs_saving = false;
}
if (high_regs_pushed)
@@ -23768,7 +23772,9 @@ thumb1_expand_prologue (void)
/* Here we need to mask out registers used for passing arguments
even if they can be pushed. This is to avoid using them to stash the high
registers. Such kind of stash may clobber the use of arguments. */
- pushable_regs = l_mask & (~arg_regs_mask) & 0xff;
+ pushable_regs = l_mask & (~arg_regs_mask);
+ if (lr_needs_saving)
+ pushable_regs &= ~(1 << LR_REGNUM);
if (pushable_regs == 0)
pushable_regs = 1 << thumb_find_work_register (live_regs_mask);
@@ -23776,8 +23782,9 @@ thumb1_expand_prologue (void)
while (high_regs_pushed > 0)
{
unsigned long real_regs_mask = 0;
+ unsigned long push_mask = 0;
- for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
+ for (regno = LR_REGNUM; regno >= 0; regno --)
{
if (pushable_regs & (1 << regno))
{
@@ -23786,6 +23793,7 @@ thumb1_expand_prologue (void)
high_regs_pushed --;
real_regs_mask |= (1 << next_hi_reg);
+ push_mask |= (1 << regno);
if (high_regs_pushed)
{
@@ -23795,23 +23803,20 @@ thumb1_expand_prologue (void)
break;
}
else
- {
- pushable_regs &= ~((1 << regno) - 1);
- break;
- }
+ break;
}
}
/* If we had to find a work register and we have not yet
saved the LR then add it to the list of regs to push. */
- if (l_mask == (1 << LR_REGNUM))
+ if (lr_needs_saving)
{
- pushable_regs |= l_mask;
- real_regs_mask |= l_mask;
- l_mask = 0;
+ push_mask |= 1 << LR_REGNUM;
+ real_regs_mask |= 1 << LR_REGNUM;
+ lr_needs_saving = false;
}
- insn = thumb1_emit_multi_reg_push (pushable_regs, real_regs_mask);
+ insn = thumb1_emit_multi_reg_push (push_mask, real_regs_mask);
RTX_FRAME_RELATED_P (insn) = 1;
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index cce390b..55f7d83 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2016-11-17 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ PR target/77933
+ * gcc.target/arm/pr77933-1.c: New test.
+ * gcc.target/arm/pr77933-2.c: Likewise.
+
2016-11-17 Jakub Jelinek <jakub@redhat.com>
PR middle-end/78201
diff --git a/gcc/testsuite/gcc.target/arm/pr77933-1.c b/gcc/testsuite/gcc.target/arm/pr77933-1.c
new file mode 100644
index 0000000..95cf68e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr77933-1.c
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+__attribute__ ((noinline, noclone)) void
+clobber_lr_and_highregs (void)
+{
+ __asm__ volatile ("" : : : "r8", "r9", "lr");
+}
+
+int
+main (void)
+{
+ int ret;
+
+ __asm volatile ("mov\tr4, #0xf4\n\t"
+ "mov\tr5, #0xf5\n\t"
+ "mov\tr6, #0xf6\n\t"
+ "mov\tr7, #0xf7\n\t"
+ "mov\tr0, #0xf8\n\t"
+ "mov\tr8, r0\n\t"
+ "mov\tr0, #0xfa\n\t"
+ "mov\tr10, r0"
+ : : : "r0", "r4", "r5", "r6", "r7", "r8", "r10");
+
+ clobber_lr_and_highregs ();
+
+ __asm volatile ("cmp\tr4, #0xf4\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr5, #0xf5\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr6, #0xf6\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr7, #0xf7\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r8\n\t"
+ "cmp\tr0, #0xf8\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r10\n\t"
+ "cmp\tr0, #0xfa\n\t"
+ "bne\tfail\n\t"
+ "mov\t%0, #1\n"
+ "fail:\n\t"
+ "sub\tr0, #1"
+ : "=r" (ret) : :);
+ return ret;
+}
diff --git a/gcc/testsuite/gcc.target/arm/pr77933-2.c b/gcc/testsuite/gcc.target/arm/pr77933-2.c
new file mode 100644
index 0000000..9028c4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr77933-2.c
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { ! { arm_thumb1_ok || arm_thumb2_ok } } } */
+/* { dg-options "-mthumb -O2 -mtpcs-leaf-frame" } */
+
+__attribute__ ((noinline, noclone)) void
+clobber_lr_and_highregs (void)
+{
+ __asm__ volatile ("" : : : "r8", "r9", "lr");
+}
+
+int
+main (void)
+{
+ int ret;
+
+ __asm volatile ("mov\tr4, #0xf4\n\t"
+ "mov\tr5, #0xf5\n\t"
+ "mov\tr6, #0xf6\n\t"
+ "mov\tr7, #0xf7\n\t"
+ "mov\tr0, #0xf8\n\t"
+ "mov\tr8, r0\n\t"
+ "mov\tr0, #0xfa\n\t"
+ "mov\tr10, r0"
+ : : : "r0", "r4", "r5", "r6", "r7", "r8", "r10");
+
+ clobber_lr_and_highregs ();
+
+ __asm volatile ("cmp\tr4, #0xf4\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr5, #0xf5\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr6, #0xf6\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr7, #0xf7\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r8\n\t"
+ "cmp\tr0, #0xf8\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r10\n\t"
+ "cmp\tr0, #0xfa\n\t"
+ "bne\tfail\n\t"
+ "mov\t%0, #1\n"
+ "fail:\n\t"
+ "sub\tr0, #1"
+ : "=r" (ret) : :);
+ return ret;
+}