On Tue, Sep 23, 2025 at 2:22 PM Florian Weimer <[email protected]> wrote:
>
> * H. J. Lu:
>
> >> It seems to me this goes in the wrong direction: guard_decl doesn't have
> >> proper location information, so any subsequent diagnostics against it
> >> will look wrong.  I would expect this to be more like the re-declaration
> >
> > It looks normal to me:
> >
> > [hjl@gnu-zen4-1 pr121911]$ cat bad.c
> > extern const int __stack_chk_guard;
> > [hjl@gnu-zen4-1 pr121911]$ make bad.s
> > /export/build/gnu/tools-build/gcc-gitlab-debug/build-x86_64-linux/gcc/xgcc
> > -B/export/build/gnu/tools-build/gcc-gitlab-debug/build-x86_64-linux/gcc/
> > -O0 -g -fPIC -fstack-protector-all -mstack-protector-guard=global -S
> > bad.c
> > bad.c:1:1: error: conflicting types for __stack_chk_guard; have ‘int’,
> > should be ‘long unsigned int’
> >     1 | extern const int __stack_chk_guard;
> >       | ^~~~~~
> > make: *** [Makefile:43: bad.s] Error 1
> > [hjl@gnu-zen4-1 pr121911]$
>
> This:
>
> extern const char *__stack_chk_guard;
> char
> f (void)
> {
>   return *__stack_chk_guard;
> }
>
> gives:
>
> t.c: In function ‘f’:
> t.c:5:10: error: invalid type argument of unary ‘*’ (have ‘long unsigned int’)
>     5 |   return *__stack_chk_guard;
>       |          ^~~~~~~~~~~~~~~~~~
>
> This doesn't look quite right to me.
>

Here is the v3 patch:

$ cat bad2.c
extern const char *__stack_chk_guard;
char
f (void)
{
  return *__stack_chk_guard;
}
$ make bad2.s
/export/build/gnu/tools-build/gcc-gitlab-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-gitlab-debug/build-x86_64-linux/gcc/
-O0 -g -fPIC -fstack-protector-all -mstack-protector-guard=global -S
bad2.c
bad2.c:1:1: error: conflicting types for __stack_chk_guard; have
‘const char *’, should be ‘long unsigned int’
    1 | extern const char *__stack_chk_guard;
      | ^~~~~~
make: *** [Makefile:43: bad2.s] Error 1
$

-- 
H.J.
From 2404c5f460a63b42197305f6c558830ff420b1c7 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Fri, 12 Sep 2025 18:52:39 -0700
Subject: [PATCH v3] c/c++: Treat stack protection guard as an internal symbol

Add a new target hook, stack_protect_guard_symbol, to support a user
provided the stack protection guard:

1. Treat the stack protect guard as an internal C/C++ symbol.
2. If not nullptr, use the stack_protect_guard_symbol hook as the stack
protect guard symbol.
3. Declare the stack protection guard as a size_t variable if size_t has
the same size as pointer so that the guard symbol can be initialized as
an integer.
4. If a user declared variable name is the same as the target hook,
stack_protect_guard_symbol, use the internal stack protect guard
declaration and apply its visibility attribute to the internal stack
protect guard declaration.
5. Define the __stack_protection_guard_is_internal_symbol__ macro if
the target hook, stack_protect_guard_symbol, isn't nullptr to indicate
that the stack protection guard is treated as an internal symbol.

gcc/

	PR c/121911
	* target.def (stack_protect_guard_symbol): New target hook.
	* targhooks.cc (default_stack_protect_guard): Use
	targetm.stack_protect_guard_symbol if it isn't nullptr.  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.
	* config/i386/i386.cc (TARGET_STACK_PROTECT_GUARD_SYMBOL):
	Likewise.
	* doc/tm.texi: Regenerated.
	* doc/tm.texi.in (TARGET_STACK_PROTECT_GUARD_SYMBOL): New.

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.
	* c-cppbuiltin.cc (c_cpp_builtins): Define the
	__stack_protection_guard_is_internal_symbol__ macro if
	targetm.stack_protect_guard_symbol isn't nullptr.

