c/c++: Treat __stack_chk_guard as an internal symbol

Message ID 20250913174217.141258-1-hjl.tools@gmail.com
State New
Headers
Series c/c++: Treat __stack_chk_guard as an internal symbol |

Commit Message

H.J. Lu Sept. 13, 2025, 5:42 p.m. UTC
  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.tools@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
  

Comments

Florian Weimer Sept. 15, 2025, 9:52 a.m. UTC | #1
* H. J. Lu:

> 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.

Can we get a preprocessor macro that indicates whether GCC supports
this?

> 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;

Is it possible to enable stack protector for individual functions if
!flag_stack_protect?
  
H.J. Lu Sept. 15, 2025, 1 p.m. UTC | #2
On Mon, Sep 15, 2025 at 2:52 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > 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.
>
> Can we get a preprocessor macro that indicates whether GCC supports
> this?

We can do

diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index 6b22f9e60b1..c997fa61637 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 (flag_stack_protect)
+    {
+      /* Define this to indicate that __stack_chk_guard may be treated
+   as an internal symbol.  */
+      cpp_define (pfile, "__stack_chk_guard_may_be_internal_symbol__");
+    }
+
   /* Represents the C++ ABI version, always defined so it can be used while
      preprocessing C and assembler.  */
   if (flag_abi_version == 0)

__stack_chk_guard is an internal symbol only if targetm.stack_protect_guard
returns __stack_chk_guard.   We can add another target hook to indicate that
__stack_chk_guard is an internal symbol.

>
> > 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;
>
> Is it possible to enable stack protector for individual functions if
> !flag_stack_protect?

I don't think so.   We only have

@cindex @code{no_stack_protector} function attribute
@item no_stack_protector
This attribute prevents stack protection code for the function.

and

@cindex @code{stack_protect} function attribute
@item stack_protect
This attribute adds stack protection code to the function if
flags @option{-fstack-protector}, @option{-fstack-protector-strong}
or @option{-fstack-protector-explicit} are set.

If we add another attribute to enable stack protector for individual functions
without -fstack-protector, I will try to accommodate it.
  
Florian Weimer Sept. 15, 2025, 1:04 p.m. UTC | #3
* H. J. Lu:

>> Is it possible to enable stack protector for individual functions if
>> !flag_stack_protect?
>
> I don't think so.   We only have
>
> @cindex @code{no_stack_protector} function attribute
> @item no_stack_protector
> This attribute prevents stack protection code for the function.
>
> and
>
> @cindex @code{stack_protect} function attribute
> @item stack_protect
> This attribute adds stack protection code to the function if
> flags @option{-fstack-protector}, @option{-fstack-protector-strong}
> or @option{-fstack-protector-explicit} are set.
>
> If we add another attribute to enable stack protector for individual functions
> without -fstack-protector, I will try to accommodate it.

This already seems to have the effect:

int f (void);

__attribute__ ((optimize ("stack-protector-all"))) int
g (void)
{
  f();
}
  
H.J. Lu Sept. 15, 2025, 4:31 p.m. UTC | #4
On Mon, Sep 15, 2025 at 6:04 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> >> Is it possible to enable stack protector for individual functions if
> >> !flag_stack_protect?
> >
> > I don't think so.   We only have
> >
> > @cindex @code{no_stack_protector} function attribute
> > @item no_stack_protector
> > This attribute prevents stack protection code for the function.
> >
> > and
> >
> > @cindex @code{stack_protect} function attribute
> > @item stack_protect
> > This attribute adds stack protection code to the function if
> > flags @option{-fstack-protector}, @option{-fstack-protector-strong}
> > or @option{-fstack-protector-explicit} are set.
> >
> > If we add another attribute to enable stack protector for individual functions
> > without -fstack-protector, I will try to accommodate it.
>
> This already seems to have the effect:
>
> int f (void);
>
> __attribute__ ((optimize ("stack-protector-all"))) int
> g (void)
> {
>   f();
> }
>

No, it doesn't work:

[hjl@gnu-zen4-1 pr121911]$ cat bar.c
#include <stdlib.h>
#include <stddef.h>

const size_t __stack_chk_guard = 0x2d853605a4d9a09cUL;

void
__stack_chk_fail (void)
{
  exit (0); /* pass */
}

__attribute__ ((noipa, optimize ("stack-protector-all")))
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;
}
[hjl@gnu-zen4-1 pr121911]$ gcc -O2 -g -mstack-protector-guard=global
ssp-global-hidden-3.c
[hjl@gnu-zen4-1 pr121911]$ gdb a.out
GNU gdb (Fedora Linux) 16.3-1.fc42
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...
(gdb) r
Starting program: /export/home/hjl/bugs/gcc/pr121911/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00000000004003b2 in main () at ssp-global-hidden-3.c:37
37 }
Missing rpms, try: dnf --enablerepo='*debug*' install
glibc-debuginfo-2.41-11.0.fc42.x86_64
(gdb)
  
Florian Weimer Sept. 15, 2025, 4:51 p.m. UTC | #5
* H. J. Lu:

> No, it doesn't work:
>
> [hjl@gnu-zen4-1 pr121911]$ cat bar.c
> #include <stdlib.h>
> #include <stddef.h>
>
> const size_t __stack_chk_guard = 0x2d853605a4d9a09cUL;
>
> void
> __stack_chk_fail (void)
> {
>   exit (0); /* pass */
> }
>
> __attribute__ ((noipa, optimize ("stack-protector-all")))
> 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;
> }

I think the test seems invalid?  In the smash function, its own return
address is at a negative pointer offset from the start of the foo
array.
  
H.J. Lu Sept. 15, 2025, 6:11 p.m. UTC | #6
On Mon, Sep 15, 2025 at 9:51 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > No, it doesn't work:
> >
> > [hjl@gnu-zen4-1 pr121911]$ cat bar.c
> > #include <stdlib.h>
> > #include <stddef.h>
> >
> > const size_t __stack_chk_guard = 0x2d853605a4d9a09cUL;
> >
> > void
> > __stack_chk_fail (void)
> > {
> >   exit (0); /* pass */
> > }
> >
> > __attribute__ ((noipa, optimize ("stack-protector-all")))
> > 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;
> > }
>
> I think the test seems invalid?  In the smash function, its own return
> address is at a negative pointer offset from the start of the foo
> array.

I am testing an updated patch in:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121911
  

Patch

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);