On Thu, May 11, 2023 at 10:45 PM liuhongt via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > 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.
I think this could be simplified if you use either EnumSet or EnumBitSet instead in common.opt for `-fcf-protection=`. Thanks, Andrew > > 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 >