gcc/c/

	PR c/121911
	* c-decl.cc (duplicate_decls): Don't free the stack protect guard
	decl.
	(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 (duplicate_decls): Don't free the stack protect guard
	decl.
	(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-1.C: New test.
	* g++.target/i386/ssp-global-2.C: Likewise.
	* g++.target/i386/ssp-global-3.C: Likewise.
	* g++.target/i386/ssp-global-4.C: Likewise.
	* g++.target/i386/ssp-global-hidden-1.C: Likewise.
	* g++.target/i386/ssp-global-hidden-2.C: Likewise.
	* g++.target/i386/ssp-global-hidden-3.C: Likewise.
	* gcc.target/i386/ssp-global-2.c: Likewise.
	* gcc.target/i386/ssp-global-3.c: Likewise.
	* gcc.target/i386/ssp-global-4.c: Likewise.
	* gcc.target/i386/ssp-global-hidden-1.c: Likewise.
	* gcc.target/i386/ssp-global-hidden-2.c: Likewise.
	* gcc.target/i386/ssp-global-hidden-3.c: Likewise.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/c-family/c-attribs.cc                     |  5 ++
 gcc/c-family/c-cppbuiltin.cc                  |  7 +++
 gcc/c/c-decl.cc                               | 32 +++++++++++-
 gcc/config/i386/i386.cc                       |  3 ++
 gcc/cp/decl.cc                                | 31 +++++++++++-
 gcc/doc/tm.texi                               |  6 +++
 gcc/doc/tm.texi.in                            |  2 +
 gcc/target.def                                |  9 ++++
 gcc/targhooks.cc                              | 18 ++++++-
 gcc/testsuite/g++.target/i386/ssp-global-1.C  | 35 +++++++++++++
 gcc/testsuite/g++.target/i386/ssp-global-2.C  | 35 +++++++++++++
 gcc/testsuite/g++.target/i386/ssp-global-3.C  | 10 ++++
 gcc/testsuite/g++.target/i386/ssp-global-4.C  | 10 ++++
 .../g++.target/i386/ssp-global-hidden-1.C     | 49 ++++++++++++++++++
 .../g++.target/i386/ssp-global-hidden-2.C     | 20 ++++++++
 .../g++.target/i386/ssp-global-hidden-3.C     | 50 +++++++++++++++++++
 gcc/testsuite/gcc.target/i386/ssp-global-2.c  | 35 +++++++++++++
 gcc/testsuite/gcc.target/i386/ssp-global-3.c  | 10 ++++
 gcc/testsuite/gcc.target/i386/ssp-global-4.c  | 10 ++++
 .../gcc.target/i386/ssp-global-hidden-1.c     | 49 ++++++++++++++++++
 .../gcc.target/i386/ssp-global-hidden-2.c     | 20 ++++++++
 .../gcc.target/i386/ssp-global-hidden-3.c     | 50 +++++++++++++++++++
 gcc/varasm.cc                                 | 13 +++++
 gcc/varasm.h                                  |  1 +
 24 files changed, 506 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/i386/ssp-global-1.C
 create mode 100644 gcc/testsuite/g++.target/i386/ssp-global-2.C
 create mode 100644 gcc/testsuite/g++.target/i386/ssp-global-3.C
 create mode 100644 gcc/testsuite/g++.target/i386/ssp-global-4.C
 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/g++.target/i386/ssp-global-hidden-3.C
 create mode 100644 gcc/testsuite/gcc.target/i386/ssp-global-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/ssp-global-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/ssp-global-4.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
 create mode 100644 gcc/testsuite/gcc.target/i386/ssp-global-hidden-3.c

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 1e3a94ed949..9326eb2c1b8 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 (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-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index 6b22f9e60b1..d4c64646525 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -1191,6 +1191,13 @@ c_cpp_builtins (cpp_reader *pfile)
 	cpp_define (pfile, "__cpp_exceptions=199711L");
     }
 
+  if (targetm.stack_protect_guard_symbol != nullptr)
+    {
+      /* Define this to indicate that the stack protection guard is
+	 treated as an internal symbol.  */
+      cpp_define (pfile, "__stack_protection_guard_is_internal_symbol__");
+    }
+
   /* Represents the C++ ABI version, always defined so it can be used while
      preprocessing C and assembler.  */
   if (flag_abi_version == 0)
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b122e82bfc4..76550a1f732 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -3199,7 +3199,10 @@ duplicate_decls (tree newdecl, tree olddecl)
       if (snode)
 	snode->remove ();
     }
-  ggc_free (newdecl);
+  /* Don't free the stack protect guard decl.  */
+  if (targetm.stack_protect_guard_symbol == nullptr
+      || newdecl != targetm.stack_protect_guard ())
+    ggc_free (newdecl);
   return true;
 }
 
