Treat the user defined stack protect guard, __stack_chk_guard, as an
internal C/C++ symbol and declare __stack_chk_guard as a size_t variable
if size_t has the same size as pointer.  If a user defined variable name
is the same as the stack protect guard, use the predefined stack protect
guard declaration and apply its visibility attribute to the internal
__stack_chk_guard symbol.

gcc/

        PR c/121911
        * targhooks.cc (default_stack_protect_guard): Use size_type_node
        if it has the same size as ptr_type_node.
        * varasm.cc (mark_stack_protect_guard_decl_local): New.
        * varasm.h (mark_stack_protect_guard_decl_local): Likewise.

gcc/c-family/

        PR c/121911
        * c-attribs.cc (handle_visibility_attribute): Call
        mark_stack_protect_guard_decl_local as local for non-default
        visibility.

gcc/c/

        PR c/121911
        * c-decl.cc (grokdeclarator): If the variable name is the same
        as the stack protect guard, use the stack protect guard decl.

gcc/cp/

        PR c/121911
        * decl.cc (grokdeclarator): If the variable name is the same as
        the stack protect guard, use the stack protect guard decl.

gcc/testsuite/

        PR c/121911
        * g++.target/i386/ssp-global-hidden-1.C: New test.
        * g++.target/i386/ssp-global-hidden-2.C: Likewise.
        * gcc.target/i386/ssp-global-hidden-1.c: Likewise.
        * gcc.target/i386/ssp-global-hidden-2.c: Likewise.

