diff mbox series

[v4] gcc: Introduce -fhardened

Message ID ZUV5ZDgmrPJlLSdd@redhat.com
State New
Headers show
Series [v4] gcc: Introduce -fhardened | expand

Commit Message

Marek Polacek Nov. 3, 2023, 10:51 p.m. UTC
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


base-commit: ae8abcb81ed81456c0fe5ff8e0c060c9fb9c82d7

Comments

Marek Polacek Nov. 13, 2023, 3:41 p.m. UTC | #1
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
Richard Biener Nov. 14, 2023, 7:46 a.m. UTC | #2
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
>
Marek Polacek Nov. 14, 2023, 4 p.m. UTC | #3
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
Richard Biener Nov. 15, 2023, 11:42 a.m. UTC | #4
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
>
Jakub Jelinek Nov. 15, 2023, 12:25 p.m. UTC | #5
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
diff mbox series

Patch

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)