@@ -8106,6 +8109,33 @@ grokdeclarator (const struct c_declarator *declarator,
     else
       {
 	/* It's a variable.  */
+
+	const char *stack_protect_guard_name
+	  = targetm.stack_protect_guard_symbol;
+	if (stack_protect_guard_name)
+	  {
+	    /* 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)
+		&& strcmp (stack_protect_guard_name,
+			   IDENTIFIER_POINTER (declarator->u.id.id)) == 0)
+	      {
+		/* Allow different integer types with the same size.  */
+		tree guard_type = TREE_TYPE (guard_decl);
+		if (TYPE_CANONICAL (type) == TYPE_CANONICAL (guard_type)
+		    || (TREE_CODE (type) == INTEGER_TYPE
+			&& TREE_CODE (guard_type) == INTEGER_TYPE
+			&& (TYPE_PRECISION (type)
+			    == TYPE_PRECISION (guard_type))))
+		  return guard_decl;
+
+		error ("conflicting types for %s; have %qT, should be %qT",
+		       stack_protect_guard_name, type, guard_type);
+	      }
+	  }
+
 	/* An uninitialized decl with `extern' is a reference.  */
 	int extern_ref = !initialized && storage_class == csc_extern;
 
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 5ef7c315091..da651f6a15f 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -28152,6 +28152,9 @@ ix86_libgcc_floating_mode_supported_p
 #undef TARGET_STACK_PROTECT_GUARD
 #define TARGET_STACK_PROTECT_GUARD ix86_stack_protect_guard
 
+#undef TARGET_STACK_PROTECT_GUARD_SYMBOL
+#define TARGET_STACK_PROTECT_GUARD_SYMBOL "__stack_chk_guard"
+
 #undef TARGET_STACK_PROTECT_RUNTIME_ENABLED_P
 #define TARGET_STACK_PROTECT_RUNTIME_ENABLED_P \
   ix86_stack_protect_runtime_enabled_p
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a6a98426ed9..73e996db763 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -3388,7 +3388,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
   if (modules_p ())
     remove_defining_module (newdecl);
 
-  ggc_free (newdecl);
+  /* Don't free the stack protect guard decl.  */
+  if (targetm.stack_protect_guard_symbol == nullptr
+      || newdecl != targetm.stack_protect_guard ())
+    ggc_free (newdecl);
 
   return olddecl;
 }
@@ -16233,6 +16236,32 @@ grokdeclarator (const cp_declarator *declarator,
       {
 	/* It's a variable.  */
 
+	const char *stack_protect_guard_name
+	  = targetm.stack_protect_guard_symbol;
+	if (stack_protect_guard_name && 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)
+		&& strcmp (stack_protect_guard_name,
+			   IDENTIFIER_POINTER (unqualified_id)) == 0)
+	      {
+		/* Allow different integer types with the same size.  */
+		tree guard_type = TREE_TYPE (guard_decl);
+		if (TYPE_CANONICAL (type) == TYPE_CANONICAL (guard_type)
+		    || (TREE_CODE (type) == INTEGER_TYPE
+			&& TREE_CODE (guard_type) == INTEGER_TYPE
+			&& (TYPE_PRECISION (type)
+			    == TYPE_PRECISION (guard_type))))
+		  return guard_decl;
+
+		error ("conflicting types for %s; have %qT, should be %qT",
+		       stack_protect_guard_name, type, guard_type);
+	      }
+	  }
+
 	/* An uninitialized decl with `extern' is a reference.  */
 	decl = grokvardecl (type, dname, unqualified_id,
 			    declspecs,
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index b80e6846dd7..e731e611494 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -5399,6 +5399,12 @@ The default version of this hook creates a variable called
 @samp{__stack_chk_guard}, which is normally defined in @file{libgcc2.c}.
 @end deftypefn
 
+@deftypevr {Target Hook} {const char *} TARGET_STACK_PROTECT_GUARD_SYMBOL
+Usually, the compiler uses an external variable @samp{__stack_chk_guard}
+defined in @file{libgcc2.c} as the stack protection guard symbol.  Define
+this macro to a user provided string for the stack protection guard symbol.
+@end deftypevr
+
 @deftypefn {Target Hook} tree TARGET_STACK_PROTECT_FAIL (void)
 This hook returns a @code{CALL_EXPR} that alerts the runtime that the
 stack protect guard variable has been modified.  This expression should
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index c3ed9a9fd7c..7c6c478fe39 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -3799,6 +3799,8 @@ generic code.
 
 @hook TARGET_STACK_PROTECT_GUARD
 
+@hook TARGET_STACK_PROTECT_GUARD_SYMBOL
+
 @hook TARGET_STACK_PROTECT_FAIL
 
 @hook TARGET_STACK_PROTECT_RUNTIME_ENABLED_P
diff --git a/gcc/target.def b/gcc/target.def
index d4fd3b46a7d..8466400d2d0 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4595,6 +4595,15 @@ The default version of this hook creates a variable called\n\
  tree, (void),
  default_stack_protect_guard)
 
