public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] gcc: Introduce -fhardened
@ 2023-09-15 15:08 Marek Polacek
  2023-09-18  6:57 ` Richard Biener
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2023-09-15 15:08 UTC (permalink / raw)
  To: GCC Patches

Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
and aarch64-unknown-linux-gnu; ok for trunk?

-- >8 --
In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
I proposed -fhardened, a new umbrella option that enables a reasonable set
of hardening flags.  The read of the room seems to be that the option
would be useful.  So here's a patch implementing that option.

Currently, -fhardened enables:

  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
  -D_GLIBCXX_ASSERTIONS
  -ftrivial-auto-var-init=pattern
  -fPIE  -pie  -Wl,-z,relro,-z,now
  -fstack-protector-strong
  -fstack-clash-protection
  -fcf-protection=full (x86 GNU/Linux only)

-fhardened will not override options that were specified on the command line
(before or after -fhardened).  For example,

     -D_FORTIFY_SOURCE=1 -fhardened

means that _FORTIFY_SOURCE=1 will be used.  Similarly,

      -fhardened -fstack-protector

will not enable -fstack-protector-strong.

In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
to anything.  I think we need a better way to show what it actually
enables.

gcc/c-family/ChangeLog:

	* c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
	and _GLIBCXX_ASSERTIONS.

gcc/ChangeLog:

	* common.opt (fhardened): New option.
	* config.in: Regenerate.
	* config/bpf/bpf.cc: Include "opts.h".
	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
	not inform that -fstack-protector does not work.
	* config/i386/i386-options.cc (ix86_option_override_internal): When
	-fhardened, maybe enable -fcf-protection=full.
	* configure: Regenerate.
	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
	* doc/invoke.texi: Document -fhardened.
	* gcc.cc (driver_handle_option): Remember if any link options or -static
	were specified on the command line.
	(process_command): When -fhardened, maybe enable -pie and
	-Wl,-z,relro,-z,now.
	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
	(finish_options): When -fhardened, enable
	-ftrivial-auto-var-init=pattern and -fstack-protector-strong.
	(print_help_hardened): New.
	(print_help): Call it.
	* toplev.cc (process_options): When -fhardened, enable
	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
	do not warn that -fstack-protector not supported for this target.

gcc/testsuite/ChangeLog:

	* gcc.misc-tests/help.exp: Test -fhardened.
	* c-c++-common/fhardened-1.S: New test.
	* c-c++-common/fhardened-1.c: New test.
	* c-c++-common/fhardened-10.c: New test.
	* c-c++-common/fhardened-11.c: New test.
	* c-c++-common/fhardened-12.c: New test.
	* c-c++-common/fhardened-13.c: New test.
	* c-c++-common/fhardened-14.c: New test.
	* c-c++-common/fhardened-2.c: New test.
	* c-c++-common/fhardened-3.c: New test.
	* c-c++-common/fhardened-5.c: New test.
	* c-c++-common/fhardened-6.c: New test.
	* c-c++-common/fhardened-7.c: New test.
	* c-c++-common/fhardened-8.c: New test.
	* c-c++-common/fhardened-9.c: New test.
	* gcc.target/i386/cf_check-6.c: New test.
---
 gcc/c-family/c-opts.cc                     | 29 ++++++++++++
 gcc/common.opt                             |  4 ++
 gcc/config.in                              | 12 +++++
 gcc/config/bpf/bpf.cc                      |  8 ++--
 gcc/config/i386/i386-options.cc            | 11 ++++-
 gcc/configure                              | 50 +++++++++++++++++++-
 gcc/configure.ac                           | 42 ++++++++++++++++-
 gcc/doc/invoke.texi                        | 29 +++++++++++-
 gcc/gcc.cc                                 | 39 +++++++++++++++-
 gcc/opts.cc                                | 53 ++++++++++++++++++++--
 gcc/opts.h                                 |  1 +
 gcc/testsuite/c-c++-common/fhardened-1.S   |  6 +++
 gcc/testsuite/c-c++-common/fhardened-1.c   | 14 ++++++
 gcc/testsuite/c-c++-common/fhardened-10.c  | 10 ++++
 gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
 gcc/testsuite/c-c++-common/fhardened-12.c  | 11 +++++
 gcc/testsuite/c-c++-common/fhardened-13.c  |  6 +++
 gcc/testsuite/c-c++-common/fhardened-14.c  |  6 +++
 gcc/testsuite/c-c++-common/fhardened-2.c   |  9 ++++
 gcc/testsuite/c-c++-common/fhardened-3.c   | 12 +++++
 gcc/testsuite/c-c++-common/fhardened-5.c   | 11 +++++
 gcc/testsuite/c-c++-common/fhardened-6.c   | 11 +++++
 gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-9.c   |  6 +++
 gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
 gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 +++++
 gcc/toplev.cc                              | 11 ++++-
 28 files changed, 416 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c

diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index d9f55f45e03..004e37be9c0 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -1514,6 +1514,9 @@ c_finish_options (void)
       cb_file_change (parse_in, cmd_map);
       linemap_line_start (line_table, 0, 1);
 
+      bool fortify_seen_p = false;
+      bool cxx_assert_seen_p = false;
+
       /* All command line defines must have the same location.  */
       cpp_force_token_locations (parse_in, line_table->highest_line);
       for (size_t i = 0; i < deferred_count; i++)
@@ -1531,6 +1534,32 @@ c_finish_options (void)
 	      else
 		cpp_assert (parse_in, opt->arg);
 	    }
+
+	  if (UNLIKELY (flag_hardened)
+	      && (opt->code == OPT_D || opt->code == OPT_U))
+	    {
+	      if (!fortify_seen_p)
+		fortify_seen_p
+		  = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
+		     && (opt->arg[15] == '\0' || opt->arg[15] == '='));
+	      if (!cxx_assert_seen_p)
+		cxx_assert_seen_p
+		  = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
+		     && (opt->arg[19] == '\0' || opt->arg[19] == '='));
+	    }
+	}
+
+      if (flag_hardened)
+	{
+	  if (!fortify_seen_p && optimize > 0)
+	    {
+	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
+		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
+	      else
+		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
+	    }
+	  if (!cxx_assert_seen_p)
+	    cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
 	}
 
       cpp_stop_forcing_token_locations (parse_in);
diff --git a/gcc/common.opt b/gcc/common.opt
index f137a1f81ac..cc6238bd656 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1827,6 +1827,10 @@ fharden-conditional-branches
 Common Var(flag_harden_conditional_branches) Optimization
 Harden conditional branches by checking reversed conditions.
 
+fhardened
+Common Driver Var(flag_hardened)
+Enable various security-relevant flags.
+
 ; Nonzero means ignore `#ident' directives.  0 means handle them.
 ; Generate position-independent code for executables if possible
 ; On SVR4 targets, it also controls whether or not to emit a
diff --git a/gcc/config.in b/gcc/config.in
index f0071456f03..54c4999f36d 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1670,6 +1670,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z now */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_NOW_SUPPORT
+#endif
+
+
 /* Define if your PowerPC64 linker only needs function descriptor syms. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_NO_DOT_SYMS
@@ -1713,6 +1719,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z relro */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_RELRO_SUPPORT
+#endif
+
+
 /* Define if your linker links a mix of read-only and read-write sections into
    a read-write section. */
 #ifndef USED_FOR_TARGET
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 437bd652de3..41dc7fd3dae 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 
 #include "core-builtins.h"
+#include "opts.h"
 
 /* Per-function machine data.  */
 struct GTY(()) machine_function
@@ -250,9 +251,10 @@ bpf_option_override (void)
   /* Disable -fstack-protector as it is not supported in BPF.  */
   if (flag_stack_protect)
     {
-      inform (input_location,
-              "%<-fstack-protector%> does not work "
-	      "on this architecture");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	inform (input_location,
+		"%<-fstack-protector%> does not work "
+		"on this architecture");
       flag_stack_protect = 0;
     }
 
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index e47f9ed5d5f..963593bcd27 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3024,10 +3024,19 @@ ix86_option_override_internal (bool main_args_p,
         = build_target_option_node (opts, opts_set);
     }
 
+  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
+  /* When -fhardened, enable -fcf-protection=full, but only when it's
+     compatible with this target, and when it wasn't already specified
+     on the command line.  */
+  if (opts->x_flag_hardened
+      && cf_okay_p
+      && opts->x_flag_cf_protection == CF_NONE)
+    opts->x_flag_cf_protection = CF_FULL;
+
   if (opts->x_flag_cf_protection != CF_NONE)
     {
       if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
-	  && !TARGET_64BIT && !TARGET_CMOV)
+	  && !cf_okay_p)
 	error ("%<-fcf-protection%> is not compatible with this target");
 
       opts->x_flag_cf_protection
diff --git a/gcc/configure b/gcc/configure
index 07e8a64afbb..9234a60636a 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -32602,7 +32602,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -32731,6 +32731,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
+$as_echo_n "checking linker -z now option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
+$as_echo "$ld_now_support" >&6; }
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
+$as_echo_n "checking linker -z relro option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
+$as_echo "$ld_relro_support" >&6; }
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index cb4be11facd..950a3f51370 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -7623,7 +7623,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -7724,6 +7724,46 @@ standards-compatible mode on s390 targets.])
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+AC_MSG_CHECKING(linker -z now option)
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
+  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z now])
+AC_MSG_RESULT($ld_now_support)
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+AC_MSG_CHECKING(linker -z relro option)
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
+  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z relro])
+AC_MSG_RESULT($ld_relro_support)
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 03d93e6b185..ecd81c113ef 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
 -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
 -fsanitize-undefined-trap-on-error  -fbounds-check
 -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
--fharden-compares -fharden-conditional-branches
+-fharden-compares -fharden-conditional-branches -fhardened
 -fstack-protector  -fstack-protector-all  -fstack-protector-strong
 -fstack-protector-explicit  -fstack-check
 -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym}
@@ -17369,6 +17369,33 @@ condition, and to call @code{__builtin_trap} if the result is
 unexpected.  Use with @samp{-fharden-compares} to cover all
 conditionals.
 
+@opindex fhardened
+@item -fhardened
+Enable a set of flags for C and C++ that improve the security of the
+generated code without affecting its ABI.  The precise flags enabled
+may change between major releases of GCC, but are currently:
+
+@gccoptlist{
+-D_FORTIFY_SOURCE=3
+-D_GLIBCXX_ASSERTIONS
+-ftrivial-auto-var-init=pattern
+-fPIE  -pie  -Wl,-z,relro,-z,now
+-fstack-protector-strong
+-fstack-clash-protection
+-fcf-protection=full @r{(x86 GNU/Linux only)}
+}
+
+The list of options enabled by @option{-fhardened} can be generated using
+the @option{--help=hardened} option.
+
+When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
+is used instead.
+
+@option{-fhardened} only enables a particular option if it wasn't
+already specified anywhere on the command line.  For instance,
+@option{-fhardened} @option{-fstack-protector} will only enable
+@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
+
 @opindex fstack-protector
 @item -fstack-protector
 Emit extra code to check for buffer overflows, such as stack smashing
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index a9dd0eb655c..db87c400c02 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
    driver added to dumpdir after dumpbase or linker output name.  */
 static bool dumpdir_trailing_dash_added = false;
 
+/* True if -r, -shared, -pie, or -no-pie were specified on the command
+   line.  */
+static bool any_link_options_p;
+
+/* True if -static was specified on the command line.  */
+static bool static_p;
+
 /* Basename of dump and aux outputs, computed from dumpbase (given or
    derived from output name), to override input_basename in non-%w %b
    et al.  */
@@ -4597,10 +4604,20 @@ driver_handle_option (struct gcc_options *opts,
       save_switch ("-o", 1, &arg, validated, true);
       return true;
 
-#ifdef ENABLE_DEFAULT_PIE
     case OPT_pie:
+#ifdef ENABLE_DEFAULT_PIE
       /* -pie is turned on by default.  */
+      validated = true;
 #endif
+    case OPT_r:
+    case OPT_shared:
+    case OPT_no_pie:
+      any_link_options_p = true;
+      break;
+
+    case OPT_static:
+      static_p = true;
+      break;
 
     case OPT_static_libgcc:
     case OPT_shared_libgcc:
@@ -4976,6 +4993,26 @@ process_command (unsigned int decoded_options_count,
 #endif
     }
 
+  /* TODO: check if -static -pie works and maybe use it.  */
+  if (flag_hardened && !any_link_options_p && !static_p)
+    {
+#ifdef HAVE_LD_PIE
+      save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
+#endif
+      /* These are passed straight down to collect2 so we have to break
+	 it up like this.  */
+      if (HAVE_LD_NOW_SUPPORT)
+	{
+	  add_infile ("-z", "*");
+	  add_infile ("now", "*");
+	}
+      if (HAVE_LD_RELRO_SUPPORT)
+	{
+	  add_infile ("-z", "*");
+	  add_infile ("relro", "*");
+	}
+    }
+
   /* Handle -gtoggle as it would later in toplev.cc:process_options to
      make the debug-level-gt spec function work as expected.  */
   if (flag_gtoggle)
diff --git a/gcc/opts.cc b/gcc/opts.cc
index ac81d4e4294..03e1fdaf8d3 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
 /* Set by -fcanon-prefix-map.  */
 bool flag_canon_prefix_map;
 
+/* Set by finish_options when flag_stack_protector was set only because of
+   -fhardened.  Yuck.  */
+bool flag_stack_protector_set_by_fhardened_p;
+
 static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
 /* Names of fundamental debug info formats indexed by enum
@@ -1093,6 +1097,9 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       opts->x_flag_section_anchors = 0;
     }
 
+  if (!opts_set->x_flag_auto_var_init && opts->x_flag_hardened)
+    opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
+
   if (!opts->x_flag_opts_finished)
     {
       /* We initialize opts->x_flag_pie to -1 so that targets can set a
@@ -1102,7 +1109,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	  /* We initialize opts->x_flag_pic to -1 so that we can tell if
 	     -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
 	  if (opts->x_flag_pic == -1)
-	    opts->x_flag_pie = DEFAULT_FLAG_PIE;
+	    opts->x_flag_pie = (opts->x_flag_hardened
+				? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
 	  else
 	    opts->x_flag_pie = 0;
 	}
@@ -1117,9 +1125,23 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
     }
 
   /* We initialize opts->x_flag_stack_protect to -1 so that targets
-     can set a default value.  */
+     can set a default value.  With --enable-default-ssp or -fhardened
+     the default is -fstack-protector-strong.  */
   if (opts->x_flag_stack_protect == -1)
-    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    {
+      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
+	 defined in such a way that it uses flag_stack_protect which can't
+	 be used here.  Moreover, some targets like BPF don't support
+	 -fstack-protector at all but we don't know that here.  So remember
+	 that flag_stack_protect was set at the behest of -fhardened.  */
+      if (opts->x_flag_hardened)
+	{
+	  opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
+	  flag_stack_protector_set_by_fhardened_p = true;
+	}
+      else
+	opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    }
 
   if (opts->x_optimize == 0)
     {
@@ -2461,6 +2483,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
   free (patch_area_arg);
 }
 
+/* Print options enabled by -fhardened.  */
+
+static void
+print_help_hardened ()
+{
+  printf ("%s\n", "The following options are enabled by -fhardened:");
+  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
+	  (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
+  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
+  printf ("  %s\n", "-ftrivial-auto-var-init=pattern");
+#ifdef HAVE_LD_PIE
+  printf ("  %s  %s\n", "-fPIE", "-pie");
+#endif
+  if (HAVE_LD_NOW_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,now");
+  if (HAVE_LD_RELRO_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,relro");
+  printf ("  %s\n", "-fstack-protector-strong");
+  printf ("  %s\n", "-fstack-clash-protection");
+  printf ("  %s\n", "-fcf-protection=full");
+  putchar ('\n');
+}
+
 /* Print help when OPT__help_ is set.  */
 
 void
@@ -2576,6 +2621,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
 	}
       else if (lang_flag != 0)
 	*pflags |= lang_flag;
+      else if (strncasecmp (a, "hardened", len) == 0)
+	print_help_hardened ();
       else
 	warning (0,
 		 "unrecognized argument to %<--help=%> option: %q.*s",
diff --git a/gcc/opts.h b/gcc/opts.h
index 00f377f9ca7..d89c5de8114 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -344,6 +344,7 @@ struct cl_option_handlers
 /* Hold command-line options associated with stack limitation.  */
 extern const char *opt_fstack_limit_symbol_arg;
 extern int opt_fstack_limit_register_no;
+extern bool flag_stack_protector_set_by_fhardened_p;
 
 /* Input file names.  */
 
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
new file mode 100644
index 00000000000..026c7afbaad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.S
@@ -0,0 +1,6 @@
+/* { dg-do preprocess { target pie } } */
+/* { dg-options "-fhardened" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
new file mode 100644
index 00000000000..dd3cde93805
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O" } */
+
+#ifndef __SSP_STRONG__
+# error "-fstack-protector-strong not enabled"
+#endif
+
+#if _FORTIFY_SOURCE < 2
+# error "_FORTIFY_SOURCE not enabled"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
new file mode 100644
index 00000000000..431bd5d3a80
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-10.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
+
+#if _FORTIFY_SOURCE != 1
+# error "_FORTIFY_SOURCE != 1"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
new file mode 100644
index 00000000000..b8fd65a960c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-11.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
+
+#ifndef _FORTIFY_SOURCE
+# error "_FORTIFY_SOURCE disabled when it should not be"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
new file mode 100644
index 00000000000..340a7bdad6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-12.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
new file mode 100644
index 00000000000..629ff6ff94b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-13.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
new file mode 100644
index 00000000000..bfcd000fe6a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-14.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -fno-PIE" } */
+
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
new file mode 100644
index 00000000000..aeba4e40a42
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-2.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -fstack-protector" } */
+
+#ifdef __SSP_STRONG__
+# error "-fstack-protector-strong enabled when it should not be"
+#endif
+#ifndef __SSP__
+# error "-fstack-protector not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
new file mode 100644
index 00000000000..105e013d734
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O0" } */
+/* Test that we don't get any diagnostic coming from libc headers.  */
+
+#include <stdio.h>
+
+/* The most useful C program known to man.  */
+
+int
+main ()
+{
+}
diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
new file mode 100644
index 00000000000..340a7bdad6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
new file mode 100644
index 00000000000..478caf9895b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
new file mode 100644
index 00000000000..daf91f2ca25
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-7.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -fpie" } */
+
+/* -fpie takes precedence over -fhardened */
+#if __PIE__ != 1
+# error "__PIE__ != 1"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
new file mode 100644
index 00000000000..87e2750efe2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-8.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -fPIC" } */
+
+/* -fPIC takes precedence over -fhardened */
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
new file mode 100644
index 00000000000..f64e7eba56c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-9.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
+
+#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
+# error "hardening enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
index 52b9cb0ab90..15d618a2528 100644
--- a/gcc/testsuite/gcc.misc-tests/help.exp
+++ b/gcc/testsuite/gcc.misc-tests/help.exp
@@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
 # Listing only excludes gives empty results.
 check_for_options c "--help=^joined,^separate" "" "" ""
 
+check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
+
 if [ info exists prev_columns ] {
     # Reset the enviroment variable to its oriuginal value.
     set env(COLUMNS) $prev_columns
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
new file mode 100644
index 00000000000..73b78dce889
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+/* Test that -fhardened enables CET.  */
+
+extern void bar (void) __attribute__((__cf_check__));
+
+void
+foo (void)
+{
+  bar ();
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index db62e3e995e..68d744630e1 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1575,6 +1575,12 @@ process_options (bool no_backend)
 		  "where the stack grows from lower to higher addresses");
       flag_stack_clash_protection = 0;
     }
+  else if (flag_hardened
+	   && !flag_stack_clash_protection
+	   /* Don't enable -fstack-clash-protection when -fstack-check=
+	      is used: it would result in confusing errors.  */
+	   && flag_stack_check == NO_STACK_CHECK)
+    flag_stack_clash_protection = 1;
 
   /* We cannot support -fstack-check= and -fstack-clash-protection at
      the same time.  */
@@ -1590,8 +1596,9 @@ process_options (bool no_backend)
      target already uses a soft frame pointer, the transition is trivial.  */
   if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
     {
-      warning_at (UNKNOWN_LOCATION, 0,
-		  "%<-fstack-protector%> not supported for this target");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "%<-fstack-protector%> not supported for this target");
       flag_stack_protect = 0;
     }
   if (!flag_stack_protect)

base-commit: 540a1d936d8f73f5e2efdefafd8342ec27773ae8
-- 
2.41.0


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] gcc: Introduce -fhardened
  2023-09-15 15:08 [PATCH] gcc: Introduce -fhardened Marek Polacek
@ 2023-09-18  6:57 ` Richard Biener
  2023-09-19 14:58   ` Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Biener @ 2023-09-18  6:57 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> and aarch64-unknown-linux-gnu; ok for trunk?
>
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags.  The read of the room seems to be that the option
> would be useful.  So here's a patch implementing that option.
>
> Currently, -fhardened enables:
>
>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>   -D_GLIBCXX_ASSERTIONS
>   -ftrivial-auto-var-init=pattern
>   -fPIE  -pie  -Wl,-z,relro,-z,now
>   -fstack-protector-strong
>   -fstack-clash-protection
>   -fcf-protection=full (x86 GNU/Linux only)
>
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened).  For example,
>
>      -D_FORTIFY_SOURCE=1 -fhardened
>
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>
>       -fhardened -fstack-protector
>
> will not enable -fstack-protector-strong.
>
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything.  I think we need a better way to show what it actually
> enables.

I do think we need to find a solution here to solve asserting compliance.
Maybe we can have -Whardened that will diagnose any altering of
-fhardened by other options on the command-line or by missed target
implementations?  People might for example use -fstack-protector
but don't really want to make protection lower than requested with -fhardened.

Any such conflict is much less appearant than when you use the
flags -fhardened composes.

Richard.

>
> gcc/c-family/ChangeLog:
>
>         * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
>         and _GLIBCXX_ASSERTIONS.
>
> gcc/ChangeLog:
>
>         * common.opt (fhardened): New option.
>         * config.in: Regenerate.
>         * config/bpf/bpf.cc: Include "opts.h".
>         (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
>         not inform that -fstack-protector does not work.
>         * config/i386/i386-options.cc (ix86_option_override_internal): When
>         -fhardened, maybe enable -fcf-protection=full.
>         * configure: Regenerate.
>         * configure.ac: Check if the linker supports '-z now' and '-z relro'.
>         * doc/invoke.texi: Document -fhardened.
>         * gcc.cc (driver_handle_option): Remember if any link options or -static
>         were specified on the command line.
>         (process_command): When -fhardened, maybe enable -pie and
>         -Wl,-z,relro,-z,now.
>         * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
>         (finish_options): When -fhardened, enable
>         -ftrivial-auto-var-init=pattern and -fstack-protector-strong.
>         (print_help_hardened): New.
>         (print_help): Call it.
>         * toplev.cc (process_options): When -fhardened, enable
>         -fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
>         do not warn that -fstack-protector not supported for this target.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.misc-tests/help.exp: Test -fhardened.
>         * c-c++-common/fhardened-1.S: New test.
>         * c-c++-common/fhardened-1.c: New test.
>         * c-c++-common/fhardened-10.c: New test.
>         * c-c++-common/fhardened-11.c: New test.
>         * c-c++-common/fhardened-12.c: New test.
>         * c-c++-common/fhardened-13.c: New test.
>         * c-c++-common/fhardened-14.c: New test.
>         * c-c++-common/fhardened-2.c: New test.
>         * c-c++-common/fhardened-3.c: New test.
>         * c-c++-common/fhardened-5.c: New test.
>         * c-c++-common/fhardened-6.c: New test.
>         * c-c++-common/fhardened-7.c: New test.
>         * c-c++-common/fhardened-8.c: New test.
>         * c-c++-common/fhardened-9.c: New test.
>         * gcc.target/i386/cf_check-6.c: New test.
> ---
>  gcc/c-family/c-opts.cc                     | 29 ++++++++++++
>  gcc/common.opt                             |  4 ++
>  gcc/config.in                              | 12 +++++
>  gcc/config/bpf/bpf.cc                      |  8 ++--
>  gcc/config/i386/i386-options.cc            | 11 ++++-
>  gcc/configure                              | 50 +++++++++++++++++++-
>  gcc/configure.ac                           | 42 ++++++++++++++++-
>  gcc/doc/invoke.texi                        | 29 +++++++++++-
>  gcc/gcc.cc                                 | 39 +++++++++++++++-
>  gcc/opts.cc                                | 53 ++++++++++++++++++++--
>  gcc/opts.h                                 |  1 +
>  gcc/testsuite/c-c++-common/fhardened-1.S   |  6 +++
>  gcc/testsuite/c-c++-common/fhardened-1.c   | 14 ++++++
>  gcc/testsuite/c-c++-common/fhardened-10.c  | 10 ++++
>  gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
>  gcc/testsuite/c-c++-common/fhardened-12.c  | 11 +++++
>  gcc/testsuite/c-c++-common/fhardened-13.c  |  6 +++
>  gcc/testsuite/c-c++-common/fhardened-14.c  |  6 +++
>  gcc/testsuite/c-c++-common/fhardened-2.c   |  9 ++++
>  gcc/testsuite/c-c++-common/fhardened-3.c   | 12 +++++
>  gcc/testsuite/c-c++-common/fhardened-5.c   | 11 +++++
>  gcc/testsuite/c-c++-common/fhardened-6.c   | 11 +++++
>  gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-9.c   |  6 +++
>  gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
>  gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 +++++
>  gcc/toplev.cc                              | 11 ++++-
>  28 files changed, 416 insertions(+), 13 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index d9f55f45e03..004e37be9c0 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1514,6 +1514,9 @@ c_finish_options (void)
>        cb_file_change (parse_in, cmd_map);
>        linemap_line_start (line_table, 0, 1);
>
> +      bool fortify_seen_p = false;
> +      bool cxx_assert_seen_p = false;
> +
>        /* All command line defines must have the same location.  */
>        cpp_force_token_locations (parse_in, line_table->highest_line);
>        for (size_t i = 0; i < deferred_count; i++)
> @@ -1531,6 +1534,32 @@ c_finish_options (void)
>               else
>                 cpp_assert (parse_in, opt->arg);
>             }
> +
> +         if (UNLIKELY (flag_hardened)
> +             && (opt->code == OPT_D || opt->code == OPT_U))
> +           {
> +             if (!fortify_seen_p)
> +               fortify_seen_p
> +                 = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> +                    && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> +             if (!cxx_assert_seen_p)
> +               cxx_assert_seen_p
> +                 = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> +                    && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> +           }
> +       }
> +
> +      if (flag_hardened)
> +       {
> +         if (!fortify_seen_p && optimize > 0)
> +           {
> +             if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> +             else
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> +           }
> +         if (!cxx_assert_seen_p)
> +           cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
>         }
>
>        cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index f137a1f81ac..cc6238bd656 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1827,6 +1827,10 @@ fharden-conditional-branches
>  Common Var(flag_harden_conditional_branches) Optimization
>  Harden conditional branches by checking reversed conditions.
>
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
>  ; Nonzero means ignore `#ident' directives.  0 means handle them.
>  ; Generate position-independent code for executables if possible
>  ; On SVR4 targets, it also controls whether or not to emit a
> diff --git a/gcc/config.in b/gcc/config.in
> index f0071456f03..54c4999f36d 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1670,6 +1670,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
>  /* Define if your PowerPC64 linker only needs function descriptor syms. */
>  #ifndef USED_FOR_TARGET
>  #undef HAVE_LD_NO_DOT_SYMS
> @@ -1713,6 +1719,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
>  /* Define if your linker links a mix of read-only and read-write sections into
>     a read-write section. */
>  #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 437bd652de3..41dc7fd3dae 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimplify-me.h"
>
>  #include "core-builtins.h"
> +#include "opts.h"
>
>  /* Per-function machine data.  */
>  struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
>    /* Disable -fstack-protector as it is not supported in BPF.  */
>    if (flag_stack_protect)
>      {
> -      inform (input_location,
> -              "%<-fstack-protector%> does not work "
> -             "on this architecture");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       inform (input_location,
> +               "%<-fstack-protector%> does not work "
> +               "on this architecture");
>        flag_stack_protect = 0;
>      }
>
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index e47f9ed5d5f..963593bcd27 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3024,10 +3024,19 @@ ix86_option_override_internal (bool main_args_p,
>          = build_target_option_node (opts, opts_set);
>      }
>
> +  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> +  /* When -fhardened, enable -fcf-protection=full, but only when it's
> +     compatible with this target, and when it wasn't already specified
> +     on the command line.  */
> +  if (opts->x_flag_hardened
> +      && cf_okay_p
> +      && opts->x_flag_cf_protection == CF_NONE)
> +    opts->x_flag_cf_protection = CF_FULL;
> +
>    if (opts->x_flag_cf_protection != CF_NONE)
>      {
>        if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> -         && !TARGET_64BIT && !TARGET_CMOV)
> +         && !cf_okay_p)
>         error ("%<-fcf-protection%> is not compatible with this target");
>
>        opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index 07e8a64afbb..9234a60636a 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -32602,7 +32602,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -32731,6 +32731,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index cb4be11facd..950a3f51370 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7623,7 +7623,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -7724,6 +7724,46 @@ standards-compatible mode on s390 targets.])
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> +  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> +  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 03d93e6b185..ecd81c113ef 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
>  -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
>  -fsanitize-undefined-trap-on-error  -fbounds-check
>  -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches -fhardened
>  -fstack-protector  -fstack-protector-all  -fstack-protector-strong
>  -fstack-protector-explicit  -fstack-check
>  -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym}
> @@ -17369,6 +17369,33 @@ condition, and to call @code{__builtin_trap} if the result is
>  unexpected.  Use with @samp{-fharden-compares} to cover all
>  conditionals.
>
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI.  The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=pattern
> +-fPIE  -pie  -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line.  For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
>  @opindex fstack-protector
>  @item -fstack-protector
>  Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index a9dd0eb655c..db87c400c02 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>     driver added to dumpdir after dumpbase or linker output name.  */
>  static bool dumpdir_trailing_dash_added = false;
>
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> +   line.  */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line.  */
> +static bool static_p;
> +
>  /* Basename of dump and aux outputs, computed from dumpbase (given or
>     derived from output name), to override input_basename in non-%w %b
>     et al.  */
> @@ -4597,10 +4604,20 @@ driver_handle_option (struct gcc_options *opts,
>        save_switch ("-o", 1, &arg, validated, true);
>        return true;
>
> -#ifdef ENABLE_DEFAULT_PIE
>      case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
>        /* -pie is turned on by default.  */
> +      validated = true;
>  #endif
> +    case OPT_r:
> +    case OPT_shared:
> +    case OPT_no_pie:
> +      any_link_options_p = true;
> +      break;
> +
> +    case OPT_static:
> +      static_p = true;
> +      break;
>
>      case OPT_static_libgcc:
>      case OPT_shared_libgcc:
> @@ -4976,6 +4993,26 @@ process_command (unsigned int decoded_options_count,
>  #endif
>      }
>
> +  /* TODO: check if -static -pie works and maybe use it.  */
> +  if (flag_hardened && !any_link_options_p && !static_p)
> +    {
> +#ifdef HAVE_LD_PIE
> +      save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> +      /* These are passed straight down to collect2 so we have to break
> +        it up like this.  */
> +      if (HAVE_LD_NOW_SUPPORT)
> +       {
> +         add_infile ("-z", "*");
> +         add_infile ("now", "*");
> +       }
> +      if (HAVE_LD_RELRO_SUPPORT)
> +       {
> +         add_infile ("-z", "*");
> +         add_infile ("relro", "*");
> +       }
> +    }
> +
>    /* Handle -gtoggle as it would later in toplev.cc:process_options to
>       make the debug-level-gt spec function work as expected.  */
>    if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index ac81d4e4294..03e1fdaf8d3 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
>  /* Set by -fcanon-prefix-map.  */
>  bool flag_canon_prefix_map;
>
> +/* Set by finish_options when flag_stack_protector was set only because of
> +   -fhardened.  Yuck.  */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
>  static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>
>  /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,9 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>        opts->x_flag_section_anchors = 0;
>      }
>
> +  if (!opts_set->x_flag_auto_var_init && opts->x_flag_hardened)
> +    opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
> +
>    if (!opts->x_flag_opts_finished)
>      {
>        /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1109,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>           /* We initialize opts->x_flag_pic to -1 so that we can tell if
>              -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
>           if (opts->x_flag_pic == -1)
> -           opts->x_flag_pie = DEFAULT_FLAG_PIE;
> +           opts->x_flag_pie = (opts->x_flag_hardened
> +                               ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
>           else
>             opts->x_flag_pie = 0;
>         }
> @@ -1117,9 +1125,23 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>      }
>
>    /* We initialize opts->x_flag_stack_protect to -1 so that targets
> -     can set a default value.  */
> +     can set a default value.  With --enable-default-ssp or -fhardened
> +     the default is -fstack-protector-strong.  */
>    if (opts->x_flag_stack_protect == -1)
> -    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    {
> +      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> +        defined in such a way that it uses flag_stack_protect which can't
> +        be used here.  Moreover, some targets like BPF don't support
> +        -fstack-protector at all but we don't know that here.  So remember
> +        that flag_stack_protect was set at the behest of -fhardened.  */
> +      if (opts->x_flag_hardened)
> +       {
> +         opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> +         flag_stack_protector_set_by_fhardened_p = true;
> +       }
> +      else
> +       opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    }
>
>    if (opts->x_optimize == 0)
>      {
> @@ -2461,6 +2483,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>    free (patch_area_arg);
>  }
>
> +/* Print options enabled by -fhardened.  */
> +
> +static void
> +print_help_hardened ()
> +{
> +  printf ("%s\n", "The following options are enabled by -fhardened:");
> +  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
> +         (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> +  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
> +  printf ("  %s\n", "-ftrivial-auto-var-init=pattern");
> +#ifdef HAVE_LD_PIE
> +  printf ("  %s  %s\n", "-fPIE", "-pie");
> +#endif
> +  if (HAVE_LD_NOW_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,now");
> +  if (HAVE_LD_RELRO_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,relro");
> +  printf ("  %s\n", "-fstack-protector-strong");
> +  printf ("  %s\n", "-fstack-clash-protection");
> +  printf ("  %s\n", "-fcf-protection=full");
> +  putchar ('\n');
> +}
> +
>  /* Print help when OPT__help_ is set.  */
>
>  void
> @@ -2576,6 +2621,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
>         }
>        else if (lang_flag != 0)
>         *pflags |= lang_flag;
> +      else if (strncasecmp (a, "hardened", len) == 0)
> +       print_help_hardened ();
>        else
>         warning (0,
>                  "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
>  /* Hold command-line options associated with stack limitation.  */
>  extern const char *opt_fstack_limit_symbol_arg;
>  extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
>
>  /* Input file names.  */
>
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..026c7afbaad
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target pie } } */
> +/* { dg-options "-fhardened" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..dd3cde93805
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..431bd5d3a80
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..b8fd65a960c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..340a7bdad6d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..629ff6ff94b
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..bfcd000fe6a
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..aeba4e40a42
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..105e013d734
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers.  */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man.  */
> +
> +int
> +main ()
> +{
> +}
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..340a7bdad6d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..478caf9895b
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..daf91f2ca25
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..87e2750efe2
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..f64e7eba56c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
>  # Listing only excludes gives empty results.
>  check_for_options c "--help=^joined,^separate" "" "" ""
>
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
>  if [ info exists prev_columns ] {
>      # Reset the enviroment variable to its oriuginal value.
>      set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET.  */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> +  bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index db62e3e995e..68d744630e1 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1575,6 +1575,12 @@ process_options (bool no_backend)
>                   "where the stack grows from lower to higher addresses");
>        flag_stack_clash_protection = 0;
>      }
> +  else if (flag_hardened
> +          && !flag_stack_clash_protection
> +          /* Don't enable -fstack-clash-protection when -fstack-check=
> +             is used: it would result in confusing errors.  */
> +          && flag_stack_check == NO_STACK_CHECK)
> +    flag_stack_clash_protection = 1;
>
>    /* We cannot support -fstack-check= and -fstack-clash-protection at
>       the same time.  */
> @@ -1590,8 +1596,9 @@ process_options (bool no_backend)
>       target already uses a soft frame pointer, the transition is trivial.  */
>    if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>      {
> -      warning_at (UNKNOWN_LOCATION, 0,
> -                 "%<-fstack-protector%> not supported for this target");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "%<-fstack-protector%> not supported for this target");
>        flag_stack_protect = 0;
>      }
>    if (!flag_stack_protect)
>
> base-commit: 540a1d936d8f73f5e2efdefafd8342ec27773ae8
> --
> 2.41.0
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] gcc: Introduce -fhardened
  2023-09-18  6:57 ` Richard Biener
@ 2023-09-19 14:58   ` Marek Polacek
  2023-09-19 15:14     ` Jakub Jelinek
  2023-10-11 20:48     ` [PATCH v2] " Marek Polacek
  0 siblings, 2 replies; 28+ messages in thread
From: Marek Polacek @ 2023-09-19 14:58 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > and aarch64-unknown-linux-gnu; ok for trunk?
> >
> > -- >8 --
> > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > of hardening flags.  The read of the room seems to be that the option
> > would be useful.  So here's a patch implementing that option.
> >
> > Currently, -fhardened enables:
> >
> >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> >   -D_GLIBCXX_ASSERTIONS
> >   -ftrivial-auto-var-init=pattern
> >   -fPIE  -pie  -Wl,-z,relro,-z,now
> >   -fstack-protector-strong
> >   -fstack-clash-protection
> >   -fcf-protection=full (x86 GNU/Linux only)
> >
> > -fhardened will not override options that were specified on the command line
> > (before or after -fhardened).  For example,
> >
> >      -D_FORTIFY_SOURCE=1 -fhardened
> >
> > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> >
> >       -fhardened -fstack-protector
> >
> > will not enable -fstack-protector-strong.
> >
> > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > to anything.  I think we need a better way to show what it actually
> > enables.
> 
> I do think we need to find a solution here to solve asserting compliance.

Fair enough.

> Maybe we can have -Whardened that will diagnose any altering of
> -fhardened by other options on the command-line or by missed target
> implementations?  People might for example use -fstack-protector
> but don't really want to make protection lower than requested with -fhardened.
> 
> Any such conflict is much less appearant than when you use the
> flags -fhardened composes.

How about: --help=hardened says which options -fhardened attempts to
enable, and -Whardened warns when it didn't enable an option?  E.g.,

  -fstack-protector -fhardened -Whardened

would say that it didn't enable -fstack-protector-strong because
-fstack-protector was specified on the command line?

If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
list -z now, likewise for -z relro.

Unclear if -Whardened should be enabled by default, but probably yes?

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] gcc: Introduce -fhardened
  2023-09-19 14:58   ` Marek Polacek
@ 2023-09-19 15:14     ` Jakub Jelinek
  2023-10-11 20:48     ` [PATCH v2] " Marek Polacek
  1 sibling, 0 replies; 28+ messages in thread
From: Jakub Jelinek @ 2023-09-19 15:14 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, GCC Patches

On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > of hardening flags.  The read of the room seems to be that the option
> > > would be useful.  So here's a patch implementing that option.
> > >
> > > Currently, -fhardened enables:
> > >
> > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > >   -D_GLIBCXX_ASSERTIONS
> > >   -ftrivial-auto-var-init=pattern
> > >   -fPIE  -pie  -Wl,-z,relro,-z,now
> > >   -fstack-protector-strong
> > >   -fstack-clash-protection
> > >   -fcf-protection=full (x86 GNU/Linux only)
> > >
> > > -fhardened will not override options that were specified on the command line
> > > (before or after -fhardened).  For example,
> > >
> > >      -D_FORTIFY_SOURCE=1 -fhardened
> > >
> > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> > >
> > >       -fhardened -fstack-protector
> > >
> > > will not enable -fstack-protector-strong.
> > >
> > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > to anything.  I think we need a better way to show what it actually
> > > enables.
> > 
> > I do think we need to find a solution here to solve asserting compliance.
> 
> Fair enough.

Well, asserting compliance doesn't make sense, because many of these features
are only best effort.  So, one can assert that certain options have been
passed to the compiler (or not), and for that the current
-grecord-gcc-switches I think works mostly fine (well, it doesn't record -D*
options), one knows the compiler version/snapshot date etc. and what options
have been passed and can by repeating those options see what is and isn't
enabled in that case.
As for what exact options are actually enabled in the end, --help should be
able to answer that.  Still, even if one records that -D_FORTIFY_SOURCE=3
was passed on the command line, that doesn't mean there is no
#undef _FORTIFY_SOURCE in the source before including headers, or that
the compiler has been successful to figure out object size (static or
dynamic) for certain pointer, or that a function has some array so that it
will use stack protector guard, or that certain function didn't disable
-fstack-protector through function attributes etc.
So, if one wants to know if certain vulnerability exploit can be stopped
through hardening, one needs to analyze actually emitted code, just looking
for checkboxes isn't enough.
One can assert -D_FORTIFY_SOURCE=2 has been passed, but without glibc
headers being used and actually using __builtin_*object_size it doesn't do
anything either.  Programs can just declare memcpy etc. themselves and not
include glibc headers...

If the checkboxes are desirable for some reason, perhaps we could introduce
a new DWARF DW_AT_GNU_hardening attribute which would contain say bitfield
of which of those hardening features have been enabled (though, not sure if
we want to emit them just per DW_TAG_compile_unit, or DW_TAG_subprogram,
or both (say put on DW_TAG_compile_unit always if at least one of those is
enabled and on DW_TAG_subprogram only if it is different from the CU one).

	Jakub


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v2] gcc: Introduce -fhardened
  2023-09-19 14:58   ` Marek Polacek
  2023-09-19 15:14     ` Jakub Jelinek
@ 2023-10-11 20:48     ` Marek Polacek
  2023-10-18 20:12       ` Qing Zhao
  2023-10-19 12:24       ` Richard Biener
  1 sibling, 2 replies; 28+ messages in thread
From: Marek Polacek @ 2023-10-11 20:48 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> > >
> > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > > and aarch64-unknown-linux-gnu; ok for trunk?
> > >
> > > -- >8 --
> > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > of hardening flags.  The read of the room seems to be that the option
> > > would be useful.  So here's a patch implementing that option.
> > >
> > > Currently, -fhardened enables:
> > >
> > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > >   -D_GLIBCXX_ASSERTIONS
> > >   -ftrivial-auto-var-init=pattern
> > >   -fPIE  -pie  -Wl,-z,relro,-z,now
> > >   -fstack-protector-strong
> > >   -fstack-clash-protection
> > >   -fcf-protection=full (x86 GNU/Linux only)
> > >
> > > -fhardened will not override options that were specified on the command line
> > > (before or after -fhardened).  For example,
> > >
> > >      -D_FORTIFY_SOURCE=1 -fhardened
> > >
> > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> > >
> > >       -fhardened -fstack-protector
> > >
> > > will not enable -fstack-protector-strong.
> > >
> > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > to anything.  I think we need a better way to show what it actually
> > > enables.
> > 
> > I do think we need to find a solution here to solve asserting compliance.
> 
> Fair enough.
> 
> > Maybe we can have -Whardened that will diagnose any altering of
> > -fhardened by other options on the command-line or by missed target
> > implementations?  People might for example use -fstack-protector
> > but don't really want to make protection lower than requested with -fhardened.
> > 
> > Any such conflict is much less appearant than when you use the
> > flags -fhardened composes.
> 
> How about: --help=hardened says which options -fhardened attempts to
> enable, and -Whardened warns when it didn't enable an option?  E.g.,
> 
>   -fstack-protector -fhardened -Whardened
> 
> would say that it didn't enable -fstack-protector-strong because
> -fstack-protector was specified on the command line?
> 
> If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
> list -z now, likewise for -z relro.
> 
> Unclear if -Whardened should be enabled by default, but probably yes?

Here's v2 which adds -Whardened (enabled by default).

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
I proposed -fhardened, a new umbrella option that enables a reasonable set
of hardening flags.  The read of the room seems to be that the option
would be useful.  So here's a patch implementing that option.

Currently, -fhardened enables:

  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
  -D_GLIBCXX_ASSERTIONS
  -ftrivial-auto-var-init=pattern
  -fPIE  -pie  -Wl,-z,relro,-z,now
  -fstack-protector-strong
  -fstack-clash-protection
  -fcf-protection=full (x86 GNU/Linux only)

-fhardened will not override options that were specified on the command line
(before or after -fhardened).  For example,

     -D_FORTIFY_SOURCE=1 -fhardened

means that _FORTIFY_SOURCE=1 will be used.  Similarly,

      -fhardened -fstack-protector

will not enable -fstack-protector-strong.

In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
to anything.  This patch provides -Whardened, enabled by default, which
warns when -fhardened couldn't enable a particular option.  I think most
often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
were not enabled.

gcc/c-family/ChangeLog:

	* c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
	and _GLIBCXX_ASSERTIONS.

gcc/ChangeLog:

	* common.opt (Whardened, fhardened): New options.
	* config.in: Regenerate.
	* config/bpf/bpf.cc: Include "opts.h".
	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
	not inform that -fstack-protector does not work.
	* config/i386/i386-options.cc (ix86_option_override_internal): When
	-fhardened, maybe enable -fcf-protection=full.
	* configure: Regenerate.
	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
	* doc/invoke.texi: Document -fhardened and -Whardened.
	* gcc.cc (driver_handle_option): Remember if any link options or -static
	were specified on the command line.
	(process_command): When -fhardened, maybe enable -pie and
	-Wl,-z,relro,-z,now.
	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
	(finish_options): When -fhardened, enable
	-ftrivial-auto-var-init=pattern and -fstack-protector-strong.
	(print_help_hardened): New.
	(print_help): Call it.
	* toplev.cc (process_options): When -fhardened, enable
	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
	do not warn that -fstack-protector not supported for this target.

gcc/testsuite/ChangeLog:

	* gcc.misc-tests/help.exp: Test -fhardened.
	* c-c++-common/fhardened-1.S: New test.
	* c-c++-common/fhardened-1.c: New test.
	* c-c++-common/fhardened-10.c: New test.
	* c-c++-common/fhardened-11.c: New test.
	* c-c++-common/fhardened-12.c: New test.
	* c-c++-common/fhardened-13.c: New test.
	* c-c++-common/fhardened-14.c: New test.
	* c-c++-common/fhardened-15.c: New test.
	* c-c++-common/fhardened-2.c: New test.
	* c-c++-common/fhardened-3.c: New test.
	* c-c++-common/fhardened-4.c: New test.
	* c-c++-common/fhardened-5.c: New test.
	* c-c++-common/fhardened-6.c: New test.
	* c-c++-common/fhardened-7.c: New test.
	* c-c++-common/fhardened-8.c: New test.
	* c-c++-common/fhardened-9.c: New test.
	* gcc.target/i386/cf_check-6.c: New test.
---
 gcc/c-family/c-opts.cc                     | 42 ++++++++++++++
 gcc/common.opt                             |  8 +++
 gcc/config.in                              | 12 ++++
 gcc/config/bpf/bpf.cc                      |  8 ++-
 gcc/config/i386/i386-options.cc            | 17 +++++-
 gcc/configure                              | 50 +++++++++++++++-
 gcc/configure.ac                           | 42 +++++++++++++-
 gcc/doc/invoke.texi                        | 44 +++++++++++++-
 gcc/gcc.cc                                 | 48 +++++++++++++++-
 gcc/opts.cc                                | 67 +++++++++++++++++++++-
 gcc/opts.h                                 |  1 +
 gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
 gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
 gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
 gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
 gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
 gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
 gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
 gcc/toplev.cc                              | 18 +++++-
 30 files changed, 503 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c

diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index ce2e021e69d..f5f6ba24290 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -1556,6 +1556,9 @@ c_finish_options (void)
       cb_file_change (parse_in, cmd_map);
       linemap_line_start (line_table, 0, 1);
 
+      bool fortify_seen_p = false;
+      bool cxx_assert_seen_p = false;
+
       /* All command line defines must have the same location.  */
       cpp_force_token_locations (parse_in, line_table->highest_line);
       for (size_t i = 0; i < deferred_count; i++)
@@ -1573,6 +1576,45 @@ c_finish_options (void)
 	      else
 		cpp_assert (parse_in, opt->arg);
 	    }
+
+	  if (UNLIKELY (flag_hardened)
+	      && (opt->code == OPT_D || opt->code == OPT_U))
+	    {
+	      if (!fortify_seen_p)
+		fortify_seen_p
+		  = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
+		     && (opt->arg[15] == '\0' || opt->arg[15] == '='));
+	      if (!cxx_assert_seen_p)
+		cxx_assert_seen_p
+		  = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
+		     && (opt->arg[19] == '\0' || opt->arg[19] == '='));
+	    }
+	}
+
+      if (flag_hardened)
+	{
+	  if (!fortify_seen_p && optimize > 0)
+	    {
+	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
+		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
+	      else
+		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
+	    }
+	  else if (optimize == 0)
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because optimizations are turned off");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because it was specified in %<-D%> or %<-U%>");
+	  if (!cxx_assert_seen_p)
+	    cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_GLIBCXX_ASSERTIONS%> is not enabled by "
+			"%<-fhardened%> because it was specified in %<-D%> "
+			"or %<-U%>");
 	}
 
       cpp_stop_forcing_token_locations (parse_in);
diff --git a/gcc/common.opt b/gcc/common.opt
index f137a1f81ac..60c13b9ffd2 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -634,6 +634,10 @@ Wfree-nonheap-object
 Common Var(warn_free_nonheap_object) Init(1) Warning
 Warn when attempting to free a non-heap object.
 
+Whardened
+Common Var(warn_hardened) Init(1) Warning
+Warn when -fhardened did not enable an option from its set.
+
 Whsa
 Common Ignore Warning
 Does nothing.  Preserved for backward compatibility.
@@ -1827,6 +1831,10 @@ fharden-conditional-branches
 Common Var(flag_harden_conditional_branches) Optimization
 Harden conditional branches by checking reversed conditions.
 
+fhardened
+Common Driver Var(flag_hardened)
+Enable various security-relevant flags.
+
 ; Nonzero means ignore `#ident' directives.  0 means handle them.
 ; Generate position-independent code for executables if possible
 ; On SVR4 targets, it also controls whether or not to emit a
diff --git a/gcc/config.in b/gcc/config.in
index d04718ad128..faa941c1385 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1676,6 +1676,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z now */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_NOW_SUPPORT
+#endif
+
+
 /* Define if your PowerPC64 linker only needs function descriptor syms. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_NO_DOT_SYMS
@@ -1719,6 +1725,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z relro */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_RELRO_SUPPORT
+#endif
+
+
 /* Define if your linker links a mix of read-only and read-write sections into
    a read-write section. */
 #ifndef USED_FOR_TARGET
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 437bd652de3..41dc7fd3dae 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 
 #include "core-builtins.h"
+#include "opts.h"
 
 /* Per-function machine data.  */
 struct GTY(()) machine_function
@@ -250,9 +251,10 @@ bpf_option_override (void)
   /* Disable -fstack-protector as it is not supported in BPF.  */
   if (flag_stack_protect)
     {
-      inform (input_location,
-              "%<-fstack-protector%> does not work "
-	      "on this architecture");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	inform (input_location,
+		"%<-fstack-protector%> does not work "
+		"on this architecture");
       flag_stack_protect = 0;
     }
 
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index 06af373ca57..22ede9e15b5 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
         = build_target_option_node (opts, opts_set);
     }
 
+  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
+  /* When -fhardened, enable -fcf-protection=full, but only when it's
+     compatible with this target, and when it wasn't already specified
+     on the command line.  */
+  if (opts->x_flag_hardened && cf_okay_p)
+    {
+      if (opts->x_flag_cf_protection == CF_NONE)
+	opts->x_flag_cf_protection = CF_FULL;
+      else if (opts->x_flag_cf_protection != CF_FULL)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fcf-protection=full%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (opts->x_flag_cf_protection != CF_NONE)
     {
       if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
-	  && !TARGET_64BIT && !TARGET_CMOV)
+	  && !cf_okay_p)
 	error ("%<-fcf-protection%> is not compatible with this target");
 
       opts->x_flag_cf_protection
diff --git a/gcc/configure b/gcc/configure
index c43bde8174b..e2aac56edf6 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
+$as_echo_n "checking linker -z now option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
+$as_echo "$ld_now_support" >&6; }
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
+$as_echo_n "checking linker -z relro option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
+$as_echo "$ld_relro_support" >&6; }
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index fb8e32f8ee5..6a090ccf3bd 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+AC_MSG_CHECKING(linker -z now option)
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
+  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z now])
+AC_MSG_RESULT($ld_now_support)
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+AC_MSG_CHECKING(linker -z relro option)
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
+  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z relro])
+AC_MSG_RESULT($ld_relro_support)
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7c5f81d9783..48e6a3f433c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-y2k  -Wframe-address
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
 -Wno-if-not-aligned  -Wno-ignored-attributes
--Wignored-qualifiers  -Wno-incompatible-pointer-types
+-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
 -Wno-implicit-function-declaration  -Wno-implicit-int
 -Winfinite-recursion
@@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
 -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
 -fsanitize-undefined-trap-on-error  -fbounds-check
 -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
--fharden-compares -fharden-conditional-branches
+-fharden-compares -fharden-conditional-branches -fhardened
 -fstack-protector  -fstack-protector-all  -fstack-protector-strong
 -fstack-protector-explicit  -fstack-check
 -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym}
@@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
 Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
 This warning is enabled by @option{-Wall}.
 
+@opindex Whardened
+@opindex Wno-hardened
+@item -Whardened
+Warn when @option{-fhardened} did not enable an option from its set (for
+which see @option{-fhardened}).  For instance, using @option{-fhardened}
+and @option{-fstack-protector} at the same time on the command line causes
+@option{-Whardened} to warn because @option{-fstack-protector-strong} is
+not enabled by @option{-fhardened}.
+
+This warning is enabled by default and has effect only when @option{-fhardened}
+is enabled.
+
 @opindex Wimplicit-fallthrough
 @opindex Wno-implicit-fallthrough
 @item -Wimplicit-fallthrough
@@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
 unexpected.  Use with @samp{-fharden-compares} to cover all
 conditionals.
 
+@opindex fhardened
+@item -fhardened
+Enable a set of flags for C and C++ that improve the security of the
+generated code without affecting its ABI.  The precise flags enabled
+may change between major releases of GCC, but are currently:
+
+@c Keep this in sync with print_help_hardened!
+@gccoptlist{
+-D_FORTIFY_SOURCE=3
+-D_GLIBCXX_ASSERTIONS
+-ftrivial-auto-var-init=pattern
+-fPIE  -pie  -Wl,-z,relro,-z,now
+-fstack-protector-strong
+-fstack-clash-protection
+-fcf-protection=full @r{(x86 GNU/Linux only)}
+}
+
+The list of options enabled by @option{-fhardened} can be generated using
+the @option{--help=hardened} option.
+
+When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
+is used instead.
+
+@option{-fhardened} only enables a particular option if it wasn't
+already specified anywhere on the command line.  For instance,
+@option{-fhardened} @option{-fstack-protector} will only enable
+@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
+
 @opindex fstack-protector
 @item -fstack-protector
 Emit extra code to check for buffer overflows, such as stack smashing
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index c6e600fa0d3..ed4e2400e91 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
    driver added to dumpdir after dumpbase or linker output name.  */
 static bool dumpdir_trailing_dash_added = false;
 
+/* True if -r, -shared, -pie, or -no-pie were specified on the command
+   line.  */
+static bool any_link_options_p;
+
+/* True if -static was specified on the command line.  */
+static bool static_p;
+
 /* Basename of dump and aux outputs, computed from dumpbase (given or
    derived from output name), to override input_basename in non-%w %b
    et al.  */
@@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
       save_switch ("-o", 1, &arg, validated, true);
       return true;
 
-#ifdef ENABLE_DEFAULT_PIE
     case OPT_pie:
+#ifdef ENABLE_DEFAULT_PIE
       /* -pie is turned on by default.  */
+      validated = true;
 #endif
+    case OPT_r:
+    case OPT_shared:
+    case OPT_no_pie:
+      any_link_options_p = true;
+      break;
+
+    case OPT_static:
+      static_p = true;
+      break;
 
     case OPT_static_libgcc:
     case OPT_shared_libgcc:
@@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
 #endif
     }
 
+  /* TODO: check if -static -pie works and maybe use it.  */
+  if (flag_hardened)
+    {
+      if (!any_link_options_p && !static_p)
+	{
+#ifdef HAVE_LD_PIE
+	  save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
+#endif
+	  /* These are passed straight down to collect2 so we have to break
+	     it up like this.  */
+	  if (HAVE_LD_NOW_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("now", "*");
+	    }
+	  if (HAVE_LD_RELRO_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("relro", "*");
+	    }
+	}
+      /* We can't use OPT_Whardened yet.  Sigh.  */
+      else if (warn_hardened)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "linker hardening options not enabled by %<-fhardened%> "
+		    "because other link options were specified on the command "
+		    "line");
+    }
+
   /* Handle -gtoggle as it would later in toplev.cc:process_options to
      make the debug-level-gt spec function work as expected.  */
   if (flag_gtoggle)
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 573dcf8e497..8265c5b3c1b 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
 /* Set by -fcanon-prefix-map.  */
 bool flag_canon_prefix_map;
 
+/* Set by finish_options when flag_stack_protector was set only because of
+   -fhardened.  Yuck.  */
+bool flag_stack_protector_set_by_fhardened_p;
+
 static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
 /* Names of fundamental debug info formats indexed by enum
@@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       opts->x_flag_section_anchors = 0;
     }
 
+  if (opts->x_flag_hardened)
+    {
+      if (!opts_set->x_flag_auto_var_init)
+	opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
+      else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
+	warning_at (loc, OPT_Whardened,
+		    "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (!opts->x_flag_opts_finished)
     {
       /* We initialize opts->x_flag_pie to -1 so that targets can set a
@@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	  /* We initialize opts->x_flag_pic to -1 so that we can tell if
 	     -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
 	  if (opts->x_flag_pic == -1)
-	    opts->x_flag_pie = DEFAULT_FLAG_PIE;
+	    opts->x_flag_pie = (opts->x_flag_hardened
+				? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
 	  else
 	    opts->x_flag_pie = 0;
 	}
@@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
     }
 
   /* We initialize opts->x_flag_stack_protect to -1 so that targets
-     can set a default value.  */
+     can set a default value.  With --enable-default-ssp or -fhardened
+     the default is -fstack-protector-strong.  */
   if (opts->x_flag_stack_protect == -1)
-    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    {
+      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
+	 defined in such a way that it uses flag_stack_protect which can't
+	 be used here.  Moreover, some targets like BPF don't support
+	 -fstack-protector at all but we don't know that here.  So remember
+	 that flag_stack_protect was set at the behest of -fhardened.  */
+      if (opts->x_flag_hardened)
+	{
+	  opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
+	  flag_stack_protector_set_by_fhardened_p = true;
+	}
+      else
+	opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    }
+  else if (opts->x_flag_hardened
+	   && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
+    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		"%<-fstack-protector-strong%> is not enabled by "
+		"%<-fhardened%> because it was specified on the command "
+		"line");
 
   if (opts->x_optimize == 0)
     {
@@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
   free (patch_area_arg);
 }
 
+/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
+
+static void
+print_help_hardened ()
+{
+  printf ("%s\n", "The following options are enabled by -fhardened:");
+  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
+	  (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
+  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
+  printf ("  %s\n", "-ftrivial-auto-var-init=pattern");
+#ifdef HAVE_LD_PIE
+  printf ("  %s  %s\n", "-fPIE", "-pie");
+#endif
+  if (HAVE_LD_NOW_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,now");
+  if (HAVE_LD_RELRO_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,relro");
+  printf ("  %s\n", "-fstack-protector-strong");
+  printf ("  %s\n", "-fstack-clash-protection");
+  printf ("  %s\n", "-fcf-protection=full");
+  putchar ('\n');
+}
+
 /* Print help when OPT__help_ is set.  */
 
 void
@@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
 	}
       else if (lang_flag != 0)
 	*pflags |= lang_flag;
+      else if (strncasecmp (a, "hardened", len) == 0)
+	print_help_hardened ();
       else
 	warning (0,
 		 "unrecognized argument to %<--help=%> option: %q.*s",
diff --git a/gcc/opts.h b/gcc/opts.h
index 00f377f9ca7..d89c5de8114 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -344,6 +344,7 @@ struct cl_option_handlers
 /* Hold command-line options associated with stack limitation.  */
 extern const char *opt_fstack_limit_symbol_arg;
 extern int opt_fstack_limit_register_no;
+extern bool flag_stack_protector_set_by_fhardened_p;
 
 /* Input file names.  */
 
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
new file mode 100644
index 00000000000..4dd22cdfe45
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.S
@@ -0,0 +1,6 @@
+/* { dg-do preprocess { target pie } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
new file mode 100644
index 00000000000..dd3cde93805
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O" } */
+
+#ifndef __SSP_STRONG__
+# error "-fstack-protector-strong not enabled"
+#endif
+
+#if _FORTIFY_SOURCE < 2
+# error "_FORTIFY_SOURCE not enabled"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
new file mode 100644
index 00000000000..8242530bc4d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-10.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
+
+#if _FORTIFY_SOURCE != 1
+# error "_FORTIFY_SOURCE != 1"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
new file mode 100644
index 00000000000..b8fd65a960c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-11.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
+
+#ifndef _FORTIFY_SOURCE
+# error "_FORTIFY_SOURCE disabled when it should not be"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
new file mode 100644
index 00000000000..42594e4c0e0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-12.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
new file mode 100644
index 00000000000..6945a6391a9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-13.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
new file mode 100644
index 00000000000..652ece3d4c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-14.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fno-PIE" } */
+
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
new file mode 100644
index 00000000000..c6202754bf5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-15.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-require-stack-check "specific" } */
+/* { dg-options "-fhardened -O -fstack-check" } */
+
+/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
new file mode 100644
index 00000000000..283867ca806
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -fstack-protector" } */
+
+#ifdef __SSP_STRONG__
+# error "-fstack-protector-strong enabled when it should not be"
+#endif
+#ifndef __SSP__
+# error "-fstack-protector not enabled"
+#endif
+
+/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
new file mode 100644
index 00000000000..6924ba242f0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O0" } */
+/* Test that we don't get any diagnostic coming from libc headers.  */
+
+#include <stdio.h>
+
+/* The most useful C program known to man.  */
+
+int
+main ()
+{
+}
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
new file mode 100644
index 00000000000..7d44d299f19
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-4.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O0 -Wno-hardened" } */
+
+/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
new file mode 100644
index 00000000000..42594e4c0e0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
new file mode 100644
index 00000000000..a757cbf0d12
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
+/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
new file mode 100644
index 00000000000..32f35eb2595
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-7.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fpie" } */
+
+/* -fpie takes precedence over -fhardened */
+#if __PIE__ != 1
+# error "__PIE__ != 1"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
new file mode 100644
index 00000000000..5b3162b4d1f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-8.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fPIC" } */
+
+/* -fPIC takes precedence over -fhardened */
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
new file mode 100644
index 00000000000..d3b9e79b9b6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-9.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
+
+#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
+# error "hardening enabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
index 52b9cb0ab90..15d618a2528 100644
--- a/gcc/testsuite/gcc.misc-tests/help.exp
+++ b/gcc/testsuite/gcc.misc-tests/help.exp
@@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
 # Listing only excludes gives empty results.
 check_for_options c "--help=^joined,^separate" "" "" ""
 
+check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
+
 if [ info exists prev_columns ] {
     # Reset the enviroment variable to its oriuginal value.
     set env(COLUMNS) $prev_columns
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
new file mode 100644
index 00000000000..73b78dce889
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+/* Test that -fhardened enables CET.  */
+
+extern void bar (void) __attribute__((__cf_check__));
+
+void
+foo (void)
+{
+  bar ();
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 8af9bf5090e..743a3a91684 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1575,6 +1575,19 @@ process_options (bool no_backend)
 		  "where the stack grows from lower to higher addresses");
       flag_stack_clash_protection = 0;
     }
+  else if (flag_hardened)
+    {
+      if (!flag_stack_clash_protection
+	   /* Don't enable -fstack-clash-protection when -fstack-check=
+	      is used: it would result in confusing errors.  */
+	   && flag_stack_check == NO_STACK_CHECK)
+	flag_stack_clash_protection = 1;
+      else if (flag_stack_check != NO_STACK_CHECK)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fstack-clash-protection%> is not enabled by "
+		    "%<-fhardened%> because %<-fstack-check%> was "
+		    "specified on the command line");
+    }
 
   /* We cannot support -fstack-check= and -fstack-clash-protection at
      the same time.  */
@@ -1590,8 +1603,9 @@ process_options (bool no_backend)
      target already uses a soft frame pointer, the transition is trivial.  */
   if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
     {
-      warning_at (UNKNOWN_LOCATION, 0,
-		  "%<-fstack-protector%> not supported for this target");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "%<-fstack-protector%> not supported for this target");
       flag_stack_protect = 0;
     }
   if (!flag_stack_protect)

base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
-- 
2.41.0


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2] gcc: Introduce -fhardened
  2023-10-11 20:48     ` [PATCH v2] " Marek Polacek
@ 2023-10-18 20:12       ` Qing Zhao
  2023-10-19 18:32         ` Marek Polacek
  2023-10-19 12:24       ` Richard Biener
  1 sibling, 1 reply; 28+ messages in thread
From: Qing Zhao @ 2023-10-18 20:12 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, GCC Patches

Marek,

Sorry for the late comment (I was just back from a long vacation immediate after Cauldron). 

One question:

Is the option “-fhandened” for production build or for development build? 

If it’s for development build, then adding -ftrivial-auto-var-init=pattern is reasonable since the major purpose for  -ftrivial-auto-var-init=pattern is for debugging, the runtime overhead of -ftrivial-auto-var-init=pattern is higher then -ftrivial-auto-var-init=zero.

However, if it’s for production build, then adding -ftrivial-auto-var-init=zero is better since the major purpose for -ftrivial-auto-var-init=zero is for production build to eliminate all uninitialization. And the runtime overhead of =zero is smaller than =pattern.

Qing
> On Oct 11, 2023, at 4:48 PM, Marek Polacek <polacek@redhat.com> wrote:
> 
> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>>> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>>> <gcc-patches@gcc.gnu.org> wrote:
>>>> 
>>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
>>>> and aarch64-unknown-linux-gnu; ok for trunk?
>>>> 
>>>> -- >8 --
>>>> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
>>>> I proposed -fhardened, a new umbrella option that enables a reasonable set
>>>> of hardening flags.  The read of the room seems to be that the option
>>>> would be useful.  So here's a patch implementing that option.
>>>> 
>>>> Currently, -fhardened enables:
>>>> 
>>>>  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>>>>  -D_GLIBCXX_ASSERTIONS
>>>>  -ftrivial-auto-var-init=pattern
>>>>  -fPIE  -pie  -Wl,-z,relro,-z,now
>>>>  -fstack-protector-strong
>>>>  -fstack-clash-protection
>>>>  -fcf-protection=full (x86 GNU/Linux only)
>>>> 
>>>> -fhardened will not override options that were specified on the command line
>>>> (before or after -fhardened).  For example,
>>>> 
>>>>     -D_FORTIFY_SOURCE=1 -fhardened
>>>> 
>>>> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>>>> 
>>>>      -fhardened -fstack-protector
>>>> 
>>>> will not enable -fstack-protector-strong.
>>>> 
>>>> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
>>>> to anything.  I think we need a better way to show what it actually
>>>> enables.
>>> 
>>> I do think we need to find a solution here to solve asserting compliance.
>> 
>> Fair enough.
>> 
>>> Maybe we can have -Whardened that will diagnose any altering of
>>> -fhardened by other options on the command-line or by missed target
>>> implementations?  People might for example use -fstack-protector
>>> but don't really want to make protection lower than requested with -fhardened.
>>> 
>>> Any such conflict is much less appearant than when you use the
>>> flags -fhardened composes.
>> 
>> How about: --help=hardened says which options -fhardened attempts to
>> enable, and -Whardened warns when it didn't enable an option?  E.g.,
>> 
>>  -fstack-protector -fhardened -Whardened
>> 
>> would say that it didn't enable -fstack-protector-strong because
>> -fstack-protector was specified on the command line?
>> 
>> If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
>> list -z now, likewise for -z relro.
>> 
>> Unclear if -Whardened should be enabled by default, but probably yes?
> 
> Here's v2 which adds -Whardened (enabled by default).
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags.  The read of the room seems to be that the option
> would be useful.  So here's a patch implementing that option.
> 
> Currently, -fhardened enables:
> 
>  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>  -D_GLIBCXX_ASSERTIONS
>  -ftrivial-auto-var-init=pattern
>  -fPIE  -pie  -Wl,-z,relro,-z,now
>  -fstack-protector-strong
>  -fstack-clash-protection
>  -fcf-protection=full (x86 GNU/Linux only)
> 
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened).  For example,
> 
>     -D_FORTIFY_SOURCE=1 -fhardened
> 
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> 
>      -fhardened -fstack-protector
> 
> will not enable -fstack-protector-strong.
> 
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything.  This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option.  I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
> 	and _GLIBCXX_ASSERTIONS.
> 
> gcc/ChangeLog:
> 
> 	* common.opt (Whardened, fhardened): New options.
> 	* config.in: Regenerate.
> 	* config/bpf/bpf.cc: Include "opts.h".
> 	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
> 	not inform that -fstack-protector does not work.
> 	* config/i386/i386-options.cc (ix86_option_override_internal): When
> 	-fhardened, maybe enable -fcf-protection=full.
> 	* configure: Regenerate.
> 	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
> 	* doc/invoke.texi: Document -fhardened and -Whardened.
> 	* gcc.cc (driver_handle_option): Remember if any link options or -static
> 	were specified on the command line.
> 	(process_command): When -fhardened, maybe enable -pie and
> 	-Wl,-z,relro,-z,now.
> 	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
> 	(finish_options): When -fhardened, enable
> 	-ftrivial-auto-var-init=pattern and -fstack-protector-strong.
> 	(print_help_hardened): New.
> 	(print_help): Call it.
> 	* toplev.cc (process_options): When -fhardened, enable
> 	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
> 	do not warn that -fstack-protector not supported for this target.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.misc-tests/help.exp: Test -fhardened.
> 	* c-c++-common/fhardened-1.S: New test.
> 	* c-c++-common/fhardened-1.c: New test.
> 	* c-c++-common/fhardened-10.c: New test.
> 	* c-c++-common/fhardened-11.c: New test.
> 	* c-c++-common/fhardened-12.c: New test.
> 	* c-c++-common/fhardened-13.c: New test.
> 	* c-c++-common/fhardened-14.c: New test.
> 	* c-c++-common/fhardened-15.c: New test.
> 	* c-c++-common/fhardened-2.c: New test.
> 	* c-c++-common/fhardened-3.c: New test.
> 	* c-c++-common/fhardened-4.c: New test.
> 	* c-c++-common/fhardened-5.c: New test.
> 	* c-c++-common/fhardened-6.c: New test.
> 	* c-c++-common/fhardened-7.c: New test.
> 	* c-c++-common/fhardened-8.c: New test.
> 	* c-c++-common/fhardened-9.c: New test.
> 	* gcc.target/i386/cf_check-6.c: New test.
> ---
> gcc/c-family/c-opts.cc                     | 42 ++++++++++++++
> gcc/common.opt                             |  8 +++
> gcc/config.in                              | 12 ++++
> gcc/config/bpf/bpf.cc                      |  8 ++-
> gcc/config/i386/i386-options.cc            | 17 +++++-
> gcc/configure                              | 50 +++++++++++++++-
> gcc/configure.ac                           | 42 +++++++++++++-
> gcc/doc/invoke.texi                        | 44 +++++++++++++-
> gcc/gcc.cc                                 | 48 +++++++++++++++-
> gcc/opts.cc                                | 67 +++++++++++++++++++++-
> gcc/opts.h                                 |  1 +
> gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
> gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
> gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
> gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
> gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
> gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
> gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
> gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
> gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
> gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
> gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
> gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
> gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
> gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
> gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
> gcc/toplev.cc                              | 18 +++++-
> 30 files changed, 503 insertions(+), 14 deletions(-)
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
> create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
> 
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index ce2e021e69d..f5f6ba24290 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1556,6 +1556,9 @@ c_finish_options (void)
>       cb_file_change (parse_in, cmd_map);
>       linemap_line_start (line_table, 0, 1);
> 
> +      bool fortify_seen_p = false;
> +      bool cxx_assert_seen_p = false;
> +
>       /* All command line defines must have the same location.  */
>       cpp_force_token_locations (parse_in, line_table->highest_line);
>       for (size_t i = 0; i < deferred_count; i++)
> @@ -1573,6 +1576,45 @@ c_finish_options (void)
> 	      else
> 		cpp_assert (parse_in, opt->arg);
> 	    }
> +
> +	  if (UNLIKELY (flag_hardened)
> +	      && (opt->code == OPT_D || opt->code == OPT_U))
> +	    {
> +	      if (!fortify_seen_p)
> +		fortify_seen_p
> +		  = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> +		     && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> +	      if (!cxx_assert_seen_p)
> +		cxx_assert_seen_p
> +		  = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> +		     && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> +	    }
> +	}
> +
> +      if (flag_hardened)
> +	{
> +	  if (!fortify_seen_p && optimize > 0)
> +	    {
> +	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> +		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> +	      else
> +		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> +	    }
> +	  else if (optimize == 0)
> +	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +			"because optimizations are turned off");
> +	  else
> +	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +			"because it was specified in %<-D%> or %<-U%>");
> +	  if (!cxx_assert_seen_p)
> +	    cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
> +	  else
> +	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +			"%<_GLIBCXX_ASSERTIONS%> is not enabled by "
> +			"%<-fhardened%> because it was specified in %<-D%> "
> +			"or %<-U%>");
> 	}
> 
>       cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index f137a1f81ac..60c13b9ffd2 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -634,6 +634,10 @@ Wfree-nonheap-object
> Common Var(warn_free_nonheap_object) Init(1) Warning
> Warn when attempting to free a non-heap object.
> 
> +Whardened
> +Common Var(warn_hardened) Init(1) Warning
> +Warn when -fhardened did not enable an option from its set.
> +
> Whsa
> Common Ignore Warning
> Does nothing.  Preserved for backward compatibility.
> @@ -1827,6 +1831,10 @@ fharden-conditional-branches
> Common Var(flag_harden_conditional_branches) Optimization
> Harden conditional branches by checking reversed conditions.
> 
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
> ; Nonzero means ignore `#ident' directives.  0 means handle them.
> ; Generate position-independent code for executables if possible
> ; On SVR4 targets, it also controls whether or not to emit a
> diff --git a/gcc/config.in b/gcc/config.in
> index d04718ad128..faa941c1385 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1676,6 +1676,12 @@
> #endif
> 
> 
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
> /* Define if your PowerPC64 linker only needs function descriptor syms. */
> #ifndef USED_FOR_TARGET
> #undef HAVE_LD_NO_DOT_SYMS
> @@ -1719,6 +1725,12 @@
> #endif
> 
> 
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
> /* Define if your linker links a mix of read-only and read-write sections into
>    a read-write section. */
> #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 437bd652de3..41dc7fd3dae 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "gimplify-me.h"
> 
> #include "core-builtins.h"
> +#include "opts.h"
> 
> /* Per-function machine data.  */
> struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
>   /* Disable -fstack-protector as it is not supported in BPF.  */
>   if (flag_stack_protect)
>     {
> -      inform (input_location,
> -              "%<-fstack-protector%> does not work "
> -	      "on this architecture");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +	inform (input_location,
> +		"%<-fstack-protector%> does not work "
> +		"on this architecture");
>       flag_stack_protect = 0;
>     }
> 
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index 06af373ca57..22ede9e15b5 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
>         = build_target_option_node (opts, opts_set);
>     }
> 
> +  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> +  /* When -fhardened, enable -fcf-protection=full, but only when it's
> +     compatible with this target, and when it wasn't already specified
> +     on the command line.  */
> +  if (opts->x_flag_hardened && cf_okay_p)
> +    {
> +      if (opts->x_flag_cf_protection == CF_NONE)
> +	opts->x_flag_cf_protection = CF_FULL;
> +      else if (opts->x_flag_cf_protection != CF_FULL)
> +	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +		    "%<-fcf-protection=full%> is not enabled by "
> +		    "%<-fhardened%> because it was specified on the command "
> +		    "line");
> +    }
> +
>   if (opts->x_flag_cf_protection != CF_NONE)
>     {
>       if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> -	  && !TARGET_64BIT && !TARGET_CMOV)
> +	  && !cf_okay_p)
> 	error ("%<-fcf-protection%> is not compatible with this target");
> 
>       opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index c43bde8174b..e2aac56edf6 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
>       ld_bndplt_support=yes
>     fi
>   elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>       ld_bndplt_support=yes
>     fi
> @@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>   ;;
> esac
> 
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
> # Configure the subdirectories
> # AC_CONFIG_SUBDIRS($subdirs)
> 
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index fb8e32f8ee5..6a090ccf3bd 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
>       ld_bndplt_support=yes
>     fi
>   elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>       ld_bndplt_support=yes
>     fi
> @@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
>   ;;
> esac
> 
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> +  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> +  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
> # Configure the subdirectories
> # AC_CONFIG_SUBDIRS($subdirs)
> 
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 7c5f81d9783..48e6a3f433c 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
> -Wformat-y2k  -Wframe-address
> -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
> -Wno-if-not-aligned  -Wno-ignored-attributes
> --Wignored-qualifiers  -Wno-incompatible-pointer-types
> +-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
> -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
> -Wno-implicit-function-declaration  -Wno-implicit-int
> -Winfinite-recursion
> @@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
> -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
> -fsanitize-undefined-trap-on-error  -fbounds-check
> -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches -fhardened
> -fstack-protector  -fstack-protector-all  -fstack-protector-strong
> -fstack-protector-explicit  -fstack-check
> -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym}
> @@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
> Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
> This warning is enabled by @option{-Wall}.
> 
> +@opindex Whardened
> +@opindex Wno-hardened
> +@item -Whardened
> +Warn when @option{-fhardened} did not enable an option from its set (for
> +which see @option{-fhardened}).  For instance, using @option{-fhardened}
> +and @option{-fstack-protector} at the same time on the command line causes
> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
> +not enabled by @option{-fhardened}.
> +
> +This warning is enabled by default and has effect only when @option{-fhardened}
> +is enabled.
> +
> @opindex Wimplicit-fallthrough
> @opindex Wno-implicit-fallthrough
> @item -Wimplicit-fallthrough
> @@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
> unexpected.  Use with @samp{-fharden-compares} to cover all
> conditionals.
> 
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI.  The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@c Keep this in sync with print_help_hardened!
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=pattern
> +-fPIE  -pie  -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line.  For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
> @opindex fstack-protector
> @item -fstack-protector
> Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index c6e600fa0d3..ed4e2400e91 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>    driver added to dumpdir after dumpbase or linker output name.  */
> static bool dumpdir_trailing_dash_added = false;
> 
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> +   line.  */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line.  */
> +static bool static_p;
> +
> /* Basename of dump and aux outputs, computed from dumpbase (given or
>    derived from output name), to override input_basename in non-%w %b
>    et al.  */
> @@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
>       save_switch ("-o", 1, &arg, validated, true);
>       return true;
> 
> -#ifdef ENABLE_DEFAULT_PIE
>     case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
>       /* -pie is turned on by default.  */
> +      validated = true;
> #endif
> +    case OPT_r:
> +    case OPT_shared:
> +    case OPT_no_pie:
> +      any_link_options_p = true;
> +      break;
> +
> +    case OPT_static:
> +      static_p = true;
> +      break;
> 
>     case OPT_static_libgcc:
>     case OPT_shared_libgcc:
> @@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
> #endif
>     }
> 
> +  /* TODO: check if -static -pie works and maybe use it.  */
> +  if (flag_hardened)
> +    {
> +      if (!any_link_options_p && !static_p)
> +	{
> +#ifdef HAVE_LD_PIE
> +	  save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> +	  /* These are passed straight down to collect2 so we have to break
> +	     it up like this.  */
> +	  if (HAVE_LD_NOW_SUPPORT)
> +	    {
> +	      add_infile ("-z", "*");
> +	      add_infile ("now", "*");
> +	    }
> +	  if (HAVE_LD_RELRO_SUPPORT)
> +	    {
> +	      add_infile ("-z", "*");
> +	      add_infile ("relro", "*");
> +	    }
> +	}
> +      /* We can't use OPT_Whardened yet.  Sigh.  */
> +      else if (warn_hardened)
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "linker hardening options not enabled by %<-fhardened%> "
> +		    "because other link options were specified on the command "
> +		    "line");
> +    }
> +
>   /* Handle -gtoggle as it would later in toplev.cc:process_options to
>      make the debug-level-gt spec function work as expected.  */
>   if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 573dcf8e497..8265c5b3c1b 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
> /* Set by -fcanon-prefix-map.  */
> bool flag_canon_prefix_map;
> 
> +/* Set by finish_options when flag_stack_protector was set only because of
> +   -fhardened.  Yuck.  */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
> static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
> 
> /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>       opts->x_flag_section_anchors = 0;
>     }
> 
> +  if (opts->x_flag_hardened)
> +    {
> +      if (!opts_set->x_flag_auto_var_init)
> +	opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
> +      else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
> +	warning_at (loc, OPT_Whardened,
> +		    "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
> +		    "%<-fhardened%> because it was specified on the command "
> +		    "line");
> +    }
> +
>   if (!opts->x_flag_opts_finished)
>     {
>       /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> 	  /* We initialize opts->x_flag_pic to -1 so that we can tell if
> 	     -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
> 	  if (opts->x_flag_pic == -1)
> -	    opts->x_flag_pie = DEFAULT_FLAG_PIE;
> +	    opts->x_flag_pie = (opts->x_flag_hardened
> +				? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
> 	  else
> 	    opts->x_flag_pie = 0;
> 	}
> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>     }
> 
>   /* We initialize opts->x_flag_stack_protect to -1 so that targets
> -     can set a default value.  */
> +     can set a default value.  With --enable-default-ssp or -fhardened
> +     the default is -fstack-protector-strong.  */
>   if (opts->x_flag_stack_protect == -1)
> -    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    {
> +      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> +	 defined in such a way that it uses flag_stack_protect which can't
> +	 be used here.  Moreover, some targets like BPF don't support
> +	 -fstack-protector at all but we don't know that here.  So remember
> +	 that flag_stack_protect was set at the behest of -fhardened.  */
> +      if (opts->x_flag_hardened)
> +	{
> +	  opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> +	  flag_stack_protector_set_by_fhardened_p = true;
> +	}
> +      else
> +	opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    }
> +  else if (opts->x_flag_hardened
> +	   && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
> +    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +		"%<-fstack-protector-strong%> is not enabled by "
> +		"%<-fhardened%> because it was specified on the command "
> +		"line");
> 
>   if (opts->x_optimize == 0)
>     {
> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>   free (patch_area_arg);
> }
> 
> +/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
> +
> +static void
> +print_help_hardened ()
> +{
> +  printf ("%s\n", "The following options are enabled by -fhardened:");
> +  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
> +	  (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> +  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
> +  printf ("  %s\n", "-ftrivial-auto-var-init=pattern");
> +#ifdef HAVE_LD_PIE
> +  printf ("  %s  %s\n", "-fPIE", "-pie");
> +#endif
> +  if (HAVE_LD_NOW_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,now");
> +  if (HAVE_LD_RELRO_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,relro");
> +  printf ("  %s\n", "-fstack-protector-strong");
> +  printf ("  %s\n", "-fstack-clash-protection");
> +  printf ("  %s\n", "-fcf-protection=full");
> +  putchar ('\n');
> +}
> +
> /* Print help when OPT__help_ is set.  */
> 
> void
> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
> 	}
>       else if (lang_flag != 0)
> 	*pflags |= lang_flag;
> +      else if (strncasecmp (a, "hardened", len) == 0)
> +	print_help_hardened ();
>       else
> 	warning (0,
> 		 "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
> /* Hold command-line options associated with stack limitation.  */
> extern const char *opt_fstack_limit_symbol_arg;
> extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
> 
> /* Input file names.  */
> 
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..4dd22cdfe45
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..dd3cde93805
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..8242530bc4d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..b8fd65a960c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..6945a6391a9
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..652ece3d4c4
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
> new file mode 100644
> index 00000000000..c6202754bf5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile } */
> +/* { dg-require-stack-check "specific" } */
> +/* { dg-options "-fhardened -O -fstack-check" } */
> +
> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..283867ca806
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> +
> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..6924ba242f0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers.  */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man.  */
> +
> +int
> +main ()
> +{
> +}
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
> new file mode 100644
> index 00000000000..7d44d299f19
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
> +
> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..a757cbf0d12
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> +/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..32f35eb2595
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..5b3162b4d1f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..d3b9e79b9b6
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
> # Listing only excludes gives empty results.
> check_for_options c "--help=^joined,^separate" "" "" ""
> 
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
> if [ info exists prev_columns ] {
>     # Reset the enviroment variable to its oriuginal value.
>     set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET.  */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> +  bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index 8af9bf5090e..743a3a91684 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1575,6 +1575,19 @@ process_options (bool no_backend)
> 		  "where the stack grows from lower to higher addresses");
>       flag_stack_clash_protection = 0;
>     }
> +  else if (flag_hardened)
> +    {
> +      if (!flag_stack_clash_protection
> +	   /* Don't enable -fstack-clash-protection when -fstack-check=
> +	      is used: it would result in confusing errors.  */
> +	   && flag_stack_check == NO_STACK_CHECK)
> +	flag_stack_clash_protection = 1;
> +      else if (flag_stack_check != NO_STACK_CHECK)
> +	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +		    "%<-fstack-clash-protection%> is not enabled by "
> +		    "%<-fhardened%> because %<-fstack-check%> was "
> +		    "specified on the command line");
> +    }
> 
>   /* We cannot support -fstack-check= and -fstack-clash-protection at
>      the same time.  */
> @@ -1590,8 +1603,9 @@ process_options (bool no_backend)
>      target already uses a soft frame pointer, the transition is trivial.  */
>   if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>     {
> -      warning_at (UNKNOWN_LOCATION, 0,
> -		  "%<-fstack-protector%> not supported for this target");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "%<-fstack-protector%> not supported for this target");
>       flag_stack_protect = 0;
>     }
>   if (!flag_stack_protect)
> 
> base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
> -- 
> 2.41.0
> 


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2] gcc: Introduce -fhardened
  2023-10-11 20:48     ` [PATCH v2] " Marek Polacek
  2023-10-18 20:12       ` Qing Zhao
@ 2023-10-19 12:24       ` Richard Biener
  2023-10-19 12:33         ` Sam James
  2023-10-23 19:25         ` [PATCH v3] " Marek Polacek
  1 sibling, 2 replies; 28+ messages in thread
From: Richard Biener @ 2023-10-19 12:24 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>
> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> > > <gcc-patches@gcc.gnu.org> wrote:
> > > >
> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > > > and aarch64-unknown-linux-gnu; ok for trunk?
> > > >
> > > > -- >8 --
> > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > > of hardening flags.  The read of the room seems to be that the option
> > > > would be useful.  So here's a patch implementing that option.
> > > >
> > > > Currently, -fhardened enables:
> > > >
> > > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > > >   -D_GLIBCXX_ASSERTIONS
> > > >   -ftrivial-auto-var-init=pattern

I think =zero is much better here given the overhead is way
cheaper and pointers get a more reliable behavior.

> > > >   -fPIE  -pie  -Wl,-z,relro,-z,now
> > > >   -fstack-protector-strong
> > > >   -fstack-clash-protection
> > > >   -fcf-protection=full (x86 GNU/Linux only)
> > > >
> > > > -fhardened will not override options that were specified on the command line
> > > > (before or after -fhardened).  For example,
> > > >
> > > >      -D_FORTIFY_SOURCE=1 -fhardened
> > > >
> > > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> > > >
> > > >       -fhardened -fstack-protector
> > > >
> > > > will not enable -fstack-protector-strong.
> > > >
> > > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > > to anything.  I think we need a better way to show what it actually
> > > > enables.
> > >
> > > I do think we need to find a solution here to solve asserting compliance.
> >
> > Fair enough.
> >
> > > Maybe we can have -Whardened that will diagnose any altering of
> > > -fhardened by other options on the command-line or by missed target
> > > implementations?  People might for example use -fstack-protector
> > > but don't really want to make protection lower than requested with -fhardened.
> > >
> > > Any such conflict is much less appearant than when you use the
> > > flags -fhardened composes.
> >
> > How about: --help=hardened says which options -fhardened attempts to
> > enable, and -Whardened warns when it didn't enable an option?  E.g.,
> >
> >   -fstack-protector -fhardened -Whardened
> >
> > would say that it didn't enable -fstack-protector-strong because
> > -fstack-protector was specified on the command line?
> >
> > If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
> > list -z now, likewise for -z relro.
> >
> > Unclear if -Whardened should be enabled by default, but probably yes?
>
> Here's v2 which adds -Whardened (enabled by default).
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

I think it's OK but I'd like to see a second ACK here.  Can you see how our
primary and secondary targets (+ host OS) behave here?  I think the
documentation should elaborate a bit on expectations for non-Linux/GNU
targets, specifically I think the default configuration for a target should
with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
have a testcase for this?

Thanks,
Richard.

>
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags.  The read of the room seems to be that the option
> would be useful.  So here's a patch implementing that option.
>
> Currently, -fhardened enables:
>
>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>   -D_GLIBCXX_ASSERTIONS
>   -ftrivial-auto-var-init=pattern
>   -fPIE  -pie  -Wl,-z,relro,-z,now
>   -fstack-protector-strong
>   -fstack-clash-protection
>   -fcf-protection=full (x86 GNU/Linux only)
>
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened).  For example,
>
>      -D_FORTIFY_SOURCE=1 -fhardened
>
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>
>       -fhardened -fstack-protector
>
> will not enable -fstack-protector-strong.
>
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything.  This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option.  I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
>
> gcc/c-family/ChangeLog:
>
>         * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
>         and _GLIBCXX_ASSERTIONS.
>
> gcc/ChangeLog:
>
>         * common.opt (Whardened, fhardened): New options.
>         * config.in: Regenerate.
>         * config/bpf/bpf.cc: Include "opts.h".
>         (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
>         not inform that -fstack-protector does not work.
>         * config/i386/i386-options.cc (ix86_option_override_internal): When
>         -fhardened, maybe enable -fcf-protection=full.
>         * configure: Regenerate.
>         * configure.ac: Check if the linker supports '-z now' and '-z relro'.
>         * doc/invoke.texi: Document -fhardened and -Whardened.
>         * gcc.cc (driver_handle_option): Remember if any link options or -static
>         were specified on the command line.
>         (process_command): When -fhardened, maybe enable -pie and
>         -Wl,-z,relro,-z,now.
>         * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
>         (finish_options): When -fhardened, enable
>         -ftrivial-auto-var-init=pattern and -fstack-protector-strong.
>         (print_help_hardened): New.
>         (print_help): Call it.
>         * toplev.cc (process_options): When -fhardened, enable
>         -fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
>         do not warn that -fstack-protector not supported for this target.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.misc-tests/help.exp: Test -fhardened.
>         * c-c++-common/fhardened-1.S: New test.
>         * c-c++-common/fhardened-1.c: New test.
>         * c-c++-common/fhardened-10.c: New test.
>         * c-c++-common/fhardened-11.c: New test.
>         * c-c++-common/fhardened-12.c: New test.
>         * c-c++-common/fhardened-13.c: New test.
>         * c-c++-common/fhardened-14.c: New test.
>         * c-c++-common/fhardened-15.c: New test.
>         * c-c++-common/fhardened-2.c: New test.
>         * c-c++-common/fhardened-3.c: New test.
>         * c-c++-common/fhardened-4.c: New test.
>         * c-c++-common/fhardened-5.c: New test.
>         * c-c++-common/fhardened-6.c: New test.
>         * c-c++-common/fhardened-7.c: New test.
>         * c-c++-common/fhardened-8.c: New test.
>         * c-c++-common/fhardened-9.c: New test.
>         * gcc.target/i386/cf_check-6.c: New test.
> ---
>  gcc/c-family/c-opts.cc                     | 42 ++++++++++++++
>  gcc/common.opt                             |  8 +++
>  gcc/config.in                              | 12 ++++
>  gcc/config/bpf/bpf.cc                      |  8 ++-
>  gcc/config/i386/i386-options.cc            | 17 +++++-
>  gcc/configure                              | 50 +++++++++++++++-
>  gcc/configure.ac                           | 42 +++++++++++++-
>  gcc/doc/invoke.texi                        | 44 +++++++++++++-
>  gcc/gcc.cc                                 | 48 +++++++++++++++-
>  gcc/opts.cc                                | 67 +++++++++++++++++++++-
>  gcc/opts.h                                 |  1 +
>  gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
>  gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
>  gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
>  gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
>  gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
>  gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
>  gcc/toplev.cc                              | 18 +++++-
>  30 files changed, 503 insertions(+), 14 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index ce2e021e69d..f5f6ba24290 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1556,6 +1556,9 @@ c_finish_options (void)
>        cb_file_change (parse_in, cmd_map);
>        linemap_line_start (line_table, 0, 1);
>
> +      bool fortify_seen_p = false;
> +      bool cxx_assert_seen_p = false;
> +
>        /* All command line defines must have the same location.  */
>        cpp_force_token_locations (parse_in, line_table->highest_line);
>        for (size_t i = 0; i < deferred_count; i++)
> @@ -1573,6 +1576,45 @@ c_finish_options (void)
>               else
>                 cpp_assert (parse_in, opt->arg);
>             }
> +
> +         if (UNLIKELY (flag_hardened)
> +             && (opt->code == OPT_D || opt->code == OPT_U))
> +           {
> +             if (!fortify_seen_p)
> +               fortify_seen_p
> +                 = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> +                    && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> +             if (!cxx_assert_seen_p)
> +               cxx_assert_seen_p
> +                 = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> +                    && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> +           }
> +       }
> +
> +      if (flag_hardened)
> +       {
> +         if (!fortify_seen_p && optimize > 0)
> +           {
> +             if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> +             else
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> +           }
> +         else if (optimize == 0)
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +                       "because optimizations are turned off");
> +         else
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +                       "because it was specified in %<-D%> or %<-U%>");
> +         if (!cxx_assert_seen_p)
> +           cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
> +         else
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
> +                       "%<-fhardened%> because it was specified in %<-D%> "
> +                       "or %<-U%>");
>         }
>
>        cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index f137a1f81ac..60c13b9ffd2 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -634,6 +634,10 @@ Wfree-nonheap-object
>  Common Var(warn_free_nonheap_object) Init(1) Warning
>  Warn when attempting to free a non-heap object.
>
> +Whardened
> +Common Var(warn_hardened) Init(1) Warning
> +Warn when -fhardened did not enable an option from its set.
> +
>  Whsa
>  Common Ignore Warning
>  Does nothing.  Preserved for backward compatibility.
> @@ -1827,6 +1831,10 @@ fharden-conditional-branches
>  Common Var(flag_harden_conditional_branches) Optimization
>  Harden conditional branches by checking reversed conditions.
>
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
>  ; Nonzero means ignore `#ident' directives.  0 means handle them.
>  ; Generate position-independent code for executables if possible
>  ; On SVR4 targets, it also controls whether or not to emit a
> diff --git a/gcc/config.in b/gcc/config.in
> index d04718ad128..faa941c1385 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1676,6 +1676,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
>  /* Define if your PowerPC64 linker only needs function descriptor syms. */
>  #ifndef USED_FOR_TARGET
>  #undef HAVE_LD_NO_DOT_SYMS
> @@ -1719,6 +1725,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
>  /* Define if your linker links a mix of read-only and read-write sections into
>     a read-write section. */
>  #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 437bd652de3..41dc7fd3dae 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimplify-me.h"
>
>  #include "core-builtins.h"
> +#include "opts.h"
>
>  /* Per-function machine data.  */
>  struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
>    /* Disable -fstack-protector as it is not supported in BPF.  */
>    if (flag_stack_protect)
>      {
> -      inform (input_location,
> -              "%<-fstack-protector%> does not work "
> -             "on this architecture");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       inform (input_location,
> +               "%<-fstack-protector%> does not work "
> +               "on this architecture");
>        flag_stack_protect = 0;
>      }
>
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index 06af373ca57..22ede9e15b5 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
>          = build_target_option_node (opts, opts_set);
>      }
>
> +  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> +  /* When -fhardened, enable -fcf-protection=full, but only when it's
> +     compatible with this target, and when it wasn't already specified
> +     on the command line.  */
> +  if (opts->x_flag_hardened && cf_okay_p)
> +    {
> +      if (opts->x_flag_cf_protection == CF_NONE)
> +       opts->x_flag_cf_protection = CF_FULL;
> +      else if (opts->x_flag_cf_protection != CF_FULL)
> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                   "%<-fcf-protection=full%> is not enabled by "
> +                   "%<-fhardened%> because it was specified on the command "
> +                   "line");
> +    }
> +
>    if (opts->x_flag_cf_protection != CF_NONE)
>      {
>        if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> -         && !TARGET_64BIT && !TARGET_CMOV)
> +         && !cf_okay_p)
>         error ("%<-fcf-protection%> is not compatible with this target");
>
>        opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index c43bde8174b..e2aac56edf6 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index fb8e32f8ee5..6a090ccf3bd 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> +  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> +  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 7c5f81d9783..48e6a3f433c 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wformat-y2k  -Wframe-address
>  -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
>  -Wno-if-not-aligned  -Wno-ignored-attributes
> --Wignored-qualifiers  -Wno-incompatible-pointer-types
> +-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
>  -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
>  -Wno-implicit-function-declaration  -Wno-implicit-int
>  -Winfinite-recursion
> @@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
>  -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
>  -fsanitize-undefined-trap-on-error  -fbounds-check
>  -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches -fhardened
>  -fstack-protector  -fstack-protector-all  -fstack-protector-strong
>  -fstack-protector-explicit  -fstack-check
>  -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym}
> @@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
>  Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
>  This warning is enabled by @option{-Wall}.
>
> +@opindex Whardened
> +@opindex Wno-hardened
> +@item -Whardened
> +Warn when @option{-fhardened} did not enable an option from its set (for
> +which see @option{-fhardened}).  For instance, using @option{-fhardened}
> +and @option{-fstack-protector} at the same time on the command line causes
> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
> +not enabled by @option{-fhardened}.
> +
> +This warning is enabled by default and has effect only when @option{-fhardened}
> +is enabled.
> +
>  @opindex Wimplicit-fallthrough
>  @opindex Wno-implicit-fallthrough
>  @item -Wimplicit-fallthrough
> @@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
>  unexpected.  Use with @samp{-fharden-compares} to cover all
>  conditionals.
>
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI.  The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@c Keep this in sync with print_help_hardened!
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=pattern
> +-fPIE  -pie  -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line.  For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
>  @opindex fstack-protector
>  @item -fstack-protector
>  Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index c6e600fa0d3..ed4e2400e91 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>     driver added to dumpdir after dumpbase or linker output name.  */
>  static bool dumpdir_trailing_dash_added = false;
>
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> +   line.  */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line.  */
> +static bool static_p;
> +
>  /* Basename of dump and aux outputs, computed from dumpbase (given or
>     derived from output name), to override input_basename in non-%w %b
>     et al.  */
> @@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
>        save_switch ("-o", 1, &arg, validated, true);
>        return true;
>
> -#ifdef ENABLE_DEFAULT_PIE
>      case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
>        /* -pie is turned on by default.  */
> +      validated = true;
>  #endif
> +    case OPT_r:
> +    case OPT_shared:
> +    case OPT_no_pie:
> +      any_link_options_p = true;
> +      break;
> +
> +    case OPT_static:
> +      static_p = true;
> +      break;
>
>      case OPT_static_libgcc:
>      case OPT_shared_libgcc:
> @@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
>  #endif
>      }
>
> +  /* TODO: check if -static -pie works and maybe use it.  */
> +  if (flag_hardened)
> +    {
> +      if (!any_link_options_p && !static_p)
> +       {
> +#ifdef HAVE_LD_PIE
> +         save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> +         /* These are passed straight down to collect2 so we have to break
> +            it up like this.  */
> +         if (HAVE_LD_NOW_SUPPORT)
> +           {
> +             add_infile ("-z", "*");
> +             add_infile ("now", "*");
> +           }
> +         if (HAVE_LD_RELRO_SUPPORT)
> +           {
> +             add_infile ("-z", "*");
> +             add_infile ("relro", "*");
> +           }
> +       }
> +      /* We can't use OPT_Whardened yet.  Sigh.  */
> +      else if (warn_hardened)
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "linker hardening options not enabled by %<-fhardened%> "
> +                   "because other link options were specified on the command "
> +                   "line");
> +    }
> +
>    /* Handle -gtoggle as it would later in toplev.cc:process_options to
>       make the debug-level-gt spec function work as expected.  */
>    if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 573dcf8e497..8265c5b3c1b 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
>  /* Set by -fcanon-prefix-map.  */
>  bool flag_canon_prefix_map;
>
> +/* Set by finish_options when flag_stack_protector was set only because of
> +   -fhardened.  Yuck.  */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
>  static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>
>  /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>        opts->x_flag_section_anchors = 0;
>      }
>
> +  if (opts->x_flag_hardened)
> +    {
> +      if (!opts_set->x_flag_auto_var_init)
> +       opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
> +      else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
> +       warning_at (loc, OPT_Whardened,
> +                   "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
> +                   "%<-fhardened%> because it was specified on the command "
> +                   "line");
> +    }
> +
>    if (!opts->x_flag_opts_finished)
>      {
>        /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>           /* We initialize opts->x_flag_pic to -1 so that we can tell if
>              -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
>           if (opts->x_flag_pic == -1)
> -           opts->x_flag_pie = DEFAULT_FLAG_PIE;
> +           opts->x_flag_pie = (opts->x_flag_hardened
> +                               ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
>           else
>             opts->x_flag_pie = 0;
>         }
> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>      }
>
>    /* We initialize opts->x_flag_stack_protect to -1 so that targets
> -     can set a default value.  */
> +     can set a default value.  With --enable-default-ssp or -fhardened
> +     the default is -fstack-protector-strong.  */
>    if (opts->x_flag_stack_protect == -1)
> -    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    {
> +      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> +        defined in such a way that it uses flag_stack_protect which can't
> +        be used here.  Moreover, some targets like BPF don't support
> +        -fstack-protector at all but we don't know that here.  So remember
> +        that flag_stack_protect was set at the behest of -fhardened.  */
> +      if (opts->x_flag_hardened)
> +       {
> +         opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> +         flag_stack_protector_set_by_fhardened_p = true;
> +       }
> +      else
> +       opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    }
> +  else if (opts->x_flag_hardened
> +          && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
> +    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +               "%<-fstack-protector-strong%> is not enabled by "
> +               "%<-fhardened%> because it was specified on the command "
> +               "line");
>
>    if (opts->x_optimize == 0)
>      {
> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>    free (patch_area_arg);
>  }
>
> +/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
> +
> +static void
> +print_help_hardened ()
> +{
> +  printf ("%s\n", "The following options are enabled by -fhardened:");
> +  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
> +         (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> +  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
> +  printf ("  %s\n", "-ftrivial-auto-var-init=pattern");
> +#ifdef HAVE_LD_PIE
> +  printf ("  %s  %s\n", "-fPIE", "-pie");
> +#endif
> +  if (HAVE_LD_NOW_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,now");
> +  if (HAVE_LD_RELRO_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,relro");
> +  printf ("  %s\n", "-fstack-protector-strong");
> +  printf ("  %s\n", "-fstack-clash-protection");
> +  printf ("  %s\n", "-fcf-protection=full");
> +  putchar ('\n');
> +}
> +
>  /* Print help when OPT__help_ is set.  */
>
>  void
> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
>         }
>        else if (lang_flag != 0)
>         *pflags |= lang_flag;
> +      else if (strncasecmp (a, "hardened", len) == 0)
> +       print_help_hardened ();
>        else
>         warning (0,
>                  "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
>  /* Hold command-line options associated with stack limitation.  */
>  extern const char *opt_fstack_limit_symbol_arg;
>  extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
>
>  /* Input file names.  */
>
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..4dd22cdfe45
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..dd3cde93805
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..8242530bc4d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..b8fd65a960c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..6945a6391a9
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..652ece3d4c4
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
> new file mode 100644
> index 00000000000..c6202754bf5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile } */
> +/* { dg-require-stack-check "specific" } */
> +/* { dg-options "-fhardened -O -fstack-check" } */
> +
> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..283867ca806
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> +
> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..6924ba242f0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers.  */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man.  */
> +
> +int
> +main ()
> +{
> +}
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
> new file mode 100644
> index 00000000000..7d44d299f19
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
> +
> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..a757cbf0d12
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> +/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..32f35eb2595
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..5b3162b4d1f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..d3b9e79b9b6
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
>  # Listing only excludes gives empty results.
>  check_for_options c "--help=^joined,^separate" "" "" ""
>
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
>  if [ info exists prev_columns ] {
>      # Reset the enviroment variable to its oriuginal value.
>      set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET.  */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> +  bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index 8af9bf5090e..743a3a91684 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1575,6 +1575,19 @@ process_options (bool no_backend)
>                   "where the stack grows from lower to higher addresses");
>        flag_stack_clash_protection = 0;
>      }
> +  else if (flag_hardened)
> +    {
> +      if (!flag_stack_clash_protection
> +          /* Don't enable -fstack-clash-protection when -fstack-check=
> +             is used: it would result in confusing errors.  */
> +          && flag_stack_check == NO_STACK_CHECK)
> +       flag_stack_clash_protection = 1;
> +      else if (flag_stack_check != NO_STACK_CHECK)
> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                   "%<-fstack-clash-protection%> is not enabled by "
> +                   "%<-fhardened%> because %<-fstack-check%> was "
> +                   "specified on the command line");
> +    }
>
>    /* We cannot support -fstack-check= and -fstack-clash-protection at
>       the same time.  */
> @@ -1590,8 +1603,9 @@ process_options (bool no_backend)
>       target already uses a soft frame pointer, the transition is trivial.  */
>    if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>      {
> -      warning_at (UNKNOWN_LOCATION, 0,
> -                 "%<-fstack-protector%> not supported for this target");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "%<-fstack-protector%> not supported for this target");
>        flag_stack_protect = 0;
>      }
>    if (!flag_stack_protect)
>
> base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
> --
> 2.41.0
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2] gcc: Introduce -fhardened
  2023-10-19 12:24       ` Richard Biener
@ 2023-10-19 12:33         ` Sam James
  2023-10-19 18:33           ` Marek Polacek
  2023-10-23 19:25         ` [PATCH v3] " Marek Polacek
  1 sibling, 1 reply; 28+ messages in thread
From: Sam James @ 2023-10-19 12:33 UTC (permalink / raw)
  To: Richard Biener; +Cc: Marek Polacek, gcc-patches


Richard Biener <richard.guenther@gmail.com> writes:

> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>>
>> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>> > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>> > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>> > > <gcc-patches@gcc.gnu.org> wrote:
>> > > >
>> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
>> > > > and aarch64-unknown-linux-gnu; ok for trunk?
>> > > >
>> > > > -- >8 --
>> > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
>> > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
>> > > > of hardening flags.  The read of the room seems to be that the option
>> > > > would be useful.  So here's a patch implementing that option.
>> > > >
>> > > > Currently, -fhardened enables:
>> > > >
>> > > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>> > > >   -D_GLIBCXX_ASSERTIONS
>> > > >   -ftrivial-auto-var-init=pattern
>
> I think =zero is much better here given the overhead is way
> cheaper and pointers get a more reliable behavior.

Yes please, as I wouldn't want us to use =pattern distro-wide.

>
>> > > >   -fPIE  -pie  -Wl,-z,relro,-z,now
>> > > >   -fstack-protector-strong
>> > > >   -fstack-clash-protection
>> > > >   -fcf-protection=full (x86 GNU/Linux only)
>> > > >
>> > > > -fhardened will not override options that were specified on the command line
>> > > > (before or after -fhardened).  For example,
>> > > >
>> > > >      -D_FORTIFY_SOURCE=1 -fhardened
>> > > >
>> > > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>> > > >
>> > > >       -fhardened -fstack-protector
>> > > >
>> > > > will not enable -fstack-protector-strong.
>> > > >
>> > > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
>> > > > to anything.  I think we need a better way to show what it actually
>> > > > enables.
>> > >
>> > > I do think we need to find a solution here to solve asserting compliance.
>> >
>> > Fair enough.
>> >
>> > > Maybe we can have -Whardened that will diagnose any altering of
>> > > -fhardened by other options on the command-line or by missed target
>> > > implementations?  People might for example use -fstack-protector
>> > > but don't really want to make protection lower than requested with -fhardened.
>> > >
>> > > Any such conflict is much less appearant than when you use the
>> > > flags -fhardened composes.
>> >
>> > How about: --help=hardened says which options -fhardened attempts to
>> > enable, and -Whardened warns when it didn't enable an option?  E.g.,
>> >
>> >   -fstack-protector -fhardened -Whardened
>> >
>> > would say that it didn't enable -fstack-protector-strong because
>> > -fstack-protector was specified on the command line?
>> >
>> > If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
>> > list -z now, likewise for -z relro.
>> >
>> > Unclear if -Whardened should be enabled by default, but probably yes?
>>
>> Here's v2 which adds -Whardened (enabled by default).
>>
>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>
> I think it's OK but I'd like to see a second ACK here.  Can you see how our
> primary and secondary targets (+ host OS) behave here?  I think the
> documentation should elaborate a bit on expectations for non-Linux/GNU
> targets, specifically I think the default configuration for a target should
> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> have a testcase for this?
>
> Thanks,
> Richard.
>
>>
>> -- >8 --
>> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
>> I proposed -fhardened, a new umbrella option that enables a reasonable set
>> of hardening flags.  The read of the room seems to be that the option
>> would be useful.  So here's a patch implementing that option.
>>
>> Currently, -fhardened enables:
>>
>>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>>   -D_GLIBCXX_ASSERTIONS
>>   -ftrivial-auto-var-init=pattern
>>   -fPIE  -pie  -Wl,-z,relro,-z,now
>>   -fstack-protector-strong
>>   -fstack-clash-protection
>>   -fcf-protection=full (x86 GNU/Linux only)
>>
>> -fhardened will not override options that were specified on the command line
>> (before or after -fhardened).  For example,
>>
>>      -D_FORTIFY_SOURCE=1 -fhardened
>>
>> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>>
>>       -fhardened -fstack-protector
>>
>> will not enable -fstack-protector-strong.
>>
>> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
>> to anything.  This patch provides -Whardened, enabled by default, which
>> warns when -fhardened couldn't enable a particular option.  I think most
>> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
>> were not enabled.
>>
>> gcc/c-family/ChangeLog:
>>
>>         * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
>>         and _GLIBCXX_ASSERTIONS.
>>
>> gcc/ChangeLog:
>>
>>         * common.opt (Whardened, fhardened): New options.
>>         * config.in: Regenerate.
>>         * config/bpf/bpf.cc: Include "opts.h".
>>         (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
>>         not inform that -fstack-protector does not work.
>>         * config/i386/i386-options.cc (ix86_option_override_internal): When
>>         -fhardened, maybe enable -fcf-protection=full.
>>         * configure: Regenerate.
>>         * configure.ac: Check if the linker supports '-z now' and '-z relro'.
>>         * doc/invoke.texi: Document -fhardened and -Whardened.
>>         * gcc.cc (driver_handle_option): Remember if any link options or -static
>>         were specified on the command line.
>>         (process_command): When -fhardened, maybe enable -pie and
>>         -Wl,-z,relro,-z,now.
>>         * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
>>         (finish_options): When -fhardened, enable
>>         -ftrivial-auto-var-init=pattern and -fstack-protector-strong.
>>         (print_help_hardened): New.
>>         (print_help): Call it.
>>         * toplev.cc (process_options): When -fhardened, enable
>>         -fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
>>         do not warn that -fstack-protector not supported for this target.
>>
>> gcc/testsuite/ChangeLog:
>>
>>         * gcc.misc-tests/help.exp: Test -fhardened.
>>         * c-c++-common/fhardened-1.S: New test.
>>         * c-c++-common/fhardened-1.c: New test.
>>         * c-c++-common/fhardened-10.c: New test.
>>         * c-c++-common/fhardened-11.c: New test.
>>         * c-c++-common/fhardened-12.c: New test.
>>         * c-c++-common/fhardened-13.c: New test.
>>         * c-c++-common/fhardened-14.c: New test.
>>         * c-c++-common/fhardened-15.c: New test.
>>         * c-c++-common/fhardened-2.c: New test.
>>         * c-c++-common/fhardened-3.c: New test.
>>         * c-c++-common/fhardened-4.c: New test.
>>         * c-c++-common/fhardened-5.c: New test.
>>         * c-c++-common/fhardened-6.c: New test.
>>         * c-c++-common/fhardened-7.c: New test.
>>         * c-c++-common/fhardened-8.c: New test.
>>         * c-c++-common/fhardened-9.c: New test.
>>         * gcc.target/i386/cf_check-6.c: New test.
>> ---
>>  gcc/c-family/c-opts.cc                     | 42 ++++++++++++++
>>  gcc/common.opt                             |  8 +++
>>  gcc/config.in                              | 12 ++++
>>  gcc/config/bpf/bpf.cc                      |  8 ++-
>>  gcc/config/i386/i386-options.cc            | 17 +++++-
>>  gcc/configure                              | 50 +++++++++++++++-
>>  gcc/configure.ac                           | 42 +++++++++++++-
>>  gcc/doc/invoke.texi                        | 44 +++++++++++++-
>>  gcc/gcc.cc                                 | 48 +++++++++++++++-
>>  gcc/opts.cc                                | 67 +++++++++++++++++++++-
>>  gcc/opts.h                                 |  1 +
>>  gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
>>  gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
>>  gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
>>  gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
>>  gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
>>  gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
>>  gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
>>  gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
>>  gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
>>  gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
>>  gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
>>  gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
>>  gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
>>  gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
>>  gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
>>  gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
>>  gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
>>  gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
>>  gcc/toplev.cc                              | 18 +++++-
>>  30 files changed, 503 insertions(+), 14 deletions(-)
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
>>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
>>  create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>>
>> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
>> index ce2e021e69d..f5f6ba24290 100644
>> --- a/gcc/c-family/c-opts.cc
>> +++ b/gcc/c-family/c-opts.cc
>> @@ -1556,6 +1556,9 @@ c_finish_options (void)
>>        cb_file_change (parse_in, cmd_map);
>>        linemap_line_start (line_table, 0, 1);
>>
>> +      bool fortify_seen_p = false;
>> +      bool cxx_assert_seen_p = false;
>> +
>>        /* All command line defines must have the same location.  */
>>        cpp_force_token_locations (parse_in, line_table->highest_line);
>>        for (size_t i = 0; i < deferred_count; i++)
>> @@ -1573,6 +1576,45 @@ c_finish_options (void)
>>               else
>>                 cpp_assert (parse_in, opt->arg);
>>             }
>> +
>> +         if (UNLIKELY (flag_hardened)
>> +             && (opt->code == OPT_D || opt->code == OPT_U))
>> +           {
>> +             if (!fortify_seen_p)
>> +               fortify_seen_p
>> +                 = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
>> +                    && (opt->arg[15] == '\0' || opt->arg[15] == '='));
>> +             if (!cxx_assert_seen_p)
>> +               cxx_assert_seen_p
>> +                 = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
>> +                    && (opt->arg[19] == '\0' || opt->arg[19] == '='));
>> +           }
>> +       }
>> +
>> +      if (flag_hardened)
>> +       {
>> +         if (!fortify_seen_p && optimize > 0)
>> +           {
>> +             if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
>> +               cpp_define (parse_in, "_FORTIFY_SOURCE=3");
>> +             else
>> +               cpp_define (parse_in, "_FORTIFY_SOURCE=2");
>> +           }
>> +         else if (optimize == 0)
>> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
>> +                       "because optimizations are turned off");
>> +         else
>> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
>> +                       "because it was specified in %<-D%> or %<-U%>");
>> +         if (!cxx_assert_seen_p)
>> +           cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
>> +         else
>> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> +                       "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
>> +                       "%<-fhardened%> because it was specified in %<-D%> "
>> +                       "or %<-U%>");
>>         }
>>
>>        cpp_stop_forcing_token_locations (parse_in);
>> diff --git a/gcc/common.opt b/gcc/common.opt
>> index f137a1f81ac..60c13b9ffd2 100644
>> --- a/gcc/common.opt
>> +++ b/gcc/common.opt
>> @@ -634,6 +634,10 @@ Wfree-nonheap-object
>>  Common Var(warn_free_nonheap_object) Init(1) Warning
>>  Warn when attempting to free a non-heap object.
>>
>> +Whardened
>> +Common Var(warn_hardened) Init(1) Warning
>> +Warn when -fhardened did not enable an option from its set.
>> +
>>  Whsa
>>  Common Ignore Warning
>>  Does nothing.  Preserved for backward compatibility.
>> @@ -1827,6 +1831,10 @@ fharden-conditional-branches
>>  Common Var(flag_harden_conditional_branches) Optimization
>>  Harden conditional branches by checking reversed conditions.
>>
>> +fhardened
>> +Common Driver Var(flag_hardened)
>> +Enable various security-relevant flags.
>> +
>>  ; Nonzero means ignore `#ident' directives.  0 means handle them.
>>  ; Generate position-independent code for executables if possible
>>  ; On SVR4 targets, it also controls whether or not to emit a
>> diff --git a/gcc/config.in b/gcc/config.in
>> index d04718ad128..faa941c1385 100644
>> --- a/gcc/config.in
>> +++ b/gcc/config.in
>> @@ -1676,6 +1676,12 @@
>>  #endif
>>
>>
>> +/* Define 0/1 if your linker supports -z now */
>> +#ifndef USED_FOR_TARGET
>> +#undef HAVE_LD_NOW_SUPPORT
>> +#endif
>> +
>> +
>>  /* Define if your PowerPC64 linker only needs function descriptor syms. */
>>  #ifndef USED_FOR_TARGET
>>  #undef HAVE_LD_NO_DOT_SYMS
>> @@ -1719,6 +1725,12 @@
>>  #endif
>>
>>
>> +/* Define 0/1 if your linker supports -z relro */
>> +#ifndef USED_FOR_TARGET
>> +#undef HAVE_LD_RELRO_SUPPORT
>> +#endif
>> +
>> +
>>  /* Define if your linker links a mix of read-only and read-write sections into
>>     a read-write section. */
>>  #ifndef USED_FOR_TARGET
>> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
>> index 437bd652de3..41dc7fd3dae 100644
>> --- a/gcc/config/bpf/bpf.cc
>> +++ b/gcc/config/bpf/bpf.cc
>> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
>>  #include "gimplify-me.h"
>>
>>  #include "core-builtins.h"
>> +#include "opts.h"
>>
>>  /* Per-function machine data.  */
>>  struct GTY(()) machine_function
>> @@ -250,9 +251,10 @@ bpf_option_override (void)
>>    /* Disable -fstack-protector as it is not supported in BPF.  */
>>    if (flag_stack_protect)
>>      {
>> -      inform (input_location,
>> -              "%<-fstack-protector%> does not work "
>> -             "on this architecture");
>> +      if (!flag_stack_protector_set_by_fhardened_p)
>> +       inform (input_location,
>> +               "%<-fstack-protector%> does not work "
>> +               "on this architecture");
>>        flag_stack_protect = 0;
>>      }
>>
>> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
>> index 06af373ca57..22ede9e15b5 100644
>> --- a/gcc/config/i386/i386-options.cc
>> +++ b/gcc/config/i386/i386-options.cc
>> @@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
>>          = build_target_option_node (opts, opts_set);
>>      }
>>
>> +  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
>> +  /* When -fhardened, enable -fcf-protection=full, but only when it's
>> +     compatible with this target, and when it wasn't already specified
>> +     on the command line.  */
>> +  if (opts->x_flag_hardened && cf_okay_p)
>> +    {
>> +      if (opts->x_flag_cf_protection == CF_NONE)
>> +       opts->x_flag_cf_protection = CF_FULL;
>> +      else if (opts->x_flag_cf_protection != CF_FULL)
>> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> +                   "%<-fcf-protection=full%> is not enabled by "
>> +                   "%<-fhardened%> because it was specified on the command "
>> +                   "line");
>> +    }
>> +
>>    if (opts->x_flag_cf_protection != CF_NONE)
>>      {
>>        if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
>> -         && !TARGET_64BIT && !TARGET_CMOV)
>> +         && !cf_okay_p)
>>         error ("%<-fcf-protection%> is not compatible with this target");
>>
>>        opts->x_flag_cf_protection
>> diff --git a/gcc/configure b/gcc/configure
>> index c43bde8174b..e2aac56edf6 100755
>> --- a/gcc/configure
>> +++ b/gcc/configure
>> @@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
>>        ld_bndplt_support=yes
>>      fi
>>    elif test x$gcc_cv_ld != x; then
>> -    # Check if linker supports -a bndplt option
>> +    # Check if linker supports -z bndplt option
>>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>>        ld_bndplt_support=yes
>>      fi
>> @@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>>    ;;
>>  esac
>>
>> +# Check if the linker supports '-z now'
>> +ld_now_support=no
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
>> +$as_echo_n "checking linker -z now option... " >&6; }
>> +if test x"$ld_is_gold" = xyes; then
>> +  ld_now_support=yes
>> +elif test $in_tree_ld = yes ; then
>> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
>> +    ld_now_support=yes
>> +  fi
>> +elif test x$gcc_cv_ld != x; then
>> +  # Check if linker supports -z now
>> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
>> +    ld_now_support=yes
>> +  fi
>> +fi
>> +
>> +cat >>confdefs.h <<_ACEOF
>> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
>> +_ACEOF
>> +
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
>> +$as_echo "$ld_now_support" >&6; }
>> +
>> +# Check if the linker supports '-z relro'
>> +ld_relro_support=no
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
>> +$as_echo_n "checking linker -z relro option... " >&6; }
>> +if test x"$ld_is_gold" = xyes; then
>> +  ld_relro_support=yes
>> +elif test $in_tree_ld = yes ; then
>> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
>> +    ld_relro_support=yes
>> +  fi
>> +elif test x$gcc_cv_ld != x; then
>> +  # Check if linker supports -z relro
>> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
>> +    ld_relro_support=yes
>> +  fi
>> +fi
>> +
>> +cat >>confdefs.h <<_ACEOF
>> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
>> +_ACEOF
>> +
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
>> +$as_echo "$ld_relro_support" >&6; }
>> +
>>  # Configure the subdirectories
>>  # AC_CONFIG_SUBDIRS($subdirs)
>>
>> diff --git a/gcc/configure.ac b/gcc/configure.ac
>> index fb8e32f8ee5..6a090ccf3bd 100644
>> --- a/gcc/configure.ac
>> +++ b/gcc/configure.ac
>> @@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
>>        ld_bndplt_support=yes
>>      fi
>>    elif test x$gcc_cv_ld != x; then
>> -    # Check if linker supports -a bndplt option
>> +    # Check if linker supports -z bndplt option
>>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>>        ld_bndplt_support=yes
>>      fi
>> @@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
>>    ;;
>>  esac
>>
>> +# Check if the linker supports '-z now'
>> +ld_now_support=no
>> +AC_MSG_CHECKING(linker -z now option)
>> +if test x"$ld_is_gold" = xyes; then
>> +  ld_now_support=yes
>> +elif test $in_tree_ld = yes ; then
>> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
>> +    ld_now_support=yes
>> +  fi
>> +elif test x$gcc_cv_ld != x; then
>> +  # Check if linker supports -z now
>> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
>> +    ld_now_support=yes
>> +  fi
>> +fi
>> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
>> +  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
>> +  [Define 0/1 if your linker supports -z now])
>> +AC_MSG_RESULT($ld_now_support)
>> +
>> +# Check if the linker supports '-z relro'
>> +ld_relro_support=no
>> +AC_MSG_CHECKING(linker -z relro option)
>> +if test x"$ld_is_gold" = xyes; then
>> +  ld_relro_support=yes
>> +elif test $in_tree_ld = yes ; then
>> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
>> +    ld_relro_support=yes
>> +  fi
>> +elif test x$gcc_cv_ld != x; then
>> +  # Check if linker supports -z relro
>> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
>> +    ld_relro_support=yes
>> +  fi
>> +fi
>> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
>> +  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
>> +  [Define 0/1 if your linker supports -z relro])
>> +AC_MSG_RESULT($ld_relro_support)
>> +
>>  # Configure the subdirectories
>>  # AC_CONFIG_SUBDIRS($subdirs)
>>
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index 7c5f81d9783..48e6a3f433c 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
>>  -Wformat-y2k  -Wframe-address
>>  -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
>>  -Wno-if-not-aligned  -Wno-ignored-attributes
>> --Wignored-qualifiers  -Wno-incompatible-pointer-types
>> +-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
>>  -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
>>  -Wno-implicit-function-declaration  -Wno-implicit-int
>>  -Winfinite-recursion
>> @@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
>>  -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
>>  -fsanitize-undefined-trap-on-error  -fbounds-check
>>  -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
>> --fharden-compares -fharden-conditional-branches
>> +-fharden-compares -fharden-conditional-branches -fhardened
>>  -fstack-protector  -fstack-protector-all  -fstack-protector-strong
>>  -fstack-protector-explicit  -fstack-check
>>  -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym}
>> @@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
>>  Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
>>  This warning is enabled by @option{-Wall}.
>>
>> +@opindex Whardened
>> +@opindex Wno-hardened
>> +@item -Whardened
>> +Warn when @option{-fhardened} did not enable an option from its set (for
>> +which see @option{-fhardened}).  For instance, using @option{-fhardened}
>> +and @option{-fstack-protector} at the same time on the command line causes
>> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
>> +not enabled by @option{-fhardened}.
>> +
>> +This warning is enabled by default and has effect only when @option{-fhardened}
>> +is enabled.
>> +
>>  @opindex Wimplicit-fallthrough
>>  @opindex Wno-implicit-fallthrough
>>  @item -Wimplicit-fallthrough
>> @@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
>>  unexpected.  Use with @samp{-fharden-compares} to cover all
>>  conditionals.
>>
>> +@opindex fhardened
>> +@item -fhardened
>> +Enable a set of flags for C and C++ that improve the security of the
>> +generated code without affecting its ABI.  The precise flags enabled
>> +may change between major releases of GCC, but are currently:
>> +
>> +@c Keep this in sync with print_help_hardened!
>> +@gccoptlist{
>> +-D_FORTIFY_SOURCE=3
>> +-D_GLIBCXX_ASSERTIONS
>> +-ftrivial-auto-var-init=pattern
>> +-fPIE  -pie  -Wl,-z,relro,-z,now
>> +-fstack-protector-strong
>> +-fstack-clash-protection
>> +-fcf-protection=full @r{(x86 GNU/Linux only)}
>> +}
>> +
>> +The list of options enabled by @option{-fhardened} can be generated using
>> +the @option{--help=hardened} option.
>> +
>> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
>> +is used instead.
>> +
>> +@option{-fhardened} only enables a particular option if it wasn't
>> +already specified anywhere on the command line.  For instance,
>> +@option{-fhardened} @option{-fstack-protector} will only enable
>> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
>> +
>>  @opindex fstack-protector
>>  @item -fstack-protector
>>  Emit extra code to check for buffer overflows, such as stack smashing
>> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
>> index c6e600fa0d3..ed4e2400e91 100644
>> --- a/gcc/gcc.cc
>> +++ b/gcc/gcc.cc
>> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>>     driver added to dumpdir after dumpbase or linker output name.  */
>>  static bool dumpdir_trailing_dash_added = false;
>>
>> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
>> +   line.  */
>> +static bool any_link_options_p;
>> +
>> +/* True if -static was specified on the command line.  */
>> +static bool static_p;
>> +
>>  /* Basename of dump and aux outputs, computed from dumpbase (given or
>>     derived from output name), to override input_basename in non-%w %b
>>     et al.  */
>> @@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
>>        save_switch ("-o", 1, &arg, validated, true);
>>        return true;
>>
>> -#ifdef ENABLE_DEFAULT_PIE
>>      case OPT_pie:
>> +#ifdef ENABLE_DEFAULT_PIE
>>        /* -pie is turned on by default.  */
>> +      validated = true;
>>  #endif
>> +    case OPT_r:
>> +    case OPT_shared:
>> +    case OPT_no_pie:
>> +      any_link_options_p = true;
>> +      break;
>> +
>> +    case OPT_static:
>> +      static_p = true;
>> +      break;
>>
>>      case OPT_static_libgcc:
>>      case OPT_shared_libgcc:
>> @@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
>>  #endif
>>      }
>>
>> +  /* TODO: check if -static -pie works and maybe use it.  */
>> +  if (flag_hardened)
>> +    {
>> +      if (!any_link_options_p && !static_p)
>> +       {
>> +#ifdef HAVE_LD_PIE
>> +         save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
>> +#endif
>> +         /* These are passed straight down to collect2 so we have to break
>> +            it up like this.  */
>> +         if (HAVE_LD_NOW_SUPPORT)
>> +           {
>> +             add_infile ("-z", "*");
>> +             add_infile ("now", "*");
>> +           }
>> +         if (HAVE_LD_RELRO_SUPPORT)
>> +           {
>> +             add_infile ("-z", "*");
>> +             add_infile ("relro", "*");
>> +           }
>> +       }
>> +      /* We can't use OPT_Whardened yet.  Sigh.  */
>> +      else if (warn_hardened)
>> +       warning_at (UNKNOWN_LOCATION, 0,
>> +                   "linker hardening options not enabled by %<-fhardened%> "
>> +                   "because other link options were specified on the command "
>> +                   "line");
>> +    }
>> +
>>    /* Handle -gtoggle as it would later in toplev.cc:process_options to
>>       make the debug-level-gt spec function work as expected.  */
>>    if (flag_gtoggle)
>> diff --git a/gcc/opts.cc b/gcc/opts.cc
>> index 573dcf8e497..8265c5b3c1b 100644
>> --- a/gcc/opts.cc
>> +++ b/gcc/opts.cc
>> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
>>  /* Set by -fcanon-prefix-map.  */
>>  bool flag_canon_prefix_map;
>>
>> +/* Set by finish_options when flag_stack_protector was set only because of
>> +   -fhardened.  Yuck.  */
>> +bool flag_stack_protector_set_by_fhardened_p;
>> +
>>  static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>>
>>  /* Names of fundamental debug info formats indexed by enum
>> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>>        opts->x_flag_section_anchors = 0;
>>      }
>>
>> +  if (opts->x_flag_hardened)
>> +    {
>> +      if (!opts_set->x_flag_auto_var_init)
>> +       opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
>> +      else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
>> +       warning_at (loc, OPT_Whardened,
>> +                   "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
>> +                   "%<-fhardened%> because it was specified on the command "
>> +                   "line");
>> +    }
>> +
>>    if (!opts->x_flag_opts_finished)
>>      {
>>        /* We initialize opts->x_flag_pie to -1 so that targets can set a
>> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>>           /* We initialize opts->x_flag_pic to -1 so that we can tell if
>>              -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
>>           if (opts->x_flag_pic == -1)
>> -           opts->x_flag_pie = DEFAULT_FLAG_PIE;
>> +           opts->x_flag_pie = (opts->x_flag_hardened
>> +                               ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
>>           else
>>             opts->x_flag_pie = 0;
>>         }
>> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>>      }
>>
>>    /* We initialize opts->x_flag_stack_protect to -1 so that targets
>> -     can set a default value.  */
>> +     can set a default value.  With --enable-default-ssp or -fhardened
>> +     the default is -fstack-protector-strong.  */
>>    if (opts->x_flag_stack_protect == -1)
>> -    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
>> +    {
>> +      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
>> +        defined in such a way that it uses flag_stack_protect which can't
>> +        be used here.  Moreover, some targets like BPF don't support
>> +        -fstack-protector at all but we don't know that here.  So remember
>> +        that flag_stack_protect was set at the behest of -fhardened.  */
>> +      if (opts->x_flag_hardened)
>> +       {
>> +         opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
>> +         flag_stack_protector_set_by_fhardened_p = true;
>> +       }
>> +      else
>> +       opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
>> +    }
>> +  else if (opts->x_flag_hardened
>> +          && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
>> +    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> +               "%<-fstack-protector-strong%> is not enabled by "
>> +               "%<-fhardened%> because it was specified on the command "
>> +               "line");
>>
>>    if (opts->x_optimize == 0)
>>      {
>> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>>    free (patch_area_arg);
>>  }
>>
>> +/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
>> +
>> +static void
>> +print_help_hardened ()
>> +{
>> +  printf ("%s\n", "The following options are enabled by -fhardened:");
>> +  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
>> +         (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
>> +  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
>> +  printf ("  %s\n", "-ftrivial-auto-var-init=pattern");
>> +#ifdef HAVE_LD_PIE
>> +  printf ("  %s  %s\n", "-fPIE", "-pie");
>> +#endif
>> +  if (HAVE_LD_NOW_SUPPORT)
>> +    printf ("  %s\n", "-Wl,-z,now");
>> +  if (HAVE_LD_RELRO_SUPPORT)
>> +    printf ("  %s\n", "-Wl,-z,relro");
>> +  printf ("  %s\n", "-fstack-protector-strong");
>> +  printf ("  %s\n", "-fstack-clash-protection");
>> +  printf ("  %s\n", "-fcf-protection=full");
>> +  putchar ('\n');
>> +}
>> +
>>  /* Print help when OPT__help_ is set.  */
>>
>>  void
>> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
>>         }
>>        else if (lang_flag != 0)
>>         *pflags |= lang_flag;
>> +      else if (strncasecmp (a, "hardened", len) == 0)
>> +       print_help_hardened ();
>>        else
>>         warning (0,
>>                  "unrecognized argument to %<--help=%> option: %q.*s",
>> diff --git a/gcc/opts.h b/gcc/opts.h
>> index 00f377f9ca7..d89c5de8114 100644
>> --- a/gcc/opts.h
>> +++ b/gcc/opts.h
>> @@ -344,6 +344,7 @@ struct cl_option_handlers
>>  /* Hold command-line options associated with stack limitation.  */
>>  extern const char *opt_fstack_limit_symbol_arg;
>>  extern int opt_fstack_limit_register_no;
>> +extern bool flag_stack_protector_set_by_fhardened_p;
>>
>>  /* Input file names.  */
>>
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
>> new file mode 100644
>> index 00000000000..4dd22cdfe45
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
>> @@ -0,0 +1,6 @@
>> +/* { dg-do preprocess { target pie } } */
>> +/* { dg-options "-fhardened -O" } */
>> +
>> +#if __PIE__ != 2
>> +# error "-fPIE not enabled"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
>> new file mode 100644
>> index 00000000000..dd3cde93805
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
>> @@ -0,0 +1,14 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O" } */
>> +
>> +#ifndef __SSP_STRONG__
>> +# error "-fstack-protector-strong not enabled"
>> +#endif
>> +
>> +#if _FORTIFY_SOURCE < 2
>> +# error "_FORTIFY_SOURCE not enabled"
>> +#endif
>> +
>> +#ifndef _GLIBCXX_ASSERTIONS
>> +# error "_GLIBCXX_ASSERTIONS not enabled"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
>> new file mode 100644
>> index 00000000000..8242530bc4d
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
>> +
>> +#if _FORTIFY_SOURCE != 1
>> +# error "_FORTIFY_SOURCE != 1"
>> +#endif
>> +
>> +#ifndef _GLIBCXX_ASSERTIONS
>> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
>> +#endif
>> +
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
>> new file mode 100644
>> index 00000000000..b8fd65a960c
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
>> @@ -0,0 +1,10 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
>> +
>> +#ifndef _FORTIFY_SOURCE
>> +# error "_FORTIFY_SOURCE disabled when it should not be"
>> +#endif
>> +
>> +#ifndef _GLIBCXX_ASSERTIONS
>> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
>> new file mode 100644
>> index 00000000000..42594e4c0e0
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
>> @@ -0,0 +1,11 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
>> +
>> +int
>> +foo ()
>> +{
>> +  int i;
>> +  return i;
>> +}
>> +
>> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
>> new file mode 100644
>> index 00000000000..6945a6391a9
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
>> @@ -0,0 +1,6 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O" } */
>> +
>> +#if __PIE__ != 2
>> +# error "-fPIE not enabled"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
>> new file mode 100644
>> index 00000000000..652ece3d4c4
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
>> @@ -0,0 +1,6 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O -fno-PIE" } */
>> +
>> +#ifdef __PIE__
>> +# error "PIE enabled when it should not be"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
>> new file mode 100644
>> index 00000000000..c6202754bf5
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
>> @@ -0,0 +1,5 @@
>> +/* { dg-do compile } */
>> +/* { dg-require-stack-check "specific" } */
>> +/* { dg-options "-fhardened -O -fstack-check" } */
>> +
>> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
>> new file mode 100644
>> index 00000000000..283867ca806
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -fstack-protector" } */
>> +
>> +#ifdef __SSP_STRONG__
>> +# error "-fstack-protector-strong enabled when it should not be"
>> +#endif
>> +#ifndef __SSP__
>> +# error "-fstack-protector not enabled"
>> +#endif
>> +
>> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
>> new file mode 100644
>> index 00000000000..6924ba242f0
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
>> @@ -0,0 +1,14 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O0" } */
>> +/* Test that we don't get any diagnostic coming from libc headers.  */
>> +
>> +#include <stdio.h>
>> +
>> +/* The most useful C program known to man.  */
>> +
>> +int
>> +main ()
>> +{
>> +}
>> +
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
>> new file mode 100644
>> index 00000000000..7d44d299f19
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
>> @@ -0,0 +1,4 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
>> +
>> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
>> new file mode 100644
>> index 00000000000..42594e4c0e0
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
>> @@ -0,0 +1,11 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
>> +
>> +int
>> +foo ()
>> +{
>> +  int i;
>> +  return i;
>> +}
>> +
>> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
>> new file mode 100644
>> index 00000000000..a757cbf0d12
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
>> +
>> +int
>> +foo ()
>> +{
>> +  int i;
>> +  return i;
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
>> +/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
>> new file mode 100644
>> index 00000000000..32f35eb2595
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
>> @@ -0,0 +1,7 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O -fpie" } */
>> +
>> +/* -fpie takes precedence over -fhardened */
>> +#if __PIE__ != 1
>> +# error "__PIE__ != 1"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
>> new file mode 100644
>> index 00000000000..5b3162b4d1f
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
>> @@ -0,0 +1,7 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O -fPIC" } */
>> +
>> +/* -fPIC takes precedence over -fhardened */
>> +#ifdef __PIE__
>> +# error "PIE enabled when it should not be"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
>> new file mode 100644
>> index 00000000000..d3b9e79b9b6
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
>> @@ -0,0 +1,9 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
>> +
>> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
>> +# error "hardening enabled when it should not be"
>> +#endif
>> +
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
>> index 52b9cb0ab90..15d618a2528 100644
>> --- a/gcc/testsuite/gcc.misc-tests/help.exp
>> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
>> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
>>  # Listing only excludes gives empty results.
>>  check_for_options c "--help=^joined,^separate" "" "" ""
>>
>> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
>> +
>>  if [ info exists prev_columns ] {
>>      # Reset the enviroment variable to its oriuginal value.
>>      set env(COLUMNS) $prev_columns
>> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
>> new file mode 100644
>> index 00000000000..73b78dce889
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
>> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
>> +/* Test that -fhardened enables CET.  */
>> +
>> +extern void bar (void) __attribute__((__cf_check__));
>> +
>> +void
>> +foo (void)
>> +{
>> +  bar ();
>> +}
>> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
>> index 8af9bf5090e..743a3a91684 100644
>> --- a/gcc/toplev.cc
>> +++ b/gcc/toplev.cc
>> @@ -1575,6 +1575,19 @@ process_options (bool no_backend)
>>                   "where the stack grows from lower to higher addresses");
>>        flag_stack_clash_protection = 0;
>>      }
>> +  else if (flag_hardened)
>> +    {
>> +      if (!flag_stack_clash_protection
>> +          /* Don't enable -fstack-clash-protection when -fstack-check=
>> +             is used: it would result in confusing errors.  */
>> +          && flag_stack_check == NO_STACK_CHECK)
>> +       flag_stack_clash_protection = 1;
>> +      else if (flag_stack_check != NO_STACK_CHECK)
>> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> +                   "%<-fstack-clash-protection%> is not enabled by "
>> +                   "%<-fhardened%> because %<-fstack-check%> was "
>> +                   "specified on the command line");
>> +    }
>>
>>    /* We cannot support -fstack-check= and -fstack-clash-protection at
>>       the same time.  */
>> @@ -1590,8 +1603,9 @@ process_options (bool no_backend)
>>       target already uses a soft frame pointer, the transition is trivial.  */
>>    if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>>      {
>> -      warning_at (UNKNOWN_LOCATION, 0,
>> -                 "%<-fstack-protector%> not supported for this target");
>> +      if (!flag_stack_protector_set_by_fhardened_p)
>> +       warning_at (UNKNOWN_LOCATION, 0,
>> +                   "%<-fstack-protector%> not supported for this target");
>>        flag_stack_protect = 0;
>>      }
>>    if (!flag_stack_protect)
>>
>> base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
>> --
>> 2.41.0
>>


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2] gcc: Introduce -fhardened
  2023-10-18 20:12       ` Qing Zhao
@ 2023-10-19 18:32         ` Marek Polacek
  0 siblings, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2023-10-19 18:32 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, GCC Patches

On Wed, Oct 18, 2023 at 08:12:37PM +0000, Qing Zhao wrote:
> Marek,
> 
> Sorry for the late comment (I was just back from a long vacation immediate after Cauldron). 

No worries.
 
> One question:
> 
> Is the option “-fhandened” for production build or for development build? 

I intend -fhardened to be for production builds.

> If it’s for development build, then adding -ftrivial-auto-var-init=pattern is reasonable since the major purpose for  -ftrivial-auto-var-init=pattern is for debugging, the runtime overhead of -ftrivial-auto-var-init=pattern is higher then -ftrivial-auto-var-init=zero.
> 
> However, if it’s for production build, then adding -ftrivial-auto-var-init=zero is better since the major purpose for -ftrivial-auto-var-init=zero is for production build to eliminate all uninitialization. And the runtime overhead of =zero is smaller than =pattern.

Okay, I've changed the patch back to enabling -ftrivial-auto-var-init=zero.

In future C++ modes, we may have to default to -ftrivial-auto-var-init=zero
as per <http://wg21.link/P2723> anyway.  On the other hand, it seems that
<https://wg21.link/p2795r3> might change that again...

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2] gcc: Introduce -fhardened
  2023-10-19 12:33         ` Sam James
@ 2023-10-19 18:33           ` Marek Polacek
  0 siblings, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2023-10-19 18:33 UTC (permalink / raw)
  To: Sam James; +Cc: Richard Biener, gcc-patches

On Thu, Oct 19, 2023 at 01:33:51PM +0100, Sam James wrote:
> 
> Richard Biener <richard.guenther@gmail.com> writes:
> 
> > On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
> >>
> >> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> >> > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> >> > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> >> > > <gcc-patches@gcc.gnu.org> wrote:
> >> > > >
> >> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> >> > > > and aarch64-unknown-linux-gnu; ok for trunk?
> >> > > >
> >> > > > -- >8 --
> >> > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> >> > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> >> > > > of hardening flags.  The read of the room seems to be that the option
> >> > > > would be useful.  So here's a patch implementing that option.
> >> > > >
> >> > > > Currently, -fhardened enables:
> >> > > >
> >> > > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> >> > > >   -D_GLIBCXX_ASSERTIONS
> >> > > >   -ftrivial-auto-var-init=pattern
> >
> > I think =zero is much better here given the overhead is way
> > cheaper and pointers get a more reliable behavior.
> 
> Yes please, as I wouldn't want us to use =pattern distro-wide.

Thanks for the feedback, I switched back to =zero.

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v3] gcc: Introduce -fhardened
  2023-10-19 12:24       ` Richard Biener
  2023-10-19 12:33         ` Sam James
@ 2023-10-23 19:25         ` Marek Polacek
  2023-10-24  7:22           ` Richard Biener
  2023-10-24  7:44           ` [PATCH v3] " Iain Sandoe
  1 sibling, 2 replies; 28+ messages in thread
From: Marek Polacek @ 2023-10-23 19:25 UTC (permalink / raw)
  To: Richard Biener; +Cc: iain, GCC Patches

On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
> >
> > On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> > > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> > > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > >
> > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > > > > and aarch64-unknown-linux-gnu; ok for trunk?
> > > > >
> > > > > -- >8 --
> > > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > > > of hardening flags.  The read of the room seems to be that the option
> > > > > would be useful.  So here's a patch implementing that option.
> > > > >
> > > > > Currently, -fhardened enables:
> > > > >
> > > > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > > > >   -D_GLIBCXX_ASSERTIONS
> > > > >   -ftrivial-auto-var-init=pattern
> 
> I think =zero is much better here given the overhead is way
> cheaper and pointers get a more reliable behavior.

Ok, changed now.
 
> > > > >   -fPIE  -pie  -Wl,-z,relro,-z,now
> > > > >   -fstack-protector-strong
> > > > >   -fstack-clash-protection
> > > > >   -fcf-protection=full (x86 GNU/Linux only)
> > > > >
> > > > > -fhardened will not override options that were specified on the command line
> > > > > (before or after -fhardened).  For example,
> > > > >
> > > > >      -D_FORTIFY_SOURCE=1 -fhardened
> > > > >
> > > > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> > > > >
> > > > >       -fhardened -fstack-protector
> > > > >
> > > > > will not enable -fstack-protector-strong.
> > > > >
> > > > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > > > to anything.  I think we need a better way to show what it actually
> > > > > enables.
> > > >
> > > > I do think we need to find a solution here to solve asserting compliance.
> > >
> > > Fair enough.
> > >
> > > > Maybe we can have -Whardened that will diagnose any altering of
> > > > -fhardened by other options on the command-line or by missed target
> > > > implementations?  People might for example use -fstack-protector
> > > > but don't really want to make protection lower than requested with -fhardened.
> > > >
> > > > Any such conflict is much less appearant than when you use the
> > > > flags -fhardened composes.
> > >
> > > How about: --help=hardened says which options -fhardened attempts to
> > > enable, and -Whardened warns when it didn't enable an option?  E.g.,
> > >
> > >   -fstack-protector -fhardened -Whardened
> > >
> > > would say that it didn't enable -fstack-protector-strong because
> > > -fstack-protector was specified on the command line?
> > >
> > > If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
> > > list -z now, likewise for -z relro.
> > >
> > > Unclear if -Whardened should be enabled by default, but probably yes?
> >
> > Here's v2 which adds -Whardened (enabled by default).
> >
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> I think it's OK but I'd like to see a second ACK here.  

Thanks!

> Can you see how our
> primary and secondary targets (+ host OS) behave here?

That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
that fails with:

ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'

and I tried Darwin (104) and that fails with

*** Configuration aarch64-apple-darwin21.6.0 not supported

Is anyone else able to build gcc on those machines, or test the attached
patch?

> I think the
> documentation should elaborate a bit on expectations for non-Linux/GNU
> targets, specifically I think the default configuration for a target should
> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> have a testcase for this?

Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
something not supported on those systems, and it's something for which
we have a configure test, then we shouldn't warn.  This is already the
case for -pie, -z relro, and -z now.  

Should the docs say something like the following for features without
configure checks?

@option{-fhardened} can, on certain systems, attempt to enable features
not supported on that particular system.  In that case, it's possible to
prevent the warning using the @option{-Wno-hardened} option.

I've added a line saying:

+This option is intended to be used in production builds, not merely
+in debug builds.

-- >8 --
In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
I proposed -fhardened, a new umbrella option that enables a reasonable set
of hardening flags.  The read of the room seems to be that the option
would be useful.  So here's a patch implementing that option.

Currently, -fhardened enables:

  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
  -D_GLIBCXX_ASSERTIONS
  -ftrivial-auto-var-init=zero
  -fPIE  -pie  -Wl,-z,relro,-z,now
  -fstack-protector-strong
  -fstack-clash-protection
  -fcf-protection=full (x86 GNU/Linux only)

-fhardened will not override options that were specified on the command line
(before or after -fhardened).  For example,

     -D_FORTIFY_SOURCE=1 -fhardened

means that _FORTIFY_SOURCE=1 will be used.  Similarly,

      -fhardened -fstack-protector

will not enable -fstack-protector-strong.

In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
to anything.  This patch provides -Whardened, enabled by default, which
warns when -fhardened couldn't enable a particular option.  I think most
often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
were not enabled.

gcc/c-family/ChangeLog:

	* c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
	and _GLIBCXX_ASSERTIONS.

gcc/ChangeLog:

	* common.opt (Whardened, fhardened): New options.
	* config.in: Regenerate.
	* config/bpf/bpf.cc: Include "opts.h".
	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
	not inform that -fstack-protector does not work.
	* config/i386/i386-options.cc (ix86_option_override_internal): When
	-fhardened, maybe enable -fcf-protection=full.
	* configure: Regenerate.
	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
	* doc/invoke.texi: Document -fhardened and -Whardened.
	* gcc.cc (driver_handle_option): Remember if any link options or -static
	were specified on the command line.
	(process_command): When -fhardened, maybe enable -pie and
	-Wl,-z,relro,-z,now.
	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
	(finish_options): When -fhardened, enable
	-ftrivial-auto-var-init=zero and -fstack-protector-strong.
	(print_help_hardened): New.
	(print_help): Call it.
	* toplev.cc (process_options): When -fhardened, enable
	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
	do not warn that -fstack-protector not supported for this target.

gcc/testsuite/ChangeLog:

	* gcc.misc-tests/help.exp: Test -fhardened.
	* c-c++-common/fhardened-1.S: New test.
	* c-c++-common/fhardened-1.c: New test.
	* c-c++-common/fhardened-10.c: New test.
	* c-c++-common/fhardened-11.c: New test.
	* c-c++-common/fhardened-12.c: New test.
	* c-c++-common/fhardened-13.c: New test.
	* c-c++-common/fhardened-14.c: New test.
	* c-c++-common/fhardened-15.c: New test.
	* c-c++-common/fhardened-2.c: New test.
	* c-c++-common/fhardened-3.c: New test.
	* c-c++-common/fhardened-4.c: New test.
	* c-c++-common/fhardened-5.c: New test.
	* c-c++-common/fhardened-6.c: New test.
	* c-c++-common/fhardened-7.c: New test.
	* c-c++-common/fhardened-8.c: New test.
	* c-c++-common/fhardened-9.c: New test.
	* gcc.target/i386/cf_check-6.c: New test.
---
 gcc/c-family/c-opts.cc                     | 42 ++++++++++++++
 gcc/common.opt                             |  8 +++
 gcc/config.in                              | 12 ++++
 gcc/config/bpf/bpf.cc                      |  8 ++-
 gcc/config/i386/i386-options.cc            | 17 +++++-
 gcc/configure                              | 50 +++++++++++++++-
 gcc/configure.ac                           | 42 +++++++++++++-
 gcc/doc/invoke.texi                        | 47 ++++++++++++++-
 gcc/gcc.cc                                 | 48 +++++++++++++++-
 gcc/opts.cc                                | 67 +++++++++++++++++++++-
 gcc/opts.h                                 |  1 +
 gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
 gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
 gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
 gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
 gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
 gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
 gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
 gcc/toplev.cc                              | 18 +++++-
 30 files changed, 506 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c

diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index ce2e021e69d..f5f6ba24290 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -1556,6 +1556,9 @@ c_finish_options (void)
       cb_file_change (parse_in, cmd_map);
       linemap_line_start (line_table, 0, 1);
 
+      bool fortify_seen_p = false;
+      bool cxx_assert_seen_p = false;
+
       /* All command line defines must have the same location.  */
       cpp_force_token_locations (parse_in, line_table->highest_line);
       for (size_t i = 0; i < deferred_count; i++)
@@ -1573,6 +1576,45 @@ c_finish_options (void)
 	      else
 		cpp_assert (parse_in, opt->arg);
 	    }
+
+	  if (UNLIKELY (flag_hardened)
+	      && (opt->code == OPT_D || opt->code == OPT_U))
+	    {
+	      if (!fortify_seen_p)
+		fortify_seen_p
+		  = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
+		     && (opt->arg[15] == '\0' || opt->arg[15] == '='));
+	      if (!cxx_assert_seen_p)
+		cxx_assert_seen_p
+		  = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
+		     && (opt->arg[19] == '\0' || opt->arg[19] == '='));
+	    }
+	}
+
+      if (flag_hardened)
+	{
+	  if (!fortify_seen_p && optimize > 0)
+	    {
+	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
+		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
+	      else
+		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
+	    }
+	  else if (optimize == 0)
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because optimizations are turned off");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because it was specified in %<-D%> or %<-U%>");
+	  if (!cxx_assert_seen_p)
+	    cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_GLIBCXX_ASSERTIONS%> is not enabled by "
+			"%<-fhardened%> because it was specified in %<-D%> "
+			"or %<-U%>");
 	}
 
       cpp_stop_forcing_token_locations (parse_in);
diff --git a/gcc/common.opt b/gcc/common.opt
index 1cf3bdd3b51..48a15f077ef 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -634,6 +634,10 @@ Wfree-nonheap-object
 Common Var(warn_free_nonheap_object) Init(1) Warning
 Warn when attempting to free a non-heap object.
 
+Whardened
+Common Var(warn_hardened) Init(1) Warning
+Warn when -fhardened did not enable an option from its set.
+
 Whsa
 Common Ignore Warning
 Does nothing.  Preserved for backward compatibility.
@@ -1823,6 +1827,10 @@ fguess-branch-probability
 Common Var(flag_guess_branch_prob) Optimization
 Enable guessing of branch probabilities.
 
+fhardened
+Common Driver Var(flag_hardened)
+Enable various security-relevant flags.
+
 fharden-compares
 Common Var(flag_harden_compares) Optimization
 Harden conditionals not used in branches, checking reversed conditions.
diff --git a/gcc/config.in b/gcc/config.in
index 03faee1c6ac..327b1e3e2ee 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1695,6 +1695,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z now */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_NOW_SUPPORT
+#endif
+
+
 /* Define if your PowerPC64 linker only needs function descriptor syms. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_NO_DOT_SYMS
@@ -1738,6 +1744,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z relro */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_RELRO_SUPPORT
+#endif
+
+
 /* Define if your linker links a mix of read-only and read-write sections into
    a read-write section. */
 #ifndef USED_FOR_TARGET
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 437bd652de3..41dc7fd3dae 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 
 #include "core-builtins.h"
+#include "opts.h"
 
 /* Per-function machine data.  */
 struct GTY(()) machine_function
@@ -250,9 +251,10 @@ bpf_option_override (void)
   /* Disable -fstack-protector as it is not supported in BPF.  */
   if (flag_stack_protect)
     {
-      inform (input_location,
-              "%<-fstack-protector%> does not work "
-	      "on this architecture");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	inform (input_location,
+		"%<-fstack-protector%> does not work "
+		"on this architecture");
       flag_stack_protect = 0;
     }
 
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index 072bbc628e2..8b31ee5b80c 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3069,10 +3069,25 @@ ix86_option_override_internal (bool main_args_p,
         = build_target_option_node (opts, opts_set);
     }
 
+  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
+  /* When -fhardened, enable -fcf-protection=full, but only when it's
+     compatible with this target, and when it wasn't already specified
+     on the command line.  */
+  if (opts->x_flag_hardened && cf_okay_p)
+    {
+      if (opts->x_flag_cf_protection == CF_NONE)
+	opts->x_flag_cf_protection = CF_FULL;
+      else if (opts->x_flag_cf_protection != CF_FULL)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fcf-protection=full%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (opts->x_flag_cf_protection != CF_NONE)
     {
       if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
-	  && !TARGET_64BIT && !TARGET_CMOV)
+	  && !cf_okay_p)
 	error ("%<-fcf-protection%> is not compatible with this target");
 
       opts->x_flag_cf_protection
diff --git a/gcc/configure b/gcc/configure
index 77f33ee4df6..00ffc82ced8 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -32883,7 +32883,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -33012,6 +33012,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
+$as_echo_n "checking linker -z now option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
+$as_echo "$ld_now_support" >&6; }
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
+$as_echo_n "checking linker -z relro option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
+$as_echo "$ld_relro_support" >&6; }
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 10982cdfc09..fd845308a24 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -7701,7 +7701,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -7802,6 +7802,46 @@ standards-compatible mode on s390 targets.])
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+AC_MSG_CHECKING(linker -z now option)
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
+  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z now])
+AC_MSG_RESULT($ld_now_support)
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+AC_MSG_CHECKING(linker -z relro option)
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
+  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z relro])
+AC_MSG_RESULT($ld_relro_support)
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5a9284d635c..e4237c28608 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-y2k  -Wframe-address
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
 -Wno-if-not-aligned  -Wno-ignored-attributes
--Wignored-qualifiers  -Wno-incompatible-pointer-types
+-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
 -Wno-implicit-function-declaration  -Wno-implicit-int
 -Winfinite-recursion
@@ -641,7 +641,7 @@ Objective-C and Objective-C++ Dialects}.
 -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
 -fsanitize-undefined-trap-on-error  -fbounds-check
 -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
--fharden-compares -fharden-conditional-branches
+-fharden-compares -fharden-conditional-branches  -fhardened
 -fharden-control-flow-redundancy  -fhardcfr-skip-leaf
 -fhardcfr-check-exceptions  -fhardcfr-check-returning-calls
 -fhardcfr-check-noreturn-calls=@r{[}always@r{|}no-xthrow@r{|}nothrow@r{|}never@r{]}
@@ -6860,6 +6860,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
 Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
 This warning is enabled by @option{-Wall}.
 
+@opindex Whardened
+@opindex Wno-hardened
+@item -Whardened
+Warn when @option{-fhardened} did not enable an option from its set (for
+which see @option{-fhardened}).  For instance, using @option{-fhardened}
+and @option{-fstack-protector} at the same time on the command line causes
+@option{-Whardened} to warn because @option{-fstack-protector-strong} is
+not enabled by @option{-fhardened}.
+
+This warning is enabled by default and has effect only when @option{-fhardened}
+is enabled.
+
 @opindex Wimplicit-fallthrough
 @opindex Wno-implicit-fallthrough
 @item -Wimplicit-fallthrough
@@ -17542,6 +17554,37 @@ made @option{no-xthrow} the default setting for this option: it excludes
 from the @code{noreturn} treatment only internal functions used to
 (re)raise exceptions, that are not affected by these optimizations.
 
+@opindex fhardened
+@item -fhardened
+Enable a set of flags for C and C++ that improve the security of the
+generated code without affecting its ABI.  The precise flags enabled
+may change between major releases of GCC, but are currently:
+
+@c Keep this in sync with print_help_hardened!
+@gccoptlist{
+-D_FORTIFY_SOURCE=3
+-D_GLIBCXX_ASSERTIONS
+-ftrivial-auto-var-init=zero
+-fPIE  -pie  -Wl,-z,relro,-z,now
+-fstack-protector-strong
+-fstack-clash-protection
+-fcf-protection=full @r{(x86 GNU/Linux only)}
+}
+
+The list of options enabled by @option{-fhardened} can be generated using
+the @option{--help=hardened} option.
+
+When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
+is used instead.
+
+This option is intended to be used in production builds, not merely
+in debug builds.
+
+@option{-fhardened} only enables a particular option if it wasn't
+already specified anywhere on the command line.  For instance,
+@option{-fhardened} @option{-fstack-protector} will only enable
+@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
+
 @opindex fstack-protector
 @item -fstack-protector
 Emit extra code to check for buffer overflows, such as stack smashing
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 884284e66b4..a7e5774dcfa 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
    driver added to dumpdir after dumpbase or linker output name.  */
 static bool dumpdir_trailing_dash_added = false;
 
+/* True if -r, -shared, -pie, or -no-pie were specified on the command
+   line.  */
+static bool any_link_options_p;
+
+/* True if -static was specified on the command line.  */
+static bool static_p;
+
 /* Basename of dump and aux outputs, computed from dumpbase (given or
    derived from output name), to override input_basename in non-%w %b
    et al.  */
@@ -4606,10 +4613,20 @@ driver_handle_option (struct gcc_options *opts,
       save_switch ("-o", 1, &arg, validated, true);
       return true;
 
-#ifdef ENABLE_DEFAULT_PIE
     case OPT_pie:
+#ifdef ENABLE_DEFAULT_PIE
       /* -pie is turned on by default.  */
+      validated = true;
 #endif
+    case OPT_r:
+    case OPT_shared:
+    case OPT_no_pie:
+      any_link_options_p = true;
+      break;
+
+    case OPT_static:
+      static_p = true;
+      break;
 
     case OPT_static_libgcc:
     case OPT_shared_libgcc:
@@ -4985,6 +5002,35 @@ process_command (unsigned int decoded_options_count,
 #endif
     }
 
+  /* TODO: check if -static -pie works and maybe use it.  */
+  if (flag_hardened)
+    {
+      if (!any_link_options_p && !static_p)
+	{
+#ifdef HAVE_LD_PIE
+	  save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
+#endif
+	  /* These are passed straight down to collect2 so we have to break
+	     it up like this.  */
+	  if (HAVE_LD_NOW_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("now", "*");
+	    }
+	  if (HAVE_LD_RELRO_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("relro", "*");
+	    }
+	}
+      /* We can't use OPT_Whardened yet.  Sigh.  */
+      else if (warn_hardened)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "linker hardening options not enabled by %<-fhardened%> "
+		    "because other link options were specified on the command "
+		    "line");
+    }
+
   /* Handle -gtoggle as it would later in toplev.cc:process_options to
      make the debug-level-gt spec function work as expected.  */
   if (flag_gtoggle)
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 573dcf8e497..c5fc065ce68 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
 /* Set by -fcanon-prefix-map.  */
 bool flag_canon_prefix_map;
 
+/* Set by finish_options when flag_stack_protector was set only because of
+   -fhardened.  Yuck.  */
+bool flag_stack_protector_set_by_fhardened_p;
+
 static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
 /* Names of fundamental debug info formats indexed by enum
@@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       opts->x_flag_section_anchors = 0;
     }
 
+  if (opts->x_flag_hardened)
+    {
+      if (!opts_set->x_flag_auto_var_init)
+	opts->x_flag_auto_var_init = AUTO_INIT_ZERO;
+      else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO)
+	warning_at (loc, OPT_Whardened,
+		    "%<-ftrivial-auto-var-init=zero%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (!opts->x_flag_opts_finished)
     {
       /* We initialize opts->x_flag_pie to -1 so that targets can set a
@@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	  /* We initialize opts->x_flag_pic to -1 so that we can tell if
 	     -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
 	  if (opts->x_flag_pic == -1)
-	    opts->x_flag_pie = DEFAULT_FLAG_PIE;
+	    opts->x_flag_pie = (opts->x_flag_hardened
+				? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
 	  else
 	    opts->x_flag_pie = 0;
 	}
@@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
     }
 
   /* We initialize opts->x_flag_stack_protect to -1 so that targets
-     can set a default value.  */
+     can set a default value.  With --enable-default-ssp or -fhardened
+     the default is -fstack-protector-strong.  */
   if (opts->x_flag_stack_protect == -1)
-    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    {
+      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
+	 defined in such a way that it uses flag_stack_protect which can't
+	 be used here.  Moreover, some targets like BPF don't support
+	 -fstack-protector at all but we don't know that here.  So remember
+	 that flag_stack_protect was set at the behest of -fhardened.  */
+      if (opts->x_flag_hardened)
+	{
+	  opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
+	  flag_stack_protector_set_by_fhardened_p = true;
+	}
+      else
+	opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    }
+  else if (opts->x_flag_hardened
+	   && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
+    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		"%<-fstack-protector-strong%> is not enabled by "
+		"%<-fhardened%> because it was specified on the command "
+		"line");
 
   if (opts->x_optimize == 0)
     {
@@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
   free (patch_area_arg);
 }
 
+/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
+
+static void
+print_help_hardened ()
+{
+  printf ("%s\n", "The following options are enabled by -fhardened:");
+  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
+	  (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
+  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
+  printf ("  %s\n", "-ftrivial-auto-var-init=zero");
+#ifdef HAVE_LD_PIE
+  printf ("  %s  %s\n", "-fPIE", "-pie");
+#endif
+  if (HAVE_LD_NOW_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,now");
+  if (HAVE_LD_RELRO_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,relro");
+  printf ("  %s\n", "-fstack-protector-strong");
+  printf ("  %s\n", "-fstack-clash-protection");
+  printf ("  %s\n", "-fcf-protection=full");
+  putchar ('\n');
+}
+
 /* Print help when OPT__help_ is set.  */
 
 void
@@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
 	}
       else if (lang_flag != 0)
 	*pflags |= lang_flag;
+      else if (strncasecmp (a, "hardened", len) == 0)
+	print_help_hardened ();
       else
 	warning (0,
 		 "unrecognized argument to %<--help=%> option: %q.*s",
diff --git a/gcc/opts.h b/gcc/opts.h
index 00f377f9ca7..d89c5de8114 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -344,6 +344,7 @@ struct cl_option_handlers
 /* Hold command-line options associated with stack limitation.  */
 extern const char *opt_fstack_limit_symbol_arg;
 extern int opt_fstack_limit_register_no;
+extern bool flag_stack_protector_set_by_fhardened_p;
 
 /* Input file names.  */
 
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
new file mode 100644
index 00000000000..4dd22cdfe45
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.S
@@ -0,0 +1,6 @@
+/* { dg-do preprocess { target pie } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
new file mode 100644
index 00000000000..dd3cde93805
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O" } */
+
+#ifndef __SSP_STRONG__
+# error "-fstack-protector-strong not enabled"
+#endif
+
+#if _FORTIFY_SOURCE < 2
+# error "_FORTIFY_SOURCE not enabled"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
new file mode 100644
index 00000000000..8242530bc4d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-10.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
+
+#if _FORTIFY_SOURCE != 1
+# error "_FORTIFY_SOURCE != 1"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
new file mode 100644
index 00000000000..b8fd65a960c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-11.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
+
+#ifndef _FORTIFY_SOURCE
+# error "_FORTIFY_SOURCE disabled when it should not be"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
new file mode 100644
index 00000000000..42594e4c0e0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-12.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
new file mode 100644
index 00000000000..6945a6391a9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-13.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
new file mode 100644
index 00000000000..652ece3d4c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-14.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fno-PIE" } */
+
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
new file mode 100644
index 00000000000..c6202754bf5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-15.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-require-stack-check "specific" } */
+/* { dg-options "-fhardened -O -fstack-check" } */
+
+/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
new file mode 100644
index 00000000000..283867ca806
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -fstack-protector" } */
+
+#ifdef __SSP_STRONG__
+# error "-fstack-protector-strong enabled when it should not be"
+#endif
+#ifndef __SSP__
+# error "-fstack-protector not enabled"
+#endif
+
+/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
new file mode 100644
index 00000000000..6924ba242f0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O0" } */
+/* Test that we don't get any diagnostic coming from libc headers.  */
+
+#include <stdio.h>
+
+/* The most useful C program known to man.  */
+
+int
+main ()
+{
+}
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
new file mode 100644
index 00000000000..7d44d299f19
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-4.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O0 -Wno-hardened" } */
+
+/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
new file mode 100644
index 00000000000..42594e4c0e0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
new file mode 100644
index 00000000000..744384f317f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
+/* { dg-warning ".-ftrivial-auto-var-init=zero. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
new file mode 100644
index 00000000000..32f35eb2595
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-7.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fpie" } */
+
+/* -fpie takes precedence over -fhardened */
+#if __PIE__ != 1
+# error "__PIE__ != 1"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
new file mode 100644
index 00000000000..5b3162b4d1f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-8.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fPIC" } */
+
+/* -fPIC takes precedence over -fhardened */
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
new file mode 100644
index 00000000000..d3b9e79b9b6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-9.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
+
+#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
+# error "hardening enabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
index 52b9cb0ab90..15d618a2528 100644
--- a/gcc/testsuite/gcc.misc-tests/help.exp
+++ b/gcc/testsuite/gcc.misc-tests/help.exp
@@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
 # Listing only excludes gives empty results.
 check_for_options c "--help=^joined,^separate" "" "" ""
 
+check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
+
 if [ info exists prev_columns ] {
     # Reset the enviroment variable to its oriuginal value.
     set env(COLUMNS) $prev_columns
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
new file mode 100644
index 00000000000..73b78dce889
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+/* Test that -fhardened enables CET.  */
+
+extern void bar (void) __attribute__((__cf_check__));
+
+void
+foo (void)
+{
+  bar ();
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 8af9bf5090e..743a3a91684 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1575,6 +1575,19 @@ process_options (bool no_backend)
 		  "where the stack grows from lower to higher addresses");
       flag_stack_clash_protection = 0;
     }
+  else if (flag_hardened)
+    {
+      if (!flag_stack_clash_protection
+	   /* Don't enable -fstack-clash-protection when -fstack-check=
+	      is used: it would result in confusing errors.  */
+	   && flag_stack_check == NO_STACK_CHECK)
+	flag_stack_clash_protection = 1;
+      else if (flag_stack_check != NO_STACK_CHECK)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fstack-clash-protection%> is not enabled by "
+		    "%<-fhardened%> because %<-fstack-check%> was "
+		    "specified on the command line");
+    }
 
   /* We cannot support -fstack-check= and -fstack-clash-protection at
      the same time.  */
@@ -1590,8 +1603,9 @@ process_options (bool no_backend)
      target already uses a soft frame pointer, the transition is trivial.  */
   if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
     {
-      warning_at (UNKNOWN_LOCATION, 0,
-		  "%<-fstack-protector%> not supported for this target");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "%<-fstack-protector%> not supported for this target");
       flag_stack_protect = 0;
     }
   if (!flag_stack_protect)

base-commit: 32b74c9e1d46932a4bbb1f46353bfc43c702c20a
-- 
2.41.0


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] gcc: Introduce -fhardened
  2023-10-23 19:25         ` [PATCH v3] " Marek Polacek
@ 2023-10-24  7:22           ` Richard Biener
  2023-10-24 19:09             ` Marek Polacek
  2023-10-24  7:44           ` [PATCH v3] " Iain Sandoe
  1 sibling, 1 reply; 28+ messages in thread
From: Richard Biener @ 2023-10-24  7:22 UTC (permalink / raw)
  To: Marek Polacek; +Cc: iain, GCC Patches

On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
>
> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> > On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
> > >
> > > On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> > > > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> > > > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > >
> > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > > > > > and aarch64-unknown-linux-gnu; ok for trunk?
> > > > > >
> > > > > > -- >8 --
> > > > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > > > > of hardening flags.  The read of the room seems to be that the option
> > > > > > would be useful.  So here's a patch implementing that option.
> > > > > >
> > > > > > Currently, -fhardened enables:
> > > > > >
> > > > > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > > > > >   -D_GLIBCXX_ASSERTIONS
> > > > > >   -ftrivial-auto-var-init=pattern
> >
> > I think =zero is much better here given the overhead is way
> > cheaper and pointers get a more reliable behavior.
>
> Ok, changed now.
>
> > > > > >   -fPIE  -pie  -Wl,-z,relro,-z,now
> > > > > >   -fstack-protector-strong
> > > > > >   -fstack-clash-protection
> > > > > >   -fcf-protection=full (x86 GNU/Linux only)
> > > > > >
> > > > > > -fhardened will not override options that were specified on the command line
> > > > > > (before or after -fhardened).  For example,
> > > > > >
> > > > > >      -D_FORTIFY_SOURCE=1 -fhardened
> > > > > >
> > > > > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> > > > > >
> > > > > >       -fhardened -fstack-protector
> > > > > >
> > > > > > will not enable -fstack-protector-strong.
> > > > > >
> > > > > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > > > > to anything.  I think we need a better way to show what it actually
> > > > > > enables.
> > > > >
> > > > > I do think we need to find a solution here to solve asserting compliance.
> > > >
> > > > Fair enough.
> > > >
> > > > > Maybe we can have -Whardened that will diagnose any altering of
> > > > > -fhardened by other options on the command-line or by missed target
> > > > > implementations?  People might for example use -fstack-protector
> > > > > but don't really want to make protection lower than requested with -fhardened.
> > > > >
> > > > > Any such conflict is much less appearant than when you use the
> > > > > flags -fhardened composes.
> > > >
> > > > How about: --help=hardened says which options -fhardened attempts to
> > > > enable, and -Whardened warns when it didn't enable an option?  E.g.,
> > > >
> > > >   -fstack-protector -fhardened -Whardened
> > > >
> > > > would say that it didn't enable -fstack-protector-strong because
> > > > -fstack-protector was specified on the command line?
> > > >
> > > > If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
> > > > list -z now, likewise for -z relro.
> > > >
> > > > Unclear if -Whardened should be enabled by default, but probably yes?
> > >
> > > Here's v2 which adds -Whardened (enabled by default).
> > >
> > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> >
> > I think it's OK but I'd like to see a second ACK here.
>
> Thanks!
>
> > Can you see how our
> > primary and secondary targets (+ host OS) behave here?
>
> That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
> that fails with:
>
> ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
> ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
> make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
> make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
>
> and I tried Darwin (104) and that fails with
>
> *** Configuration aarch64-apple-darwin21.6.0 not supported
>
> Is anyone else able to build gcc on those machines, or test the attached
> patch?
>
> > I think the
> > documentation should elaborate a bit on expectations for non-Linux/GNU
> > targets, specifically I think the default configuration for a target should
> > with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> > have a testcase for this?
>
> Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
> something not supported on those systems, and it's something for which
> we have a configure test, then we shouldn't warn.  This is already the
> case for -pie, -z relro, and -z now.

I was thinking of

/* { dg-do compile } */
/* { dg-additional-options "-fhardened -Whardened" } */

int main () {}

and excess errors should catch "misconfigurations"?

> Should the docs say something like the following for features without
> configure checks?
>
> @option{-fhardened} can, on certain systems, attempt to enable features
> not supported on that particular system.  In that case, it's possible to
> prevent the warning using the @option{-Wno-hardened} option.

Yeah, but ideally

@option{-fhardened} can, on certain systems, not enable features not
available on those systems and @option{-Whardened} will not diagnose
those as missing.

But I understand it doesn't work like that?

> I've added a line saying:
>
> +This option is intended to be used in production builds, not merely
> +in debug builds.
>
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags.  The read of the room seems to be that the option
> would be useful.  So here's a patch implementing that option.
>
> Currently, -fhardened enables:
>
>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>   -D_GLIBCXX_ASSERTIONS
>   -ftrivial-auto-var-init=zero
>   -fPIE  -pie  -Wl,-z,relro,-z,now
>   -fstack-protector-strong
>   -fstack-clash-protection
>   -fcf-protection=full (x86 GNU/Linux only)
>
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened).  For example,
>
>      -D_FORTIFY_SOURCE=1 -fhardened
>
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>
>       -fhardened -fstack-protector
>
> will not enable -fstack-protector-strong.
>
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything.  This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option.  I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
>
> gcc/c-family/ChangeLog:
>
>         * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
>         and _GLIBCXX_ASSERTIONS.
>
> gcc/ChangeLog:
>
>         * common.opt (Whardened, fhardened): New options.
>         * config.in: Regenerate.
>         * config/bpf/bpf.cc: Include "opts.h".
>         (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
>         not inform that -fstack-protector does not work.
>         * config/i386/i386-options.cc (ix86_option_override_internal): When
>         -fhardened, maybe enable -fcf-protection=full.
>         * configure: Regenerate.
>         * configure.ac: Check if the linker supports '-z now' and '-z relro'.
>         * doc/invoke.texi: Document -fhardened and -Whardened.
>         * gcc.cc (driver_handle_option): Remember if any link options or -static
>         were specified on the command line.
>         (process_command): When -fhardened, maybe enable -pie and
>         -Wl,-z,relro,-z,now.
>         * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
>         (finish_options): When -fhardened, enable
>         -ftrivial-auto-var-init=zero and -fstack-protector-strong.
>         (print_help_hardened): New.
>         (print_help): Call it.
>         * toplev.cc (process_options): When -fhardened, enable
>         -fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
>         do not warn that -fstack-protector not supported for this target.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.misc-tests/help.exp: Test -fhardened.
>         * c-c++-common/fhardened-1.S: New test.
>         * c-c++-common/fhardened-1.c: New test.
>         * c-c++-common/fhardened-10.c: New test.
>         * c-c++-common/fhardened-11.c: New test.
>         * c-c++-common/fhardened-12.c: New test.
>         * c-c++-common/fhardened-13.c: New test.
>         * c-c++-common/fhardened-14.c: New test.
>         * c-c++-common/fhardened-15.c: New test.
>         * c-c++-common/fhardened-2.c: New test.
>         * c-c++-common/fhardened-3.c: New test.
>         * c-c++-common/fhardened-4.c: New test.
>         * c-c++-common/fhardened-5.c: New test.
>         * c-c++-common/fhardened-6.c: New test.
>         * c-c++-common/fhardened-7.c: New test.
>         * c-c++-common/fhardened-8.c: New test.
>         * c-c++-common/fhardened-9.c: New test.
>         * gcc.target/i386/cf_check-6.c: New test.
> ---
>  gcc/c-family/c-opts.cc                     | 42 ++++++++++++++
>  gcc/common.opt                             |  8 +++
>  gcc/config.in                              | 12 ++++
>  gcc/config/bpf/bpf.cc                      |  8 ++-
>  gcc/config/i386/i386-options.cc            | 17 +++++-
>  gcc/configure                              | 50 +++++++++++++++-
>  gcc/configure.ac                           | 42 +++++++++++++-
>  gcc/doc/invoke.texi                        | 47 ++++++++++++++-
>  gcc/gcc.cc                                 | 48 +++++++++++++++-
>  gcc/opts.cc                                | 67 +++++++++++++++++++++-
>  gcc/opts.h                                 |  1 +
>  gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
>  gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
>  gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
>  gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
>  gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
>  gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
>  gcc/toplev.cc                              | 18 +++++-
>  30 files changed, 506 insertions(+), 14 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index ce2e021e69d..f5f6ba24290 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1556,6 +1556,9 @@ c_finish_options (void)
>        cb_file_change (parse_in, cmd_map);
>        linemap_line_start (line_table, 0, 1);
>
> +      bool fortify_seen_p = false;
> +      bool cxx_assert_seen_p = false;
> +
>        /* All command line defines must have the same location.  */
>        cpp_force_token_locations (parse_in, line_table->highest_line);
>        for (size_t i = 0; i < deferred_count; i++)
> @@ -1573,6 +1576,45 @@ c_finish_options (void)
>               else
>                 cpp_assert (parse_in, opt->arg);
>             }
> +
> +         if (UNLIKELY (flag_hardened)
> +             && (opt->code == OPT_D || opt->code == OPT_U))
> +           {
> +             if (!fortify_seen_p)
> +               fortify_seen_p
> +                 = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> +                    && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> +             if (!cxx_assert_seen_p)
> +               cxx_assert_seen_p
> +                 = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> +                    && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> +           }
> +       }
> +
> +      if (flag_hardened)
> +       {
> +         if (!fortify_seen_p && optimize > 0)
> +           {
> +             if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> +             else
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> +           }
> +         else if (optimize == 0)
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +                       "because optimizations are turned off");
> +         else
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +                       "because it was specified in %<-D%> or %<-U%>");
> +         if (!cxx_assert_seen_p)
> +           cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
> +         else
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
> +                       "%<-fhardened%> because it was specified in %<-D%> "
> +                       "or %<-U%>");
>         }
>
>        cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 1cf3bdd3b51..48a15f077ef 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -634,6 +634,10 @@ Wfree-nonheap-object
>  Common Var(warn_free_nonheap_object) Init(1) Warning
>  Warn when attempting to free a non-heap object.
>
> +Whardened
> +Common Var(warn_hardened) Init(1) Warning
> +Warn when -fhardened did not enable an option from its set.
> +
>  Whsa
>  Common Ignore Warning
>  Does nothing.  Preserved for backward compatibility.
> @@ -1823,6 +1827,10 @@ fguess-branch-probability
>  Common Var(flag_guess_branch_prob) Optimization
>  Enable guessing of branch probabilities.
>
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
>  fharden-compares
>  Common Var(flag_harden_compares) Optimization
>  Harden conditionals not used in branches, checking reversed conditions.
> diff --git a/gcc/config.in b/gcc/config.in
> index 03faee1c6ac..327b1e3e2ee 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1695,6 +1695,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
>  /* Define if your PowerPC64 linker only needs function descriptor syms. */
>  #ifndef USED_FOR_TARGET
>  #undef HAVE_LD_NO_DOT_SYMS
> @@ -1738,6 +1744,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
>  /* Define if your linker links a mix of read-only and read-write sections into
>     a read-write section. */
>  #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 437bd652de3..41dc7fd3dae 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimplify-me.h"
>
>  #include "core-builtins.h"
> +#include "opts.h"
>
>  /* Per-function machine data.  */
>  struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
>    /* Disable -fstack-protector as it is not supported in BPF.  */
>    if (flag_stack_protect)
>      {
> -      inform (input_location,
> -              "%<-fstack-protector%> does not work "
> -             "on this architecture");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       inform (input_location,
> +               "%<-fstack-protector%> does not work "
> +               "on this architecture");
>        flag_stack_protect = 0;
>      }
>
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index 072bbc628e2..8b31ee5b80c 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3069,10 +3069,25 @@ ix86_option_override_internal (bool main_args_p,
>          = build_target_option_node (opts, opts_set);
>      }
>
> +  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> +  /* When -fhardened, enable -fcf-protection=full, but only when it's
> +     compatible with this target, and when it wasn't already specified
> +     on the command line.  */
> +  if (opts->x_flag_hardened && cf_okay_p)
> +    {
> +      if (opts->x_flag_cf_protection == CF_NONE)
> +       opts->x_flag_cf_protection = CF_FULL;
> +      else if (opts->x_flag_cf_protection != CF_FULL)
> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                   "%<-fcf-protection=full%> is not enabled by "
> +                   "%<-fhardened%> because it was specified on the command "
> +                   "line");
> +    }
> +
>    if (opts->x_flag_cf_protection != CF_NONE)
>      {
>        if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> -         && !TARGET_64BIT && !TARGET_CMOV)
> +         && !cf_okay_p)
>         error ("%<-fcf-protection%> is not compatible with this target");
>
>        opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index 77f33ee4df6..00ffc82ced8 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -32883,7 +32883,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -33012,6 +33012,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index 10982cdfc09..fd845308a24 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7701,7 +7701,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -7802,6 +7802,46 @@ standards-compatible mode on s390 targets.])
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> +  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> +  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 5a9284d635c..e4237c28608 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wformat-y2k  -Wframe-address
>  -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
>  -Wno-if-not-aligned  -Wno-ignored-attributes
> --Wignored-qualifiers  -Wno-incompatible-pointer-types
> +-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
>  -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
>  -Wno-implicit-function-declaration  -Wno-implicit-int
>  -Winfinite-recursion
> @@ -641,7 +641,7 @@ Objective-C and Objective-C++ Dialects}.
>  -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
>  -fsanitize-undefined-trap-on-error  -fbounds-check
>  -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches  -fhardened
>  -fharden-control-flow-redundancy  -fhardcfr-skip-leaf
>  -fhardcfr-check-exceptions  -fhardcfr-check-returning-calls
>  -fhardcfr-check-noreturn-calls=@r{[}always@r{|}no-xthrow@r{|}nothrow@r{|}never@r{]}
> @@ -6860,6 +6860,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
>  Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
>  This warning is enabled by @option{-Wall}.
>
> +@opindex Whardened
> +@opindex Wno-hardened
> +@item -Whardened
> +Warn when @option{-fhardened} did not enable an option from its set (for
> +which see @option{-fhardened}).  For instance, using @option{-fhardened}
> +and @option{-fstack-protector} at the same time on the command line causes
> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
> +not enabled by @option{-fhardened}.
> +
> +This warning is enabled by default and has effect only when @option{-fhardened}
> +is enabled.
> +
>  @opindex Wimplicit-fallthrough
>  @opindex Wno-implicit-fallthrough
>  @item -Wimplicit-fallthrough
> @@ -17542,6 +17554,37 @@ made @option{no-xthrow} the default setting for this option: it excludes
>  from the @code{noreturn} treatment only internal functions used to
>  (re)raise exceptions, that are not affected by these optimizations.
>
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI.  The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@c Keep this in sync with print_help_hardened!
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=zero
> +-fPIE  -pie  -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +This option is intended to be used in production builds, not merely
> +in debug builds.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line.  For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
>  @opindex fstack-protector
>  @item -fstack-protector
>  Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index 884284e66b4..a7e5774dcfa 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>     driver added to dumpdir after dumpbase or linker output name.  */
>  static bool dumpdir_trailing_dash_added = false;
>
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> +   line.  */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line.  */
> +static bool static_p;
> +
>  /* Basename of dump and aux outputs, computed from dumpbase (given or
>     derived from output name), to override input_basename in non-%w %b
>     et al.  */
> @@ -4606,10 +4613,20 @@ driver_handle_option (struct gcc_options *opts,
>        save_switch ("-o", 1, &arg, validated, true);
>        return true;
>
> -#ifdef ENABLE_DEFAULT_PIE
>      case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
>        /* -pie is turned on by default.  */
> +      validated = true;
>  #endif
> +    case OPT_r:
> +    case OPT_shared:
> +    case OPT_no_pie:
> +      any_link_options_p = true;
> +      break;
> +
> +    case OPT_static:
> +      static_p = true;
> +      break;
>
>      case OPT_static_libgcc:
>      case OPT_shared_libgcc:
> @@ -4985,6 +5002,35 @@ process_command (unsigned int decoded_options_count,
>  #endif
>      }
>
> +  /* TODO: check if -static -pie works and maybe use it.  */
> +  if (flag_hardened)
> +    {
> +      if (!any_link_options_p && !static_p)
> +       {
> +#ifdef HAVE_LD_PIE
> +         save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> +         /* These are passed straight down to collect2 so we have to break
> +            it up like this.  */
> +         if (HAVE_LD_NOW_SUPPORT)
> +           {
> +             add_infile ("-z", "*");
> +             add_infile ("now", "*");
> +           }
> +         if (HAVE_LD_RELRO_SUPPORT)
> +           {
> +             add_infile ("-z", "*");
> +             add_infile ("relro", "*");
> +           }
> +       }
> +      /* We can't use OPT_Whardened yet.  Sigh.  */
> +      else if (warn_hardened)
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "linker hardening options not enabled by %<-fhardened%> "
> +                   "because other link options were specified on the command "
> +                   "line");
> +    }
> +
>    /* Handle -gtoggle as it would later in toplev.cc:process_options to
>       make the debug-level-gt spec function work as expected.  */
>    if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 573dcf8e497..c5fc065ce68 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
>  /* Set by -fcanon-prefix-map.  */
>  bool flag_canon_prefix_map;
>
> +/* Set by finish_options when flag_stack_protector was set only because of
> +   -fhardened.  Yuck.  */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
>  static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>
>  /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>        opts->x_flag_section_anchors = 0;
>      }
>
> +  if (opts->x_flag_hardened)
> +    {
> +      if (!opts_set->x_flag_auto_var_init)
> +       opts->x_flag_auto_var_init = AUTO_INIT_ZERO;
> +      else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO)
> +       warning_at (loc, OPT_Whardened,
> +                   "%<-ftrivial-auto-var-init=zero%> is not enabled by "
> +                   "%<-fhardened%> because it was specified on the command "
> +                   "line");
> +    }
> +
>    if (!opts->x_flag_opts_finished)
>      {
>        /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>           /* We initialize opts->x_flag_pic to -1 so that we can tell if
>              -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
>           if (opts->x_flag_pic == -1)
> -           opts->x_flag_pie = DEFAULT_FLAG_PIE;
> +           opts->x_flag_pie = (opts->x_flag_hardened
> +                               ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
>           else
>             opts->x_flag_pie = 0;
>         }
> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>      }
>
>    /* We initialize opts->x_flag_stack_protect to -1 so that targets
> -     can set a default value.  */
> +     can set a default value.  With --enable-default-ssp or -fhardened
> +     the default is -fstack-protector-strong.  */
>    if (opts->x_flag_stack_protect == -1)
> -    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    {
> +      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> +        defined in such a way that it uses flag_stack_protect which can't
> +        be used here.  Moreover, some targets like BPF don't support
> +        -fstack-protector at all but we don't know that here.  So remember
> +        that flag_stack_protect was set at the behest of -fhardened.  */
> +      if (opts->x_flag_hardened)
> +       {
> +         opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> +         flag_stack_protector_set_by_fhardened_p = true;
> +       }
> +      else
> +       opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    }
> +  else if (opts->x_flag_hardened
> +          && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
> +    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +               "%<-fstack-protector-strong%> is not enabled by "
> +               "%<-fhardened%> because it was specified on the command "
> +               "line");
>
>    if (opts->x_optimize == 0)
>      {
> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>    free (patch_area_arg);
>  }
>
> +/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
> +
> +static void
> +print_help_hardened ()
> +{
> +  printf ("%s\n", "The following options are enabled by -fhardened:");
> +  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
> +         (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> +  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
> +  printf ("  %s\n", "-ftrivial-auto-var-init=zero");
> +#ifdef HAVE_LD_PIE
> +  printf ("  %s  %s\n", "-fPIE", "-pie");
> +#endif
> +  if (HAVE_LD_NOW_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,now");
> +  if (HAVE_LD_RELRO_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,relro");
> +  printf ("  %s\n", "-fstack-protector-strong");
> +  printf ("  %s\n", "-fstack-clash-protection");
> +  printf ("  %s\n", "-fcf-protection=full");
> +  putchar ('\n');
> +}
> +
>  /* Print help when OPT__help_ is set.  */
>
>  void
> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
>         }
>        else if (lang_flag != 0)
>         *pflags |= lang_flag;
> +      else if (strncasecmp (a, "hardened", len) == 0)
> +       print_help_hardened ();
>        else
>         warning (0,
>                  "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
>  /* Hold command-line options associated with stack limitation.  */
>  extern const char *opt_fstack_limit_symbol_arg;
>  extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
>
>  /* Input file names.  */
>
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..4dd22cdfe45
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..dd3cde93805
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..8242530bc4d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..b8fd65a960c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..6945a6391a9
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..652ece3d4c4
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
> new file mode 100644
> index 00000000000..c6202754bf5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile } */
> +/* { dg-require-stack-check "specific" } */
> +/* { dg-options "-fhardened -O -fstack-check" } */
> +
> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..283867ca806
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> +
> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..6924ba242f0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers.  */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man.  */
> +
> +int
> +main ()
> +{
> +}
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
> new file mode 100644
> index 00000000000..7d44d299f19
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
> +
> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..744384f317f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> +/* { dg-warning ".-ftrivial-auto-var-init=zero. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..32f35eb2595
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..5b3162b4d1f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..d3b9e79b9b6
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
>  # Listing only excludes gives empty results.
>  check_for_options c "--help=^joined,^separate" "" "" ""
>
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
>  if [ info exists prev_columns ] {
>      # Reset the enviroment variable to its oriuginal value.
>      set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET.  */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> +  bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index 8af9bf5090e..743a3a91684 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1575,6 +1575,19 @@ process_options (bool no_backend)
>                   "where the stack grows from lower to higher addresses");
>        flag_stack_clash_protection = 0;
>      }
> +  else if (flag_hardened)
> +    {
> +      if (!flag_stack_clash_protection
> +          /* Don't enable -fstack-clash-protection when -fstack-check=
> +             is used: it would result in confusing errors.  */
> +          && flag_stack_check == NO_STACK_CHECK)
> +       flag_stack_clash_protection = 1;
> +      else if (flag_stack_check != NO_STACK_CHECK)
> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                   "%<-fstack-clash-protection%> is not enabled by "
> +                   "%<-fhardened%> because %<-fstack-check%> was "
> +                   "specified on the command line");
> +    }
>
>    /* We cannot support -fstack-check= and -fstack-clash-protection at
>       the same time.  */
> @@ -1590,8 +1603,9 @@ process_options (bool no_backend)
>       target already uses a soft frame pointer, the transition is trivial.  */
>    if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>      {
> -      warning_at (UNKNOWN_LOCATION, 0,
> -                 "%<-fstack-protector%> not supported for this target");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "%<-fstack-protector%> not supported for this target");
>        flag_stack_protect = 0;
>      }
>    if (!flag_stack_protect)
>
> base-commit: 32b74c9e1d46932a4bbb1f46353bfc43c702c20a
> --
> 2.41.0
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] gcc: Introduce -fhardened
  2023-10-23 19:25         ` [PATCH v3] " Marek Polacek
  2023-10-24  7:22           ` Richard Biener
@ 2023-10-24  7:44           ` Iain Sandoe
  2023-10-24  9:34             ` Iain Sandoe
  1 sibling, 1 reply; 28+ messages in thread
From: Iain Sandoe @ 2023-10-24  7:44 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, GCC Patches

Hi Marek,

> On 23 Oct 2023, at 20:25, Marek Polacek <polacek@redhat.com> wrote:
> 
> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
>> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>>> 
>>> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>>>> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>>>>> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>>>>> <gcc-patches@gcc.gnu.org> wrote:
> 

> and I tried Darwin (104) and that fails with
> 
> *** Configuration aarch64-apple-darwin21.6.0 not supported
> 
> Is anyone else able to build gcc on those machines, or test the attached
> patch?

We’re still working on upstreaming the aarch64 Darwin port - the devt. branch
is here; https://github.com/iains/gcc-darwin-arm64 (but it will be rebased soon
because we just upstreamed some dependencies).

In the meantime, I will put your patch into my test queue - hopefully before
next week.

Iain


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] gcc: Introduce -fhardened
  2023-10-24  7:44           ` [PATCH v3] " Iain Sandoe
@ 2023-10-24  9:34             ` Iain Sandoe
  2023-10-24 19:03               ` Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Iain Sandoe @ 2023-10-24  9:34 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, GCC Patches

hi Marek,

> On 24 Oct 2023, at 08:44, Iain Sandoe <iain@sandoe.co.uk> wrote:
> On 23 Oct 2023, at 20:25, Marek Polacek <polacek@redhat.com> wrote:
>> 
>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
>>> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>>>> 
>>>> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>>>>> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>>>>>> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>> 
> 
>> and I tried Darwin (104) and that fails with
>> 
>> *** Configuration aarch64-apple-darwin21.6.0 not supported
>> 
>> Is anyone else able to build gcc on those machines, or test the attached
>> patch?
> 
> We’re still working on upstreaming the aarch64 Darwin port - the devt. branch
> is here; https://github.com/iains/gcc-darwin-arm64 (but it will be rebased soon
> because we just upstreamed some dependencies).
> 
> In the meantime, I will put your patch into my test queue - hopefully before
> next week.

actually, I rebased already .. (but not pushed yet, pending testing).

aarch64-darwin21 bootstrapped fine with your patch (as did x86_64-darwin19)

===

$ /opt/iains/aarch64-apple-darwin21/gcc-14-0-0/bin/gcc /source/test/hello.c -o hc -fhardened -Whardened
cc1: warning: ‘_FORTIFY_SOURCE’ is not enabled by ‘-fhardened’ because optimizations are turned off [-Whardened]

$ /opt/iains/aarch64-apple-darwin21/gcc-14-0-0/bin/gcc /source/test/hello.c -o hc -fhardened -Whardened -O
<no output>

I’m about to run the testsuite, but if there’s something else to be tested please let me know (NOTE: I have not read the patch, just applied it and built).

thanks,
Iain


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] gcc: Introduce -fhardened
  2023-10-24  9:34             ` Iain Sandoe
@ 2023-10-24 19:03               ` Marek Polacek
  2023-10-24 19:16                 ` Iain Sandoe
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2023-10-24 19:03 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: Richard Biener, GCC Patches

On Tue, Oct 24, 2023 at 10:34:22AM +0100, Iain Sandoe wrote:
> hi Marek,
> 
> > On 24 Oct 2023, at 08:44, Iain Sandoe <iain@sandoe.co.uk> wrote:
> > On 23 Oct 2023, at 20:25, Marek Polacek <polacek@redhat.com> wrote:
> >> 
> >> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> >>> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
> >>>> 
> >>>> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> >>>>> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> >>>>>> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> >>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >> 
> > 
> >> and I tried Darwin (104) and that fails with
> >> 
> >> *** Configuration aarch64-apple-darwin21.6.0 not supported
> >> 
> >> Is anyone else able to build gcc on those machines, or test the attached
> >> patch?
> > 
> > We’re still working on upstreaming the aarch64 Darwin port - the devt. branch
> > is here; https://github.com/iains/gcc-darwin-arm64 (but it will be rebased soon
> > because we just upstreamed some dependencies).
> > 
> > In the meantime, I will put your patch into my test queue - hopefully before
> > next week.
> 
> actually, I rebased already .. (but not pushed yet, pending testing).
> 
> aarch64-darwin21 bootstrapped fine with your patch (as did x86_64-darwin19)

Thank you so much Iain!
 
> ===
> 
> $ /opt/iains/aarch64-apple-darwin21/gcc-14-0-0/bin/gcc /source/test/hello.c -o hc -fhardened -Whardened
> cc1: warning: ‘_FORTIFY_SOURCE’ is not enabled by ‘-fhardened’ because optimizations are turned off [-Whardened]
> 
> $ /opt/iains/aarch64-apple-darwin21/gcc-14-0-0/bin/gcc /source/test/hello.c -o hc -fhardened -Whardened -O
> <no output>

That looks correct.
 
> I’m about to run the testsuite, but if there’s something else to be tested please let me know (NOTE: I have not read the patch, just applied it and built).

I am mostly curious about the fhardened* tests, if they all pass.

Thanks,
Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] gcc: Introduce -fhardened
  2023-10-24  7:22           ` Richard Biener
@ 2023-10-24 19:09             ` Marek Polacek
  2023-10-26 15:55               ` Richard Biener
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2023-10-24 19:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: iain, GCC Patches

On Tue, Oct 24, 2023 at 09:22:25AM +0200, Richard Biener wrote:
> On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
> >
> > On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> > > On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
> > > >
> > > > On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> > > > > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> > > > > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > >
> > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > > > > > > and aarch64-unknown-linux-gnu; ok for trunk?
> > > > > > >
> > > > > > > -- >8 --
> > > > > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > > > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > > > > > of hardening flags.  The read of the room seems to be that the option
> > > > > > > would be useful.  So here's a patch implementing that option.
> > > > > > >
> > > > > > > Currently, -fhardened enables:
> > > > > > >
> > > > > > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > > > > > >   -D_GLIBCXX_ASSERTIONS
> > > > > > >   -ftrivial-auto-var-init=pattern
> > >
> > > I think =zero is much better here given the overhead is way
> > > cheaper and pointers get a more reliable behavior.
> >
> > Ok, changed now.
> >
> > > > > > >   -fPIE  -pie  -Wl,-z,relro,-z,now
> > > > > > >   -fstack-protector-strong
> > > > > > >   -fstack-clash-protection
> > > > > > >   -fcf-protection=full (x86 GNU/Linux only)
> > > > > > >
> > > > > > > -fhardened will not override options that were specified on the command line
> > > > > > > (before or after -fhardened).  For example,
> > > > > > >
> > > > > > >      -D_FORTIFY_SOURCE=1 -fhardened
> > > > > > >
> > > > > > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> > > > > > >
> > > > > > >       -fhardened -fstack-protector
> > > > > > >
> > > > > > > will not enable -fstack-protector-strong.
> > > > > > >
> > > > > > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > > > > > to anything.  I think we need a better way to show what it actually
> > > > > > > enables.
> > > > > >
> > > > > > I do think we need to find a solution here to solve asserting compliance.
> > > > >
> > > > > Fair enough.
> > > > >
> > > > > > Maybe we can have -Whardened that will diagnose any altering of
> > > > > > -fhardened by other options on the command-line or by missed target
> > > > > > implementations?  People might for example use -fstack-protector
> > > > > > but don't really want to make protection lower than requested with -fhardened.
> > > > > >
> > > > > > Any such conflict is much less appearant than when you use the
> > > > > > flags -fhardened composes.
> > > > >
> > > > > How about: --help=hardened says which options -fhardened attempts to
> > > > > enable, and -Whardened warns when it didn't enable an option?  E.g.,
> > > > >
> > > > >   -fstack-protector -fhardened -Whardened
> > > > >
> > > > > would say that it didn't enable -fstack-protector-strong because
> > > > > -fstack-protector was specified on the command line?
> > > > >
> > > > > If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
> > > > > list -z now, likewise for -z relro.
> > > > >
> > > > > Unclear if -Whardened should be enabled by default, but probably yes?
> > > >
> > > > Here's v2 which adds -Whardened (enabled by default).
> > > >
> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > >
> > > I think it's OK but I'd like to see a second ACK here.
> >
> > Thanks!
> >
> > > Can you see how our
> > > primary and secondary targets (+ host OS) behave here?
> >
> > That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
> > that fails with:
> >
> > ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
> > ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
> > make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
> > make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
> >
> > and I tried Darwin (104) and that fails with
> >
> > *** Configuration aarch64-apple-darwin21.6.0 not supported
> >
> > Is anyone else able to build gcc on those machines, or test the attached
> > patch?
> >
> > > I think the
> > > documentation should elaborate a bit on expectations for non-Linux/GNU
> > > targets, specifically I think the default configuration for a target should
> > > with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> > > have a testcase for this?
> >
> > Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
> > something not supported on those systems, and it's something for which
> > we have a configure test, then we shouldn't warn.  This is already the
> > case for -pie, -z relro, and -z now.
> 
> I was thinking of
> 
> /* { dg-do compile } */
> /* { dg-additional-options "-fhardened -Whardened" } */
> 
> int main () {}
> 
> and excess errors should catch "misconfigurations"?

I see.  fhardened-3.c is basically just like this (-Whardened is on by default).
 
> > Should the docs say something like the following for features without
> > configure checks?
> >
> > @option{-fhardened} can, on certain systems, attempt to enable features
> > not supported on that particular system.  In that case, it's possible to
> > prevent the warning using the @option{-Wno-hardened} option.
> 
> Yeah, but ideally
> 
> @option{-fhardened} can, on certain systems, not enable features not
> available on those systems and @option{-Whardened} will not diagnose
> those as missing.
> 
> But I understand it doesn't work like that?

Right.  It will not diagnose missing features if they have a configure
check, otherwise it will.  And I don't know if we want a configure check
for every feature.  Maybe we can add them in the future if the current
patch turns out to be problematical in practice?

Thanks,

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] gcc: Introduce -fhardened
  2023-10-24 19:03               ` Marek Polacek
@ 2023-10-24 19:16                 ` Iain Sandoe
  0 siblings, 0 replies; 28+ messages in thread
From: Iain Sandoe @ 2023-10-24 19:16 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, GCC Patches



> On 24 Oct 2023, at 20:03, Marek Polacek <polacek@redhat.com> wrote:
> 
> On Tue, Oct 24, 2023 at 10:34:22AM +0100, Iain Sandoe wrote:
>> hi Marek,
>> 
>>> On 24 Oct 2023, at 08:44, Iain Sandoe <iain@sandoe.co.uk> wrote:
>>> On 23 Oct 2023, at 20:25, Marek Polacek <polacek@redhat.com> wrote:
>>>> 
>>>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
>>>>> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>>>>>> 
>>>>>> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>>>>>>> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>>>>>>>> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>> 
>>> 
>>>> and I tried Darwin (104) and that fails with
>>>> 
>>>> *** Configuration aarch64-apple-darwin21.6.0 not supported
>>>> 
>>>> Is anyone else able to build gcc on those machines, or test the attached
>>>> patch?
>>> 
>>> We’re still working on upstreaming the aarch64 Darwin port - the devt. branch
>>> is here; https://github.com/iains/gcc-darwin-arm64 (but it will be rebased soon
>>> because we just upstreamed some dependencies).
>>> 
>>> In the meantime, I will put your patch into my test queue - hopefully before
>>> next week.
>> 
>> actually, I rebased already .. (but not pushed yet, pending testing).
>> 
>> aarch64-darwin21 bootstrapped fine with your patch (as did x86_64-darwin19)
> 
> Thank you so much Iain!
> 
>> ===
>> 
>> $ /opt/iains/aarch64-apple-darwin21/gcc-14-0-0/bin/gcc /source/test/hello.c -o hc -fhardened -Whardened
>> cc1: warning: ‘_FORTIFY_SOURCE’ is not enabled by ‘-fhardened’ because optimizations are turned off [-Whardened]
>> 
>> $ /opt/iains/aarch64-apple-darwin21/gcc-14-0-0/bin/gcc /source/test/hello.c -o hc -fhardened -Whardened -O
>> <no output>
> 
> That looks correct.
> 
>> I’m about to run the testsuite, but if there’s something else to be tested please let me know (NOTE: I have not read the patch, just applied it and built).
> 
> I am mostly curious about the fhardened* tests, if they all pass.

No, some that require __PIE__=2 fail.

That is because Darwin has to handle PIE and PIC locally, because the way in which those options interact is different from Linux.  I need to amend Darwin’s handling to work together with fhardening on platform versions tor which that’s relevant (but do not expect that to be too tricky).

For aarch64-darwin, PIE is mandatory so we had not even been considering it [we basically ignore the flag, because all it does is to create tool warnings] (I need to fix the ouput of the pp define tho).

For all x86_64  Darwin>=20 warns about no-PIE so we are also defaulting it on there.

Of course, none of this should affect these tests (it just means that fhardening will be a NOP for PIE on later Darwin).

I’ll look into these changes over the next few days, if I have a chance, in any case, they do not need to be relevant to your patch.

Iain

> 
> Thanks,
> Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] gcc: Introduce -fhardened
  2023-10-24 19:09             ` Marek Polacek
@ 2023-10-26 15:55               ` Richard Biener
  2023-11-03 22:51                 ` [PATCH v4] " Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Biener @ 2023-10-26 15:55 UTC (permalink / raw)
  To: Marek Polacek; +Cc: iain, GCC Patches



> Am 24.10.2023 um 21:09 schrieb Marek Polacek <polacek@redhat.com>:
> 
> On Tue, Oct 24, 2023 at 09:22:25AM +0200, Richard Biener wrote:
>>> On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
>>> 
>>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
>>>> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>>>>> 
>>>>> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>>>>>> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>>>>>>> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>> 
>>>>>>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
>>>>>>>> and aarch64-unknown-linux-gnu; ok for trunk?
>>>>>>>> 
>>>>>>>> -- >8 --
>>>>>>>> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
>>>>>>>> I proposed -fhardened, a new umbrella option that enables a reasonable set
>>>>>>>> of hardening flags.  The read of the room seems to be that the option
>>>>>>>> would be useful.  So here's a patch implementing that option.
>>>>>>>> 
>>>>>>>> Currently, -fhardened enables:
>>>>>>>> 
>>>>>>>>  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>>>>>>>>  -D_GLIBCXX_ASSERTIONS
>>>>>>>>  -ftrivial-auto-var-init=pattern
>>>> 
>>>> I think =zero is much better here given the overhead is way
>>>> cheaper and pointers get a more reliable behavior.
>>> 
>>> Ok, changed now.
>>> 
>>>>>>>>  -fPIE  -pie  -Wl,-z,relro,-z,now
>>>>>>>>  -fstack-protector-strong
>>>>>>>>  -fstack-clash-protection
>>>>>>>>  -fcf-protection=full (x86 GNU/Linux only)
>>>>>>>> 
>>>>>>>> -fhardened will not override options that were specified on the command line
>>>>>>>> (before or after -fhardened).  For example,
>>>>>>>> 
>>>>>>>>     -D_FORTIFY_SOURCE=1 -fhardened
>>>>>>>> 
>>>>>>>> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>>>>>>>> 
>>>>>>>>      -fhardened -fstack-protector
>>>>>>>> 
>>>>>>>> will not enable -fstack-protector-strong.
>>>>>>>> 
>>>>>>>> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
>>>>>>>> to anything.  I think we need a better way to show what it actually
>>>>>>>> enables.
>>>>>>> 
>>>>>>> I do think we need to find a solution here to solve asserting compliance.
>>>>>> 
>>>>>> Fair enough.
>>>>>> 
>>>>>>> Maybe we can have -Whardened that will diagnose any altering of
>>>>>>> -fhardened by other options on the command-line or by missed target
>>>>>>> implementations?  People might for example use -fstack-protector
>>>>>>> but don't really want to make protection lower than requested with -fhardened.
>>>>>>> 
>>>>>>> Any such conflict is much less appearant than when you use the
>>>>>>> flags -fhardened composes.
>>>>>> 
>>>>>> How about: --help=hardened says which options -fhardened attempts to
>>>>>> enable, and -Whardened warns when it didn't enable an option?  E.g.,
>>>>>> 
>>>>>>  -fstack-protector -fhardened -Whardened
>>>>>> 
>>>>>> would say that it didn't enable -fstack-protector-strong because
>>>>>> -fstack-protector was specified on the command line?
>>>>>> 
>>>>>> If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
>>>>>> list -z now, likewise for -z relro.
>>>>>> 
>>>>>> Unclear if -Whardened should be enabled by default, but probably yes?
>>>>> 
>>>>> Here's v2 which adds -Whardened (enabled by default).
>>>>> 
>>>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>>>> 
>>>> I think it's OK but I'd like to see a second ACK here.
>>> 
>>> Thanks!
>>> 
>>>> Can you see how our
>>>> primary and secondary targets (+ host OS) behave here?
>>> 
>>> That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
>>> that fails with:
>>> 
>>> ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
>>> ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
>>> make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
>>> make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
>>> 
>>> and I tried Darwin (104) and that fails with
>>> 
>>> *** Configuration aarch64-apple-darwin21.6.0 not supported
>>> 
>>> Is anyone else able to build gcc on those machines, or test the attached
>>> patch?
>>> 
>>>> I think the
>>>> documentation should elaborate a bit on expectations for non-Linux/GNU
>>>> targets, specifically I think the default configuration for a target should
>>>> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
>>>> have a testcase for this?
>>> 
>>> Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
>>> something not supported on those systems, and it's something for which
>>> we have a configure test, then we shouldn't warn.  This is already the
>>> case for -pie, -z relro, and -z now.
>> 
>> I was thinking of
>> 
>> /* { dg-do compile } */
>> /* { dg-additional-options "-fhardened -Whardened" } */
>> 
>> int main () {}
>> 
>> and excess errors should catch "misconfigurations"?
> 
> I see.  fhardened-3.c is basically just like this (-Whardened is on by default).
> 
>>> Should the docs say something like the following for features without
>>> configure checks?
>>> 
>>> @option{-fhardened} can, on certain systems, attempt to enable features
>>> not supported on that particular system.  In that case, it's possible to
>>> prevent the warning using the @option{-Wno-hardened} option.
>> 
>> Yeah, but ideally
>> 
>> @option{-fhardened} can, on certain systems, not enable features not
>> available on those systems and @option{-Whardened} will not diagnose
>> those as missing.
>> 
>> But I understand it doesn't work like that?
> 
> Right.  It will not diagnose missing features if they have a configure
> check, otherwise it will.  And I don't know if we want a configure check
> for every feature.  Maybe we can add them in the future if the current
> patch turns out to be problematical in practice?

Maybe we can have a switch on known target triples and statically configure based
On that, eventually even not support -fhardened for targets not listed.  That’s certainly easier than detecting the target system features (think of cross compilers)

> Thanks,
> 
> Marek
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v4] gcc: Introduce -fhardened
  2023-10-26 15:55               ` Richard Biener
@ 2023-11-03 22:51                 ` Marek Polacek
  2023-11-13 15:41                   ` Marek Polacek
                                     ` (2 more replies)
  0 siblings, 3 replies; 28+ messages in thread
From: Marek Polacek @ 2023-11-03 22:51 UTC (permalink / raw)
  To: Richard Biener; +Cc: iain, GCC Patches

On Thu, Oct 26, 2023 at 05:55:56PM +0200, Richard Biener wrote:
> 
> 
> > Am 24.10.2023 um 21:09 schrieb Marek Polacek <polacek@redhat.com>:
> > 
> > On Tue, Oct 24, 2023 at 09:22:25AM +0200, Richard Biener wrote:
> >>> On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
> >>> 
> >>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> >>>> Can you see how our
> >>>> primary and secondary targets (+ host OS) behave here?
> >>> 
> >>> That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
> >>> that fails with:
> >>> 
> >>> ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
> >>> ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
> >>> make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
> >>> make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
> >>> 
> >>> and I tried Darwin (104) and that fails with
> >>> 
> >>> *** Configuration aarch64-apple-darwin21.6.0 not supported
> >>> 
> >>> Is anyone else able to build gcc on those machines, or test the attached
> >>> patch?
> >>> 
> >>>> I think the
> >>>> documentation should elaborate a bit on expectations for non-Linux/GNU
> >>>> targets, specifically I think the default configuration for a target should
> >>>> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> >>>> have a testcase for this?
> >>> 
> >>> Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
> >>> something not supported on those systems, and it's something for which
> >>> we have a configure test, then we shouldn't warn.  This is already the
> >>> case for -pie, -z relro, and -z now.
> >> 
> >> I was thinking of
> >> 
> >> /* { dg-do compile } */
> >> /* { dg-additional-options "-fhardened -Whardened" } */
> >> 
> >> int main () {}
> >> 
> >> and excess errors should catch "misconfigurations"?
> > 
> > I see.  fhardened-3.c is basically just like this (-Whardened is on by default).
> > 
> >>> Should the docs say something like the following for features without
> >>> configure checks?
> >>> 
> >>> @option{-fhardened} can, on certain systems, attempt to enable features
> >>> not supported on that particular system.  In that case, it's possible to
> >>> prevent the warning using the @option{-Wno-hardened} option.
> >> 
> >> Yeah, but ideally
> >> 
> >> @option{-fhardened} can, on certain systems, not enable features not
> >> available on those systems and @option{-Whardened} will not diagnose
> >> those as missing.
> >> 
> >> But I understand it doesn't work like that?
> > 
> > Right.  It will not diagnose missing features if they have a configure
> > check, otherwise it will.  And I don't know if we want a configure check
> > for every feature.  Maybe we can add them in the future if the current
> > patch turns out to be problematical in practice?
> 
> Maybe we can have a switch on known target triples and statically configure based
> On that, eventually even not support -fhardened for targets not listed.  That’s certainly easier than detecting the target system features (think of cross compilers)

You mean like the following?  The only difference is the addition of
HAVE_FHARDENED_SUPPORT and updating the tests to only run on gnu/linux
targets.  If other OSs want to use -fhardened, they need to update the
configure test.  Thanks,

Bootstrapped/regtested on x86_64-pc-linux-gnu and
powerpc64le-unknown-linux-gnu.

-- >8 --
In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
I proposed -fhardened, a new umbrella option that enables a reasonable set
of hardening flags.  The read of the room seems to be that the option
would be useful.  So here's a patch implementing that option.

Currently, -fhardened enables:

  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
  -D_GLIBCXX_ASSERTIONS
  -ftrivial-auto-var-init=zero
  -fPIE  -pie  -Wl,-z,relro,-z,now
  -fstack-protector-strong
  -fstack-clash-protection
  -fcf-protection=full (x86 GNU/Linux only)

-fhardened will not override options that were specified on the command line
(before or after -fhardened).  For example,

     -D_FORTIFY_SOURCE=1 -fhardened

means that _FORTIFY_SOURCE=1 will be used.  Similarly,

      -fhardened -fstack-protector

will not enable -fstack-protector-strong.

Currently, -fhardened is only supported on GNU/Linux.

In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
to anything.  This patch provides -Whardened, enabled by default, which
warns when -fhardened couldn't enable a particular option.  I think most
often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
were not enabled.

gcc/c-family/ChangeLog:

	* c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
	and _GLIBCXX_ASSERTIONS.

gcc/ChangeLog:

	* common.opt (Whardened, fhardened): New options.
	* config.in: Regenerate.
	* config/bpf/bpf.cc: Include "opts.h".
	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
	not inform that -fstack-protector does not work.
	* config/i386/i386-options.cc (ix86_option_override_internal): When
	-fhardened, maybe enable -fcf-protection=full.
	* configure: Regenerate.
	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
	Check if -fhardened is supported on $target_os.
	* doc/invoke.texi: Document -fhardened and -Whardened.
	* gcc.cc (driver_handle_option): Remember if any link options or -static
	were specified on the command line.
	(process_command): When -fhardened, maybe enable -pie and
	-Wl,-z,relro,-z,now.
	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
	(finish_options): When -fhardened, enable
	-ftrivial-auto-var-init=zero and -fstack-protector-strong.
	(print_help_hardened): New.
	(print_help): Call it.
	* toplev.cc (process_options): When -fhardened, enable
	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
	do not warn that -fstack-protector not supported for this target.
	Don't enable -fhardened when !HAVE_FHARDENED_SUPPORT.

gcc/testsuite/ChangeLog:

	* gcc.misc-tests/help.exp: Test -fhardened.
	* c-c++-common/fhardened-1.S: New test.
	* c-c++-common/fhardened-1.c: New test.
	* c-c++-common/fhardened-10.c: New test.
	* c-c++-common/fhardened-11.c: New test.
	* c-c++-common/fhardened-12.c: New test.
	* c-c++-common/fhardened-13.c: New test.
	* c-c++-common/fhardened-14.c: New test.
	* c-c++-common/fhardened-15.c: New test.
	* c-c++-common/fhardened-2.c: New test.
	* c-c++-common/fhardened-3.c: New test.
	* c-c++-common/fhardened-4.c: New test.
	* c-c++-common/fhardened-5.c: New test.
	* c-c++-common/fhardened-6.c: New test.
	* c-c++-common/fhardened-7.c: New test.
	* c-c++-common/fhardened-8.c: New test.
	* c-c++-common/fhardened-9.c: New test.
	* gcc.target/i386/cf_check-6.c: New test.
---
 gcc/c-family/c-opts.cc                     | 42 +++++++++++++
 gcc/common.opt                             |  8 +++
 gcc/config.in                              | 18 ++++++
 gcc/config/bpf/bpf.cc                      |  8 ++-
 gcc/config/i386/i386-options.cc            | 17 ++++-
 gcc/configure                              | 72 +++++++++++++++++++++-
 gcc/configure.ac                           | 57 ++++++++++++++++-
 gcc/doc/invoke.texi                        | 49 ++++++++++++++-
 gcc/gcc.cc                                 | 48 ++++++++++++++-
 gcc/opts.cc                                | 67 +++++++++++++++++++-
 gcc/opts.h                                 |  1 +
 gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
 gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-11.c  | 10 +++
 gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
 gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
 gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
 gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
 gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
 gcc/toplev.cc                              | 25 +++++++-
 30 files changed, 556 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c

diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index e9f7e6d424d..26f009f2da5 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -1556,6 +1556,9 @@ c_finish_options (void)
       cb_file_change (parse_in, cmd_map);
       linemap_line_start (line_table, 0, 1);
 
+      bool fortify_seen_p = false;
+      bool cxx_assert_seen_p = false;
+
       /* All command line defines must have the same location.  */
       cpp_force_token_locations (parse_in, line_table->highest_line);
       for (size_t i = 0; i < deferred_count; i++)
@@ -1573,6 +1576,45 @@ c_finish_options (void)
 	      else
 		cpp_assert (parse_in, opt->arg);
 	    }
+
+	  if (UNLIKELY (flag_hardened)
+	      && (opt->code == OPT_D || opt->code == OPT_U))
+	    {
+	      if (!fortify_seen_p)
+		fortify_seen_p
+		  = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
+		     && (opt->arg[15] == '\0' || opt->arg[15] == '='));
+	      if (!cxx_assert_seen_p)
+		cxx_assert_seen_p
+		  = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
+		     && (opt->arg[19] == '\0' || opt->arg[19] == '='));
+	    }
+	}
+
+      if (flag_hardened)
+	{
+	  if (!fortify_seen_p && optimize > 0)
+	    {
+	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
+		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
+	      else
+		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
+	    }
+	  else if (optimize == 0)
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because optimizations are turned off");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because it was specified in %<-D%> or %<-U%>");
+	  if (!cxx_assert_seen_p)
+	    cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_GLIBCXX_ASSERTIONS%> is not enabled by "
+			"%<-fhardened%> because it was specified in %<-D%> "
+			"or %<-U%>");
 	}
 
       cpp_stop_forcing_token_locations (parse_in);
diff --git a/gcc/common.opt b/gcc/common.opt
index 1cf3bdd3b51..48a15f077ef 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -634,6 +634,10 @@ Wfree-nonheap-object
 Common Var(warn_free_nonheap_object) Init(1) Warning
 Warn when attempting to free a non-heap object.
 
+Whardened
+Common Var(warn_hardened) Init(1) Warning
+Warn when -fhardened did not enable an option from its set.
+
 Whsa
 Common Ignore Warning
 Does nothing.  Preserved for backward compatibility.
@@ -1823,6 +1827,10 @@ fguess-branch-probability
 Common Var(flag_guess_branch_prob) Optimization
 Enable guessing of branch probabilities.
 
+fhardened
+Common Driver Var(flag_hardened)
+Enable various security-relevant flags.
+
 fharden-compares
 Common Var(flag_harden_compares) Optimization
 Harden conditionals not used in branches, checking reversed conditions.
diff --git a/gcc/config.in b/gcc/config.in
index 03faee1c6ac..97b483ddd97 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1293,6 +1293,12 @@
 #endif
 
 
+/* Define 0/1 if -fhardened is supported */
+#ifndef USED_FOR_TARGET
+#undef HAVE_FHARDENED_SUPPORT
+#endif
+
+
 /* Define to 1 if you have the `fileno_unlocked' function. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_FILENO_UNLOCKED
@@ -1695,6 +1701,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z now */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_NOW_SUPPORT
+#endif
+
+
 /* Define if your PowerPC64 linker only needs function descriptor syms. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_NO_DOT_SYMS
@@ -1738,6 +1750,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z relro */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_RELRO_SUPPORT
+#endif
+
+
 /* Define if your linker links a mix of read-only and read-write sections into
    a read-write section. */
 #ifndef USED_FOR_TARGET
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 63637ece78e..804f6f3304a 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 
 #include "core-builtins.h"
+#include "opts.h"
 
 /* Per-function machine data.  */
 struct GTY(()) machine_function
@@ -250,9 +251,10 @@ bpf_option_override (void)
   /* Disable -fstack-protector as it is not supported in BPF.  */
   if (flag_stack_protect)
     {
-      inform (input_location,
-              "%<-fstack-protector%> does not work "
-	      "on this architecture");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	inform (input_location,
+		"%<-fstack-protector%> does not work "
+		"on this architecture");
       flag_stack_protect = 0;
     }
 
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index df7d24352d1..76adba672b9 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3072,10 +3072,25 @@ ix86_option_override_internal (bool main_args_p,
         = build_target_option_node (opts, opts_set);
     }
 
+  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
+  /* When -fhardened, enable -fcf-protection=full, but only when it's
+     compatible with this target, and when it wasn't already specified
+     on the command line.  */
+  if (opts->x_flag_hardened && cf_okay_p)
+    {
+      if (opts->x_flag_cf_protection == CF_NONE)
+	opts->x_flag_cf_protection = CF_FULL;
+      else if (opts->x_flag_cf_protection != CF_FULL)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fcf-protection=full%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (opts->x_flag_cf_protection != CF_NONE)
     {
       if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
-	  && !TARGET_64BIT && !TARGET_CMOV)
+	  && !cf_okay_p)
 	error ("%<-fcf-protection%> is not compatible with this target");
 
       opts->x_flag_cf_protection
diff --git a/gcc/configure b/gcc/configure
index d4ad988000f..e701f6be063 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -20000,7 +20000,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19995 "configure"
+#line 20003 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -20106,7 +20106,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 20101 "configure"
+#line 20109 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -32903,7 +32903,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -33032,6 +33032,72 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
+$as_echo_n "checking linker -z now option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
+$as_echo "$ld_now_support" >&6; }
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
+$as_echo_n "checking linker -z relro option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
+$as_echo "$ld_relro_support" >&6; }
+
+case $target_os in
+linux* | gnu*)
+  # -fhardened is only supported on GNU/Linux.
+  fhardened_support=yes
+  ;;
+*)
+  fhardened_support=no
+  ;;
+esac
+
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FHARDENED_SUPPORT `if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fhardened_support" >&5
+$as_echo "$fhardened_support" >&6; }
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index dc8cb6a33de..feb81b114b4 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -7714,7 +7714,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -7815,6 +7815,61 @@ standards-compatible mode on s390 targets.])
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+AC_MSG_CHECKING(linker -z now option)
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
+  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z now])
+AC_MSG_RESULT($ld_now_support)
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+AC_MSG_CHECKING(linker -z relro option)
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
+  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z relro])
+AC_MSG_RESULT($ld_relro_support)
+
+case $target_os in
+linux* | gnu*)
+  # -fhardened is only supported on GNU/Linux.
+  fhardened_support=yes
+  ;;
+*)
+  fhardened_support=no
+  ;;
+esac
+
+AC_DEFINE_UNQUOTED(HAVE_FHARDENED_SUPPORT,
+  [`if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if -fhardened is supported])
+AC_MSG_RESULT($fhardened_support)
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 6e776a0faa1..7f145468950 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-y2k  -Wframe-address
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
 -Wno-if-not-aligned  -Wno-ignored-attributes
--Wignored-qualifiers  -Wno-incompatible-pointer-types
+-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
 -Wno-implicit-function-declaration  -Wno-implicit-int
 -Winfinite-recursion
@@ -641,7 +641,7 @@ Objective-C and Objective-C++ Dialects}.
 -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
 -fsanitize-undefined-trap-on-error  -fbounds-check
 -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
--fharden-compares -fharden-conditional-branches
+-fharden-compares -fharden-conditional-branches  -fhardened
 -fharden-control-flow-redundancy  -fhardcfr-skip-leaf
 -fhardcfr-check-exceptions  -fhardcfr-check-returning-calls
 -fhardcfr-check-noreturn-calls=@r{[}always@r{|}no-xthrow@r{|}nothrow@r{|}never@r{]}
@@ -6860,6 +6860,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
 Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
 This warning is enabled by @option{-Wall}.
 
+@opindex Whardened
+@opindex Wno-hardened
+@item -Whardened
+Warn when @option{-fhardened} did not enable an option from its set (for
+which see @option{-fhardened}).  For instance, using @option{-fhardened}
+and @option{-fstack-protector} at the same time on the command line causes
+@option{-Whardened} to warn because @option{-fstack-protector-strong} is
+not enabled by @option{-fhardened}.
+
+This warning is enabled by default and has effect only when @option{-fhardened}
+is enabled.
+
 @opindex Wimplicit-fallthrough
 @opindex Wno-implicit-fallthrough
 @item -Wimplicit-fallthrough
@@ -17552,6 +17564,39 @@ made @option{no-xthrow} the default setting for this option: it excludes
 from the @code{noreturn} treatment only internal functions used to
 (re)raise exceptions, that are not affected by these optimizations.
 
+@opindex fhardened
+@item -fhardened
+Enable a set of flags for C and C++ that improve the security of the
+generated code without affecting its ABI.  The precise flags enabled
+may change between major releases of GCC, but are currently:
+
+@c Keep this in sync with print_help_hardened!
+@gccoptlist{
+-D_FORTIFY_SOURCE=3
+-D_GLIBCXX_ASSERTIONS
+-ftrivial-auto-var-init=zero
+-fPIE  -pie  -Wl,-z,relro,-z,now
+-fstack-protector-strong
+-fstack-clash-protection
+-fcf-protection=full @r{(x86 GNU/Linux only)}
+}
+
+The list of options enabled by @option{-fhardened} can be generated using
+the @option{--help=hardened} option.
+
+When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
+is used instead.
+
+This option is intended to be used in production builds, not merely
+in debug builds.
+
+Currently, @option{-fhardened} is only supported on GNU/Linux targets.
+
+@option{-fhardened} only enables a particular option if it wasn't
+already specified anywhere on the command line.  For instance,
+@option{-fhardened} @option{-fstack-protector} will only enable
+@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
+
 @opindex fstack-protector
 @item -fstack-protector
 Emit extra code to check for buffer overflows, such as stack smashing
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 884284e66b4..a7e5774dcfa 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
    driver added to dumpdir after dumpbase or linker output name.  */
 static bool dumpdir_trailing_dash_added = false;
 
+/* True if -r, -shared, -pie, or -no-pie were specified on the command
+   line.  */
+static bool any_link_options_p;
+
+/* True if -static was specified on the command line.  */
+static bool static_p;
+
 /* Basename of dump and aux outputs, computed from dumpbase (given or
    derived from output name), to override input_basename in non-%w %b
    et al.  */
@@ -4606,10 +4613,20 @@ driver_handle_option (struct gcc_options *opts,
       save_switch ("-o", 1, &arg, validated, true);
       return true;
 
-#ifdef ENABLE_DEFAULT_PIE
     case OPT_pie:
+#ifdef ENABLE_DEFAULT_PIE
       /* -pie is turned on by default.  */
+      validated = true;
 #endif
+    case OPT_r:
+    case OPT_shared:
+    case OPT_no_pie:
+      any_link_options_p = true;
+      break;
+
+    case OPT_static:
+      static_p = true;
+      break;
 
     case OPT_static_libgcc:
     case OPT_shared_libgcc:
@@ -4985,6 +5002,35 @@ process_command (unsigned int decoded_options_count,
 #endif
     }
 
+  /* TODO: check if -static -pie works and maybe use it.  */
+  if (flag_hardened)
+    {
+      if (!any_link_options_p && !static_p)
+	{
+#ifdef HAVE_LD_PIE
+	  save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
+#endif
+	  /* These are passed straight down to collect2 so we have to break
+	     it up like this.  */
+	  if (HAVE_LD_NOW_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("now", "*");
+	    }
+	  if (HAVE_LD_RELRO_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("relro", "*");
+	    }
+	}
+      /* We can't use OPT_Whardened yet.  Sigh.  */
+      else if (warn_hardened)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "linker hardening options not enabled by %<-fhardened%> "
+		    "because other link options were specified on the command "
+		    "line");
+    }
+
   /* Handle -gtoggle as it would later in toplev.cc:process_options to
      make the debug-level-gt spec function work as expected.  */
   if (flag_gtoggle)
diff --git a/gcc/opts.cc b/gcc/opts.cc
index f54cf8305ca..787f3f47db3 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
 /* Set by -fcanon-prefix-map.  */
 bool flag_canon_prefix_map;
 
+/* Set by finish_options when flag_stack_protector was set only because of
+   -fhardened.  Yuck.  */
+bool flag_stack_protector_set_by_fhardened_p;
+
 static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
 /* Names of fundamental debug info formats indexed by enum
@@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       opts->x_flag_section_anchors = 0;
     }
 
+  if (opts->x_flag_hardened)
+    {
+      if (!opts_set->x_flag_auto_var_init)
+	opts->x_flag_auto_var_init = AUTO_INIT_ZERO;
+      else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO)
+	warning_at (loc, OPT_Whardened,
+		    "%<-ftrivial-auto-var-init=zero%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (!opts->x_flag_opts_finished)
     {
       /* We initialize opts->x_flag_pie to -1 so that targets can set a
@@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	  /* We initialize opts->x_flag_pic to -1 so that we can tell if
 	     -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
 	  if (opts->x_flag_pic == -1)
-	    opts->x_flag_pie = DEFAULT_FLAG_PIE;
+	    opts->x_flag_pie = (opts->x_flag_hardened
+				? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
 	  else
 	    opts->x_flag_pie = 0;
 	}
@@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
     }
 
   /* We initialize opts->x_flag_stack_protect to -1 so that targets
-     can set a default value.  */
+     can set a default value.  With --enable-default-ssp or -fhardened
+     the default is -fstack-protector-strong.  */
   if (opts->x_flag_stack_protect == -1)
-    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    {
+      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
+	 defined in such a way that it uses flag_stack_protect which can't
+	 be used here.  Moreover, some targets like BPF don't support
+	 -fstack-protector at all but we don't know that here.  So remember
+	 that flag_stack_protect was set at the behest of -fhardened.  */
+      if (opts->x_flag_hardened)
+	{
+	  opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
+	  flag_stack_protector_set_by_fhardened_p = true;
+	}
+      else
+	opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    }
+  else if (opts->x_flag_hardened
+	   && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
+    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		"%<-fstack-protector-strong%> is not enabled by "
+		"%<-fhardened%> because it was specified on the command "
+		"line");
 
   if (opts->x_optimize == 0)
     {
@@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
   free (patch_area_arg);
 }
 
+/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
+
+static void
+print_help_hardened ()
+{
+  printf ("%s\n", "The following options are enabled by -fhardened:");
+  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
+	  (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
+  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
+  printf ("  %s\n", "-ftrivial-auto-var-init=zero");
+#ifdef HAVE_LD_PIE
+  printf ("  %s  %s\n", "-fPIE", "-pie");
+#endif
+  if (HAVE_LD_NOW_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,now");
+  if (HAVE_LD_RELRO_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,relro");
+  printf ("  %s\n", "-fstack-protector-strong");
+  printf ("  %s\n", "-fstack-clash-protection");
+  printf ("  %s\n", "-fcf-protection=full");
+  putchar ('\n');
+}
+
 /* Print help when OPT__help_ is set.  */
 
 void
@@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
 	}
       else if (lang_flag != 0)
 	*pflags |= lang_flag;
+      else if (strncasecmp (a, "hardened", len) == 0)
+	print_help_hardened ();
       else
 	warning (0,
 		 "unrecognized argument to %<--help=%> option: %q.*s",
diff --git a/gcc/opts.h b/gcc/opts.h
index 00f377f9ca7..d89c5de8114 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -344,6 +344,7 @@ struct cl_option_handlers
 /* Hold command-line options associated with stack limitation.  */
 extern const char *opt_fstack_limit_symbol_arg;
 extern int opt_fstack_limit_register_no;
+extern bool flag_stack_protector_set_by_fhardened_p;
 
 /* Input file names.  */
 
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
new file mode 100644
index 00000000000..9d0a5772d9e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.S
@@ -0,0 +1,6 @@
+/* { dg-do preprocess { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
new file mode 100644
index 00000000000..7e6740655fe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O" } */
+
+#ifndef __SSP_STRONG__
+# error "-fstack-protector-strong not enabled"
+#endif
+
+#if _FORTIFY_SOURCE < 2
+# error "_FORTIFY_SOURCE not enabled"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
new file mode 100644
index 00000000000..badebc56440
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-10.c
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
+
+#if _FORTIFY_SOURCE != 1
+# error "_FORTIFY_SOURCE != 1"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
new file mode 100644
index 00000000000..d1a973d177a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-11.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
+
+#ifndef _FORTIFY_SOURCE
+# error "_FORTIFY_SOURCE disabled when it should not be"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
new file mode 100644
index 00000000000..eb128f61ba3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-12.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
new file mode 100644
index 00000000000..8722e6d4b1a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-13.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
new file mode 100644
index 00000000000..04d6c8ff954
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-14.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O -fno-PIE" } */
+
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
new file mode 100644
index 00000000000..86dc5220159
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-15.c
@@ -0,0 +1,5 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-require-stack-check "specific" } */
+/* { dg-options "-fhardened -O -fstack-check" } */
+
+/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
new file mode 100644
index 00000000000..280ff96eb15
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -fstack-protector" } */
+
+#ifdef __SSP_STRONG__
+# error "-fstack-protector-strong enabled when it should not be"
+#endif
+#ifndef __SSP__
+# error "-fstack-protector not enabled"
+#endif
+
+/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
new file mode 100644
index 00000000000..f2306ca5d33
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O0" } */
+/* Test that we don't get any diagnostic coming from libc headers.  */
+
+#include <stdio.h>
+
+/* The most useful C program known to man.  */
+
+int
+main ()
+{
+}
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
new file mode 100644
index 00000000000..312fabb95a5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-4.c
@@ -0,0 +1,4 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O0 -Wno-hardened" } */
+
+/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
new file mode 100644
index 00000000000..eb128f61ba3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
new file mode 100644
index 00000000000..d3cb7c8b353
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
+/* { dg-warning ".-ftrivial-auto-var-init=zero. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
new file mode 100644
index 00000000000..b47bf43f360
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-7.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O -fpie" } */
+
+/* -fpie takes precedence over -fhardened */
+#if __PIE__ != 1
+# error "__PIE__ != 1"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
new file mode 100644
index 00000000000..85c9ad9103f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-8.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O -fPIC" } */
+
+/* -fPIC takes precedence over -fhardened */
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
new file mode 100644
index 00000000000..4e4131f0bdd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-9.c
@@ -0,0 +1,9 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
+
+#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
+# error "hardening enabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
index 52b9cb0ab90..15d618a2528 100644
--- a/gcc/testsuite/gcc.misc-tests/help.exp
+++ b/gcc/testsuite/gcc.misc-tests/help.exp
@@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
 # Listing only excludes gives empty results.
 check_for_options c "--help=^joined,^separate" "" "" ""
 
+check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
+
 if [ info exists prev_columns ] {
     # Reset the enviroment variable to its oriuginal value.
     set env(COLUMNS) $prev_columns
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
new file mode 100644
index 00000000000..73b78dce889
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+/* Test that -fhardened enables CET.  */
+
+extern void bar (void) __attribute__((__cf_check__));
+
+void
+foo (void)
+{
+  bar ();
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 9a734890a18..841444d545c 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1567,6 +1567,13 @@ process_options ()
       flag_associative_math = 0;
     }
 
+  if (flag_hardened && !HAVE_FHARDENED_SUPPORT)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "%<-fhardened%> not supported for this target");
+      flag_hardened = 0;
+    }
+
   /* -fstack-clash-protection is not currently supported on targets
      where the stack grows up.  */
   if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD)
@@ -1576,6 +1583,19 @@ process_options ()
 		  "where the stack grows from lower to higher addresses");
       flag_stack_clash_protection = 0;
     }
+  else if (flag_hardened)
+    {
+      if (!flag_stack_clash_protection
+	   /* Don't enable -fstack-clash-protection when -fstack-check=
+	      is used: it would result in confusing errors.  */
+	   && flag_stack_check == NO_STACK_CHECK)
+	flag_stack_clash_protection = 1;
+      else if (flag_stack_check != NO_STACK_CHECK)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fstack-clash-protection%> is not enabled by "
+		    "%<-fhardened%> because %<-fstack-check%> was "
+		    "specified on the command line");
+    }
 
   /* We cannot support -fstack-check= and -fstack-clash-protection at
      the same time.  */
@@ -1591,8 +1611,9 @@ process_options ()
      target already uses a soft frame pointer, the transition is trivial.  */
   if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
     {
-      warning_at (UNKNOWN_LOCATION, 0,
-		  "%<-fstack-protector%> not supported for this target");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "%<-fstack-protector%> not supported for this target");
       flag_stack_protect = 0;
     }
   if (!flag_stack_protect)

base-commit: ae8abcb81ed81456c0fe5ff8e0c060c9fb9c82d7
-- 
2.41.0


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] gcc: Introduce -fhardened
  2023-11-03 22:51                 ` [PATCH v4] " Marek Polacek
@ 2023-11-13 15:41                   ` Marek Polacek
  2023-11-14  7:46                   ` Richard Biener
  2023-11-15 12:25                   ` Jakub Jelinek
  2 siblings, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2023-11-13 15:41 UTC (permalink / raw)
  To: Richard Biener; +Cc: iain, GCC Patches

Ping.

On Fri, Nov 03, 2023 at 06:51:16PM -0400, Marek Polacek wrote:
> On Thu, Oct 26, 2023 at 05:55:56PM +0200, Richard Biener wrote:
> > 
> > 
> > > Am 24.10.2023 um 21:09 schrieb Marek Polacek <polacek@redhat.com>:
> > > 
> > > On Tue, Oct 24, 2023 at 09:22:25AM +0200, Richard Biener wrote:
> > >>> On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
> > >>> 
> > >>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> > >>>> Can you see how our
> > >>>> primary and secondary targets (+ host OS) behave here?
> > >>> 
> > >>> That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
> > >>> that fails with:
> > >>> 
> > >>> ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
> > >>> ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
> > >>> make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
> > >>> make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
> > >>> 
> > >>> and I tried Darwin (104) and that fails with
> > >>> 
> > >>> *** Configuration aarch64-apple-darwin21.6.0 not supported
> > >>> 
> > >>> Is anyone else able to build gcc on those machines, or test the attached
> > >>> patch?
> > >>> 
> > >>>> I think the
> > >>>> documentation should elaborate a bit on expectations for non-Linux/GNU
> > >>>> targets, specifically I think the default configuration for a target should
> > >>>> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> > >>>> have a testcase for this?
> > >>> 
> > >>> Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
> > >>> something not supported on those systems, and it's something for which
> > >>> we have a configure test, then we shouldn't warn.  This is already the
> > >>> case for -pie, -z relro, and -z now.
> > >> 
> > >> I was thinking of
> > >> 
> > >> /* { dg-do compile } */
> > >> /* { dg-additional-options "-fhardened -Whardened" } */
> > >> 
> > >> int main () {}
> > >> 
> > >> and excess errors should catch "misconfigurations"?
> > > 
> > > I see.  fhardened-3.c is basically just like this (-Whardened is on by default).
> > > 
> > >>> Should the docs say something like the following for features without
> > >>> configure checks?
> > >>> 
> > >>> @option{-fhardened} can, on certain systems, attempt to enable features
> > >>> not supported on that particular system.  In that case, it's possible to
> > >>> prevent the warning using the @option{-Wno-hardened} option.
> > >> 
> > >> Yeah, but ideally
> > >> 
> > >> @option{-fhardened} can, on certain systems, not enable features not
> > >> available on those systems and @option{-Whardened} will not diagnose
> > >> those as missing.
> > >> 
> > >> But I understand it doesn't work like that?
> > > 
> > > Right.  It will not diagnose missing features if they have a configure
> > > check, otherwise it will.  And I don't know if we want a configure check
> > > for every feature.  Maybe we can add them in the future if the current
> > > patch turns out to be problematical in practice?
> > 
> > Maybe we can have a switch on known target triples and statically configure based
> > On that, eventually even not support -fhardened for targets not listed.  That’s certainly easier than detecting the target system features (think of cross compilers)
> 
> You mean like the following?  The only difference is the addition of
> HAVE_FHARDENED_SUPPORT and updating the tests to only run on gnu/linux
> targets.  If other OSs want to use -fhardened, they need to update the
> configure test.  Thanks,
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu and
> powerpc64le-unknown-linux-gnu.
> 
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags.  The read of the room seems to be that the option
> would be useful.  So here's a patch implementing that option.
> 
> Currently, -fhardened enables:
> 
>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>   -D_GLIBCXX_ASSERTIONS
>   -ftrivial-auto-var-init=zero
>   -fPIE  -pie  -Wl,-z,relro,-z,now
>   -fstack-protector-strong
>   -fstack-clash-protection
>   -fcf-protection=full (x86 GNU/Linux only)
> 
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened).  For example,
> 
>      -D_FORTIFY_SOURCE=1 -fhardened
> 
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> 
>       -fhardened -fstack-protector
> 
> will not enable -fstack-protector-strong.
> 
> Currently, -fhardened is only supported on GNU/Linux.
> 
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything.  This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option.  I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
> 	and _GLIBCXX_ASSERTIONS.
> 
> gcc/ChangeLog:
> 
> 	* common.opt (Whardened, fhardened): New options.
> 	* config.in: Regenerate.
> 	* config/bpf/bpf.cc: Include "opts.h".
> 	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
> 	not inform that -fstack-protector does not work.
> 	* config/i386/i386-options.cc (ix86_option_override_internal): When
> 	-fhardened, maybe enable -fcf-protection=full.
> 	* configure: Regenerate.
> 	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
> 	Check if -fhardened is supported on $target_os.
> 	* doc/invoke.texi: Document -fhardened and -Whardened.
> 	* gcc.cc (driver_handle_option): Remember if any link options or -static
> 	were specified on the command line.
> 	(process_command): When -fhardened, maybe enable -pie and
> 	-Wl,-z,relro,-z,now.
> 	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
> 	(finish_options): When -fhardened, enable
> 	-ftrivial-auto-var-init=zero and -fstack-protector-strong.
> 	(print_help_hardened): New.
> 	(print_help): Call it.
> 	* toplev.cc (process_options): When -fhardened, enable
> 	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
> 	do not warn that -fstack-protector not supported for this target.
> 	Don't enable -fhardened when !HAVE_FHARDENED_SUPPORT.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.misc-tests/help.exp: Test -fhardened.
> 	* c-c++-common/fhardened-1.S: New test.
> 	* c-c++-common/fhardened-1.c: New test.
> 	* c-c++-common/fhardened-10.c: New test.
> 	* c-c++-common/fhardened-11.c: New test.
> 	* c-c++-common/fhardened-12.c: New test.
> 	* c-c++-common/fhardened-13.c: New test.
> 	* c-c++-common/fhardened-14.c: New test.
> 	* c-c++-common/fhardened-15.c: New test.
> 	* c-c++-common/fhardened-2.c: New test.
> 	* c-c++-common/fhardened-3.c: New test.
> 	* c-c++-common/fhardened-4.c: New test.
> 	* c-c++-common/fhardened-5.c: New test.
> 	* c-c++-common/fhardened-6.c: New test.
> 	* c-c++-common/fhardened-7.c: New test.
> 	* c-c++-common/fhardened-8.c: New test.
> 	* c-c++-common/fhardened-9.c: New test.
> 	* gcc.target/i386/cf_check-6.c: New test.
> ---
>  gcc/c-family/c-opts.cc                     | 42 +++++++++++++
>  gcc/common.opt                             |  8 +++
>  gcc/config.in                              | 18 ++++++
>  gcc/config/bpf/bpf.cc                      |  8 ++-
>  gcc/config/i386/i386-options.cc            | 17 ++++-
>  gcc/configure                              | 72 +++++++++++++++++++++-
>  gcc/configure.ac                           | 57 ++++++++++++++++-
>  gcc/doc/invoke.texi                        | 49 ++++++++++++++-
>  gcc/gcc.cc                                 | 48 ++++++++++++++-
>  gcc/opts.cc                                | 67 +++++++++++++++++++-
>  gcc/opts.h                                 |  1 +
>  gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-11.c  | 10 +++
>  gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
>  gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
>  gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
>  gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
>  gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
>  gcc/toplev.cc                              | 25 +++++++-
>  30 files changed, 556 insertions(+), 16 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
> 
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index e9f7e6d424d..26f009f2da5 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1556,6 +1556,9 @@ c_finish_options (void)
>        cb_file_change (parse_in, cmd_map);
>        linemap_line_start (line_table, 0, 1);
>  
> +      bool fortify_seen_p = false;
> +      bool cxx_assert_seen_p = false;
> +
>        /* All command line defines must have the same location.  */
>        cpp_force_token_locations (parse_in, line_table->highest_line);
>        for (size_t i = 0; i < deferred_count; i++)
> @@ -1573,6 +1576,45 @@ c_finish_options (void)
>  	      else
>  		cpp_assert (parse_in, opt->arg);
>  	    }
> +
> +	  if (UNLIKELY (flag_hardened)
> +	      && (opt->code == OPT_D || opt->code == OPT_U))
> +	    {
> +	      if (!fortify_seen_p)
> +		fortify_seen_p
> +		  = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> +		     && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> +	      if (!cxx_assert_seen_p)
> +		cxx_assert_seen_p
> +		  = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> +		     && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> +	    }
> +	}
> +
> +      if (flag_hardened)
> +	{
> +	  if (!fortify_seen_p && optimize > 0)
> +	    {
> +	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> +		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> +	      else
> +		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> +	    }
> +	  else if (optimize == 0)
> +	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +			"because optimizations are turned off");
> +	  else
> +	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +			"because it was specified in %<-D%> or %<-U%>");
> +	  if (!cxx_assert_seen_p)
> +	    cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
> +	  else
> +	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +			"%<_GLIBCXX_ASSERTIONS%> is not enabled by "
> +			"%<-fhardened%> because it was specified in %<-D%> "
> +			"or %<-U%>");
>  	}
>  
>        cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 1cf3bdd3b51..48a15f077ef 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -634,6 +634,10 @@ Wfree-nonheap-object
>  Common Var(warn_free_nonheap_object) Init(1) Warning
>  Warn when attempting to free a non-heap object.
>  
> +Whardened
> +Common Var(warn_hardened) Init(1) Warning
> +Warn when -fhardened did not enable an option from its set.
> +
>  Whsa
>  Common Ignore Warning
>  Does nothing.  Preserved for backward compatibility.
> @@ -1823,6 +1827,10 @@ fguess-branch-probability
>  Common Var(flag_guess_branch_prob) Optimization
>  Enable guessing of branch probabilities.
>  
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
>  fharden-compares
>  Common Var(flag_harden_compares) Optimization
>  Harden conditionals not used in branches, checking reversed conditions.
> diff --git a/gcc/config.in b/gcc/config.in
> index 03faee1c6ac..97b483ddd97 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1293,6 +1293,12 @@
>  #endif
>  
>  
> +/* Define 0/1 if -fhardened is supported */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_FHARDENED_SUPPORT
> +#endif
> +
> +
>  /* Define to 1 if you have the `fileno_unlocked' function. */
>  #ifndef USED_FOR_TARGET
>  #undef HAVE_FILENO_UNLOCKED
> @@ -1695,6 +1701,12 @@
>  #endif
>  
>  
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
>  /* Define if your PowerPC64 linker only needs function descriptor syms. */
>  #ifndef USED_FOR_TARGET
>  #undef HAVE_LD_NO_DOT_SYMS
> @@ -1738,6 +1750,12 @@
>  #endif
>  
>  
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
>  /* Define if your linker links a mix of read-only and read-write sections into
>     a read-write section. */
>  #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 63637ece78e..804f6f3304a 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimplify-me.h"
>  
>  #include "core-builtins.h"
> +#include "opts.h"
>  
>  /* Per-function machine data.  */
>  struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
>    /* Disable -fstack-protector as it is not supported in BPF.  */
>    if (flag_stack_protect)
>      {
> -      inform (input_location,
> -              "%<-fstack-protector%> does not work "
> -	      "on this architecture");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +	inform (input_location,
> +		"%<-fstack-protector%> does not work "
> +		"on this architecture");
>        flag_stack_protect = 0;
>      }
>  
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index df7d24352d1..76adba672b9 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3072,10 +3072,25 @@ ix86_option_override_internal (bool main_args_p,
>          = build_target_option_node (opts, opts_set);
>      }
>  
> +  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> +  /* When -fhardened, enable -fcf-protection=full, but only when it's
> +     compatible with this target, and when it wasn't already specified
> +     on the command line.  */
> +  if (opts->x_flag_hardened && cf_okay_p)
> +    {
> +      if (opts->x_flag_cf_protection == CF_NONE)
> +	opts->x_flag_cf_protection = CF_FULL;
> +      else if (opts->x_flag_cf_protection != CF_FULL)
> +	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +		    "%<-fcf-protection=full%> is not enabled by "
> +		    "%<-fhardened%> because it was specified on the command "
> +		    "line");
> +    }
> +
>    if (opts->x_flag_cf_protection != CF_NONE)
>      {
>        if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> -	  && !TARGET_64BIT && !TARGET_CMOV)
> +	  && !cf_okay_p)
>  	error ("%<-fcf-protection%> is not compatible with this target");
>  
>        opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index d4ad988000f..e701f6be063 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -20000,7 +20000,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 19995 "configure"
> +#line 20003 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -20106,7 +20106,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 20101 "configure"
> +#line 20109 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -32903,7 +32903,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -33032,6 +33032,72 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>    ;;
>  esac
>  
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
> +case $target_os in
> +linux* | gnu*)
> +  # -fhardened is only supported on GNU/Linux.
> +  fhardened_support=yes
> +  ;;
> +*)
> +  fhardened_support=no
> +  ;;
> +esac
> +
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_FHARDENED_SUPPORT `if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fhardened_support" >&5
> +$as_echo "$fhardened_support" >&6; }
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>  
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index dc8cb6a33de..feb81b114b4 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7714,7 +7714,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -7815,6 +7815,61 @@ standards-compatible mode on s390 targets.])
>    ;;
>  esac
>  
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> +  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> +  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
> +case $target_os in
> +linux* | gnu*)
> +  # -fhardened is only supported on GNU/Linux.
> +  fhardened_support=yes
> +  ;;
> +*)
> +  fhardened_support=no
> +  ;;
> +esac
> +
> +AC_DEFINE_UNQUOTED(HAVE_FHARDENED_SUPPORT,
> +  [`if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if -fhardened is supported])
> +AC_MSG_RESULT($fhardened_support)
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>  
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 6e776a0faa1..7f145468950 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wformat-y2k  -Wframe-address
>  -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
>  -Wno-if-not-aligned  -Wno-ignored-attributes
> --Wignored-qualifiers  -Wno-incompatible-pointer-types
> +-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
>  -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
>  -Wno-implicit-function-declaration  -Wno-implicit-int
>  -Winfinite-recursion
> @@ -641,7 +641,7 @@ Objective-C and Objective-C++ Dialects}.
>  -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
>  -fsanitize-undefined-trap-on-error  -fbounds-check
>  -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches  -fhardened
>  -fharden-control-flow-redundancy  -fhardcfr-skip-leaf
>  -fhardcfr-check-exceptions  -fhardcfr-check-returning-calls
>  -fhardcfr-check-noreturn-calls=@r{[}always@r{|}no-xthrow@r{|}nothrow@r{|}never@r{]}
> @@ -6860,6 +6860,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
>  Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
>  This warning is enabled by @option{-Wall}.
>  
> +@opindex Whardened
> +@opindex Wno-hardened
> +@item -Whardened
> +Warn when @option{-fhardened} did not enable an option from its set (for
> +which see @option{-fhardened}).  For instance, using @option{-fhardened}
> +and @option{-fstack-protector} at the same time on the command line causes
> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
> +not enabled by @option{-fhardened}.
> +
> +This warning is enabled by default and has effect only when @option{-fhardened}
> +is enabled.
> +
>  @opindex Wimplicit-fallthrough
>  @opindex Wno-implicit-fallthrough
>  @item -Wimplicit-fallthrough
> @@ -17552,6 +17564,39 @@ made @option{no-xthrow} the default setting for this option: it excludes
>  from the @code{noreturn} treatment only internal functions used to
>  (re)raise exceptions, that are not affected by these optimizations.
>  
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI.  The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@c Keep this in sync with print_help_hardened!
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=zero
> +-fPIE  -pie  -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +This option is intended to be used in production builds, not merely
> +in debug builds.
> +
> +Currently, @option{-fhardened} is only supported on GNU/Linux targets.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line.  For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
>  @opindex fstack-protector
>  @item -fstack-protector
>  Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index 884284e66b4..a7e5774dcfa 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>     driver added to dumpdir after dumpbase or linker output name.  */
>  static bool dumpdir_trailing_dash_added = false;
>  
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> +   line.  */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line.  */
> +static bool static_p;
> +
>  /* Basename of dump and aux outputs, computed from dumpbase (given or
>     derived from output name), to override input_basename in non-%w %b
>     et al.  */
> @@ -4606,10 +4613,20 @@ driver_handle_option (struct gcc_options *opts,
>        save_switch ("-o", 1, &arg, validated, true);
>        return true;
>  
> -#ifdef ENABLE_DEFAULT_PIE
>      case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
>        /* -pie is turned on by default.  */
> +      validated = true;
>  #endif
> +    case OPT_r:
> +    case OPT_shared:
> +    case OPT_no_pie:
> +      any_link_options_p = true;
> +      break;
> +
> +    case OPT_static:
> +      static_p = true;
> +      break;
>  
>      case OPT_static_libgcc:
>      case OPT_shared_libgcc:
> @@ -4985,6 +5002,35 @@ process_command (unsigned int decoded_options_count,
>  #endif
>      }
>  
> +  /* TODO: check if -static -pie works and maybe use it.  */
> +  if (flag_hardened)
> +    {
> +      if (!any_link_options_p && !static_p)
> +	{
> +#ifdef HAVE_LD_PIE
> +	  save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> +	  /* These are passed straight down to collect2 so we have to break
> +	     it up like this.  */
> +	  if (HAVE_LD_NOW_SUPPORT)
> +	    {
> +	      add_infile ("-z", "*");
> +	      add_infile ("now", "*");
> +	    }
> +	  if (HAVE_LD_RELRO_SUPPORT)
> +	    {
> +	      add_infile ("-z", "*");
> +	      add_infile ("relro", "*");
> +	    }
> +	}
> +      /* We can't use OPT_Whardened yet.  Sigh.  */
> +      else if (warn_hardened)
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "linker hardening options not enabled by %<-fhardened%> "
> +		    "because other link options were specified on the command "
> +		    "line");
> +    }
> +
>    /* Handle -gtoggle as it would later in toplev.cc:process_options to
>       make the debug-level-gt spec function work as expected.  */
>    if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index f54cf8305ca..787f3f47db3 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
>  /* Set by -fcanon-prefix-map.  */
>  bool flag_canon_prefix_map;
>  
> +/* Set by finish_options when flag_stack_protector was set only because of
> +   -fhardened.  Yuck.  */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
>  static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>  
>  /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>        opts->x_flag_section_anchors = 0;
>      }
>  
> +  if (opts->x_flag_hardened)
> +    {
> +      if (!opts_set->x_flag_auto_var_init)
> +	opts->x_flag_auto_var_init = AUTO_INIT_ZERO;
> +      else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO)
> +	warning_at (loc, OPT_Whardened,
> +		    "%<-ftrivial-auto-var-init=zero%> is not enabled by "
> +		    "%<-fhardened%> because it was specified on the command "
> +		    "line");
> +    }
> +
>    if (!opts->x_flag_opts_finished)
>      {
>        /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>  	  /* We initialize opts->x_flag_pic to -1 so that we can tell if
>  	     -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
>  	  if (opts->x_flag_pic == -1)
> -	    opts->x_flag_pie = DEFAULT_FLAG_PIE;
> +	    opts->x_flag_pie = (opts->x_flag_hardened
> +				? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
>  	  else
>  	    opts->x_flag_pie = 0;
>  	}
> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>      }
>  
>    /* We initialize opts->x_flag_stack_protect to -1 so that targets
> -     can set a default value.  */
> +     can set a default value.  With --enable-default-ssp or -fhardened
> +     the default is -fstack-protector-strong.  */
>    if (opts->x_flag_stack_protect == -1)
> -    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    {
> +      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> +	 defined in such a way that it uses flag_stack_protect which can't
> +	 be used here.  Moreover, some targets like BPF don't support
> +	 -fstack-protector at all but we don't know that here.  So remember
> +	 that flag_stack_protect was set at the behest of -fhardened.  */
> +      if (opts->x_flag_hardened)
> +	{
> +	  opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> +	  flag_stack_protector_set_by_fhardened_p = true;
> +	}
> +      else
> +	opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    }
> +  else if (opts->x_flag_hardened
> +	   && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
> +    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +		"%<-fstack-protector-strong%> is not enabled by "
> +		"%<-fhardened%> because it was specified on the command "
> +		"line");
>  
>    if (opts->x_optimize == 0)
>      {
> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>    free (patch_area_arg);
>  }
>  
> +/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
> +
> +static void
> +print_help_hardened ()
> +{
> +  printf ("%s\n", "The following options are enabled by -fhardened:");
> +  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
> +	  (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> +  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
> +  printf ("  %s\n", "-ftrivial-auto-var-init=zero");
> +#ifdef HAVE_LD_PIE
> +  printf ("  %s  %s\n", "-fPIE", "-pie");
> +#endif
> +  if (HAVE_LD_NOW_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,now");
> +  if (HAVE_LD_RELRO_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,relro");
> +  printf ("  %s\n", "-fstack-protector-strong");
> +  printf ("  %s\n", "-fstack-clash-protection");
> +  printf ("  %s\n", "-fcf-protection=full");
> +  putchar ('\n');
> +}
> +
>  /* Print help when OPT__help_ is set.  */
>  
>  void
> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
>  	}
>        else if (lang_flag != 0)
>  	*pflags |= lang_flag;
> +      else if (strncasecmp (a, "hardened", len) == 0)
> +	print_help_hardened ();
>        else
>  	warning (0,
>  		 "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
>  /* Hold command-line options associated with stack limitation.  */
>  extern const char *opt_fstack_limit_symbol_arg;
>  extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
>  
>  /* Input file names.  */
>  
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..9d0a5772d9e
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..7e6740655fe
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..badebc56440
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..d1a973d177a
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..eb128f61ba3
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..8722e6d4b1a
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..04d6c8ff954
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
> new file mode 100644
> index 00000000000..86dc5220159
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-require-stack-check "specific" } */
> +/* { dg-options "-fhardened -O -fstack-check" } */
> +
> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..280ff96eb15
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> +
> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..f2306ca5d33
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers.  */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man.  */
> +
> +int
> +main ()
> +{
> +}
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
> new file mode 100644
> index 00000000000..312fabb95a5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
> +
> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..eb128f61ba3
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..d3cb7c8b353
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> +/* { dg-warning ".-ftrivial-auto-var-init=zero. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..b47bf43f360
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..85c9ad9103f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..4e4131f0bdd
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
>  # Listing only excludes gives empty results.
>  check_for_options c "--help=^joined,^separate" "" "" ""
>  
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
>  if [ info exists prev_columns ] {
>      # Reset the enviroment variable to its oriuginal value.
>      set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET.  */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> +  bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index 9a734890a18..841444d545c 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1567,6 +1567,13 @@ process_options ()
>        flag_associative_math = 0;
>      }
>  
> +  if (flag_hardened && !HAVE_FHARDENED_SUPPORT)
> +    {
> +      warning_at (UNKNOWN_LOCATION, 0,
> +		  "%<-fhardened%> not supported for this target");
> +      flag_hardened = 0;
> +    }
> +
>    /* -fstack-clash-protection is not currently supported on targets
>       where the stack grows up.  */
>    if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD)
> @@ -1576,6 +1583,19 @@ process_options ()
>  		  "where the stack grows from lower to higher addresses");
>        flag_stack_clash_protection = 0;
>      }
> +  else if (flag_hardened)
> +    {
> +      if (!flag_stack_clash_protection
> +	   /* Don't enable -fstack-clash-protection when -fstack-check=
> +	      is used: it would result in confusing errors.  */
> +	   && flag_stack_check == NO_STACK_CHECK)
> +	flag_stack_clash_protection = 1;
> +      else if (flag_stack_check != NO_STACK_CHECK)
> +	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +		    "%<-fstack-clash-protection%> is not enabled by "
> +		    "%<-fhardened%> because %<-fstack-check%> was "
> +		    "specified on the command line");
> +    }
>  
>    /* We cannot support -fstack-check= and -fstack-clash-protection at
>       the same time.  */
> @@ -1591,8 +1611,9 @@ process_options ()
>       target already uses a soft frame pointer, the transition is trivial.  */
>    if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>      {
> -      warning_at (UNKNOWN_LOCATION, 0,
> -		  "%<-fstack-protector%> not supported for this target");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "%<-fstack-protector%> not supported for this target");
>        flag_stack_protect = 0;
>      }
>    if (!flag_stack_protect)
> 
> base-commit: ae8abcb81ed81456c0fe5ff8e0c060c9fb9c82d7
> -- 
> 2.41.0
> 

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] gcc: Introduce -fhardened
  2023-11-03 22:51                 ` [PATCH v4] " Marek Polacek
  2023-11-13 15:41                   ` Marek Polacek
@ 2023-11-14  7:46                   ` Richard Biener
  2023-11-14 16:00                     ` Marek Polacek
  2023-11-15 12:25                   ` Jakub Jelinek
  2 siblings, 1 reply; 28+ messages in thread
From: Richard Biener @ 2023-11-14  7:46 UTC (permalink / raw)
  To: Marek Polacek; +Cc: iain, GCC Patches

On Fri, Nov 3, 2023 at 11:51 PM Marek Polacek <polacek@redhat.com> wrote:
>
> On Thu, Oct 26, 2023 at 05:55:56PM +0200, Richard Biener wrote:
> >
> >
> > > Am 24.10.2023 um 21:09 schrieb Marek Polacek <polacek@redhat.com>:
> > >
> > > On Tue, Oct 24, 2023 at 09:22:25AM +0200, Richard Biener wrote:
> > >>> On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
> > >>>
> > >>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> > >>>> Can you see how our
> > >>>> primary and secondary targets (+ host OS) behave here?
> > >>>
> > >>> That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
> > >>> that fails with:
> > >>>
> > >>> ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
> > >>> ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
> > >>> make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
> > >>> make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
> > >>>
> > >>> and I tried Darwin (104) and that fails with
> > >>>
> > >>> *** Configuration aarch64-apple-darwin21.6.0 not supported
> > >>>
> > >>> Is anyone else able to build gcc on those machines, or test the attached
> > >>> patch?
> > >>>
> > >>>> I think the
> > >>>> documentation should elaborate a bit on expectations for non-Linux/GNU
> > >>>> targets, specifically I think the default configuration for a target should
> > >>>> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> > >>>> have a testcase for this?
> > >>>
> > >>> Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
> > >>> something not supported on those systems, and it's something for which
> > >>> we have a configure test, then we shouldn't warn.  This is already the
> > >>> case for -pie, -z relro, and -z now.
> > >>
> > >> I was thinking of
> > >>
> > >> /* { dg-do compile } */
> > >> /* { dg-additional-options "-fhardened -Whardened" } */
> > >>
> > >> int main () {}
> > >>
> > >> and excess errors should catch "misconfigurations"?
> > >
> > > I see.  fhardened-3.c is basically just like this (-Whardened is on by default).
> > >
> > >>> Should the docs say something like the following for features without
> > >>> configure checks?
> > >>>
> > >>> @option{-fhardened} can, on certain systems, attempt to enable features
> > >>> not supported on that particular system.  In that case, it's possible to
> > >>> prevent the warning using the @option{-Wno-hardened} option.
> > >>
> > >> Yeah, but ideally
> > >>
> > >> @option{-fhardened} can, on certain systems, not enable features not
> > >> available on those systems and @option{-Whardened} will not diagnose
> > >> those as missing.
> > >>
> > >> But I understand it doesn't work like that?
> > >
> > > Right.  It will not diagnose missing features if they have a configure
> > > check, otherwise it will.  And I don't know if we want a configure check
> > > for every feature.  Maybe we can add them in the future if the current
> > > patch turns out to be problematical in practice?
> >
> > Maybe we can have a switch on known target triples and statically configure based
> > On that, eventually even not support -fhardened for targets not listed.  That’s certainly easier than detecting the target system features (think of cross compilers)
>
> You mean like the following?  The only difference is the addition of
> HAVE_FHARDENED_SUPPORT and updating the tests to only run on gnu/linux
> targets.  If other OSs want to use -fhardened, they need to update the
> configure test.  Thanks,

Yes, something like this.  IMHO we should aim to at least support all
our primary platforms (and maybe secondary if they have a relevant
host OS part).

> Bootstrapped/regtested on x86_64-pc-linux-gnu and
> powerpc64le-unknown-linux-gnu.
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags.  The read of the room seems to be that the option
> would be useful.  So here's a patch implementing that option.
>
> Currently, -fhardened enables:
>
>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>   -D_GLIBCXX_ASSERTIONS
>   -ftrivial-auto-var-init=zero
>   -fPIE  -pie  -Wl,-z,relro,-z,now
>   -fstack-protector-strong
>   -fstack-clash-protection
>   -fcf-protection=full (x86 GNU/Linux only)
>
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened).  For example,
>
>      -D_FORTIFY_SOURCE=1 -fhardened
>
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
>
>       -fhardened -fstack-protector
>
> will not enable -fstack-protector-strong.
>
> Currently, -fhardened is only supported on GNU/Linux.
>
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything.  This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option.  I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
>
> gcc/c-family/ChangeLog:
>
>         * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
>         and _GLIBCXX_ASSERTIONS.
>
> gcc/ChangeLog:
>
>         * common.opt (Whardened, fhardened): New options.
>         * config.in: Regenerate.
>         * config/bpf/bpf.cc: Include "opts.h".
>         (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
>         not inform that -fstack-protector does not work.
>         * config/i386/i386-options.cc (ix86_option_override_internal): When
>         -fhardened, maybe enable -fcf-protection=full.
>         * configure: Regenerate.
>         * configure.ac: Check if the linker supports '-z now' and '-z relro'.
>         Check if -fhardened is supported on $target_os.
>         * doc/invoke.texi: Document -fhardened and -Whardened.
>         * gcc.cc (driver_handle_option): Remember if any link options or -static
>         were specified on the command line.
>         (process_command): When -fhardened, maybe enable -pie and
>         -Wl,-z,relro,-z,now.
>         * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
>         (finish_options): When -fhardened, enable
>         -ftrivial-auto-var-init=zero and -fstack-protector-strong.
>         (print_help_hardened): New.
>         (print_help): Call it.
>         * toplev.cc (process_options): When -fhardened, enable
>         -fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
>         do not warn that -fstack-protector not supported for this target.
>         Don't enable -fhardened when !HAVE_FHARDENED_SUPPORT.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.misc-tests/help.exp: Test -fhardened.
>         * c-c++-common/fhardened-1.S: New test.
>         * c-c++-common/fhardened-1.c: New test.
>         * c-c++-common/fhardened-10.c: New test.
>         * c-c++-common/fhardened-11.c: New test.
>         * c-c++-common/fhardened-12.c: New test.
>         * c-c++-common/fhardened-13.c: New test.
>         * c-c++-common/fhardened-14.c: New test.
>         * c-c++-common/fhardened-15.c: New test.
>         * c-c++-common/fhardened-2.c: New test.
>         * c-c++-common/fhardened-3.c: New test.
>         * c-c++-common/fhardened-4.c: New test.
>         * c-c++-common/fhardened-5.c: New test.
>         * c-c++-common/fhardened-6.c: New test.
>         * c-c++-common/fhardened-7.c: New test.
>         * c-c++-common/fhardened-8.c: New test.
>         * c-c++-common/fhardened-9.c: New test.
>         * gcc.target/i386/cf_check-6.c: New test.
> ---
>  gcc/c-family/c-opts.cc                     | 42 +++++++++++++
>  gcc/common.opt                             |  8 +++
>  gcc/config.in                              | 18 ++++++
>  gcc/config/bpf/bpf.cc                      |  8 ++-
>  gcc/config/i386/i386-options.cc            | 17 ++++-
>  gcc/configure                              | 72 +++++++++++++++++++++-
>  gcc/configure.ac                           | 57 ++++++++++++++++-
>  gcc/doc/invoke.texi                        | 49 ++++++++++++++-
>  gcc/gcc.cc                                 | 48 ++++++++++++++-
>  gcc/opts.cc                                | 67 +++++++++++++++++++-
>  gcc/opts.h                                 |  1 +
>  gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-11.c  | 10 +++
>  gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
>  gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
>  gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
>  gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
>  gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
>  gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
>  gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
>  gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
>  gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
>  gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
>  gcc/toplev.cc                              | 25 +++++++-
>  30 files changed, 556 insertions(+), 16 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
>  create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index e9f7e6d424d..26f009f2da5 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1556,6 +1556,9 @@ c_finish_options (void)
>        cb_file_change (parse_in, cmd_map);
>        linemap_line_start (line_table, 0, 1);
>
> +      bool fortify_seen_p = false;
> +      bool cxx_assert_seen_p = false;
> +
>        /* All command line defines must have the same location.  */
>        cpp_force_token_locations (parse_in, line_table->highest_line);
>        for (size_t i = 0; i < deferred_count; i++)
> @@ -1573,6 +1576,45 @@ c_finish_options (void)
>               else
>                 cpp_assert (parse_in, opt->arg);
>             }
> +
> +         if (UNLIKELY (flag_hardened)
> +             && (opt->code == OPT_D || opt->code == OPT_U))
> +           {
> +             if (!fortify_seen_p)
> +               fortify_seen_p
> +                 = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> +                    && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> +             if (!cxx_assert_seen_p)
> +               cxx_assert_seen_p
> +                 = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> +                    && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> +           }
> +       }
> +
> +      if (flag_hardened)
> +       {
> +         if (!fortify_seen_p && optimize > 0)
> +           {
> +             if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> +             else
> +               cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> +           }
> +         else if (optimize == 0)
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +                       "because optimizations are turned off");
> +         else
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> +                       "because it was specified in %<-D%> or %<-U%>");
> +         if (!cxx_assert_seen_p)
> +           cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
> +         else
> +           warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                       "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
> +                       "%<-fhardened%> because it was specified in %<-D%> "
> +                       "or %<-U%>");
>         }
>
>        cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 1cf3bdd3b51..48a15f077ef 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -634,6 +634,10 @@ Wfree-nonheap-object
>  Common Var(warn_free_nonheap_object) Init(1) Warning
>  Warn when attempting to free a non-heap object.
>
> +Whardened
> +Common Var(warn_hardened) Init(1) Warning
> +Warn when -fhardened did not enable an option from its set.
> +
>  Whsa
>  Common Ignore Warning
>  Does nothing.  Preserved for backward compatibility.
> @@ -1823,6 +1827,10 @@ fguess-branch-probability
>  Common Var(flag_guess_branch_prob) Optimization
>  Enable guessing of branch probabilities.
>
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
>  fharden-compares
>  Common Var(flag_harden_compares) Optimization
>  Harden conditionals not used in branches, checking reversed conditions.
> diff --git a/gcc/config.in b/gcc/config.in
> index 03faee1c6ac..97b483ddd97 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1293,6 +1293,12 @@
>  #endif
>
>
> +/* Define 0/1 if -fhardened is supported */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_FHARDENED_SUPPORT
> +#endif
> +
> +
>  /* Define to 1 if you have the `fileno_unlocked' function. */
>  #ifndef USED_FOR_TARGET
>  #undef HAVE_FILENO_UNLOCKED
> @@ -1695,6 +1701,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
>  /* Define if your PowerPC64 linker only needs function descriptor syms. */
>  #ifndef USED_FOR_TARGET
>  #undef HAVE_LD_NO_DOT_SYMS
> @@ -1738,6 +1750,12 @@
>  #endif
>
>
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
>  /* Define if your linker links a mix of read-only and read-write sections into
>     a read-write section. */
>  #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 63637ece78e..804f6f3304a 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimplify-me.h"
>
>  #include "core-builtins.h"
> +#include "opts.h"
>
>  /* Per-function machine data.  */
>  struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
>    /* Disable -fstack-protector as it is not supported in BPF.  */
>    if (flag_stack_protect)
>      {
> -      inform (input_location,
> -              "%<-fstack-protector%> does not work "
> -             "on this architecture");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       inform (input_location,
> +               "%<-fstack-protector%> does not work "
> +               "on this architecture");
>        flag_stack_protect = 0;
>      }
>
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index df7d24352d1..76adba672b9 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3072,10 +3072,25 @@ ix86_option_override_internal (bool main_args_p,
>          = build_target_option_node (opts, opts_set);
>      }
>
> +  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> +  /* When -fhardened, enable -fcf-protection=full, but only when it's
> +     compatible with this target, and when it wasn't already specified
> +     on the command line.  */
> +  if (opts->x_flag_hardened && cf_okay_p)
> +    {
> +      if (opts->x_flag_cf_protection == CF_NONE)
> +       opts->x_flag_cf_protection = CF_FULL;
> +      else if (opts->x_flag_cf_protection != CF_FULL)
> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                   "%<-fcf-protection=full%> is not enabled by "
> +                   "%<-fhardened%> because it was specified on the command "
> +                   "line");
> +    }
> +
>    if (opts->x_flag_cf_protection != CF_NONE)
>      {
>        if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> -         && !TARGET_64BIT && !TARGET_CMOV)
> +         && !cf_okay_p)
>         error ("%<-fcf-protection%> is not compatible with this target");
>
>        opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index d4ad988000f..e701f6be063 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -20000,7 +20000,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 19995 "configure"
> +#line 20003 "configure"
>  #include "confdefs.h"
>
>  #if HAVE_DLFCN_H
> @@ -20106,7 +20106,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 20101 "configure"
> +#line 20109 "configure"
>  #include "confdefs.h"
>
>  #if HAVE_DLFCN_H
> @@ -32903,7 +32903,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -33032,6 +33032,72 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
> +case $target_os in
> +linux* | gnu*)
> +  # -fhardened is only supported on GNU/Linux.
> +  fhardened_support=yes
> +  ;;
> +*)
> +  fhardened_support=no
> +  ;;
> +esac
> +
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_FHARDENED_SUPPORT `if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fhardened_support" >&5
> +$as_echo "$fhardened_support" >&6; }
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index dc8cb6a33de..feb81b114b4 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7714,7 +7714,7 @@ if test x"$ld_is_gold" = xno; then
>        ld_bndplt_support=yes
>      fi
>    elif test x$gcc_cv_ld != x; then
> -    # Check if linker supports -a bndplt option
> +    # Check if linker supports -z bndplt option
>      if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>        ld_bndplt_support=yes
>      fi
> @@ -7815,6 +7815,61 @@ standards-compatible mode on s390 targets.])
>    ;;
>  esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_now_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z now
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> +    ld_now_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> +  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> +  ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> +  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> +    ld_relro_support=yes
> +  fi
> +elif test x$gcc_cv_ld != x; then
> +  # Check if linker supports -z relro
> +  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> +    ld_relro_support=yes
> +  fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> +  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
> +case $target_os in
> +linux* | gnu*)
> +  # -fhardened is only supported on GNU/Linux.
> +  fhardened_support=yes
> +  ;;
> +*)
> +  fhardened_support=no
> +  ;;
> +esac
> +
> +AC_DEFINE_UNQUOTED(HAVE_FHARDENED_SUPPORT,
> +  [`if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`],
> +  [Define 0/1 if -fhardened is supported])
> +AC_MSG_RESULT($fhardened_support)
> +
>  # Configure the subdirectories
>  # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 6e776a0faa1..7f145468950 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wformat-y2k  -Wframe-address
>  -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
>  -Wno-if-not-aligned  -Wno-ignored-attributes
> --Wignored-qualifiers  -Wno-incompatible-pointer-types
> +-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
>  -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
>  -Wno-implicit-function-declaration  -Wno-implicit-int
>  -Winfinite-recursion
> @@ -641,7 +641,7 @@ Objective-C and Objective-C++ Dialects}.
>  -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
>  -fsanitize-undefined-trap-on-error  -fbounds-check
>  -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches  -fhardened
>  -fharden-control-flow-redundancy  -fhardcfr-skip-leaf
>  -fhardcfr-check-exceptions  -fhardcfr-check-returning-calls
>  -fhardcfr-check-noreturn-calls=@r{[}always@r{|}no-xthrow@r{|}nothrow@r{|}never@r{]}
> @@ -6860,6 +6860,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
>  Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
>  This warning is enabled by @option{-Wall}.
>
> +@opindex Whardened
> +@opindex Wno-hardened
> +@item -Whardened
> +Warn when @option{-fhardened} did not enable an option from its set (for
> +which see @option{-fhardened}).  For instance, using @option{-fhardened}
> +and @option{-fstack-protector} at the same time on the command line causes
> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
> +not enabled by @option{-fhardened}.
> +
> +This warning is enabled by default and has effect only when @option{-fhardened}
> +is enabled.
> +
>  @opindex Wimplicit-fallthrough
>  @opindex Wno-implicit-fallthrough
>  @item -Wimplicit-fallthrough
> @@ -17552,6 +17564,39 @@ made @option{no-xthrow} the default setting for this option: it excludes
>  from the @code{noreturn} treatment only internal functions used to
>  (re)raise exceptions, that are not affected by these optimizations.
>
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI.  The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@c Keep this in sync with print_help_hardened!
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=zero
> +-fPIE  -pie  -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +This option is intended to be used in production builds, not merely
> +in debug builds.
> +
> +Currently, @option{-fhardened} is only supported on GNU/Linux targets.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line.  For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
>  @opindex fstack-protector
>  @item -fstack-protector
>  Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index 884284e66b4..a7e5774dcfa 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>     driver added to dumpdir after dumpbase or linker output name.  */
>  static bool dumpdir_trailing_dash_added = false;
>
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> +   line.  */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line.  */
> +static bool static_p;
> +
>  /* Basename of dump and aux outputs, computed from dumpbase (given or
>     derived from output name), to override input_basename in non-%w %b
>     et al.  */
> @@ -4606,10 +4613,20 @@ driver_handle_option (struct gcc_options *opts,
>        save_switch ("-o", 1, &arg, validated, true);
>        return true;
>
> -#ifdef ENABLE_DEFAULT_PIE
>      case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
>        /* -pie is turned on by default.  */
> +      validated = true;
>  #endif
> +    case OPT_r:
> +    case OPT_shared:
> +    case OPT_no_pie:
> +      any_link_options_p = true;
> +      break;
> +
> +    case OPT_static:
> +      static_p = true;
> +      break;
>
>      case OPT_static_libgcc:
>      case OPT_shared_libgcc:
> @@ -4985,6 +5002,35 @@ process_command (unsigned int decoded_options_count,
>  #endif
>      }
>
> +  /* TODO: check if -static -pie works and maybe use it.  */
> +  if (flag_hardened)
> +    {
> +      if (!any_link_options_p && !static_p)
> +       {
> +#ifdef HAVE_LD_PIE
> +         save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> +         /* These are passed straight down to collect2 so we have to break
> +            it up like this.  */
> +         if (HAVE_LD_NOW_SUPPORT)
> +           {
> +             add_infile ("-z", "*");
> +             add_infile ("now", "*");
> +           }
> +         if (HAVE_LD_RELRO_SUPPORT)
> +           {
> +             add_infile ("-z", "*");
> +             add_infile ("relro", "*");
> +           }
> +       }
> +      /* We can't use OPT_Whardened yet.  Sigh.  */
> +      else if (warn_hardened)
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "linker hardening options not enabled by %<-fhardened%> "
> +                   "because other link options were specified on the command "
> +                   "line");
> +    }
> +
>    /* Handle -gtoggle as it would later in toplev.cc:process_options to
>       make the debug-level-gt spec function work as expected.  */
>    if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index f54cf8305ca..787f3f47db3 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3.  If not see
>  /* Set by -fcanon-prefix-map.  */
>  bool flag_canon_prefix_map;
>
> +/* Set by finish_options when flag_stack_protector was set only because of
> +   -fhardened.  Yuck.  */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
>  static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>
>  /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>        opts->x_flag_section_anchors = 0;
>      }
>
> +  if (opts->x_flag_hardened)
> +    {
> +      if (!opts_set->x_flag_auto_var_init)
> +       opts->x_flag_auto_var_init = AUTO_INIT_ZERO;
> +      else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO)
> +       warning_at (loc, OPT_Whardened,
> +                   "%<-ftrivial-auto-var-init=zero%> is not enabled by "
> +                   "%<-fhardened%> because it was specified on the command "
> +                   "line");
> +    }
> +
>    if (!opts->x_flag_opts_finished)
>      {
>        /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>           /* We initialize opts->x_flag_pic to -1 so that we can tell if
>              -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
>           if (opts->x_flag_pic == -1)
> -           opts->x_flag_pie = DEFAULT_FLAG_PIE;
> +           opts->x_flag_pie = (opts->x_flag_hardened
> +                               ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
>           else
>             opts->x_flag_pie = 0;
>         }
> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>      }
>
>    /* We initialize opts->x_flag_stack_protect to -1 so that targets
> -     can set a default value.  */
> +     can set a default value.  With --enable-default-ssp or -fhardened
> +     the default is -fstack-protector-strong.  */
>    if (opts->x_flag_stack_protect == -1)
> -    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    {
> +      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> +        defined in such a way that it uses flag_stack_protect which can't
> +        be used here.  Moreover, some targets like BPF don't support
> +        -fstack-protector at all but we don't know that here.  So remember
> +        that flag_stack_protect was set at the behest of -fhardened.  */
> +      if (opts->x_flag_hardened)
> +       {
> +         opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> +         flag_stack_protector_set_by_fhardened_p = true;
> +       }
> +      else
> +       opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> +    }
> +  else if (opts->x_flag_hardened
> +          && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
> +    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +               "%<-fstack-protector-strong%> is not enabled by "
> +               "%<-fhardened%> because it was specified on the command "
> +               "line");
>
>    if (opts->x_optimize == 0)
>      {
> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>    free (patch_area_arg);
>  }
>
> +/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
> +
> +static void
> +print_help_hardened ()
> +{
> +  printf ("%s\n", "The following options are enabled by -fhardened:");
> +  printf ("  %s=%d\n", "-D_FORTIFY_SOURCE",
> +         (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> +  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
> +  printf ("  %s\n", "-ftrivial-auto-var-init=zero");
> +#ifdef HAVE_LD_PIE
> +  printf ("  %s  %s\n", "-fPIE", "-pie");
> +#endif
> +  if (HAVE_LD_NOW_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,now");
> +  if (HAVE_LD_RELRO_SUPPORT)
> +    printf ("  %s\n", "-Wl,-z,relro");
> +  printf ("  %s\n", "-fstack-protector-strong");
> +  printf ("  %s\n", "-fstack-clash-protection");
> +  printf ("  %s\n", "-fcf-protection=full");
> +  putchar ('\n');
> +}
> +
>  /* Print help when OPT__help_ is set.  */
>
>  void
> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
>         }
>        else if (lang_flag != 0)
>         *pflags |= lang_flag;
> +      else if (strncasecmp (a, "hardened", len) == 0)
> +       print_help_hardened ();
>        else
>         warning (0,
>                  "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
>  /* Hold command-line options associated with stack limitation.  */
>  extern const char *opt_fstack_limit_symbol_arg;
>  extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
>
>  /* Input file names.  */
>
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..9d0a5772d9e
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..7e6740655fe
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..badebc56440
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..d1a973d177a
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..eb128f61ba3
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..8722e6d4b1a
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..04d6c8ff954
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
> new file mode 100644
> index 00000000000..86dc5220159
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-require-stack-check "specific" } */
> +/* { dg-options "-fhardened -O -fstack-check" } */
> +
> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..280ff96eb15
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> +
> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..f2306ca5d33
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers.  */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man.  */
> +
> +int
> +main ()
> +{
> +}
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
> new file mode 100644
> index 00000000000..312fabb95a5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
> +
> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..eb128f61ba3
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..d3cb7c8b353
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> +  int i;
> +  return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> +/* { dg-warning ".-ftrivial-auto-var-init=zero. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..b47bf43f360
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..85c9ad9103f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
> +/* { dg-options "-fhardened -O -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..4e4131f0bdd
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
>  # Listing only excludes gives empty results.
>  check_for_options c "--help=^joined,^separate" "" "" ""
>
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
>  if [ info exists prev_columns ] {
>      # Reset the enviroment variable to its oriuginal value.
>      set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET.  */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> +  bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index 9a734890a18..841444d545c 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1567,6 +1567,13 @@ process_options ()
>        flag_associative_math = 0;
>      }
>
> +  if (flag_hardened && !HAVE_FHARDENED_SUPPORT)
> +    {
> +      warning_at (UNKNOWN_LOCATION, 0,
> +                 "%<-fhardened%> not supported for this target");
> +      flag_hardened = 0;
> +    }
> +
>    /* -fstack-clash-protection is not currently supported on targets
>       where the stack grows up.  */
>    if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD)
> @@ -1576,6 +1583,19 @@ process_options ()
>                   "where the stack grows from lower to higher addresses");
>        flag_stack_clash_protection = 0;
>      }
> +  else if (flag_hardened)
> +    {
> +      if (!flag_stack_clash_protection
> +          /* Don't enable -fstack-clash-protection when -fstack-check=
> +             is used: it would result in confusing errors.  */
> +          && flag_stack_check == NO_STACK_CHECK)
> +       flag_stack_clash_protection = 1;
> +      else if (flag_stack_check != NO_STACK_CHECK)
> +       warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> +                   "%<-fstack-clash-protection%> is not enabled by "
> +                   "%<-fhardened%> because %<-fstack-check%> was "
> +                   "specified on the command line");
> +    }
>
>    /* We cannot support -fstack-check= and -fstack-clash-protection at
>       the same time.  */
> @@ -1591,8 +1611,9 @@ process_options ()
>       target already uses a soft frame pointer, the transition is trivial.  */
>    if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>      {
> -      warning_at (UNKNOWN_LOCATION, 0,
> -                 "%<-fstack-protector%> not supported for this target");
> +      if (!flag_stack_protector_set_by_fhardened_p)
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "%<-fstack-protector%> not supported for this target");
>        flag_stack_protect = 0;
>      }
>    if (!flag_stack_protect)
>
> base-commit: ae8abcb81ed81456c0fe5ff8e0c060c9fb9c82d7
> --
> 2.41.0
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] gcc: Introduce -fhardened
  2023-11-14  7:46                   ` Richard Biener
@ 2023-11-14 16:00                     ` Marek Polacek
  2023-11-15 11:42                       ` Richard Biener
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2023-11-14 16:00 UTC (permalink / raw)
  To: Richard Biener; +Cc: iain, GCC Patches

On Tue, Nov 14, 2023 at 08:46:16AM +0100, Richard Biener wrote:
> On Fri, Nov 3, 2023 at 11:51 PM Marek Polacek <polacek@redhat.com> wrote:
> >
> > On Thu, Oct 26, 2023 at 05:55:56PM +0200, Richard Biener wrote:
> > >
> > >
> > > > Am 24.10.2023 um 21:09 schrieb Marek Polacek <polacek@redhat.com>:
> > > >
> > > > On Tue, Oct 24, 2023 at 09:22:25AM +0200, Richard Biener wrote:
> > > >>> On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
> > > >>>
> > > >>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> > > >>>> Can you see how our
> > > >>>> primary and secondary targets (+ host OS) behave here?
> > > >>>
> > > >>> That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
> > > >>> that fails with:
> > > >>>
> > > >>> ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
> > > >>> ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
> > > >>> make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
> > > >>> make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
> > > >>>
> > > >>> and I tried Darwin (104) and that fails with
> > > >>>
> > > >>> *** Configuration aarch64-apple-darwin21.6.0 not supported
> > > >>>
> > > >>> Is anyone else able to build gcc on those machines, or test the attached
> > > >>> patch?
> > > >>>
> > > >>>> I think the
> > > >>>> documentation should elaborate a bit on expectations for non-Linux/GNU
> > > >>>> targets, specifically I think the default configuration for a target should
> > > >>>> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> > > >>>> have a testcase for this?
> > > >>>
> > > >>> Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
> > > >>> something not supported on those systems, and it's something for which
> > > >>> we have a configure test, then we shouldn't warn.  This is already the
> > > >>> case for -pie, -z relro, and -z now.
> > > >>
> > > >> I was thinking of
> > > >>
> > > >> /* { dg-do compile } */
> > > >> /* { dg-additional-options "-fhardened -Whardened" } */
> > > >>
> > > >> int main () {}
> > > >>
> > > >> and excess errors should catch "misconfigurations"?
> > > >
> > > > I see.  fhardened-3.c is basically just like this (-Whardened is on by default).
> > > >
> > > >>> Should the docs say something like the following for features without
> > > >>> configure checks?
> > > >>>
> > > >>> @option{-fhardened} can, on certain systems, attempt to enable features
> > > >>> not supported on that particular system.  In that case, it's possible to
> > > >>> prevent the warning using the @option{-Wno-hardened} option.
> > > >>
> > > >> Yeah, but ideally
> > > >>
> > > >> @option{-fhardened} can, on certain systems, not enable features not
> > > >> available on those systems and @option{-Whardened} will not diagnose
> > > >> those as missing.
> > > >>
> > > >> But I understand it doesn't work like that?
> > > >
> > > > Right.  It will not diagnose missing features if they have a configure
> > > > check, otherwise it will.  And I don't know if we want a configure check
> > > > for every feature.  Maybe we can add them in the future if the current
> > > > patch turns out to be problematical in practice?
> > >
> > > Maybe we can have a switch on known target triples and statically configure based
> > > On that, eventually even not support -fhardened for targets not listed.  That’s certainly easier than detecting the target system features (think of cross compilers)
> >
> > You mean like the following?  The only difference is the addition of
> > HAVE_FHARDENED_SUPPORT and updating the tests to only run on gnu/linux
> > targets.  If other OSs want to use -fhardened, they need to update the
> > configure test.  Thanks,
> 
> Yes, something like this.  IMHO we should aim to at least support all
> our primary platforms (and maybe secondary if they have a relevant
> host OS part).

That sounds good.  Do you want to see any other changes in this patch
or are you fine with it as-is (provided that someone else also acks it)?

Thanks,

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] gcc: Introduce -fhardened
  2023-11-14 16:00                     ` Marek Polacek
@ 2023-11-15 11:42                       ` Richard Biener
  0 siblings, 0 replies; 28+ messages in thread
From: Richard Biener @ 2023-11-15 11:42 UTC (permalink / raw)
  To: Marek Polacek; +Cc: iain, GCC Patches

On Tue, Nov 14, 2023 at 5:00 PM Marek Polacek <polacek@redhat.com> wrote:
>
> On Tue, Nov 14, 2023 at 08:46:16AM +0100, Richard Biener wrote:
> > On Fri, Nov 3, 2023 at 11:51 PM Marek Polacek <polacek@redhat.com> wrote:
> > >
> > > On Thu, Oct 26, 2023 at 05:55:56PM +0200, Richard Biener wrote:
> > > >
> > > >
> > > > > Am 24.10.2023 um 21:09 schrieb Marek Polacek <polacek@redhat.com>:
> > > > >
> > > > > On Tue, Oct 24, 2023 at 09:22:25AM +0200, Richard Biener wrote:
> > > > >>> On Mon, Oct 23, 2023 at 9:26 PM Marek Polacek <polacek@redhat.com> wrote:
> > > > >>>
> > > > >>> On Thu, Oct 19, 2023 at 02:24:11PM +0200, Richard Biener wrote:
> > > > >>>> Can you see how our
> > > > >>>> primary and secondary targets (+ host OS) behave here?
> > > > >>>
> > > > >>> That's very reasonable.  I tried to build gcc on Compile Farm 119 (AIX) but
> > > > >>> that fails with:
> > > > >>>
> > > > >>> ar  -X64 x ../ppc64/libgcc/libgcc_s.a shr.o
> > > > >>> ar: 0707-100 ../ppc64/libgcc/libgcc_s.a does not exist.
> > > > >>> make[2]: *** [/home/polacek/gcc/libgcc/config/rs6000/t-slibgcc-aix:98: all] Error 1
> > > > >>> make[2]: Leaving directory '/home/polacek/x/trunk/powerpc-ibm-aix7.3.1.0/libgcc'
> > > > >>>
> > > > >>> and I tried Darwin (104) and that fails with
> > > > >>>
> > > > >>> *** Configuration aarch64-apple-darwin21.6.0 not supported
> > > > >>>
> > > > >>> Is anyone else able to build gcc on those machines, or test the attached
> > > > >>> patch?
> > > > >>>
> > > > >>>> I think the
> > > > >>>> documentation should elaborate a bit on expectations for non-Linux/GNU
> > > > >>>> targets, specifically I think the default configuration for a target should
> > > > >>>> with -fhardened _not_ have any -Whardened diagnostics.  Maybe we can
> > > > >>>> have a testcase for this?
> > > > >>>
> > > > >>> Sorry, I'm not sure how to test that.  I suppose if -fhardened enables
> > > > >>> something not supported on those systems, and it's something for which
> > > > >>> we have a configure test, then we shouldn't warn.  This is already the
> > > > >>> case for -pie, -z relro, and -z now.
> > > > >>
> > > > >> I was thinking of
> > > > >>
> > > > >> /* { dg-do compile } */
> > > > >> /* { dg-additional-options "-fhardened -Whardened" } */
> > > > >>
> > > > >> int main () {}
> > > > >>
> > > > >> and excess errors should catch "misconfigurations"?
> > > > >
> > > > > I see.  fhardened-3.c is basically just like this (-Whardened is on by default).
> > > > >
> > > > >>> Should the docs say something like the following for features without
> > > > >>> configure checks?
> > > > >>>
> > > > >>> @option{-fhardened} can, on certain systems, attempt to enable features
> > > > >>> not supported on that particular system.  In that case, it's possible to
> > > > >>> prevent the warning using the @option{-Wno-hardened} option.
> > > > >>
> > > > >> Yeah, but ideally
> > > > >>
> > > > >> @option{-fhardened} can, on certain systems, not enable features not
> > > > >> available on those systems and @option{-Whardened} will not diagnose
> > > > >> those as missing.
> > > > >>
> > > > >> But I understand it doesn't work like that?
> > > > >
> > > > > Right.  It will not diagnose missing features if they have a configure
> > > > > check, otherwise it will.  And I don't know if we want a configure check
> > > > > for every feature.  Maybe we can add them in the future if the current
> > > > > patch turns out to be problematical in practice?
> > > >
> > > > Maybe we can have a switch on known target triples and statically configure based
> > > > On that, eventually even not support -fhardened for targets not listed.  That’s certainly easier than detecting the target system features (think of cross compilers)
> > >
> > > You mean like the following?  The only difference is the addition of
> > > HAVE_FHARDENED_SUPPORT and updating the tests to only run on gnu/linux
> > > targets.  If other OSs want to use -fhardened, they need to update the
> > > configure test.  Thanks,
> >
> > Yes, something like this.  IMHO we should aim to at least support all
> > our primary platforms (and maybe secondary if they have a relevant
> > host OS part).
>
> That sounds good.  Do you want to see any other changes in this patch
> or are you fine with it as-is (provided that someone else also acks it)?

I'm fine with it as-is if somebody else also acks it.

Richard.

> Thanks,
>
> Marek
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] gcc: Introduce -fhardened
  2023-11-03 22:51                 ` [PATCH v4] " Marek Polacek
  2023-11-13 15:41                   ` Marek Polacek
  2023-11-14  7:46                   ` Richard Biener
@ 2023-11-15 12:25                   ` Jakub Jelinek
  2023-11-16 20:51                     ` [PATCH v5] " Marek Polacek
  2 siblings, 1 reply; 28+ messages in thread
From: Jakub Jelinek @ 2023-11-15 12:25 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, iain, GCC Patches

On Fri, Nov 03, 2023 at 06:51:16PM -0400, Marek Polacek wrote:
> +      if (flag_hardened)
> +	{
> +	  if (!fortify_seen_p && optimize > 0)
> +	    {
> +	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> +		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> +	      else
> +		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> +	    }

I don't like the above in generic code, the fact that gcc was configured
against glibc target headers doesn't mean it is targetting glibc.
E.g. for most *-linux* targets, config/linux.opt provides the
-mbionic/-mglibc/-muclibc/-mmusl options.

One ugly way around would be to do
#ifdef OPTION_GLIBC
  if (OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
    cpp_define (parse_in, "_FORTIFY_SOURCE=3");
  else
#endif
    cpp_define (parse_in, "_FORTIFY_SOURCE=2");
(assuming OPTION_GLIBC at that point is already computed); a cleaner way
would be to introduce a target hook for that, say
fortify_source_default_level or something similar, where the default hook
would return 2 and next to linux_libc_has_function one would override it
for OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35
to 3.  That way, in the future other targets (say *BSD) can choose to do
something similar more easily.

The rest LGTM.

	Jakub


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v5] gcc: Introduce -fhardened
  2023-11-15 12:25                   ` Jakub Jelinek
@ 2023-11-16 20:51                     ` Marek Polacek
  2023-11-20 16:32                       ` Jakub Jelinek
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2023-11-16 20:51 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, iain, GCC Patches

On Wed, Nov 15, 2023 at 01:25:27PM +0100, Jakub Jelinek wrote:
> On Fri, Nov 03, 2023 at 06:51:16PM -0400, Marek Polacek wrote:
> > +      if (flag_hardened)
> > +	{
> > +	  if (!fortify_seen_p && optimize > 0)
> > +	    {
> > +	      if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> > +		cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> > +	      else
> > +		cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> > +	    }
> 
> I don't like the above in generic code, the fact that gcc was configured
> against glibc target headers doesn't mean it is targetting glibc.
> E.g. for most *-linux* targets, config/linux.opt provides the
> -mbionic/-mglibc/-muclibc/-mmusl options.
> 
> One ugly way around would be to do
> #ifdef OPTION_GLIBC
>   if (OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
>     cpp_define (parse_in, "_FORTIFY_SOURCE=3");
>   else
> #endif
>     cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> (assuming OPTION_GLIBC at that point is already computed); a cleaner way
> would be to introduce a target hook for that, say
> fortify_source_default_level or something similar, where the default hook
> would return 2 and next to linux_libc_has_function one would override it
> for OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35
> to 3.  That way, in the future other targets (say *BSD) can choose to do
> something similar more easily.

Thanks, that's a good point.  In this version I've added a target hook.

On my system, -D_FORTIFY_SOURCE=3 will be used, and if I remove
linux_fortify_source_default_level it's =2 as expected.

The only problem was that it doesn't seem to be possible to use
targetm. in opts.cc -- I get an undefined reference.  But since
the opts.cc use is for --help only, it's not a big deal either way.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
I proposed -fhardened, a new umbrella option that enables a reasonable set
of hardening flags.  The read of the room seems to be that the option
would be useful.  So here's a patch implementing that option.

Currently, -fhardened enables:

  -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
  -D_GLIBCXX_ASSERTIONS
  -ftrivial-auto-var-init=zero
  -fPIE  -pie  -Wl,-z,relro,-z,now
  -fstack-protector-strong
  -fstack-clash-protection
  -fcf-protection=full (x86 GNU/Linux only)

-fhardened will not override options that were specified on the command line
(before or after -fhardened).  For example,

     -D_FORTIFY_SOURCE=1 -fhardened

means that _FORTIFY_SOURCE=1 will be used.  Similarly,

      -fhardened -fstack-protector

will not enable -fstack-protector-strong.

Currently, -fhardened is only supported on GNU/Linux.

In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
to anything.  This patch provides -Whardened, enabled by default, which
warns when -fhardened couldn't enable a particular option.  I think most
often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
were not enabled.

gcc/c-family/ChangeLog:

	* c-opts.cc: Include "target.h".
	(c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
	and _GLIBCXX_ASSERTIONS.

gcc/ChangeLog:

	* common.opt (Whardened, fhardened): New options.
	* config.in: Regenerate.
	* config/bpf/bpf.cc: Include "opts.h".
	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
	not inform that -fstack-protector does not work.
	* config/i386/i386-options.cc (ix86_option_override_internal): When
	-fhardened, maybe enable -fcf-protection=full.
	* config/linux-protos.h (linux_fortify_source_default_level): Declare.
	* config/linux.cc (linux_fortify_source_default_level): New.
	* config/linux.h (TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL): Redefine.
	* configure: Regenerate.
	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
	Check if -fhardened is supported on $target_os.
	* doc/invoke.texi: Document -fhardened and -Whardened.
	* doc/tm.texi: Regenerate.
	* doc/tm.texi.in (TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL): Add.
	* gcc.cc (driver_handle_option): Remember if any link options or -static
	were specified on the command line.
	(process_command): When -fhardened, maybe enable -pie and
	-Wl,-z,relro,-z,now.
	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
	(finish_options): When -fhardened, enable
	-ftrivial-auto-var-init=zero and -fstack-protector-strong.
	(print_help_hardened): New.
	(print_help): Call it.
	* target.def (fortify_source_default_level): New target hook.
	* targhooks.cc (default_fortify_source_default_level): New.
	* targhooks.h (default_fortify_source_default_level): Declare.
	* toplev.cc (process_options): When -fhardened, enable
	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
	do not warn that -fstack-protector not supported for this target.
	Don't enable -fhardened when !HAVE_FHARDENED_SUPPORT.

gcc/testsuite/ChangeLog:

	* gcc.misc-tests/help.exp: Test -fhardened.
	* c-c++-common/fhardened-1.S: New test.
	* c-c++-common/fhardened-1.c: New test.
	* c-c++-common/fhardened-10.c: New test.
	* c-c++-common/fhardened-11.c: New test.
	* c-c++-common/fhardened-12.c: New test.
	* c-c++-common/fhardened-13.c: New test.
	* c-c++-common/fhardened-14.c: New test.
	* c-c++-common/fhardened-15.c: New test.
	* c-c++-common/fhardened-2.c: New test.
	* c-c++-common/fhardened-3.c: New test.
	* c-c++-common/fhardened-4.c: New test.
	* c-c++-common/fhardened-5.c: New test.
	* c-c++-common/fhardened-6.c: New test.
	* c-c++-common/fhardened-7.c: New test.
	* c-c++-common/fhardened-8.c: New test.
	* c-c++-common/fhardened-9.c: New test.
	* gcc.target/i386/cf_check-6.c: New test.
---
 gcc/c-family/c-opts.cc                     | 39 +++++++++++++
 gcc/common.opt                             |  8 +++
 gcc/config.in                              | 18 ++++++
 gcc/config/bpf/bpf.cc                      |  8 ++-
 gcc/config/i386/i386-options.cc            | 17 +++++-
 gcc/config/linux-protos.h                  |  1 +
 gcc/config/linux.cc                        |  9 +++
 gcc/config/linux.h                         |  3 +
 gcc/configure                              | 68 +++++++++++++++++++++-
 gcc/configure.ac                           | 57 +++++++++++++++++-
 gcc/doc/invoke.texi                        | 49 +++++++++++++++-
 gcc/doc/tm.texi                            |  5 ++
 gcc/doc/tm.texi.in                         |  2 +
 gcc/gcc.cc                                 | 48 ++++++++++++++-
 gcc/opts.cc                                | 68 +++++++++++++++++++++-
 gcc/opts.h                                 |  1 +
 gcc/target.def                             |  7 +++
 gcc/targhooks.cc                           |  8 +++
 gcc/targhooks.h                            |  1 +
 gcc/testsuite/c-c++-common/fhardened-1.S   |  6 ++
 gcc/testsuite/c-c++-common/fhardened-1.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-10.c  | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-11.c  | 10 ++++
 gcc/testsuite/c-c++-common/fhardened-12.c  | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-13.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-14.c  |  6 ++
 gcc/testsuite/c-c++-common/fhardened-15.c  |  5 ++
 gcc/testsuite/c-c++-common/fhardened-2.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-3.c   | 14 +++++
 gcc/testsuite/c-c++-common/fhardened-4.c   |  4 ++
 gcc/testsuite/c-c++-common/fhardened-5.c   | 11 ++++
 gcc/testsuite/c-c++-common/fhardened-6.c   | 12 ++++
 gcc/testsuite/c-c++-common/fhardened-7.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-8.c   |  7 +++
 gcc/testsuite/c-c++-common/fhardened-9.c   |  9 +++
 gcc/testsuite/gcc.misc-tests/help.exp      |  2 +
 gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
 gcc/toplev.cc                              | 25 +++++++-
 38 files changed, 588 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
 create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c

diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index 10403c03bd6..d7faff10d66 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "target.h"
 #include "c-target.h"
 #include "c-common.h"
 #include "memmodel.h"
@@ -1573,6 +1574,9 @@ c_finish_options (void)
       cb_file_change (parse_in, cmd_map);
       linemap_line_start (line_table, 0, 1);
 
+      bool fortify_seen_p = false;
+      bool cxx_assert_seen_p = false;
+
       /* All command line defines must have the same location.  */
       cpp_force_token_locations (parse_in, line_table->highest_line);
       for (size_t i = 0; i < deferred_count; i++)
@@ -1590,6 +1594,41 @@ c_finish_options (void)
 	      else
 		cpp_assert (parse_in, opt->arg);
 	    }
+
+	  if (UNLIKELY (flag_hardened)
+	      && (opt->code == OPT_D || opt->code == OPT_U))
+	    {
+	      if (!fortify_seen_p)
+		fortify_seen_p
+		  = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
+		     && (opt->arg[15] == '\0' || opt->arg[15] == '='));
+	      if (!cxx_assert_seen_p)
+		cxx_assert_seen_p
+		  = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
+		     && (opt->arg[19] == '\0' || opt->arg[19] == '='));
+	    }
+	}
+
+      if (flag_hardened)
+	{
+	  if (!fortify_seen_p && optimize > 0)
+	    cpp_define_formatted (parse_in, "_FORTIFY_SOURCE=%u",
+				  targetm.fortify_source_default_level ());
+	  else if (optimize == 0)
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because optimizations are turned off");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+			"because it was specified in %<-D%> or %<-U%>");
+	  if (!cxx_assert_seen_p)
+	    cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
+	  else
+	    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+			"%<_GLIBCXX_ASSERTIONS%> is not enabled by "
+			"%<-fhardened%> because it was specified in %<-D%> "
+			"or %<-U%>");
 	}
 
       cpp_stop_forcing_token_locations (parse_in);
diff --git a/gcc/common.opt b/gcc/common.opt
index d21db5d4a20..6dafe51e9f3 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -634,6 +634,10 @@ Wfree-nonheap-object
 Common Var(warn_free_nonheap_object) Init(1) Warning
 Warn when attempting to free a non-heap object.
 
+Whardened
+Common Var(warn_hardened) Init(1) Warning
+Warn when -fhardened did not enable an option from its set.
+
 Whsa
 Common Ignore Warning
 Does nothing.  Preserved for backward compatibility.
@@ -1819,6 +1823,10 @@ fguess-branch-probability
 Common Var(flag_guess_branch_prob) Optimization
 Enable guessing of branch probabilities.
 
+fhardened
+Common Driver Var(flag_hardened)
+Enable various security-relevant flags.
+
 fharden-compares
 Common Var(flag_harden_compares) Optimization
 Harden conditionals not used in branches, checking reversed conditions.
diff --git a/gcc/config.in b/gcc/config.in
index 866f9fff101..fb45b556fb0 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1326,6 +1326,12 @@
 #endif
 
 
+/* Define 0/1 if -fhardened is supported */
+#ifndef USED_FOR_TARGET
+#undef HAVE_FHARDENED_SUPPORT
+#endif
+
+
 /* Define to 1 if you have the `fileno_unlocked' function. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_FILENO_UNLOCKED
@@ -1734,6 +1740,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z now */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_NOW_SUPPORT
+#endif
+
+
 /* Define if your PowerPC64 linker only needs function descriptor syms. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_NO_DOT_SYMS
@@ -1777,6 +1789,12 @@
 #endif
 
 
+/* Define 0/1 if your linker supports -z relro */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_RELRO_SUPPORT
+#endif
+
+
 /* Define if your linker links a mix of read-only and read-write sections into
    a read-write section. */
 #ifndef USED_FOR_TARGET
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index a0956a06972..223a43cbbb3 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify-me.h"
 
 #include "core-builtins.h"
+#include "opts.h"
 
 /* Per-function machine data.  */
 struct GTY(()) machine_function
@@ -250,9 +251,10 @@ bpf_option_override (void)
   /* Disable -fstack-protector as it is not supported in BPF.  */
   if (flag_stack_protect)
     {
-      inform (input_location,
-              "%<-fstack-protector%> does not work "
-	      "on this architecture");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	inform (input_location,
+		"%<-fstack-protector%> does not work "
+		"on this architecture");
       flag_stack_protect = 0;
     }
 
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index df7d24352d1..76adba672b9 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3072,10 +3072,25 @@ ix86_option_override_internal (bool main_args_p,
         = build_target_option_node (opts, opts_set);
     }
 
+  const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
+  /* When -fhardened, enable -fcf-protection=full, but only when it's
+     compatible with this target, and when it wasn't already specified
+     on the command line.  */
+  if (opts->x_flag_hardened && cf_okay_p)
+    {
+      if (opts->x_flag_cf_protection == CF_NONE)
+	opts->x_flag_cf_protection = CF_FULL;
+      else if (opts->x_flag_cf_protection != CF_FULL)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fcf-protection=full%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (opts->x_flag_cf_protection != CF_NONE)
     {
       if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
-	  && !TARGET_64BIT && !TARGET_CMOV)
+	  && !cf_okay_p)
 	error ("%<-fcf-protection%> is not compatible with this target");
 
       opts->x_flag_cf_protection
diff --git a/gcc/config/linux-protos.h b/gcc/config/linux-protos.h
index f2ea930ace7..834249867f7 100644
--- a/gcc/config/linux-protos.h
+++ b/gcc/config/linux-protos.h
@@ -22,3 +22,4 @@ extern bool linux_has_ifunc_p (void);
 extern bool linux_libc_has_function (enum function_class fn_class, tree);
 
 extern unsigned linux_libm_function_max_error (unsigned, machine_mode, bool);
+extern unsigned linux_fortify_source_default_level ();
diff --git a/gcc/config/linux.cc b/gcc/config/linux.cc
index 9114e55d44e..c8df6c7d840 100644
--- a/gcc/config/linux.cc
+++ b/gcc/config/linux.cc
@@ -49,3 +49,12 @@ linux_libm_function_max_error (unsigned cfn, machine_mode mode,
     return glibc_linux_libm_function_max_error (cfn, mode, boundary_p);
   return default_libm_function_max_error (cfn, mode, boundary_p);
 }
+
+unsigned
+linux_fortify_source_default_level ()
+{
+  if (OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
+    return 3;
+
+  return 2;
+}
diff --git a/gcc/config/linux.h b/gcc/config/linux.h
index ac56816bfca..79b6537dcf1 100644
--- a/gcc/config/linux.h
+++ b/gcc/config/linux.h
@@ -216,3 +216,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 # define TARGET_LIBM_FUNCTION_MAX_ERROR linux_libm_function_max_error
 
 #endif
+
+#undef TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL
+#define TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL linux_fortify_source_default_level
diff --git a/gcc/configure b/gcc/configure
index ee97934ac4f..a02c23ae917 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -34583,7 +34583,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -34712,6 +34712,72 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
+$as_echo_n "checking linker -z now option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
+$as_echo "$ld_now_support" >&6; }
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
+$as_echo_n "checking linker -z relro option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
+$as_echo "$ld_relro_support" >&6; }
+
+case $target_os in
+linux* | gnu*)
+  # -fhardened is only supported on GNU/Linux.
+  fhardened_support=yes
+  ;;
+*)
+  fhardened_support=no
+  ;;
+esac
+
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FHARDENED_SUPPORT `if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fhardened_support" >&5
+$as_echo "$fhardened_support" >&6; }
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index d0caf820648..86f1a4b9e4c 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -7741,7 +7741,7 @@ if test x"$ld_is_gold" = xno; then
       ld_bndplt_support=yes
     fi
   elif test x$gcc_cv_ld != x; then
-    # Check if linker supports -a bndplt option
+    # Check if linker supports -z bndplt option
     if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
       ld_bndplt_support=yes
     fi
@@ -7842,6 +7842,61 @@ standards-compatible mode on s390 targets.])
   ;;
 esac
 
+# Check if the linker supports '-z now'
+ld_now_support=no
+AC_MSG_CHECKING(linker -z now option)
+if test x"$ld_is_gold" = xyes; then
+  ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_now_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z now
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+    ld_now_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
+  [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z now])
+AC_MSG_RESULT($ld_now_support)
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+AC_MSG_CHECKING(linker -z relro option)
+if test x"$ld_is_gold" = xyes; then
+  ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+  if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+    ld_relro_support=yes
+  fi
+elif test x$gcc_cv_ld != x; then
+  # Check if linker supports -z relro
+  if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+    ld_relro_support=yes
+  fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
+  [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your linker supports -z relro])
+AC_MSG_RESULT($ld_relro_support)
+
+case $target_os in
+linux* | gnu*)
+  # -fhardened is only supported on GNU/Linux.
+  fhardened_support=yes
+  ;;
+*)
+  fhardened_support=no
+  ;;
+esac
+
+AC_DEFINE_UNQUOTED(HAVE_FHARDENED_SUPPORT,
+  [`if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if -fhardened is supported])
+AC_MSG_RESULT($fhardened_support)
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1748afdbfe0..035adaa9dbf 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-y2k  -Wframe-address
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object
 -Wno-if-not-aligned  -Wno-ignored-attributes
--Wignored-qualifiers  -Wno-incompatible-pointer-types
+-Wignored-qualifiers  -Wno-incompatible-pointer-types  -Whardened
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n}
 -Wno-implicit-function-declaration  -Wno-implicit-int
 -Winfinite-recursion
@@ -641,7 +641,7 @@ Objective-C and Objective-C++ Dialects}.
 -fasan-shadow-offset=@var{number}  -fsanitize-sections=@var{s1},@var{s2},...
 -fsanitize-undefined-trap-on-error  -fbounds-check
 -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
--fharden-compares -fharden-conditional-branches
+-fharden-compares -fharden-conditional-branches  -fhardened
 -fharden-control-flow-redundancy  -fhardcfr-skip-leaf
 -fhardcfr-check-exceptions  -fhardcfr-check-returning-calls
 -fhardcfr-check-noreturn-calls=@r{[}always@r{|}no-xthrow@r{|}nothrow@r{|}never@r{]}
@@ -6869,6 +6869,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
 Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
 This warning is enabled by @option{-Wall}.
 
+@opindex Whardened
+@opindex Wno-hardened
+@item -Whardened
+Warn when @option{-fhardened} did not enable an option from its set (for
+which see @option{-fhardened}).  For instance, using @option{-fhardened}
+and @option{-fstack-protector} at the same time on the command line causes
+@option{-Whardened} to warn because @option{-fstack-protector-strong} is
+not enabled by @option{-fhardened}.
+
+This warning is enabled by default and has effect only when @option{-fhardened}
+is enabled.
+
 @opindex Wimplicit-fallthrough
 @opindex Wno-implicit-fallthrough
 @item -Wimplicit-fallthrough
@@ -17535,6 +17547,39 @@ made @option{no-xthrow} the default setting for this option: it excludes
 from the @code{noreturn} treatment only internal functions used to
 (re)raise exceptions, that are not affected by these optimizations.
 
+@opindex fhardened
+@item -fhardened
+Enable a set of flags for C and C++ that improve the security of the
+generated code without affecting its ABI.  The precise flags enabled
+may change between major releases of GCC, but are currently:
+
+@c Keep this in sync with print_help_hardened!
+@gccoptlist{
+-D_FORTIFY_SOURCE=3
+-D_GLIBCXX_ASSERTIONS
+-ftrivial-auto-var-init=zero
+-fPIE  -pie  -Wl,-z,relro,-z,now
+-fstack-protector-strong
+-fstack-clash-protection
+-fcf-protection=full @r{(x86 GNU/Linux only)}
+}
+
+The list of options enabled by @option{-fhardened} can be generated using
+the @option{--help=hardened} option.
+
+When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
+is used instead.
+
+This option is intended to be used in production builds, not merely
+in debug builds.
+
+Currently, @option{-fhardened} is only supported on GNU/Linux targets.
+
+@option{-fhardened} only enables a particular option if it wasn't
+already specified anywhere on the command line.  For instance,
+@option{-fhardened} @option{-fstack-protector} will only enable
+@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
+
 @opindex fstack-protector
 @item -fstack-protector
 Emit extra code to check for buffer overflows, such as stack smashing
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index d83ca73b1af..864aa210db0 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -5822,6 +5822,11 @@ This hook determines whether a function from a class of functions
 @code{(enum function_class)}@var{fcode} has a fast implementation.
 @end deftypefn
 
+@deftypefn {Target Hook} unsigned TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL (void)
+This hook determines what value _FORTIFY_SOURCE will be set to when using
+the command-line option -fhardened.
+@end deftypefn
+
 @deftypefn {Target Hook} unsigned TARGET_LIBM_FUNCTION_MAX_ERROR (unsigned @var{cfn}, machine_mode @var{mode}, bool @var{boundary_p})
 This hook determines expected maximum errors for math functions measured
 in ulps (units of the last place).  0 means 0.5ulps precision (correctly
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 3d3ae12cc2f..245058eb887 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -4043,6 +4043,8 @@ macro, a reasonable default is used.
 
 @hook TARGET_LIBC_HAS_FAST_FUNCTION
 
+@hook TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL
+
 @hook TARGET_LIBM_FUNCTION_MAX_ERROR
 
 @defmac NEXT_OBJC_RUNTIME
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 51120c1489e..9f21ad9453e 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
    driver added to dumpdir after dumpbase or linker output name.  */
 static bool dumpdir_trailing_dash_added = false;
 
+/* True if -r, -shared, -pie, or -no-pie were specified on the command
+   line.  */
+static bool any_link_options_p;
+
+/* True if -static was specified on the command line.  */
+static bool static_p;
+
 /* Basename of dump and aux outputs, computed from dumpbase (given or
    derived from output name), to override input_basename in non-%w %b
    et al.  */
@@ -4605,10 +4612,20 @@ driver_handle_option (struct gcc_options *opts,
       save_switch ("-o", 1, &arg, validated, true);
       return true;
 
-#ifdef ENABLE_DEFAULT_PIE
     case OPT_pie:
+#ifdef ENABLE_DEFAULT_PIE
       /* -pie is turned on by default.  */
+      validated = true;
 #endif
+    case OPT_r:
+    case OPT_shared:
+    case OPT_no_pie:
+      any_link_options_p = true;
+      break;
+
+    case OPT_static:
+      static_p = true;
+      break;
 
     case OPT_static_libgcc:
     case OPT_shared_libgcc:
@@ -4984,6 +5001,35 @@ process_command (unsigned int decoded_options_count,
 #endif
     }
 
+  /* TODO: check if -static -pie works and maybe use it.  */
+  if (flag_hardened)
+    {
+      if (!any_link_options_p && !static_p)
+	{
+#ifdef HAVE_LD_PIE
+	  save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
+#endif
+	  /* These are passed straight down to collect2 so we have to break
+	     it up like this.  */
+	  if (HAVE_LD_NOW_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("now", "*");
+	    }
+	  if (HAVE_LD_RELRO_SUPPORT)
+	    {
+	      add_infile ("-z", "*");
+	      add_infile ("relro", "*");
+	    }
+	}
+      /* We can't use OPT_Whardened yet.  Sigh.  */
+      else if (warn_hardened)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "linker hardening options not enabled by %<-fhardened%> "
+		    "because other link options were specified on the command "
+		    "line");
+    }
+
   /* Handle -gtoggle as it would later in toplev.cc:process_options to
      make the debug-level-gt spec function work as expected.  */
   if (flag_gtoggle)
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 33165c9e74f..5d5efaf1b9e 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -42,6 +42,10 @@ along with GCC; see the file COPYING3.  If not see
 /* Set by -fcanon-prefix-map.  */
 bool flag_canon_prefix_map;
 
+/* Set by finish_options when flag_stack_protector was set only because of
+   -fhardened.  Yuck.  */
+bool flag_stack_protector_set_by_fhardened_p;
+
 static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
 /* Names of fundamental debug info formats indexed by enum
@@ -1092,6 +1096,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       opts->x_flag_section_anchors = 0;
     }
 
+  if (opts->x_flag_hardened)
+    {
+      if (!opts_set->x_flag_auto_var_init)
+	opts->x_flag_auto_var_init = AUTO_INIT_ZERO;
+      else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO)
+	warning_at (loc, OPT_Whardened,
+		    "%<-ftrivial-auto-var-init=zero%> is not enabled by "
+		    "%<-fhardened%> because it was specified on the command "
+		    "line");
+    }
+
   if (!opts->x_flag_opts_finished)
     {
       /* We initialize opts->x_flag_pie to -1 so that targets can set a
@@ -1101,7 +1116,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	  /* We initialize opts->x_flag_pic to -1 so that we can tell if
 	     -fpic, -fPIC, -fno-pic or -fno-PIC is used.  */
 	  if (opts->x_flag_pic == -1)
-	    opts->x_flag_pie = DEFAULT_FLAG_PIE;
+	    opts->x_flag_pie = (opts->x_flag_hardened
+				? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
 	  else
 	    opts->x_flag_pie = 0;
 	}
@@ -1116,9 +1132,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
     }
 
   /* We initialize opts->x_flag_stack_protect to -1 so that targets
-     can set a default value.  */
+     can set a default value.  With --enable-default-ssp or -fhardened
+     the default is -fstack-protector-strong.  */
   if (opts->x_flag_stack_protect == -1)
-    opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    {
+      /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
+	 defined in such a way that it uses flag_stack_protect which can't
+	 be used here.  Moreover, some targets like BPF don't support
+	 -fstack-protector at all but we don't know that here.  So remember
+	 that flag_stack_protect was set at the behest of -fhardened.  */
+      if (opts->x_flag_hardened)
+	{
+	  opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
+	  flag_stack_protector_set_by_fhardened_p = true;
+	}
+      else
+	opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+    }
+  else if (opts->x_flag_hardened
+	   && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
+    warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		"%<-fstack-protector-strong%> is not enabled by "
+		"%<-fhardened%> because it was specified on the command "
+		"line");
 
   if (opts->x_optimize == 0)
     {
@@ -2460,6 +2496,30 @@ parse_and_check_patch_area (const char *arg, bool report_error,
   free (patch_area_arg);
 }
 
+/* Print options enabled by -fhardened.  Keep this in sync with the manual!  */
+
+static void
+print_help_hardened ()
+{
+  printf ("%s\n", "The following options are enabled by -fhardened:");
+  /* Unfortunately, I can't seem to use targetm.fortify_source_default_level
+     here.  */
+  printf ("  %s\n", "-D_FORTIFY_SOURCE=3 (or =2 for glibc < 2.35)");
+  printf ("  %s\n", "-D_GLIBCXX_ASSERTIONS");
+  printf ("  %s\n", "-ftrivial-auto-var-init=zero");
+#ifdef HAVE_LD_PIE
+  printf ("  %s  %s\n", "-fPIE", "-pie");
+#endif
+  if (HAVE_LD_NOW_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,now");
+  if (HAVE_LD_RELRO_SUPPORT)
+    printf ("  %s\n", "-Wl,-z,relro");
+  printf ("  %s\n", "-fstack-protector-strong");
+  printf ("  %s\n", "-fstack-clash-protection");
+  printf ("  %s\n", "-fcf-protection=full");
+  putchar ('\n');
+}
+
 /* Print help when OPT__help_ is set.  */
 
 void
@@ -2575,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
 	}
       else if (lang_flag != 0)
 	*pflags |= lang_flag;
+      else if (strncasecmp (a, "hardened", len) == 0)
+	print_help_hardened ();
       else
 	warning (0,
 		 "unrecognized argument to %<--help=%> option: %q.*s",
diff --git a/gcc/opts.h b/gcc/opts.h
index 00f377f9ca7..d89c5de8114 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -344,6 +344,7 @@ struct cl_option_handlers
 /* Hold command-line options associated with stack limitation.  */
 extern const char *opt_fstack_limit_symbol_arg;
 extern int opt_fstack_limit_register_no;
+extern bool flag_stack_protector_set_by_fhardened_p;
 
 /* Input file names.  */
 
diff --git a/gcc/target.def b/gcc/target.def
index 0996da0f71a..579b9325212 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2670,6 +2670,13 @@ DEFHOOK
  bool, (int fcode),
  default_libc_has_fast_function)
 
+DEFHOOK
+(fortify_source_default_level,
+ "This hook determines what value _FORTIFY_SOURCE will be set to when using\n\
+the command-line option -fhardened.",
+ unsigned, (void),
+ default_fortify_source_default_level)
+
 DEFHOOK
 (libm_function_max_error,
  "This hook determines expected maximum errors for math functions measured\n\
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 4f5b240f8d6..6680e8ee1b7 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -1906,6 +1906,14 @@ bsd_libc_has_function (enum function_class fn_class,
   return false;
 }
 
+/* By default, -fhardened will add -D_FORTIFY_SOURCE=2.  */
+
+unsigned
+default_fortify_source_default_level ()
+{
+  return 2;
+}
+
 unsigned
 default_libm_function_max_error (unsigned, machine_mode, bool)
 {
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 189549cb1c7..26a8297c785 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -219,6 +219,7 @@ extern bool default_libc_has_fast_function (int fcode);
 extern bool no_c99_libc_has_function (enum function_class, tree);
 extern bool gnu_libc_has_function (enum function_class, tree);
 extern bool bsd_libc_has_function (enum function_class, tree);
+extern unsigned default_fortify_source_default_level (void);
 extern unsigned default_libm_function_max_error (unsigned, machine_mode, bool);
 extern unsigned glibc_linux_libm_function_max_error (unsigned, machine_mode,
 						     bool);
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
new file mode 100644
index 00000000000..9d0a5772d9e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.S
@@ -0,0 +1,6 @@
+/* { dg-do preprocess { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
new file mode 100644
index 00000000000..7e6740655fe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O" } */
+
+#ifndef __SSP_STRONG__
+# error "-fstack-protector-strong not enabled"
+#endif
+
+#if _FORTIFY_SOURCE < 2
+# error "_FORTIFY_SOURCE not enabled"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
new file mode 100644
index 00000000000..badebc56440
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-10.c
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
+
+#if _FORTIFY_SOURCE != 1
+# error "_FORTIFY_SOURCE != 1"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
new file mode 100644
index 00000000000..d1a973d177a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-11.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
+
+#ifndef _FORTIFY_SOURCE
+# error "_FORTIFY_SOURCE disabled when it should not be"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
new file mode 100644
index 00000000000..eb128f61ba3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-12.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
new file mode 100644
index 00000000000..8722e6d4b1a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-13.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
new file mode 100644
index 00000000000..04d6c8ff954
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-14.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O -fno-PIE" } */
+
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
new file mode 100644
index 00000000000..86dc5220159
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-15.c
@@ -0,0 +1,5 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-require-stack-check "specific" } */
+/* { dg-options "-fhardened -O -fstack-check" } */
+
+/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
new file mode 100644
index 00000000000..280ff96eb15
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -fstack-protector" } */
+
+#ifdef __SSP_STRONG__
+# error "-fstack-protector-strong enabled when it should not be"
+#endif
+#ifndef __SSP__
+# error "-fstack-protector not enabled"
+#endif
+
+/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
new file mode 100644
index 00000000000..f2306ca5d33
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O0" } */
+/* Test that we don't get any diagnostic coming from libc headers.  */
+
+#include <stdio.h>
+
+/* The most useful C program known to man.  */
+
+int
+main ()
+{
+}
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
new file mode 100644
index 00000000000..312fabb95a5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-4.c
@@ -0,0 +1,4 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O0 -Wno-hardened" } */
+
+/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
new file mode 100644
index 00000000000..eb128f61ba3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
new file mode 100644
index 00000000000..d3cb7c8b353
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+  int i;
+  return i;
+}
+
+/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
+/* { dg-warning ".-ftrivial-auto-var-init=zero. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
new file mode 100644
index 00000000000..b47bf43f360
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-7.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O -fpie" } */
+
+/* -fpie takes precedence over -fhardened */
+#if __PIE__ != 1
+# error "__PIE__ != 1"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
new file mode 100644
index 00000000000..85c9ad9103f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-8.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && pie } } } */
+/* { dg-options "-fhardened -O -fPIC" } */
+
+/* -fPIC takes precedence over -fhardened */
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
new file mode 100644
index 00000000000..4e4131f0bdd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fhardened-9.c
@@ -0,0 +1,9 @@
+/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
+
+#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
+# error "hardening enabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
index 52b9cb0ab90..15d618a2528 100644
--- a/gcc/testsuite/gcc.misc-tests/help.exp
+++ b/gcc/testsuite/gcc.misc-tests/help.exp
@@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
 # Listing only excludes gives empty results.
 check_for_options c "--help=^joined,^separate" "" "" ""
 
+check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
+
 if [ info exists prev_columns ] {
     # Reset the enviroment variable to its oriuginal value.
     set env(COLUMNS) $prev_columns
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
new file mode 100644
index 00000000000..73b78dce889
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+/* Test that -fhardened enables CET.  */
+
+extern void bar (void) __attribute__((__cf_check__));
+
+void
+foo (void)
+{
+  bar ();
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 8c3fcd337be..85450d97a1a 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1568,6 +1568,13 @@ process_options ()
       flag_associative_math = 0;
     }
 
+  if (flag_hardened && !HAVE_FHARDENED_SUPPORT)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "%<-fhardened%> not supported for this target");
+      flag_hardened = 0;
+    }
+
   /* -fstack-clash-protection is not currently supported on targets
      where the stack grows up.  */
   if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD)
@@ -1577,6 +1584,19 @@ process_options ()
 		  "where the stack grows from lower to higher addresses");
       flag_stack_clash_protection = 0;
     }
+  else if (flag_hardened)
+    {
+      if (!flag_stack_clash_protection
+	   /* Don't enable -fstack-clash-protection when -fstack-check=
+	      is used: it would result in confusing errors.  */
+	   && flag_stack_check == NO_STACK_CHECK)
+	flag_stack_clash_protection = 1;
+      else if (flag_stack_check != NO_STACK_CHECK)
+	warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+		    "%<-fstack-clash-protection%> is not enabled by "
+		    "%<-fhardened%> because %<-fstack-check%> was "
+		    "specified on the command line");
+    }
 
   /* We cannot support -fstack-check= and -fstack-clash-protection at
      the same time.  */
@@ -1592,8 +1612,9 @@ process_options ()
      target already uses a soft frame pointer, the transition is trivial.  */
   if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
     {
-      warning_at (UNKNOWN_LOCATION, 0,
-		  "%<-fstack-protector%> not supported for this target");
+      if (!flag_stack_protector_set_by_fhardened_p)
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "%<-fstack-protector%> not supported for this target");
       flag_stack_protect = 0;
     }
   if (!flag_stack_protect)

base-commit: a671095c208c7cf5eb934b6a31bd9fb6f6640a6b
-- 
2.41.0


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5] gcc: Introduce -fhardened
  2023-11-16 20:51                     ` [PATCH v5] " Marek Polacek
@ 2023-11-20 16:32                       ` Jakub Jelinek
  2023-11-21 15:41                         ` Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Jakub Jelinek @ 2023-11-20 16:32 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Richard Biener, iain, GCC Patches

On Thu, Nov 16, 2023 at 03:51:22PM -0500, Marek Polacek wrote:
> Thanks, that's a good point.  In this version I've added a target hook.
> 
> On my system, -D_FORTIFY_SOURCE=3 will be used, and if I remove
> linux_fortify_source_default_level it's =2 as expected.
> 
> The only problem was that it doesn't seem to be possible to use
> targetm. in opts.cc -- I get an undefined reference.  But since
> the opts.cc use is for --help only, it's not a big deal either way.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags.  The read of the room seems to be that the option
> would be useful.  So here's a patch implementing that option.
> 
> Currently, -fhardened enables:
> 
>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>   -D_GLIBCXX_ASSERTIONS
>   -ftrivial-auto-var-init=zero
>   -fPIE  -pie  -Wl,-z,relro,-z,now
>   -fstack-protector-strong
>   -fstack-clash-protection
>   -fcf-protection=full (x86 GNU/Linux only)
> 
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened).  For example,
> 
>      -D_FORTIFY_SOURCE=1 -fhardened
> 
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> 
>       -fhardened -fstack-protector
> 
> will not enable -fstack-protector-strong.
> 
> Currently, -fhardened is only supported on GNU/Linux.
> 
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything.  This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option.  I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-opts.cc: Include "target.h".
> 	(c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
> 	and _GLIBCXX_ASSERTIONS.
> 
> gcc/ChangeLog:
> 
> 	* common.opt (Whardened, fhardened): New options.
> 	* config.in: Regenerate.
> 	* config/bpf/bpf.cc: Include "opts.h".
> 	(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
> 	not inform that -fstack-protector does not work.
> 	* config/i386/i386-options.cc (ix86_option_override_internal): When
> 	-fhardened, maybe enable -fcf-protection=full.
> 	* config/linux-protos.h (linux_fortify_source_default_level): Declare.
> 	* config/linux.cc (linux_fortify_source_default_level): New.
> 	* config/linux.h (TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL): Redefine.
> 	* configure: Regenerate.
> 	* configure.ac: Check if the linker supports '-z now' and '-z relro'.
> 	Check if -fhardened is supported on $target_os.
> 	* doc/invoke.texi: Document -fhardened and -Whardened.
> 	* doc/tm.texi: Regenerate.
> 	* doc/tm.texi.in (TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL): Add.
> 	* gcc.cc (driver_handle_option): Remember if any link options or -static
> 	were specified on the command line.
> 	(process_command): When -fhardened, maybe enable -pie and
> 	-Wl,-z,relro,-z,now.
> 	* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
> 	(finish_options): When -fhardened, enable
> 	-ftrivial-auto-var-init=zero and -fstack-protector-strong.
> 	(print_help_hardened): New.
> 	(print_help): Call it.
> 	* target.def (fortify_source_default_level): New target hook.
> 	* targhooks.cc (default_fortify_source_default_level): New.
> 	* targhooks.h (default_fortify_source_default_level): Declare.
> 	* toplev.cc (process_options): When -fhardened, enable
> 	-fstack-clash-protection.  If flag_stack_protector_set_by_fhardened_p,
> 	do not warn that -fstack-protector not supported for this target.
> 	Don't enable -fhardened when !HAVE_FHARDENED_SUPPORT.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.misc-tests/help.exp: Test -fhardened.
> 	* c-c++-common/fhardened-1.S: New test.
> 	* c-c++-common/fhardened-1.c: New test.
> 	* c-c++-common/fhardened-10.c: New test.
> 	* c-c++-common/fhardened-11.c: New test.
> 	* c-c++-common/fhardened-12.c: New test.
> 	* c-c++-common/fhardened-13.c: New test.
> 	* c-c++-common/fhardened-14.c: New test.
> 	* c-c++-common/fhardened-15.c: New test.
> 	* c-c++-common/fhardened-2.c: New test.
> 	* c-c++-common/fhardened-3.c: New test.
> 	* c-c++-common/fhardened-4.c: New test.
> 	* c-c++-common/fhardened-5.c: New test.
> 	* c-c++-common/fhardened-6.c: New test.
> 	* c-c++-common/fhardened-7.c: New test.
> 	* c-c++-common/fhardened-8.c: New test.
> 	* c-c++-common/fhardened-9.c: New test.
> 	* gcc.target/i386/cf_check-6.c: New test.

LGTM.

	Jakub


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5] gcc: Introduce -fhardened
  2023-11-20 16:32                       ` Jakub Jelinek
@ 2023-11-21 15:41                         ` Marek Polacek
  2023-11-23 16:59                           ` Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2023-11-21 15:41 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, iain, GCC Patches

On Mon, Nov 20, 2023 at 05:32:47PM +0100, Jakub Jelinek wrote:
> LGTM.

Thanks a lot.  Since Richi seems to be fine with the patch as well,
I'll push it tomorrow AM if no comments.

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5] gcc: Introduce -fhardened
  2023-11-21 15:41                         ` Marek Polacek
@ 2023-11-23 16:59                           ` Marek Polacek
  0 siblings, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2023-11-23 16:59 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, iain, GCC Patches

On Tue, Nov 21, 2023 at 10:41:10AM -0500, Marek Polacek wrote:
> On Mon, Nov 20, 2023 at 05:32:47PM +0100, Jakub Jelinek wrote:
> > LGTM.
> 
> Thanks a lot.  Since Richi seems to be fine with the patch as well,
> I'll push it tomorrow AM if no comments.

Pushed.  I'll update changes.html now.

Thanks to everybody who contributed to this effort!

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2023-11-23 16:59 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-15 15:08 [PATCH] gcc: Introduce -fhardened Marek Polacek
2023-09-18  6:57 ` Richard Biener
2023-09-19 14:58   ` Marek Polacek
2023-09-19 15:14     ` Jakub Jelinek
2023-10-11 20:48     ` [PATCH v2] " Marek Polacek
2023-10-18 20:12       ` Qing Zhao
2023-10-19 18:32         ` Marek Polacek
2023-10-19 12:24       ` Richard Biener
2023-10-19 12:33         ` Sam James
2023-10-19 18:33           ` Marek Polacek
2023-10-23 19:25         ` [PATCH v3] " Marek Polacek
2023-10-24  7:22           ` Richard Biener
2023-10-24 19:09             ` Marek Polacek
2023-10-26 15:55               ` Richard Biener
2023-11-03 22:51                 ` [PATCH v4] " Marek Polacek
2023-11-13 15:41                   ` Marek Polacek
2023-11-14  7:46                   ` Richard Biener
2023-11-14 16:00                     ` Marek Polacek
2023-11-15 11:42                       ` Richard Biener
2023-11-15 12:25                   ` Jakub Jelinek
2023-11-16 20:51                     ` [PATCH v5] " Marek Polacek
2023-11-20 16:32                       ` Jakub Jelinek
2023-11-21 15:41                         ` Marek Polacek
2023-11-23 16:59                           ` Marek Polacek
2023-10-24  7:44           ` [PATCH v3] " Iain Sandoe
2023-10-24  9:34             ` Iain Sandoe
2023-10-24 19:03               ` Marek Polacek
2023-10-24 19:16                 ` Iain Sandoe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).