@@ -689,6 +689,25 @@ decl_attributes (tree *node, tree attributes, int flags,
attributes = tree_cons (get_identifier ("no_icf"), NULL, attributes);
}
+ /* -fcf-check-attribute=[yes|no] implies "cf_check" or "nocf_check"
+ function attribute. */
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ && flag_cf_check_attribute != CF_CHECK_ATTRIBUTE_NONE
+ && !fndecl_built_in_p (*node)
+ && lookup_attribute ("nocf_check",
+ DECL_ATTRIBUTES (*node)) == nullptr
+ && lookup_attribute ("cf_check",
+ DECL_ATTRIBUTES (*node)) == nullptr
+ && (!attributes
+ || (lookup_attribute ("nocf_check", attributes) == nullptr
+ && lookup_attribute ("cf_check", attributes) == nullptr)))
+ {
+ const char *attr = (flag_cf_check_attribute == CF_CHECK_ATTRIBUTE_YES
+ ? "cf_check" : "nocf_check");
+ attributes = tree_cons (get_identifier (attr), nullptr,
+ attributes);
+ }
+
targetm.insert_attributes (*node, &attributes);
/* Note that attributes on the same declaration are not necessarily
@@ -2133,7 +2133,27 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
error ("conflicting type qualifiers for %q+D", newdecl);
}
else
- error ("conflicting types for %q+D; have %qT", newdecl, newtype);
+ {
+ if (flag_cf_check_attribute == CF_CHECK_ATTRIBUTE_NO
+ && (!lookup_attribute ("nocf_check",
+ TYPE_ATTRIBUTES (oldtype))
+ != !lookup_attribute ("nocf_check",
+ TYPE_ATTRIBUTES (newtype))))
+ error ("conflicting types for %q+D; have %qT with "
+ "implied %<nocf_check%> attribute",
+ newdecl, newtype);
+ else if (flag_cf_check_attribute == CF_CHECK_ATTRIBUTE_YES
+ && (!lookup_attribute ("cf_check",
+ TYPE_ATTRIBUTES (oldtype))
+ != !lookup_attribute ("cf_check",
+ TYPE_ATTRIBUTES (newtype))))
+ error ("conflicting types for %q+D; have %qT with "
+ "implied %<cf_check%> attribute",
+ newdecl, newtype);
+ else
+ error ("conflicting types for %q+D; have %qT",
+ newdecl, newtype);
+ }
diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
locate_old_decl (olddecl);
return false;
@@ -1873,6 +1873,22 @@ Enum(cf_protection_level) String(check) Value(CF_CHECK)
EnumValue
Enum(cf_protection_level) String(none) Value(CF_NONE)
+fcf-check-attribute=
+Target RejectNegative Joined Enum(cf_check_attribute) Var(flag_cf_check_attribute) Init(CF_CHECK_ATTRIBUTE_NONE)
+-fcf-check-attribute=[none|yes|no] Select the implied function attribute.
+
+Enum
+Name(cf_check_attribute) Type(enum cf_check_attribute) UnknownError(unknown default Control-Flow attribute %qs)
+
+EnumValue
+Enum(cf_check_attribute) String(none) Value(CF_CHECK_ATTRIBUTE_NONE)
+
+EnumValue
+Enum(cf_check_attribute) String(yes) Value(CF_CHECK_ATTRIBUTE_YES)
+
+EnumValue
+Enum(cf_check_attribute) String(no) Value(CF_CHECK_ATTRIBUTE_NO)
+
finstrument-functions
Common Var(flag_instrument_function_entry_exit)
Instrument function entry and exit with profiling calls.
@@ -605,6 +605,7 @@ Objective-C and Objective-C++ Dialects}.
-fasan-shadow-offset=@var{number} -fsanitize-sections=@var{s1},@var{s2},... @gol
-fsanitize-undefined-trap-on-error -fbounds-check @gol
-fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]} @gol
+-fcf-check-attribute=@r{[}none@r{|}yes@r{|}no@r{]} @gol
-fharden-compares -fharden-conditional-branches @gol
-fstack-protector -fstack-protector-all -fstack-protector-strong @gol
-fstack-protector-explicit -fstack-check @gol
@@ -15971,6 +15972,17 @@ Currently the x86 GNU/Linux target provides an implementation based
on Intel Control-flow Enforcement Technology (CET) which works for
i686 processor or newer.
+@item -fcf-check-attribute=@r{[}none@r{|}yes@r{|}no@r{]}
+@opindex fcf-check-attribute
+Select the implied function attribute for code instrumentation of
+control-flow transfers.
+
+The value @code{yes} makes the @code{cf_check} attribute implied on
+functions. The value @code{no} makes the @code{nocf_check} attribute
+implied on functions. The value @code{none}, which is the default,
+doesn't imply the @code{cf_check} nor @code{nocf_check} attributes on
+functions.
+
@item -fharden-compares
@opindex fharden-compares
For every logical test that survives gimple optimizations and is
@@ -449,6 +449,14 @@ enum cf_protection_level
CF_CHECK = 1 << 3
};
+/* Default Control-Flow Protection attribute. */
+enum cf_check_attribute
+{
+ CF_CHECK_ATTRIBUTE_NONE = 0,
+ CF_CHECK_ATTRIBUTE_YES,
+ CF_CHECK_ATTRIBUTE_NO
+};
+
/* Parloops schedule type. */
enum parloops_schedule_type
{
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */
+
+static void __attribute__((cf_check)) foo(void);
+static void foo(void) /* { dg-error "implied 'nocf_check' attribute" } */
+{
+}
+void (*ptr)(void) = foo; /* { dg-warning "incompatible pointer type" } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */
+
+static void foo(void)
+{
+}
+void (*ptr)(void) = foo; /* { dg-warning "incompatible pointer type" } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */
+
+extern void foo(void);
+void __attribute__((cf_check)) foo(void) /* { dg-error "implied 'nocf_check' attribute" } */
+{
+}
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */
+
+static int __attribute__((cf_check)) foo(char a[], int b)
+{
+ return 0;
+}
+int (*ptr)(char[], int) = foo;