]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix PR77933: stack corruption on ARM when using high registers and LR
authorThomas Preud'homme <thomas.preudhomme@arm.com>
Tue, 13 Dec 2016 09:39:02 +0000 (09:39 +0000)
committerThomas Preud'homme <thopre01@gcc.gnu.org>
Tue, 13 Dec 2016 09:39:02 +0000 (09:39 +0000)
2016-12-13  Thomas Preud'homme  <thomas.preudhomme@arm.com>

    Backport from mainline
    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: r243600

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/pr77933-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/pr77933-2.c [new file with mode: 0644]

index a6b3df545cdecc8d185ad5ece3b208bb9df5629f..43277e0e6504cc40c72818ac1f9c94f2bd36714c 100644 (file)
@@ -1,3 +1,14 @@
+2016-12-13  Thomas Preud'homme  <thomas.preudhomme@arm.com>
+
+       Backport from mainline
+       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-12-12  Bernd Schmidt  <bschmidt@redhat.com>
 
        Backport from mainline
index c01a3c878968f6e6f07358b0686e4a59e34f56b7..5c975625bfa25d2c71c27db348cd3e70fe44a951 100644 (file)
@@ -24457,6 +24457,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 ();
 
@@ -24479,6 +24480,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;
@@ -24545,6 +24547,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;
        }
@@ -24609,12 +24612,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)
@@ -24632,7 +24636,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);
@@ -24640,8 +24646,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))
                {
@@ -24650,6 +24657,7 @@ thumb1_expand_prologue (void)
 
                  high_regs_pushed --;
                  real_regs_mask |= (1 << next_hi_reg);
+                 push_mask |= (1 << regno);
 
                  if (high_regs_pushed)
                    {
@@ -24659,23 +24667,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;
        }
     }
index f09906befb99485bc44acc018b2e8e3718738e72..a608091529583b5c52d69a7fbf03d395bb6e0bc7 100644 (file)
@@ -1,3 +1,12 @@
+2016-12-13  Thomas Preud'homme  <thomas.preudhomme@arm.com>
+
+       Backport from mainline
+       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-12-12  Bernd Schmidt  <bschmidt@redhat.com>
 
        Backport from mainline
diff --git a/gcc/testsuite/gcc.target/arm/pr77933-1.c b/gcc/testsuite/gcc.target/arm/pr77933-1.c
new file mode 100644 (file)
index 0000000..95cf68e
--- /dev/null
@@ -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 (file)
index 0000000..9028c4f
--- /dev/null
@@ -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;
+}