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-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-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 <hjl.to...@gmail.com> --- gcc/c-family/c-attribs.cc | 5 ++ gcc/c-family/c-cppbuiltin.cc | 7 +++ gcc/c/c-decl.cc | 33 +++++++++++- gcc/config/i386/i386.cc | 3 ++ gcc/cp/decl.cc | 32 +++++++++++- 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 | 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 | 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 + 20 files changed, 418 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-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-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..a0ddb0976db 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,34 @@ 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 types with the same size. */ + tree guard_type = TREE_TYPE (guard_decl); + if (TYPE_PRECISION (type) + != TYPE_PRECISION (guard_type)) + { + error ("conflicting types for %s; have %qT, " + "should be %qT", + stack_protect_guard_name, type, + guard_type); + return error_mark_node; + } + return guard_decl; + } + } + /* 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..b02bfd416ec 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,33 @@ 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) + { + tree guard_type = TREE_TYPE (guard_decl); + /* Allow different types with the same size. */ + if (TYPE_PRECISION (type) + != TYPE_PRECISION (guard_type)) + { + error ("conflicting types for %s; have %qT, " + "should be %qT", + stack_protect_guard_name, type, + guard_type); + return error_mark_node; + } + return guard_decl; + } + } + /* 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..4786cecb202 --- /dev/null +++ b/gcc/testsuite/g++.target/i386/ssp-global-2.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..4786cecb202 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/ssp-global-2.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