Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
Ok for trunk?

gcc/ChangeLog:

        PR target/89701
        * common.opt: Refactor -fcf-protection= to support combination
        of param.
        * lto-wrapper.c (merge_and_complain): Adjusted.
        * opts.c (parse_cf_protection_options): New.
        (common_handle_option): Decode argument for -fcf-protection=.
        * opts.h (parse_cf_protection_options): Declare.

gcc/testsuite/ChangeLog:

        PR target/89701
        * c-c++-common/fcf-protection-8.c: New test.
        * c-c++-common/fcf-protection-9.c: New test.
        * c-c++-common/fcf-protection-10.c: New test.
        * gcc.target/i386/pr89701-1.c: New test.
        * gcc.target/i386/pr89701-2.c: New test.
        * gcc.target/i386/pr89701-3.c: New test.
        * gcc.target/i386/pr89701-4.c: New test.
---
 gcc/common.opt                                | 24 ++----
 gcc/lto-wrapper.cc                            | 21 +++--
 gcc/opts.cc                                   | 79 +++++++++++++++++++
 gcc/opts.h                                    |  1 +
 .../c-c++-common/fcf-protection-10.c          |  3 +
 .../c-c++-common/fcf-protection-11.c          |  2 +
 .../c-c++-common/fcf-protection-12.c          |  2 +
 gcc/testsuite/c-c++-common/fcf-protection-8.c |  3 +
 gcc/testsuite/c-c++-common/fcf-protection-9.c |  3 +
 gcc/testsuite/gcc.target/i386/pr89701-1.c     |  4 +
 gcc/testsuite/gcc.target/i386/pr89701-2.c     |  4 +
 gcc/testsuite/gcc.target/i386/pr89701-3.c     |  5 ++
 gcc/testsuite/gcc.target/i386/pr89701-4.c     |  5 ++
 13 files changed, 130 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-10.c
 create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-11.c
 create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-12.c
 create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-8.c
 create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-4.c

diff --git a/gcc/common.opt b/gcc/common.opt
index a28ca13385a..ac12da52733 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -229,6 +229,10 @@ bool dump_base_name_prefixed = false
 Variable
 unsigned int flag_zero_call_used_regs
 
+;; What the CF check should instrument
+Variable
+unsigned int flag_cf_protection = 0
+
 ###
 Driver
 
@@ -1886,28 +1890,10 @@ fcf-protection
 Common RejectNegative Alias(fcf-protection=,full)
 
 fcf-protection=
-Common Joined RejectNegative Enum(cf_protection_level) Var(flag_cf_protection) 
Init(CF_NONE)
+Common Joined
 -fcf-protection=[full|branch|return|none|check]        Instrument functions 
with checks to verify jump/call/return control-flow transfer
 instructions have valid targets.
 
-Enum
-Name(cf_protection_level) Type(enum cf_protection_level) UnknownError(unknown 
Control-Flow Protection Level %qs)
-
-EnumValue
-Enum(cf_protection_level) String(full) Value(CF_FULL)
-
-EnumValue
-Enum(cf_protection_level) String(branch) Value(CF_BRANCH)
-
-EnumValue
-Enum(cf_protection_level) String(return) Value(CF_RETURN)
-
-EnumValue
-Enum(cf_protection_level) String(check) Value(CF_CHECK)
-
-EnumValue
-Enum(cf_protection_level) String(none) Value(CF_NONE)
-
 finstrument-functions
 Common Var(flag_instrument_function_entry_exit,1)
 Instrument function entry and exit with profiling calls.
diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
index 5186d040ce0..568c8af659d 100644
--- a/gcc/lto-wrapper.cc
+++ b/gcc/lto-wrapper.cc
@@ -359,26 +359,33 @@ merge_and_complain (vec<cl_decoded_option> 
&decoded_options,
        case OPT_fcf_protection_:
          /* Default to link-time option, else append or check identical.  */
          if (!cf_protection_option
-             || cf_protection_option->value == CF_CHECK)
+             || !memcmp (cf_protection_option->arg, "check", 5))
            {
+             const char* parg = decoded_options[existing_opt].arg;
              if (existing_opt == -1)
                decoded_options.safe_push (*foption);
-             else if (decoded_options[existing_opt].value != foption->value)
+             else if ((strlen (parg) != strlen (foption->arg))
+                      || memcmp (parg, foption->arg, strlen (foption->arg)))
                {
                  if (cf_protection_option
-                     && cf_protection_option->value == CF_CHECK)
+                     && !memcmp (cf_protection_option->arg, "check", 5))
                    fatal_error (input_location,
                                 "option %qs with mismatching values"
                                 " (%s, %s)",
                                 "-fcf-protection",
-                                decoded_options[existing_opt].arg,
+                                parg,
                                 foption->arg);
                  else
                    {
                      /* Merge and update the -fcf-protection option.  */
-                     decoded_options[existing_opt].value
-                       &= (foption->value & CF_FULL);
-                     switch (decoded_options[existing_opt].value)
+                     HOST_WIDE_INT flags1
+                       = parse_cf_protection_options (foption->arg,
+                                                      input_location);
+                     HOST_WIDE_INT flags2
+                       = parse_cf_protection_options (parg,
+                                                      input_location);
+                     flags2 &= (flags1 & CF_FULL);
+                     switch (flags2)
                        {
                        case CF_NONE:
                          decoded_options[existing_opt].arg = "none";
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 86b94d62b58..6389383bc92 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -2187,6 +2187,81 @@ get_closest_sanitizer_option (const string_fragment &arg,
   return bm.get_best_meaningful_candidate ();
 }
 
+unsigned int
+parse_cf_protection_options (const char *p, location_t loc)
+{
+  unsigned int flags = 0;
+  bool combined = false;
+  while (*p != 0)
+    {
+      size_t len;
+      const char *comma = strchr (p, ',');
+      if (comma == NULL)
+       len = strlen (p);
+      else
+       {
+         combined = true;
+         len = comma - p;
+       }
+
+      if (len == 0)
+       {
+         p = comma + 1;
+         continue;
+       }
+
+      switch (len)
+       {
+       case 4:
+         if (!memcmp (p, "full", 4))
+           {
+             if (combined && flags != CF_NONE)
+               warning_at (loc, 0, "better to use %<-fcf-protection=%> "
+                           "option: full alone instead of in a combination");
+             flags |= CF_FULL;
+           }
+         else if (!memcmp (p, "none", 4))
+           {
+             if (combined && flags != CF_NONE)
+               warning_at (loc, 0, "combination of %<-fcf-protection=%> "
+                           "option: none is ignored");
+           }
+         else
+           error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+                     "option: %.4s", p);
+         break;
+       case 5:
+         if (!memcmp (p, "check", 5))
+           {
+             if (combined && flags != CF_CHECK)
+               error_at (loc, "Combination for %<-fcf-protection=%> "
+                         "option: check is not valid");
+             flags |= CF_CHECK;
+           }
+         else
+           error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+                     "option: %.5s", p);
+         break;
+       case 6:
+         if (!memcmp (p, "branch", 6))
+           flags |= CF_BRANCH;
+         else if (!memcmp (p, "return", 6))
+           flags |= CF_RETURN;
+         else
+           error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+                     "option: %.6s", p);
+         break;
+       default:
+         error_at (loc, "unrecognized argument to %<-fcf-protection=%> "
+                   "option: %.*s", (int) len, p);
+       }
+
+      if (comma == NULL)
+       break;
+      p = comma + 1;
+    }
+  return flags;
+}
 /* Parse comma separated sanitizer suboptions from P for option SCODE,
    adjust previous FLAGS and return new ones.  If COMPLAIN is false,
    don't issue diagnostics.  */
