FRAME_GROWS_DOWNWARD was left commented out in alpha.h, so it defaulted
to 0 and -fstack-protector was rejected outright:

    cc1: warning: '-fstack-protector' not supported for this target

The stack protector needs a downward-growing frame.  cfgexpand allocates
the canary slot before it reorders the local arrays, so with an
upward-growing frame the canary would land below the buffers it is meant
to guard.  Define FRAME_GROWS_DOWNWARD when the stack protector is in
use, as rs6000 and xtensa do, and resolve the soft frame pointer to the
high end of the local variables in that case.

Default code generation is unaffected: FRAME_GROWS_DOWNWARD is zero
whenever flag_stack_protect is zero.  Compiling gcc.c-torture/compile
with and without this change at -O0 and at -O2 gives byte-identical
assembly for all 1625 files.

glibc already provides everything the generic expansion needs on Alpha:
__stack_chk_guard from ld.so and __stack_chk_fail from libc, both since
GLIBC_2.4.  There is no TCB stack guard on Alpha, so no
-mstack-protector-guard= option is added.

The OpenVMS elimination offsets get the same treatment for consistency,
but that path is untested.

gcc/ChangeLog:

        * config/alpha/alpha.h (FRAME_GROWS_DOWNWARD): Define.
        * config/alpha/alpha.cc (alpha_initial_elimination_offset): Resolve
        FRAME_POINTER_REGNUM to the high end of the local variables when
        FRAME_GROWS_DOWNWARD.
        (alpha_vms_initial_elimination_offset): Likewise.

gcc/testsuite/ChangeLog:

        * gcc.dg/fstack-protector-strong.c: Run on alpha*-*-*.  Expect
        twice as many stack_chk_fail matches there, since Alpha names the
        callee once for !literal and once for !lituse_jsr.
---
 gcc/config/alpha/alpha.cc                     | 19 ++++++++++++++++---
 gcc/config/alpha/alpha.h                      |  9 +++++++--
 .../gcc.dg/fstack-protector-strong.c          |  7 +++++--
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git ./gcc/config/alpha/alpha.cc ./gcc/config/alpha/alpha.cc
index be5e1776150..e80844ed853 100644
--- ./gcc/config/alpha/alpha.cc
+++ ./gcc/config/alpha/alpha.cc
@@ -8072,7 +8072,12 @@ alpha_initial_elimination_offset (unsigned int from,
   switch (from)
     {
     case FRAME_POINTER_REGNUM:
-      break;
+      /* With a downward-growing frame the frame pointer sits at the high
+        end of the local variables, which is where the argument pointer
+        is too.  */
+      if (!FRAME_GROWS_DOWNWARD)
+       break;
+      /* FALLTHRU */
 
     case ARG_POINTER_REGNUM:
       ret += (ALPHA_ROUND (get_frame_size ()
@@ -8157,8 +8162,16 @@ alpha_vms_initial_elimination_offset (unsigned int from, 
unsigned int to)
     switch (from)
       {
       case FRAME_POINTER_REGNUM:
-       offset = ALPHA_ROUND (sa_size + pv_save_size);
-       break;
+       /* With a downward-growing frame the frame pointer sits at the high
+          end of the local variables, which is where the argument pointer
+          is too.  */
+       if (!FRAME_GROWS_DOWNWARD)
+         {
+           offset = ALPHA_ROUND (sa_size + pv_save_size);
+           break;
+         }
+       /* FALLTHRU */
+
       case ARG_POINTER_REGNUM:
        offset = (ALPHA_ROUND (sa_size + pv_save_size
                               + get_frame_size ()
diff --git ./gcc/config/alpha/alpha.h ./gcc/config/alpha/alpha.h
index 1a1abfe99b4..678af6d212e 100644
--- ./gcc/config/alpha/alpha.h
+++ ./gcc/config/alpha/alpha.h
@@ -479,8 +479,13 @@ enum reg_class {
 /* Define this to nonzero if the nominal address of the stack frame
    is at the high-address end of the local variables;
    that is, each additional local variable allocated
-   goes at a more negative offset in the frame.  */
-/* #define FRAME_GROWS_DOWNWARD 0 */
+   goes at a more negative offset in the frame.
+
+   The stack protector requires that the canary be placed above the
+   local arrays it protects, which only happens with a downward-growing
+   frame.  Alpha otherwise grows the frame upward, so switch the
+   direction only when the stack protector is in use.  */
+#define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0)
 
 /* If we generate an insn to push BYTES bytes,
    this says how many the stack pointer really advances by.
diff --git ./gcc/testsuite/gcc.dg/fstack-protector-strong.c 
./gcc/testsuite/gcc.dg/fstack-protector-strong.c
index 52485b5252d..306aa905ef4 100644
--- ./gcc/testsuite/gcc.dg/fstack-protector-strong.c
+++ ./gcc/testsuite/gcc.dg/fstack-protector-strong.c
@@ -1,6 +1,6 @@
 /* Test that stack protection is done on chosen functions. */
 
-/* { dg-do compile { target i?86-*-* x86_64-*-* rs6000-*-* s390x-*-* } } */
+/* { dg-do compile { target alpha*-*-* i?86-*-* x86_64-*-* rs6000-*-* 
s390x-*-* } } */
 /* { dg-options "-O2 -fstack-protector-strong" } */
 
 /* This test checks the presence of __stack_chk_fail function in assembler.
@@ -156,4 +156,7 @@ void foo12 ()
   global3 ();
 }
 
-/* { dg-final { scan-assembler-times "stack_chk_fail" 12 } } */
+/* { dg-final { scan-assembler-times "stack_chk_fail" 12 { target { ! 
alpha*-*-* } } } } */
+/* Alpha names the callee twice per call, once for !literal and once for
+   !lituse_jsr.  */
+/* { dg-final { scan-assembler-times "stack_chk_fail" 24 { target alpha*-*-* } 
} } */
-- 
2.54.0

Reply via email to