LTO: Add -fcf-protection=check
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 16 Jul 2020 14:03:27 +0000 (07:03 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Mon, 27 Jul 2020 11:40:13 +0000 (04:40 -0700)
Mixing -fcf-protection and -fcf-protection=none objects are allowed.
Linker just merges -fcf-protection values from all input objects.

Add -fcf-protection=check for the final link with LTO.  An error is
issued if LTO object files are compiled with different -fcf-protection
values.  Otherwise, -fcf-protection=check is ignored at the compile
time.  Without explicit -fcf-protection at link time, -fcf-protection
values from LTO object files are merged at the final link.

gcc/

PR bootstrap/96203
* common.opt: Add -fcf-protection=check.
* flag-types.h (cf_protection_level): Add CF_CHECK.
* lto-wrapper.c (merge_and_complain): Issue an error for
mismatching -fcf-protection values with -fcf-protection=check.
Otherwise, merge -fcf-protection values.
* doc/invoke.texi: Document -fcf-protection=check.

gcc/testsuite/

PR bootstrap/96203
* gcc.target/i386/pr96203-1.c: New test.
* gcc.target/i386/pr96203-2.c: Likewise.

gcc/common.opt
gcc/doc/invoke.texi
gcc/flag-types.h
gcc/lto-wrapper.c
gcc/testsuite/gcc.target/i386/pr96203-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr96203-2.c [new file with mode: 0644]

index a3893a4..47f4261 100644 (file)
@@ -1776,7 +1776,7 @@ Common RejectNegative Alias(fcf-protection=,full)
 
 fcf-protection=
 Common Report Joined RejectNegative Enum(cf_protection_level) Var(flag_cf_protection) Init(CF_NONE)
--fcf-protection=[full|branch|return|none]      Instrument functions with checks to verify jump/call/return control-flow transfer
+-fcf-protection=[full|branch|return|none|check]        Instrument functions with checks to verify jump/call/return control-flow transfer
 instructions have valid targets.
 
 Enum
@@ -1792,6 +1792,9 @@ 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
index 5449c33..7c3cc14 100644 (file)
@@ -559,7 +559,7 @@ Objective-C and Objective-C++ Dialects}.
 -fsanitize=@var{style}  -fsanitize-recover  -fsanitize-recover=@var{style} @gol
 -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{]} @gol
+-fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]} @gol
 -fstack-protector  -fstack-protector-all  -fstack-protector-strong @gol
 -fstack-protector-explicit  -fstack-check @gol
 -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym} @gol
@@ -14211,7 +14211,7 @@ operand constant, @code{__sanitizer_cov_trace_cmpf} or
 @code{__sanitizer_cov_trace_cmpd} for float or double comparisons and
 @code{__sanitizer_cov_trace_switch} for switch statements.
 
-@item -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{]}
+@item -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
 @opindex fcf-protection
 Enable code instrumentation of control-flow transfers to increase
 program security by checking that target addresses of control-flow
@@ -14229,6 +14229,11 @@ function.  The value @code{full} is an alias for specifying both
 @code{branch} and @code{return}. The value @code{none} turns off
 instrumentation.
 
+The value @code{check} is used for the final link with link-time
+optimization (LTO).  An error is issued if LTO object files are
+compiled with different @option{-fcf-protection} values.  The
+value @code{check} is ignored at the compile time.
+
 The macro @code{__CET__} is defined when @option{-fcf-protection} is
 used.  The first bit of @code{__CET__} is set to 1 for the value
 @code{branch} and the second bit of @code{__CET__} is set to 1 for
index b092c56..852ea76 100644 (file)
@@ -368,7 +368,8 @@ enum cf_protection_level
   CF_BRANCH = 1 << 0,
   CF_RETURN = 1 << 1,
   CF_FULL = CF_BRANCH | CF_RETURN,
-  CF_SET = 1 << 2
+  CF_SET = 1 << 2,
+  CF_CHECK = 1 << 3
 };
 
 /* Parloops schedule type.  */
index 5578b6d..e3b5cb2 100644 (file)
@@ -310,20 +310,45 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
 
        case OPT_fcf_protection_:
          /* Default to link-time option, else append or check identical.  */
-         if (!cf_protection_option)
+         if (!cf_protection_option
+             || cf_protection_option->value == CF_CHECK)
            {
              for (j = 0; j < *decoded_options_count; ++j)
                if ((*decoded_options)[j].opt_index == foption->opt_index)
                  break;
              if (j == *decoded_options_count)
                append_option (decoded_options, decoded_options_count, foption);
-             else if (strcmp ((*decoded_options)[j].arg, foption->arg))
-               fatal_error (input_location,
-                            "option -fcf-protection with mismatching values"
-                            " (%s, %s)",
-                            (*decoded_options)[j].arg, foption->arg);
+             else if ((*decoded_options)[j].value != foption->value)
+               {
+                 if (cf_protection_option
+                     && cf_protection_option->value == CF_CHECK)
+                   fatal_error (input_location,
+                                "option -fcf-protection with mismatching values"
+                                " (%s, %s)",
+                                (*decoded_options)[j].arg, foption->arg);
+                 else
+                   {
+                     /* Merge and update the -fcf-protection option.  */
+                     (*decoded_options)[j].value &= (foption->value
+                                                     & CF_FULL);
+                     switch ((*decoded_options)[j].value)
+                       {
+                       case CF_NONE:
+                         (*decoded_options)[j].arg = "none";
+                         break;
+                       case CF_BRANCH:
+                         (*decoded_options)[j].arg = "branch";
+                         break;
+                       case CF_RETURN:
+                         (*decoded_options)[j].arg = "return";
+                         break;
+                       default:
+                         gcc_unreachable ();
+                       }
+                   }
+               }
            }
-           break;
+         break;
 
        case OPT_O:
        case OPT_Ofast:
diff --git a/gcc/testsuite/gcc.target/i386/pr96203-1.c b/gcc/testsuite/gcc.target/i386/pr96203-1.c
new file mode 100644 (file)
index 0000000..332911f
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection=check" } */
+/* { dg-final { scan-assembler-not "endbr" } } */
+
+extern int x;
+
+static void
+__attribute__ ((noinline, noclone))
+test (int i)
+{
+  x = i;
+}
+
+void
+bar (int i)
+{
+  test (i);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr96203-2.c b/gcc/testsuite/gcc.target/i386/pr96203-2.c
new file mode 100644 (file)
index 0000000..1141cf2
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection=check -mmanual-endbr" } */
+/* { dg-final { scan-assembler-not "endbr" } } */
+
+extern void bar (void) __attribute__((__cf_check__));
+
+void
+foo (void)
+{
+  bar ();
+}