Signed-off-by: H.J. Lu <hjl.to...@gmail.com>
---
 gcc/c-family/c-attribs.cc                     |  5 +++
 gcc/c/c-decl.cc                               | 16 +++++++
 gcc/cp/decl.cc                                | 15 +++++++
 gcc/targhooks.cc                              |  7 ++-
 .../g++.target/i386/ssp-global-hidden-1.C     | 45 +++++++++++++++++++
 .../g++.target/i386/ssp-global-hidden-2.C     | 19 ++++++++
 .../gcc.target/i386/ssp-global-hidden-1.c     | 45 +++++++++++++++++++
 .../gcc.target/i386/ssp-global-hidden-2.c     | 19 ++++++++
 gcc/varasm.cc                                 | 12 +++++
 gcc/varasm.h                                  |  1 +
 10 files changed, 183 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.target/i386/ssp-global-hidden-1.C
 create mode 100644 gcc/testsuite/g++.target/i386/ssp-global-hidden-2.C
 create mode 100644 gcc/testsuite/gcc.target/i386/ssp-global-hidden-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/ssp-global-hidden-2.c

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 1e3a94ed949..8d76e81bf98 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -3652,6 +3652,11 @@ handle_visibility_attribute (tree *node, tree name, tree 
args,
   DECL_VISIBILITY (decl) = vis;
   DECL_VISIBILITY_SPECIFIED (decl) = 1;
 
+  /* Mark the symbol of DECL for non-default visibility as local if it
+     is the stack protect guard decl.  */
+  if (flag_stack_protect && vis != VISIBILITY_DEFAULT)
+    mark_stack_protect_guard_decl_local (decl);
+
   /* Go ahead and attach the attribute to the node as well.  This is needed
      so we can determine whether we have VISIBILITY_DEFAULT because the
      visibility was not specified, or because it was explicitly overridden
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b122e82bfc4..89885593acc 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8106,6 +8106,22 @@ grokdeclarator (const struct c_declarator *declarator,
     else
       {
        /* It's a variable.  */
+
+       if (flag_stack_protect)
+         {
+           /* If the variable name is the same as the stack protect
+              guard, use the stack protect guard decl.  */
+           tree guard_decl = targetm.stack_protect_guard ();
+           if (guard_decl && VAR_P (guard_decl))
+             {
+               const char *stack_protect_guard_name
+                 = IDENTIFIER_POINTER (DECL_NAME (guard_decl));
+               if (strcmp (stack_protect_guard_name,
+                           IDENTIFIER_POINTER (declarator->u.id.id)) == 0)
+                 return guard_decl;
+             }
+         }
+
        /* An uninitialized decl with `extern' is a reference.  */
        int extern_ref = !initialized && storage_class == csc_extern;
 
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a6a98426ed9..2e6e935bcc9 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -16233,6 +16233,21 @@ grokdeclarator (const cp_declarator *declarator,
       {
        /* It's a variable.  */
 
+       if (flag_stack_protect && dname && identifier_p (dname))
+         {
+           /* If the variable name is the same as the stack protect
+              guard, use the stack protect guard decl.  */
+           tree guard_decl = targetm.stack_protect_guard ();
+           if (guard_decl && VAR_P (guard_decl))
+             {
+               const char *stack_protect_guard_name
+                 = IDENTIFIER_POINTER (DECL_NAME (guard_decl));
+               if (strcmp (stack_protect_guard_name,
+                           IDENTIFIER_POINTER (unqualified_id)) == 0)
+                 return guard_decl;
+             }
+         }
+
        /* An uninitialized decl with `extern' is a reference.  */
        decl = grokvardecl (type, dname, unqualified_id,
                            declspecs,
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 947e39aedc1..fc24a6fd488 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -924,9 +924,14 @@ default_stack_protect_guard (void)
     {
       rtx x;
 
+      /* __stack_chk_guard is treated as an internal C/C++ symbol.  Use
+        size_type_node if it has the same size as ptr_type_node since
+        __stack_chk_guard can be initialized as an integer.  */
       t = build_decl (UNKNOWN_LOCATION,
                      VAR_DECL, get_identifier ("__stack_chk_guard"),
-                     ptr_type_node);
+                     (TYPE_PRECISION (size_type_node)
+                      == TYPE_PRECISION (ptr_type_node)
+                      ? size_type_node : ptr_type_node));
       TREE_STATIC (t) = 1;
       TREE_PUBLIC (t) = 1;
       DECL_EXTERNAL (t) = 1;
diff --git a/gcc/testsuite/g++.target/i386/ssp-global-hidden-1.C 
b/gcc/testsuite/g++.target/i386/ssp-global-hidden-1.C
new file mode 100644
index 00000000000..2f7a554ccbd
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-hidden-1.C
@@ -0,0 +1,45 @@
+/* { dg-do run { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all 
-mstack-protector-guard=global -save-temps" } */
+
+#include <stdlib.h>
+#include <stddef.h>
+
+__attribute__ ((visibility ("hidden")))
+#ifdef __LP64__
+const size_t __stack_chk_guard = 0x2d853605a4d9a09cUL;
+#else
+const size_t __stack_chk_guard = 0xdd2cc927UL;
+#endif
+
+extern "C" void
+__stack_chk_fail (void)
+{
+  exit (0); /* pass */
+}
+
+__attribute__ ((noipa))
+void
+smash (char *p, int i)
+{
+  p[i] = 42;
+}
+
+int
+main (void)
+{
+  char foo[255];
+
+   /* smash stack */
+  for (int i = 0; i <= 400; i++)
+    smash (foo, i);
+
+  return 1;
+}
+
+/* { dg-final { scan-hidden "__stack_chk_guard" } } */
+/* { dg-final { scan-assembler "__stack_chk_guard\\(%rip\\)" { target { ! ia32 
} } } } */
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOTPCREL" { target { ! 
ia32 } } } } */
+  /* { dg-final { scan-assembler ".quad        3280087301477736604" { target { 
lp64 } } } } */
+/* { dg-final { scan-assembler "__stack_chk_guard@GOTOFF" { target ia32 } } } 
*/
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOT\\(" { target ia32 } 
} } */
+  /* { dg-final { scan-assembler ".long        -584267481" { target { ! lp64 } 
} } } */
diff --git a/gcc/testsuite/g++.target/i386/ssp-global-hidden-2.C 
b/gcc/testsuite/g++.target/i386/ssp-global-hidden-2.C
new file mode 100644
index 00000000000..845cf550eb9
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-hidden-2.C
@@ -0,0 +1,19 @@
+/* { dg-do compile { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all 
-mstack-protector-guard=global" } */
+
+#include <stddef.h>
+
+__attribute__ ((visibility ("hidden")))
+extern const size_t __stack_chk_guard;
+
+void
+smash (char *p, int i)
+{
+  p[i] = 42;
+}
+
+/* { dg-final { scan-hidden "__stack_chk_guard" } } */
+/* { dg-final { scan-assembler "__stack_chk_guard\\(%rip\\)" { target { ! ia32 
} } } } */
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOTPCREL" { target { ! 
ia32 } } } } */
+/* { dg-final { scan-assembler "__stack_chk_guard@GOTOFF" { target ia32 } } } 
*/
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOT\\(" { target ia32 } 
} } */
diff --git a/gcc/testsuite/gcc.target/i386/ssp-global-hidden-1.c 
b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-1.c
new file mode 100644
index 00000000000..cf6af3971d7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-1.c
@@ -0,0 +1,45 @@
+/* { dg-do run { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all 
-mstack-protector-guard=global -save-temps" } */
+
+#include <stdlib.h>
+#include <stddef.h>
+
+__attribute__ ((visibility ("hidden")))
+#ifdef __LP64__
+const size_t __stack_chk_guard = 0x2d853605a4d9a09cUL;
+#else
+const size_t __stack_chk_guard = 0xdd2cc927UL;
+#endif
+
+void
+__stack_chk_fail (void)
+{
+  exit (0); /* pass */
+}
+
+__attribute__ ((noipa))
+void
+smash (char *p, int i)
+{
+  p[i] = 42;
+}
+
+int
+main (void)
+{
+  char foo[255];
+
+   /* smash stack */
+  for (int i = 0; i <= 400; i++)
+    smash (foo, i);
+
+  return 1;
+}
+
+/* { dg-final { scan-hidden "__stack_chk_guard" } } */
+/* { dg-final { scan-assembler "__stack_chk_guard\\(%rip\\)" { target { ! ia32 
} } } } */
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOTPCREL" { target { ! 
ia32 } } } } */
+  /* { dg-final { scan-assembler ".quad        3280087301477736604" { target { 
lp64 } } } } */
+/* { dg-final { scan-assembler "__stack_chk_guard@GOTOFF" { target ia32 } } } 
*/
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOT\\(" { target ia32 } 
} } */
+  /* { dg-final { scan-assembler ".long        -584267481" { target { ! lp64 } 
} } } */
diff --git a/gcc/testsuite/gcc.target/i386/ssp-global-hidden-2.c 
b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-2.c
new file mode 100644
index 00000000000..845cf550eb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all 
-mstack-protector-guard=global" } */
+
+#include <stddef.h>
+
+__attribute__ ((visibility ("hidden")))
+extern const size_t __stack_chk_guard;
+
+void
+smash (char *p, int i)
+{
+  p[i] = 42;
+}
+
+/* { dg-final { scan-hidden "__stack_chk_guard" } } */
+/* { dg-final { scan-assembler "__stack_chk_guard\\(%rip\\)" { target { ! ia32 
} } } } */
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOTPCREL" { target { ! 
ia32 } } } } */
+/* { dg-final { scan-assembler "__stack_chk_guard@GOTOFF" { target ia32 } } } 
*/
+/* { dg-final { scan-assembler-not "__stack_chk_guard@GOT\\(" { target ia32 } 
} } */
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
index 0d78f5b384f..5b54293dc1e 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -2920,6 +2920,18 @@ mark_decl_referenced (tree decl)
      which do not need to be marked.  */
 }
 
+/* Mark the symbol of DECL as local if it is the stack protect guard
+   decl.  */
+
+void
+mark_stack_protect_guard_decl_local (tree decl)
+{
+  if (decl != targetm.stack_protect_guard ())
+    return;
+  rtx symbol = DECL_RTL (decl);
+  symbol = XEXP (symbol, 0);
+  SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
+}
 
 /* Output to FILE (an assembly file) a reference to NAME.  If NAME
    starts with a *, the rest of NAME is output verbatim.  Otherwise
diff --git a/gcc/varasm.h b/gcc/varasm.h
index fc31c1bbf65..33171999496 100644
--- a/gcc/varasm.h
+++ b/gcc/varasm.h
@@ -41,6 +41,7 @@ extern void process_pending_assemble_externals (void);
 extern bool decl_replaceable_p (tree, bool);
 extern bool decl_binds_to_current_def_p (const_tree);
 extern enum tls_model decl_default_tls_model (const_tree);
+extern void mark_stack_protect_guard_decl_local (tree);
 
 /* Declare DECL to be a weak symbol.  */
 extern void declare_weak (tree);
-- 
2.51.0

Reply via email to