Hi,
the attached patch adds a new attribute and option flag to control
when to do stack protection.
The new attribute (stack_protect) affects the behavior of gcc by
forcing the stack protection of the function marked with the attribute
if any of the options -fstack-protector, -fstack-protector-strong or
-fstack-protector-explicit(new) are set.
If the new option (-fstack-protector-explicit) is set only those
functions with the attribute stack_protect will have stack protection.
The stack re-ordering of the variables depends on the option set,
currently if flag -fstack-protector is set only char arrays are
reordered in the stack, whereas if flag -fstack-protector-strong or
-fstack-protector-explicit is set then char arrays and other arrays
are ordered first in the stack.
About this reordering of the non char arrays, shouldn't all to-be
protected functions have the full re-ordering? If not, for
completeness, I should make that new flag -fstack-protector-explicit
not to order the non-char arrays, and create a new -strong
counterpart, namely -fstack-protector-explicit-strong which does.
Additionally, I think that the behavior of the flag
-fstack-protector-strong lacked the re-ordering of non char arrays
(named phase 2) so I added the reordering also for such flag.
Current tests pass after applying this patch, plus the tests specially added.
Please commit it for me if OK since I don't have write access.
Changelog:
2013-11-18 Marcos Diaz <[email protected]>
gcc/
* c-family/c-cppbuiltin.c (c_cpp_builtins): New cpp define
__SSP_EXPLICIT__ for the new option fstack-protector_explicit
* c-family/c-common.c: Added new attribute stack-protect and
respective handler
* common.opt: Added new option -fstack-protector-explicit
* cfgexpand.c: Added new enum SPCT_FLAG_EXPLICIT
(stack_protect_decl_phase): Added new condition in the
look of conflictive variables for the new attribute and option.
(expand_used_vars): Added new condition in order to put stack
protection in functions with the stack protect attribute.
gcc/doc/
* cpp.texi: New description for the new cpp_define __SSP_EXPLICIT__
* extend.texi: Added description for the new stack_protect function
attribute.
* invoke.texi: description for the new -fstack-protector-strong option
gcc/testsuite/
* gcc.dg/stackprotectexplicit1.c: New test file for the flag and
the attribute
* g++.dg/stackprotectexplicit2.C: New test file for the flag and
the attribute
Index: gcc/testsuite/gcc.dg/stackprotectexplicit1.c
===================================================================
--- gcc/testsuite/gcc.dg/stackprotectexplicit1.c (revision 0)
+++ gcc/testsuite/gcc.dg/stackprotectexplicit1.c (revision 0)
@@ -0,0 +1,23 @@
+/* { dg-do run { target native } } */
+/* { dg-options "-fstack-protector-explicit" } */
+/* { dg-require-effective-target fstack_protector } */
+
+#include <stdlib.h>
+
+void
+__stack_chk_fail (void)
+{
+ exit (0); /* pass */
+}
+
+int __attribute__((stack_protect)) main ()
+{
+ int i;
+ char foo[255];
+
+ // smash stack
+ for (i = 0; i <= 400; i++)
+ foo[i] = 42;
+
+ return 1; /* fail */
+}
Index: gcc/testsuite/g++.dg/stackprotectexplicit2.C
===================================================================
--- gcc/testsuite/g++.dg/stackprotectexplicit2.C (revision 0)
+++ gcc/testsuite/g++.dg/stackprotectexplicit2.C (revision 0)
@@ -0,0 +1,27 @@
+/* Test that stack protection is done on chosen functions. */
+
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2 -fstack-protector-explicit" } */
+
+int A()
+{
+ int A[23];
+ char b[22];
+}
+
+int __attribute__((stack_protect)) B()
+{
+ int a;
+ int b;
+ return a+b;
+}
+
+int __attribute__((stack_protect)) c()
+{
+ int a;
+ char b[34];
+ return 0;
+}
+
+
+/* { dg-final { scan-assembler-times "stack_chk_fail" 2 } } */
\ No newline at end of file
Index: gcc/common.opt
===================================================================
--- gcc/common.opt (revision 204949)
+++ gcc/common.opt (working copy)
@@ -1958,6 +1958,10 @@ fstack-protector-strong
Common Report RejectNegative Var(flag_stack_protect, 3)
Use a smart stack protection method for certain functions
+fstack-protector-explicit
+Common Report RejectNegative Var(flag_stack_protect, 4)
+Use stack protection method only for functions with the stack_protect attribute
+
fstack-usage
Common RejectNegative Var(flag_stack_usage)
Output stack usage information on a per-function basis
Index: gcc/c-family/c-cppbuiltin.c
===================================================================
--- gcc/c-family/c-cppbuiltin.c (revision 204949)
+++ gcc/c-family/c-cppbuiltin.c (working copy)
@@ -984,6 +984,8 @@ c_cpp_builtins (cpp_reader *pfile)
/* Make the choice of the stack protector runtime visible to source code.
The macro names and values here were chosen for compatibility with an
earlier implementation, i.e. ProPolice. */
+ if (flag_stack_protect == 4)
+ cpp_define (pfile, "__SSP_EXPLICIT__=4");
if (flag_stack_protect == 3)
cpp_define (pfile, "__SSP_STRONG__=3");
if (flag_stack_protect == 2)
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c (revision 204949)
+++ gcc/c-family/c-common.c (working copy)
@@ -314,6 +314,7 @@ static tree handle_no_address_safety_ana
int, bool *);
static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int,
bool *);
+static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
@@ -629,6 +630,8 @@ const struct attribute_spec c_common_att
handle_noreturn_attribute, false },
{ "volatile", 0, 0, true, false, false,
handle_noreturn_attribute, false },
+ { "stack_protect", 0, 0, true, false, false,
+ handle_stack_protect_attribute, false },
{ "noinline", 0, 0, true, false, false,
handle_noinline_attribute, false },
{ "noclone", 0, 0, true, false, false,
@@ -6624,6 +6627,25 @@ handle_no_sanitize_undefined_attribute (
return NULL_TREE;
}
+
+/* Handle a "stack_protect" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_stack_protect_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else
+ DECL_ATTRIBUTES (*node)
+ = tree_cons (get_identifier ("stack_protect"),
+ NULL_TREE, DECL_ATTRIBUTES (*node));
+
+ return NULL_TREE;
+}
/* Handle a "noinline" attribute; arguments as in
struct attribute_spec.handler. */
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c (revision 204949)
+++ gcc/cfgexpand.c (working copy)
@@ -1330,7 +1330,8 @@ clear_tree_used (tree block)
enum {
SPCT_FLAG_DEFAULT = 1,
SPCT_FLAG_ALL = 2,
- SPCT_FLAG_STRONG = 3
+ SPCT_FLAG_STRONG = 3,
+ SPCT_FLAG_EXPLICIT = 4
};
/* Examine TYPE and determine a bit mask of the following features. */
@@ -1403,7 +1404,9 @@ stack_protect_decl_phase (tree decl)
has_short_buffer = true;
if (flag_stack_protect == SPCT_FLAG_ALL
- || flag_stack_protect == SPCT_FLAG_STRONG)
+ || flag_stack_protect == SPCT_FLAG_STRONG
+ || (flag_stack_protect == SPCT_FLAG_EXPLICIT
+ && lookup_attribute("stack_protect",DECL_ATTRIBUTES(current_function_decl))))
{
if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY))
&& !(bits & SPCT_HAS_AGGREGATE))
@@ -1743,7 +1746,10 @@ expand_used_vars (void)
/* If stack protection is enabled, we don't share space between
vulnerable data and non-vulnerable data. */
- if (flag_stack_protect)
+ if (flag_stack_protect != 0
+ && (flag_stack_protect != SPCT_FLAG_EXPLICIT
+ || (flag_stack_protect == SPCT_FLAG_EXPLICIT
+ && lookup_attribute("stack_protect",DECL_ATTRIBUTES(current_function_decl)))))
add_stack_protection_conflicts ();
/* Now that we have collected all stack variables, and have computed a
@@ -1761,15 +1767,22 @@ expand_used_vars (void)
case SPCT_FLAG_STRONG:
if (gen_stack_protect_signal
- || cfun->calls_alloca || has_protected_decls)
+ || cfun->calls_alloca || has_protected_decls
+ || lookup_attribute("stack_protect",DECL_ATTRIBUTES(current_function_decl)))
create_stack_guard ();
break;
case SPCT_FLAG_DEFAULT:
- if (cfun->calls_alloca || has_protected_decls)
+ if (cfun->calls_alloca || has_protected_decls
+ || lookup_attribute("stack_protect",DECL_ATTRIBUTES(current_function_decl)))
create_stack_guard ();
break;
+ case SPCT_FLAG_EXPLICIT:
+ if (lookup_attribute("stack_protect",
+ DECL_ATTRIBUTES(current_function_decl)))
+ create_stack_guard();
+ break;
default:
;
}
@@ -1793,8 +1806,11 @@ expand_used_vars (void)
expand_stack_vars (stack_protect_decl_phase_1, &data);
/* Phase 2 contains other kinds of arrays. */
- if (flag_stack_protect == 2)
- expand_stack_vars (stack_protect_decl_phase_2, &data);
+ if (flag_stack_protect == SPCT_FLAG_ALL
+ || flag_stack_protect == SPCT_FLAG_STRONG
+ || (flag_stack_protect == SPCT_FLAG_EXPLICIT
+ && lookup_attribute("stack_protect",DECL_ATTRIBUTES(current_function_decl))))
+ expand_stack_vars (stack_protect_decl_phase_2, &data);
}
if (flag_sanitize & SANITIZE_ADDRESS)
Index: gcc/doc/cpp.texi
===================================================================
--- gcc/doc/cpp.texi (revision 204949)
+++ gcc/doc/cpp.texi (working copy)
@@ -2353,6 +2353,10 @@ in use.
This macro is defined, with value 3, when @option{-fstack-protector-strong} is
in use.
+@item __SSP_EXPLICIT__
+This macro is defined, with value 4, when @option{-fstack-protector-explicit} is
+in use.
+
@item __SANITIZE_ADDRESS__
This macro is defined, with value 1, when @option{-fsanitize=address} is
in use.
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi (revision 204949)
+++ gcc/doc/invoke.texi (working copy)
@@ -408,7 +408,8 @@ Objective-C and Objective-C++ Dialects}.
-fsel-sched-pipelining -fsel-sched-pipelining-outer-loops @gol
-fshrink-wrap -fsignaling-nans -fsingle-precision-constant @gol
-fsplit-ivs-in-unroller -fsplit-wide-types -fstack-protector @gol
--fstack-protector-all -fstack-protector-strong -fstrict-aliasing @gol
+-fstack-protector-all -fstack-protector-strong -fstack-protector-explicit @gol
+-fstrict-aliasing @gol
-fstrict-overflow -fthread-jumps -ftracer -ftree-bit-ccp @gol
-ftree-builtin-call-dce -ftree-ccp -ftree-ch @gol
-ftree-coalesce-inline-vars -ftree-coalesce-vars -ftree-copy-prop @gol
@@ -9057,6 +9058,11 @@ Like @option{-fstack-protector} but incl
be protected --- those that have local array definitions, or have
references to local frame addresses.
+@item -fstack-protector-explicit
+@opindex fstack-protector-explicit
+Like @option{-fstack-protector} but only protects those functions which
+have the @code{stack_protect} attribute
+
@item -fsection-anchors
@opindex fsection-anchors
Try to reduce the number of symbolic address calculations by using
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 204949)
+++ gcc/doc/extend.texi (working copy)
@@ -2167,7 +2167,7 @@ attributes are currently defined for fun
@code{returns_nonnull}, @code{gnu_inline},
@code{externally_visible}, @code{hot}, @code{cold}, @code{artificial},
@code{no_sanitize_address}, @code{no_address_safety_analysis},
-@code{no_sanitize_undefined}, @code{bnd_legacy},
+@code{no_sanitize_undefined}, @code{bnd_legacy}, @code{stack_protect}
@code{error} and @code{warning}.
Several other attributes are defined for functions on particular
target systems. Other attributes, including @code{section} are
@@ -3319,6 +3319,12 @@ prologue which decides whether to split
@code{no_split_stack} attribute do not have that prologue, and thus
may run with only a small amount of stack space available.
+@item stack_protect
+@cindex @code{stack_protect} function attribute
+This function attribute make a stack protection of the function if
+flags @option{fstack-protector} or @option{fstack-protector-strong}
+or @option{fstack-protector-explicit} are set.
+
@item noinline
@cindex @code{noinline} function attribute
This function attribute prevents a function from being considered for