@@ -2671,6 +2746,10 @@ common_handle_option (struct gcc_options *opts,
     case OPT__completion_:
       break;
 
+    case OPT_fcf_protection_:
+      opts->x_flag_cf_protection
+       = parse_cf_protection_options (arg, loc);
+      break;
     case OPT_fsanitize_:
       opts_set->x_flag_sanitize = true;
       opts->x_flag_sanitize
diff --git a/gcc/opts.h b/gcc/opts.h
index 9959a440ca1..00d396d95f8 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -425,6 +425,7 @@ extern void control_warning_option (unsigned int opt_index, 
int kind,
 extern char *write_langs (unsigned int mask);
 extern void print_ignored_options (void);
 extern void handle_common_deferred_options (void);
+extern unsigned int parse_cf_protection_options (const char*, location_t);
 unsigned int parse_sanitizer_options (const char *, location_t, int,
                                      unsigned int, int, bool);
 
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-10.c 
b/gcc/testsuite/c-c++-common/fcf-protection-10.c
new file mode 100644
index 00000000000..8692a08374b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-10.c
@@ -0,0 +1,3 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,check" } */
+/* { dg-error "Combination for '-fcf-protection=' option: check is not valid" 
"" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-11.c 
b/gcc/testsuite/c-c++-common/fcf-protection-11.c
new file mode 100644
index 00000000000..2e566350ccd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-11.c
@@ -0,0 +1,2 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,return" } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-12.c 
b/gcc/testsuite/c-c++-common/fcf-protection-12.c
new file mode 100644
index 00000000000..b39c2f8e25d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-12.c
@@ -0,0 +1,2 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=return,branch" } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-8.c 
b/gcc/testsuite/c-c++-common/fcf-protection-8.c
new file mode 100644
index 00000000000..33e46223b6b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-8.c
@@ -0,0 +1,3 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,none" } */
+/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" 
{ target { *-*-* } } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-9.c 
b/gcc/testsuite/c-c++-common/fcf-protection-9.c
new file mode 100644
index 00000000000..7848fe4b959
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-9.c
@@ -0,0 +1,3 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-fcf-protection=branch,full" } */
+/* { dg-warning "better to use '-fcf-protection=' option: full alone instead 
of in a combination" "" { target { *-*-* } } 0 } */
diff --git a/gcc/testsuite/gcc.target/i386/pr89701-1.c 
b/gcc/testsuite/gcc.target/i386/pr89701-1.c
new file mode 100644
index 00000000000..1879c9ab4d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr89701-1.c
@@ -0,0 +1,4 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=branch,return" } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long    0x3" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr89701-2.c 
b/gcc/testsuite/gcc.target/i386/pr89701-2.c
new file mode 100644
index 00000000000..d5100575028
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr89701-2.c
@@ -0,0 +1,4 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=return,branch" } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long    0x3" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr89701-3.c 
b/gcc/testsuite/gcc.target/i386/pr89701-3.c
new file mode 100644
index 00000000000..1505051a2bb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr89701-3.c
@@ -0,0 +1,5 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=return,none" } */
+/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" 
{ target { *-*-linux* } } 0 } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long    0x2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr89701-4.c 
b/gcc/testsuite/gcc.target/i386/pr89701-4.c
new file mode 100644
index 00000000000..242b8810abb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr89701-4.c
@@ -0,0 +1,5 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection=branch,none" } */
+/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" 
{ target { *-*-* } } 0 } */
+/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */
+/* { dg-final { scan-assembler-times ".long    0x1" 1 } } */
-- 
2.39.1.388.g2fc9e9ca3c

Reply via email to