+/* Nonnull if the target supports a user defined symbol as the stack
+   protection guard.  */
+DEFHOOKPOD
+(stack_protect_guard_symbol,
+ "Usually, the compiler uses an external variable @samp{__stack_chk_guard}\n\
+defined in @file{libgcc2.c} as the stack protection guard symbol.  Define\n\
+this macro to a user provided string for the stack protection guard symbol.",
+ const char *, nullptr)
+
 /* This target hook allows the operating system to override the CALL_EXPR
    that is invoked when a check vs the guard variable fails.  */
 DEFHOOK
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 947e39aedc1..daae43938c9 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -924,9 +924,23 @@ default_stack_protect_guard (void)
     {
       rtx x;
 
+      /* If not nullptr, targetm.stack_protect_guard_symbol is treated
+	 as an internal C/C++ symbol defined by user.  Use size_type_node
+	 if it has the same size as ptr_type_node so that the guard symbol
+	 can be initialized as an integer.  */
+      const char *guard_symbol = targetm.stack_protect_guard_symbol;
+      t = ptr_type_node;
+      if (guard_symbol != nullptr)
+	{
+	  if (TYPE_PRECISION (size_type_node)
+	      == TYPE_PRECISION (ptr_type_node))
+	    t = size_type_node;
+	}
+      else
+	guard_symbol = "__stack_chk_guard";
+      gcc_assert (guard_symbol != NULL);
       t = build_decl (UNKNOWN_LOCATION,
-		      VAR_DECL, get_identifier ("__stack_chk_guard"),
-		      ptr_type_node);
+		      VAR_DECL, get_identifier (guard_symbol), t);
       TREE_STATIC (t) = 1;
       TREE_PUBLIC (t) = 1;
       DECL_EXTERNAL (t) = 1;
diff --git a/gcc/testsuite/g++.target/i386/ssp-global-1.C b/gcc/testsuite/g++.target/i386/ssp-global-1.C
new file mode 100644
index 00000000000..086a0a1d9ae
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-1.C
@@ -0,0 +1,35 @@
+/* { dg-do run { target fstack_protector } } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+#include <stdlib.h>
+
+#ifdef __LP64__
+const unsigned long int __stack_chk_guard = 0x2d853605a4d9a09cUL;
+#else
+const unsigned long int __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;
+}
diff --git a/gcc/testsuite/g++.target/i386/ssp-global-2.C b/gcc/testsuite/g++.target/i386/ssp-global-2.C
new file mode 100644
index 00000000000..9ae28f554c9
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-2.C
@@ -0,0 +1,35 @@
+/* { dg-do run { target fstack_protector } } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+#include <stdlib.h>
+
+#ifdef __LP64__
+long int __stack_chk_guard = 0x2d853605a4d9a09cUL;
+#else
+int __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;
+}
diff --git a/gcc/testsuite/g++.target/i386/ssp-global-3.C b/gcc/testsuite/g++.target/i386/ssp-global-3.C
new file mode 100644
index 00000000000..bc1ce57eee4
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-3.C
@@ -0,0 +1,10 @@
+/* { dg-do compile { target fstack_protector } } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+extern char *__stack_chk_guard; /* { dg-error "conflicting types for __stack_chk_guard;" } */
+
+char
+foo (void)
+{
+  return *__stack_chk_guard;
+}
diff --git a/gcc/testsuite/g++.target/i386/ssp-global-4.C b/gcc/testsuite/g++.target/i386/ssp-global-4.C
new file mode 100644
index 00000000000..4786cecb202
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-4.C
@@ -0,0 +1,10 @@
+/* { dg-do compile { target fstack_protector } } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+extern char __stack_chk_guard; /* { dg-error "conflicting types for __stack_chk_guard;" } */
+
+void
+smash (char *p, int i)
+{
+  p[i] = 42;
+}
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..62875423f18
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-hidden-1.C
@@ -0,0 +1,49 @@
+/* { dg-do run { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all -mstack-protector-guard=global -save-temps" } */
+
+#ifndef __stack_protection_guard_is_internal_symbol__
+# error "__stack_protection_guard_is_internal_symbol__ isn't defined"
+#endif
+
+#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..8b4e806edf1
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-hidden-2.C
@@ -0,0 +1,20 @@
+/* { dg-do compile { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all -mstack-protector-guard=global" } */
+
+#include <stddef.h>
+
+extern const size_t __stack_chk_guard;
+__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/g++.target/i386/ssp-global-hidden-3.C b/gcc/testsuite/g++.target/i386/ssp-global-hidden-3.C
new file mode 100644
index 00000000000..ecc13d8bef0
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/ssp-global-hidden-3.C
@@ -0,0 +1,50 @@
+/* { dg-do run { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -mstack-protector-guard=global -save-temps" } */
+
+#ifndef __stack_protection_guard_is_internal_symbol__
+# error "__stack_protection_guard_is_internal_symbol__ isn't defined"
+#endif
+
+#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;
+}
+
+__attribute__ ((optimize ("stack-protector-all")))
+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-2.c b/gcc/testsuite/gcc.target/i386/ssp-global-2.c
new file mode 100644
index 00000000000..11b69909327
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target fstack_protector } } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+#include <stdlib.h>
+
+#ifdef __LP64__
+long int __stack_chk_guard = 0x2d853605a4d9a09cUL;
+#else
+int __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;
+}
diff --git a/gcc/testsuite/gcc.target/i386/ssp-global-3.c b/gcc/testsuite/gcc.target/i386/ssp-global-3.c
new file mode 100644
index 00000000000..bc1ce57eee4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target fstack_protector } } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+extern char *__stack_chk_guard; /* { dg-error "conflicting types for __stack_chk_guard;" } */
+
+char
+foo (void)
+{
+  return *__stack_chk_guard;
+}
diff --git a/gcc/testsuite/gcc.target/i386/ssp-global-4.c b/gcc/testsuite/gcc.target/i386/ssp-global-4.c
new file mode 100644
index 00000000000..4786cecb202
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-4.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target fstack_protector } } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+extern char __stack_chk_guard; /* { dg-error "conflicting types for __stack_chk_guard;" } */
+
+void
+smash (char *p, int i)
+{
+  p[i] = 42;
+}
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..092d68f049c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-1.c
@@ -0,0 +1,49 @@
+/* { dg-do run { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all -mstack-protector-guard=global -save-temps" } */
+
+#ifndef __stack_protection_guard_is_internal_symbol__
+# error "__stack_protection_guard_is_internal_symbol__ isn't defined"
+#endif
+
+#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..8b4e806edf1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -fstack-protector-all -mstack-protector-guard=global" } */
+
+#include <stddef.h>
+
+extern const size_t __stack_chk_guard;
+__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-3.c b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-3.c
new file mode 100644
index 00000000000..f73856c581f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ssp-global-hidden-3.c
@@ -0,0 +1,50 @@
+/* { dg-do run { target { fstack_protector && fpic } } } */
+/* { dg-options "-O2 -fPIC -mstack-protector-guard=global -save-temps" } */
+
+#ifndef __stack_protection_guard_is_internal_symbol__
+# error "__stack_protection_guard_is_internal_symbol__ isn't defined"
+#endif
+
+#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;
+}
+
+__attribute__ ((optimize ("stack-protector-all")))
+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/varasm.cc b/gcc/varasm.cc
index 0d78f5b384f..0747c96b15b 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -2920,6 +2920,19 @@ 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 (targetm.stack_protect_guard_symbol == nullptr
+      || 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