public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] [i386] Enable Control-flow Enforcement Technology (CET).
@ 2017-06-20 20:55 Tsimbalist, Igor V
  2017-06-20 21:29 ` Joseph Myers
  0 siblings, 1 reply; 4+ messages in thread
From: Tsimbalist, Igor V @ 2017-06-20 20:55 UTC (permalink / raw)
  To: gcc-patches; +Cc: Chupin, Pavel V, Tsimbalist, Igor V

[-- Attachment #1: Type: text/plain, Size: 4455 bytes --]

Control-flow Enforcement Technology (CET) provides the following
capabilities to defend against ROP/JOP style control-flow subversion
attacks:
- Shadow Stack - return address protection to defend against Return
  Oriented Programming,
- Indirect branch tracking - free branch protection to defend
  against
  Jump/Call Oriented Programming.

Details are described in the doc
https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf

This patch enables CET in the compiler only (gcc directory). The
executables built with the CET enabled compiler can run successfully
on non-CET i386 HW as executed new instructions are NOPs there.
Functional testing can be done through Intel® Software Development
Emulator or Intel® SDE.

There will be more patches to enable remaining intrinsics, to support CET
in the compiler libraries (exception handling) and in glibc.

The patch adds 1) new options to control the technology, 2) three new
instructions (endbr, rdssp, inssp) and intrinsics, 3) a pass to generate
endbr instruction, 4) new 'notrack' attribute for functions and pointers
to function and code generation for it, 5) shadow stack processing in
setjmp/longjmp builtins.

Basic functional tests are added. Bootstrap is done successfully w/o and
w/ CET option (-mcet).

gcc/
    * builtins.c
                (expand_builtin_setjmp_setup): Add saving shadow stack pointer
       in jmpbuf using rdssp insatruction.
                (expand_builtin_longjmp): Add adjusting shadow stack pointer
       using incssp instruction.
    * c-family/c-attribs.c
                (handle_notrack_attribute): New function.
                (c_common_attribute_table): Add a 'notrack' attribute.
    * calls.c
                (emit_call_1): Set REG_CALL_NOTRACK on call insn.
                (flags_from_decl_or_type): Retrieve notrack attribute from a decl.
                (expand_call): Retrieve notrack attribute from a decl.
    * combine.c: Handle REG_CALL_NOTRACK.
    * common/config/i386/i386-common.c
                (OPTION_MASK_ISA_CET_SET, OPTION_MASK_ISA_CET_UNSET): New.
                (ix86_handle_option): Handle OPT_mcet.
    * config.gcc: Add cetintrin.h.
                * config/i386/cetintrin.h: New file.
    * config/i386/cpuid.h: (bit_CET) new bit.
    * config/i386/driver-i386.c
                (host_detect_local_cpu): Detect cet.
    * config/i386/i386-builtin.def
                (__builtin_ia32_rdsspd, __builtin_ia32_rdsspq,
                __builtin_ia32_incsspd, __builtin_ia32_incsspd): New intrinsics.
    * config/i386/i386-c.c
                (ix86_target_macros_internal): Define __CET__.
    * config/i386/i386-protos.h (ix86_notrack_prefixed_insn_p): New.
    * config/i386/i386.c
                (ix86_target_string): Add -mcet.
                (ix86_valid_target_attribute_inner_p): Add cet.
                (ix86_print_operand): Output notrack.
                BDESC_VERIFYS for CET intrinsics.
                (ix86_init_mmx_sse_builtins): Define CET intrinsics.
                (x86_output_mi_thunk): Add endbr instruction.
                (ix86_notrack_prefixed_insn_p): New function.
    * config/i386/i386.h
                (TARGET_CET, TARGET_CET_P): New.
    * config/i386/i386.md
                (define_insn "rdssp<mode>"): New instruction.
                (define_insn "incssp<mode>"): Likewise.
                (define_insn "nop_endbr"): Likewise.
    * config/i386/i386.opt
                (mcet, mcet-switch, mcet-indbranch-tracking,
                mcet-shadow-stack): New options.
    * config/i386/immintrin.h
                Add include <cetintrin.h>.
    * final.c
                (rest_of_handle_cet): New.
                (pass_data_handle_cet): New.
                (pass_handle_cet): New.
                (make_pass_handle_cet): New.
    * passes.def: (pass_handle_cet) Add pass.
    * reg-notes.def: (CALL_NOTRACK) New note for notrack.
    * timevar.def: (TV_CET) New.
    * tree-core.h: (ECF_NOTRACK) New.
    * tree-pass.h: (make_pass_handle_cet) New.

gcc/testsuite/

    * gcc.target/i386/cet-intrin.c: New test.
    * gcc.target/i386/cet-label.c: Likewise.
    * gcc.target/i386/cet-notrack.c: Likewise.
    * gcc.target/i386/cet-sjlj.c: Likewise.
    * gcc.target/i386/cet-switch-1.c: Likewise.
    * gcc.target/i386/cet-switch-2.c: Likewise.
---


[-- Attachment #2: 0001-Enable-Control-flow-Enforcement-Technology-CET.patch --]
[-- Type: application/octet-stream, Size: 42580 bytes --]

From df8f95564e081eb1169b6ae1d074f510f130c4d8 Mon Sep 17 00:00:00 2001
From: Igor Tsimbalist <igor.v.tsimbalist@intel.com>
Date: Tue, 20 Jun 2017 22:27:33 +0300
Subject: [PATCH] Enable Control-flow Enforcement Technology (CET).
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Control-flow Enforcement Technology (CET) provides the following
capabilities to defend against ROP/JOP style control-flow subversion
attacks:
- Shadow Stack – return address protection to defend against Return
  Oriented Programming,
- Indirect branch tracking – free branch protection to defend
  against
  Jump/Call Oriented Programming.

Details are described in the doc
https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf

This patch enables CET in the compiler only (gcc directory). The
executables built with the CET enabled compiler can run successfully
on non-CET i386 HW as executed new instructions are NOPs there.
Functional testing can be done through Intel® Software Development
Emulator or Intel® SDE.

There will be more patches to enable remining intrinsics, to support CET
in the compiler libraries (especially exception handling) and in glibc.

The patch adds 1) new options to control the technology, 2) three new
instructions (endbr, rdssp, inssp) and intrinsics, 3) a pass to generate
endbr instruction, 4) new 'notrack' attribute for functions and pointers
to function and code generation for it, 5) shadow stack processing in
setjmp/longjmp builtins.

Basic functional tests are added. Bootstrap is done successfully w/o and
w/ CET option (-mcet).

gcc/
    * builtins.c
	(expand_builtin_setjmp_setup): Add saving shadow stack pointer
in
	jmpbuf using rdssp insatruction.
	(expand_builtin_longjmp): Add adjusting shadow stack pointer
using
	incssp instruction.
    * c-family/c-attribs.c
	(handle_notrack_attribute): New function.
	(c_common_attribute_table): Add a 'notrack' attribute.
    * calls.c
	(emit_call_1): Set REG_CALL_NOTRACK on call insn.
	(flags_from_decl_or_type): Retrieve notrack attribute from a
decl.
	(expand_call): Retrieve notrack attribute from a decl.
	* combine.c: Handle REG_CALL_NOTRACK.
    * common/config/i386/i386-common.c
	(OPTION_MASK_ISA_CET_SET, OPTION_MASK_ISA_CET_UNSET): New.
	(ix86_handle_option): Handle OPT_mcet.
    * config.gcc: Add cetintrin.h.
	* config/i386/cetintrin.h: New file.
    * config/i386/cpuid.h: (bit_CET) new bit.
    * config/i386/driver-i386.c
	(host_detect_local_cpu): Detect cet.
    * config/i386/i386-builtin.def
	(__builtin_ia32_rdsspd, __builtin_ia32_rdsspq,
	__builtin_ia32_incsspd, __builtin_ia32_incsspd): New intrinsics.
    * config/i386/i386-c.c
	(ix86_target_macros_internal): Define __CET__.
    * config/i386/i386-protos.h (ix86_notrack_prefixed_insn_p): New.
    * config/i386/i386.c
	(ix86_target_string): Add -mcet.
	(ix86_valid_target_attribute_inner_p): Add cet.
	(ix86_print_operand): Output notrack.
	BDESC_VERIFYS for CET intrinsics.
	(ix86_init_mmx_sse_builtins): Define CET intrinsics.
	(x86_output_mi_thunk): Add endbr instruction.
	(ix86_notrack_prefixed_insn_p): New function.
    * config/i386/i386.h
	(TARGET_CET, TARGET_CET_P): New.
    * config/i386/i386.md
	(define_insn "rdssp<mode>"): New instruction.
	(define_insn "incssp<mode>"): Likewise.
	(define_insn "nop_endbr"): Likewise.
    * config/i386/i386.opt
	(mcet, mcet-switch, mcet-indbranch-tracking,
	mcet-shadow-stack): New options.
    * config/i386/immintrin.h
	Add include <cetintrin.h>.
    * final.c
	(rest_of_handle_cet): New.
	(pass_data_handle_cet): New.
	(pass_handle_cet): New.
	(make_pass_handle_cet): New.
    * passes.def: (pass_handle_cet) Add pass.
    * reg-notes.def: (CALL_NOTRACK) New note for notrack.
    * timevar.def: (TV_CET) New.
    * tree-core.h: (ECF_NOTRACK) New.
    * tree-pass.h: (make_pass_handle_cet) New.

gcc/testsuite/

    gcc.target/i386/cet-intrin.c: New test.
    gcc.target/i386/cet-label.c: Likewise.
    gcc.target/i386/cet-notrack.c: Likewise.
    gcc.target/i386/cet-sjlj.c: Likewise.
    gcc.target/i386/cet-switch-1.c: Likewise.
    gcc.target/i386/cet-switch-2.c: Likewise.
---
 gcc/builtins.c                               |  66 ++++++++++++-
 gcc/c-family/c-attribs.c                     |  23 +++++
 gcc/calls.c                                  |  30 ++++++
 gcc/combine.c                                |   1 +
 gcc/common/config/i386/i386-common.c         |  15 +++
 gcc/config.gcc                               |   4 +-
 gcc/config/i386/cetintrin.h                  |  89 +++++++++++++++++
 gcc/config/i386/cpuid.h                      |   1 +
 gcc/config/i386/driver-i386.c                |   6 +-
 gcc/config/i386/i386-builtin.def             |  11 ++-
 gcc/config/i386/i386-c.c                     |   2 +
 gcc/config/i386/i386-protos.h                |   1 +
 gcc/config/i386/i386.c                       |  68 ++++++++++++-
 gcc/config/i386/i386.h                       |   2 +
 gcc/config/i386/i386.md                      |  31 ++++++
 gcc/config/i386/i386.opt                     |  16 +++
 gcc/config/i386/immintrin.h                  |   2 +
 gcc/final.c                                  | 142 +++++++++++++++++++++++++++
 gcc/passes.def                               |   1 +
 gcc/reg-notes.def                            |   3 +
 gcc/testsuite/gcc.target/i386/cet-intrin.c   |  29 ++++++
 gcc/testsuite/gcc.target/i386/cet-label.c    |  15 +++
 gcc/testsuite/gcc.target/i386/cet-notrack.c  |  22 +++++
 gcc/testsuite/gcc.target/i386/cet-sjlj.c     |  45 +++++++++
 gcc/testsuite/gcc.target/i386/cet-switch-1.c |  25 +++++
 gcc/testsuite/gcc.target/i386/cet-switch-2.c |  25 +++++
 gcc/timevar.def                              |   1 +
 gcc/tree-core.h                              |   3 +
 gcc/tree-pass.h                              |   1 +
 29 files changed, 673 insertions(+), 7 deletions(-)
 create mode 100644 gcc/config/i386/cetintrin.h
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-intrin.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-label.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-notrack.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-sjlj.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-switch-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-switch-2.c

diff --git a/gcc/builtins.c b/gcc/builtins.c
index ce657bf..7fb1bde 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -827,7 +827,7 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
 {
   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
   rtx stack_save;
-  rtx mem;
+  rtx mem, reg_ssp;
 
   if (setjmp_alias_set == -1)
     setjmp_alias_set = new_alias_set ();
@@ -857,6 +857,21 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
   set_mem_alias_set (stack_save, setjmp_alias_set);
   emit_stack_save (SAVE_NONLOCAL, &stack_save);
 
+  /* If either CET flag is set or a special flag to process shadow
+     stack store the shadow stack pointer as a forth element.  */
+  if (TARGET_CET || flag_cet_shadow_stack)
+    {
+      mem = gen_rtx_MEM (Pmode, plus_constant (Pmode, buf_addr,
+					   3 * GET_MODE_SIZE (Pmode))),
+      set_mem_alias_set (mem, setjmp_alias_set);
+      reg_ssp = gen_reg_rtx (Pmode);
+      emit_insn (gen_rtx_SET (reg_ssp, const0_rtx));
+      emit_insn ((Pmode == SImode)
+		 ? gen_rdsspsi (reg_ssp)
+		 : gen_rdsspdi (reg_ssp));
+      emit_move_insn (mem, reg_ssp);
+    }
+
   /* If there is further processing to do, do it.  */
   if (targetm.have_builtin_setjmp_setup ())
     emit_insn (targetm.gen_builtin_setjmp_setup (buf_addr));
@@ -956,6 +971,7 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
 {
   rtx fp, lab, stack;
   rtx_insn *insn, *last;
+  rtx jump, label, reg_adj, reg_ssp, reg_minus, mem_buf, tmp, clob;
   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
 
   /* DRAP is needed for stack realign if longjmp is expanded to current
@@ -974,6 +990,54 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
      that is what builtin_setjmp will return.  */
   gcc_assert (value == const1_rtx);
 
+  /* If either CET flag is set or a special flag to process shadow
+     stack adjust the shadow stack pointer (ssp).  */
+  if (TARGET_CET || flag_cet_shadow_stack)
+    {
+       /* Get current shadow stack pointer.  The code below will check if
+	   CET is enabled.  If it's not enabled RDSSP instruction is a NOP.  */
+       reg_ssp = gen_reg_rtx (Pmode);
+       emit_insn (gen_rtx_SET (reg_ssp, const0_rtx));
+       emit_insn ((Pmode == SImode)
+		  ? gen_rdsspsi (reg_ssp)
+		  : gen_rdsspdi (reg_ssp));
+
+       mem_buf = gen_rtx_MEM (Pmode, plus_constant (Pmode, buf_addr,
+					   3 * GET_MODE_SIZE (Pmode))),
+       set_mem_alias_set (mem_buf, setjmp_alias_set);
+
+       /* Compare through substraction the saved and the current ssp to decide
+	   if ssp has to be adjusted.  */
+       reg_minus = gen_reg_rtx (Pmode);
+       tmp = gen_rtx_SET (reg_minus, gen_rtx_MINUS (Pmode, reg_ssp, mem_buf));
+       clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+       tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+       emit_insn (tmp);
+
+       label = gen_label_rtx ();
+       tmp = gen_rtx_REG (CCmode, FLAGS_REG);
+       tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
+       tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+				   gen_rtx_LABEL_REF (VOIDmode, label),
+				   pc_rtx);
+       jump = emit_jump_insn (gen_rtx_SET (pc_rtx, tmp));
+       JUMP_LABEL (jump) = label;
+
+       /* Adjust the ssp if needed.  */
+       reg_adj = gen_reg_rtx (Pmode);
+//     tmp = gen_rtx_SET (reg_adj, gen_rtx_DIV (Pmode, reg_minus, GEN_INT (UNITS_PER_WORD)));
+       tmp = gen_rtx_SET (reg_adj, gen_rtx_LSHIFTRT (Pmode, negate_rtx (Pmode, reg_minus), GEN_INT (3)));
+       clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+       tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+       emit_insn (tmp);
+       emit_insn ((Pmode == SImode)
+		  ? gen_incsspsi (reg_adj)
+		  : gen_incsspdi (reg_adj));
+
+       emit_label (label);
+       LABEL_NUSES (label) = 1;
+    }
+
   last = get_last_insn ();
   if (targetm.have_builtin_longjmp ())
     emit_insn (targetm.gen_builtin_longjmp (buf_addr));
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 2b6845f..b29d23e 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -65,6 +65,7 @@ static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
 static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
+static tree handle_notrack_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
 static tree handle_always_inline_attribute (tree *, tree, tree, int,
@@ -351,6 +352,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_bnd_instrument, false },
   { "fallthrough",	      0, 0, false, false, false,
 			      handle_fallthrough_attribute, false },
+  { "notrack",		      0, 0, true,  false, false,
+			      handle_notrack_attribute, false },
   { NULL,                     0, 0, false, false, false, NULL, false }
 };
 
@@ -752,6 +755,26 @@ handle_noclone_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+/* Handle a "notrack" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_notrack_attribute (tree *node, tree name,
+			  tree ARG_UNUSED (args),
+			  int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL
+      && (TREE_CODE (*node) != VAR_DECL
+	  || TREE_CODE (TREE_TYPE (*node)) != POINTER_TYPE
+	  || TREE_CODE (TREE_TYPE (TREE_TYPE (*node))) != FUNCTION_TYPE))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "no_icf" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/calls.c b/gcc/calls.c
index 8a23b50..9519ced 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -480,6 +480,9 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
       cfun->calls_setjmp = 1;
     }
 
+  if (ecf_flags & ECF_NOTRACK)
+    add_reg_note (call_insn, REG_CALL_NOTRACK, const0_rtx);
+
   SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
 
   /* Restore this now, so that we do defer pops for this call's args
@@ -823,6 +826,9 @@ flags_from_decl_or_type (const_tree exp)
 	flags |= ECF_LEAF;
       if (lookup_attribute ("cold", DECL_ATTRIBUTES (exp)))
 	flags |= ECF_COLD;
+      if (lookup_attribute ("notrack", DECL_ATTRIBUTES (exp)))
+	flags |= ECF_NOTRACK;
+
 
       if (TREE_NOTHROW (exp))
 	flags |= ECF_NOTHROW;
@@ -3054,6 +3060,30 @@ expand_call (tree exp, rtx target, int ignore)
     }
   else
     {
+      if (TREE_CODE (addr) == SSA_NAME)
+	{
+	  tree vardecl = SSA_NAME_VAR (addr);
+
+	  if (vardecl == NULL_TREE)
+	    {
+	      gimple *stmt = SSA_NAME_DEF_STMT (addr);
+	      /* Expecting the stmt is a GIMPLE assign and the stmt is a
+		 simple assignment like <tmp> = <var>.  The <var> should
+		 be a function pointer.  */
+	      if (gimple_code (stmt) == GIMPLE_ASSIGN)
+		{
+		  vardecl = gimple_assign_rhs1 (stmt);
+		}
+	    }
+	  /* Check that vardecl is a variable with a function pointer type
+	     and get the flags from the decl.  */
+	  if (vardecl != NULL_TREE && VAR_P (vardecl)
+	      && FUNCTION_POINTER_TYPE_P (TREE_TYPE (vardecl)))
+	    {
+	      if (lookup_attribute ("notrack", DECL_ATTRIBUTES (vardecl)))
+		flags |= ECF_NOTRACK;
+	    }
+	}
       fntype = TREE_TYPE (TREE_TYPE (addr));
       flags |= flags_from_decl_or_type (fntype);
       if (CALL_EXPR_BY_DESCRIPTOR (exp))
diff --git a/gcc/combine.c b/gcc/combine.c
index 2d49bc2..cb993f7 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -14036,6 +14036,7 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
 	case REG_SETJMP:
 	case REG_TM:
 	case REG_CALL_DECL:
+	case REG_CALL_NOTRACK:
 	  /* These notes must remain with the call.  It should not be
 	     possible for both I2 and I3 to be a call.  */
 	  if (CALL_P (i3))
diff --git a/gcc/common/config/i386/i386-common.c b/gcc/common/config/i386/i386-common.c
index 4185176..2014689 100644
--- a/gcc/common/config/i386/i386-common.c
+++ b/gcc/common/config/i386/i386-common.c
@@ -137,6 +137,7 @@ along with GCC; see the file COPYING3.  If not see
 #define OPTION_MASK_ISA_CLZERO_SET OPTION_MASK_ISA_CLZERO
 #define OPTION_MASK_ISA_PKU_SET OPTION_MASK_ISA_PKU
 #define OPTION_MASK_ISA_RDPID_SET OPTION_MASK_ISA_RDPID
+#define OPTION_MASK_ISA_CET_SET OPTION_MASK_ISA_CET
 
 /* Define a set of ISAs which aren't available when a given ISA is
    disabled.  MMX and SSE ISAs are handled separately.  */
@@ -202,6 +203,7 @@ along with GCC; see the file COPYING3.  If not see
 #define OPTION_MASK_ISA_CLZERO_UNSET OPTION_MASK_ISA_CLZERO
 #define OPTION_MASK_ISA_PKU_UNSET OPTION_MASK_ISA_PKU
 #define OPTION_MASK_ISA_RDPID_UNSET OPTION_MASK_ISA_RDPID
+#define OPTION_MASK_ISA_CET_UNSET OPTION_MASK_ISA_CET
 
 /* SSE4 includes both SSE4.1 and SSE4.2.  -mno-sse4 should the same
    as -mno-sse4.1. */
@@ -484,6 +486,19 @@ ix86_handle_option (struct gcc_options *opts,
 	}
       return true;
 
+    case OPT_mcet:
+      if (value)
+	{
+	  opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA_CET_SET;
+	  opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_CET_SET;
+	}
+      else
+	{
+	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA_CET_UNSET;
+	  opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_CET_UNSET;
+	}
+      return true;
+
     case OPT_mavx5124fmaps:
       if (value)
 	{
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 0518cb7..5a6f8f2 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -377,7 +377,7 @@ i[34567]86-*-*)
 		       avx512ifmaintrin.h avx512ifmavlintrin.h avx512vbmiintrin.h
 		       avx512vbmivlintrin.h avx5124fmapsintrin.h avx5124vnniwintrin.h
 		       avx512vpopcntdqintrin.h clwbintrin.h mwaitxintrin.h
-		       clzerointrin.h pkuintrin.h sgxintrin.h"
+		       clzerointrin.h pkuintrin.h sgxintrin.h cetintrin.h"
 	;;
 x86_64-*-*)
 	cpu_type=i386
@@ -400,7 +400,7 @@ x86_64-*-*)
 		       avx512ifmaintrin.h avx512ifmavlintrin.h avx512vbmiintrin.h
 		       avx512vbmivlintrin.h avx5124fmapsintrin.h avx5124vnniwintrin.h
 		       avx512vpopcntdqintrin.h clwbintrin.h mwaitxintrin.h
-		       clzerointrin.h pkuintrin.h sgxintrin.h"
+		       clzerointrin.h pkuintrin.h sgxintrin.h cetintrin.h"
 	;;
 ia64-*-*)
 	extra_headers=ia64intrin.h
diff --git a/gcc/config/i386/cetintrin.h b/gcc/config/i386/cetintrin.h
new file mode 100644
index 0000000..2ba1e54
--- /dev/null
+++ b/gcc/config/i386/cetintrin.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2015-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#if !defined _IMMINTRIN_H_INCLUDED
+# error "Never use <cetintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef _CETINTRIN_H_INCLUDED
+#define _CETINTRIN_H_INCLUDED
+
+#ifndef __CET__
+#pragma GCC push_options
+#pragma GCC target ("cet")
+#define __DISABLE_CET__
+#endif /* __CET__ */
+
+#ifndef __RDSSP__
+#pragma GCC push_options
+#pragma GCC target ("cet")
+#define __DISABLE_RDSSP__
+#endif /* __RDSSP__ */
+
+extern __inline unsigned int
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_rdsspd_u32 (void)
+{
+  return __builtin_ia32_rdsspd ();
+}
+
+extern __inline unsigned long long
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_rdsspq_u64 (void)
+{
+  return __builtin_ia32_rdsspq ();
+}
+#ifdef __DISABLE_RDSSP__
+#undef __DISABLE_RDSSP__
+#pragma GCC pop_options
+#endif /* __DISABLE_RDSSP__ */
+
+#ifndef __INCSSP__
+#pragma GCC push_options
+#pragma GCC target ("cet")
+#define __DISABLE_INCSSP__
+#endif /* __INCSSP__ */
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_incsspd (unsigned int __B)
+{
+  __builtin_ia32_incsspd (__B);
+}
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_incsspq (unsigned long long __B)
+{
+  __builtin_ia32_incsspq (__B);
+}
+#ifdef __DISABLE_INCSSP__
+#undef __DISABLE_INCSSP__
+#pragma GCC pop_options
+#endif /* __DISABLE_INCSSP__ */
+
+#ifdef __DISABLE_CET__
+#undef __DISABLE_CET__
+#pragma GCC pop_options
+#endif /* __DISABLE_CET__ */
+
+#endif /* _CETINTRIN_H_INCLUDED.  */
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index b3b0f91..c4da2a8 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -97,6 +97,7 @@
 #define bit_AVX512VBMI	(1 << 1)
 #define bit_PKU	(1 << 3)
 #define bit_OSPKE	(1 << 4)
+#define bit_CET	(1 << 7)
 #define bit_AVX512VPOPCNTDQ	(1 << 14)
 #define bit_RDPID	(1 << 22)
 
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index 6c81251..4324ebd 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -415,6 +415,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_avx512vbmi = 0, has_avx512ifma = 0, has_clwb = 0;
   unsigned int has_mwaitx = 0, has_clzero = 0, has_pku = 0, has_rdpid = 0;
   unsigned int has_avx5124fmaps = 0, has_avx5124vnniw = 0;
+  unsigned int has_cet = 0;
 
   bool arch;
 
@@ -507,6 +508,8 @@ const char *host_detect_local_cpu (int argc, const char **argv)
 
       has_avx5124vnniw = edx & bit_AVX5124VNNIW;
       has_avx5124fmaps = edx & bit_AVX5124FMAPS;
+
+      has_cet = ecx & bit_CET;
     }
 
   if (max_level >= 13)
@@ -1035,6 +1038,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *clzero  = has_clzero  ? " -mclzero"  : " -mno-clzero";
       const char *pku = has_pku ? " -mpku" : " -mno-pku";
       const char *rdpid = has_rdpid ? " -mrdpid" : " -mno-rdpid";
+      const char *cet = has_cet ? " -mcet" : " -mno-cet";
       options = concat (options, mmx, mmx3dnow, sse, sse2, sse3, ssse3,
 			sse4a, cx16, sahf, movbe, aes, sha, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, sgx, bmi2,
@@ -1044,7 +1048,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
 			avx512cd, avx512pf, prefetchwt1, clflushopt,
 			xsavec, xsaves, avx512dq, avx512bw, avx512vl,
 			avx512ifma, avx512vbmi, avx5124fmaps, avx5124vnniw,
-			clwb, mwaitx, clzero, pku, rdpid, NULL);
+			clwb, mwaitx, clzero, pku, rdpid, cet, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def
index 23e8883..64694a1 100644
--- a/gcc/config/i386/i386-builtin.def
+++ b/gcc/config/i386/i386-builtin.def
@@ -2775,4 +2775,13 @@ BDESC (OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v4sf3,     "__builtin_ia32_vper
 BDESC (OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v4df3,     "__builtin_ia32_vpermil2pd256", IX86_BUILTIN_VPERMIL2PD256, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I1)
 BDESC (OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v8sf3,     "__builtin_ia32_vpermil2ps256", IX86_BUILTIN_VPERMIL2PS256, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I1)
 
-BDESC_END (MULTI_ARG, MAX)
+BDESC_END (MULTI_ARG, CET)
+
+/* CET.  */
+BDESC_FIRST (cet, CET,
+       OPTION_MASK_ISA_CET, CODE_FOR_rdsspsi, "__builtin_ia32_rdsspd", IX86_BUILTIN_RDSSPD, UNKNOWN, (int) UNSIGNED_FTYPE_VOID)
+BDESC (OPTION_MASK_ISA_CET, CODE_FOR_rdsspdi, "__builtin_ia32_rdsspq", IX86_BUILTIN_RDSSPQ, UNKNOWN, (int) UINT64_FTYPE_VOID)
+BDESC (OPTION_MASK_ISA_CET, CODE_FOR_incsspsi, "__builtin_ia32_incsspd", IX86_BUILTIN_INCSSPD, UNKNOWN, (int) VOID_FTYPE_UNSIGNED)
+BDESC (OPTION_MASK_ISA_CET, CODE_FOR_incsspdi, "__builtin_ia32_incsspq", IX86_BUILTIN_INCSSPQ, UNKNOWN, (int) VOID_FTYPE_UINT64)
+
+BDESC_END (CET, MAX)
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 9a79a21..80c0166 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -450,6 +450,8 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
     def_or_undef (parse_in, "__PKU__");
   if (isa_flag2 & OPTION_MASK_ISA_RDPID)
     def_or_undef (parse_in, "__RDPID__");
+  if (isa_flag2 & OPTION_MASK_ISA_CET)
+    def_or_undef (parse_in, "__CET__");
   if (TARGET_IAMCU)
     {
       def_or_undef (parse_in, "__iamcu");
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 8bdd67e..bbc3bc1 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -241,6 +241,7 @@ extern void ix86_expand_sse2_mulvxdi3 (rtx, rtx, rtx);
 extern void ix86_expand_sse2_abs (rtx, rtx);
 
 extern bool ix86_bnd_prefixed_insn_p (rtx);
+extern bool ix86_notrack_prefixed_insn_p (rtx);
 
 /* In i386-c.c  */
 extern void ix86_target_macros (void);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d5c2d46..99dab6e 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4647,7 +4647,8 @@ ix86_target_string (HOST_WIDE_INT isa, HOST_WIDE_INT isa2,
     { "-msgx",		OPTION_MASK_ISA_SGX },
     { "-mavx5124vnniw", OPTION_MASK_ISA_AVX5124VNNIW },
     { "-mavx5124fmaps", OPTION_MASK_ISA_AVX5124FMAPS },
-    { "-mavx512vpopcntdq", OPTION_MASK_ISA_AVX512VPOPCNTDQ }
+    { "-mavx512vpopcntdq", OPTION_MASK_ISA_AVX512VPOPCNTDQ },
+    { "-mcet",	OPTION_MASK_ISA_CET }
   };
   static struct ix86_target_opts isa_opts[] =
   {
@@ -7077,6 +7078,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("mpx",	OPT_mmpx),
     IX86_ATTR_ISA ("clwb",	OPT_mclwb),
     IX86_ATTR_ISA ("rdpid",	OPT_mrdpid),
+    IX86_ATTR_ISA ("cet",	OPT_mcet),
 
     /* enum options */
     IX86_ATTR_ENUM ("fpmath=",	OPT_mfpmath_),
@@ -19170,6 +19172,8 @@ ix86_print_operand (FILE *file, rtx x, int code)
 	case '!':
 	  if (ix86_bnd_prefixed_insn_p (current_output_insn))
 	    fputs ("bnd ", file);
+	  if (ix86_notrack_prefixed_insn_p (current_output_insn))
+	    fputs ("notrack ", file);
 	  return;
 
 	default:
@@ -32355,8 +32359,10 @@ BDESC_VERIFYS (IX86_BUILTIN__BDESC_MPX_CONST_FIRST,
 	       IX86_BUILTIN__BDESC_MPX_LAST, 1);
 BDESC_VERIFYS (IX86_BUILTIN__BDESC_MULTI_ARG_FIRST,
 	       IX86_BUILTIN__BDESC_MPX_CONST_LAST, 1);
-BDESC_VERIFYS (IX86_BUILTIN_MAX,
+BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_FIRST,
 	       IX86_BUILTIN__BDESC_MULTI_ARG_LAST, 1);
+BDESC_VERIFYS (IX86_BUILTIN_MAX,
+	       IX86_BUILTIN__BDESC_CET_LAST, 1);
 
 /* Set up all the MMX/SSE builtins, even builtins for instructions that are not
    in the current target ISA to allow the user to compile particular modules
@@ -33017,6 +33023,20 @@ ix86_init_mmx_sse_builtins (void)
   BDESC_VERIFYS (IX86_BUILTIN__BDESC_MULTI_ARG_LAST,
 		 IX86_BUILTIN__BDESC_MULTI_ARG_FIRST,
 		 ARRAY_SIZE (bdesc_multi_arg) - 1);
+
+  /* Add CET inrinsics.  */
+  for (i = 0, d = bdesc_cet; i < ARRAY_SIZE (bdesc_cet); i++, d++)
+    {
+      BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_CET_FIRST, i);
+      if (d->name == 0)
+	continue;
+
+      ftype = (enum ix86_builtin_func_type) d->flag;
+      def_builtin2 (d->mask, d->name, ftype, d->code);
+    }
+  BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_LAST,
+		 IX86_BUILTIN__BDESC_CET_FIRST,
+		 ARRAY_SIZE (bdesc_cet) - 1);
 }
 
 static void
@@ -39526,6 +39546,14 @@ s4fma_expand:
 					    d->flag, d->comparison);
     }
 
+  if (fcode >= IX86_BUILTIN__BDESC_CET_FIRST
+      && fcode <= IX86_BUILTIN__BDESC_CET_LAST)
+    {
+      i = fcode - IX86_BUILTIN__BDESC_CET_FIRST;
+      return ix86_expand_special_args_builtin (bdesc_cet + i, exp,
+						     target);
+    }
+
   gcc_unreachable ();
 }
 
@@ -42333,6 +42361,12 @@ x86_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
 
   emit_note (NOTE_INSN_PROLOGUE_END);
 
+  /* CET is enabled, insert EB instruction.  */
+  if (TARGET_CET || flag_cet_indbranch_tracking)
+    {
+      emit_insn (gen_nop_endbr ());
+    }
+
   /* If VCALL_OFFSET, we'll need THIS in a register.  Might as well
      pull it in now and let DELTA benefit.  */
   if (REG_P (this_param))
@@ -50056,6 +50090,36 @@ ix86_bnd_prefixed_insn_p (rtx insn)
   return chkp_function_instrumented_p (current_function_decl);
 }
 
+/* Return 1 if control tansfer instruction INSN
+   should be encoded with notrack prefix.  */
+
+bool
+ix86_notrack_prefixed_insn_p (rtx insn)
+{
+  if (!insn || !(TARGET_CET || flag_cet_indbranch_tracking))
+    return 0;
+
+  if (CALL_P (insn))
+    {
+      return find_reg_note (insn, REG_CALL_NOTRACK, 0);
+    }
+  if (JUMP_P (insn) && !flag_cet_switch)
+    {
+      rtx target = JUMP_LABEL (insn);
+      if (target == NULL_RTX || ANY_RETURN_P (target))
+	return 0;
+
+      /* Check the jump is a switch table.  */
+      rtx_insn *label = as_a<rtx_insn *> (target);
+      rtx_insn *table = next_insn (label);
+      if (table == NULL_RTX || !JUMP_TABLE_DATA_P (table))
+	return 0;
+      else
+	return 1;
+    }
+  return 0;
+}
+
 /* Calculate integer abs() using only SSE2 instructions.  */
 
 void
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 08243c1..cf0d827 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -168,6 +168,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_MWAITX_P(x)	TARGET_ISA_MWAITX_P(x)
 #define TARGET_PKU	TARGET_ISA_PKU
 #define TARGET_PKU_P(x)	TARGET_ISA_PKU_P(x)
+#define TARGET_CET	TARGET_ISA_CET
+#define TARGET_CET_P(x)	TARGET_ISA_CET_P(x)
 
 #define TARGET_LP64	TARGET_ABI_64
 #define TARGET_LP64_P(x)	TARGET_ABI_64_P(x)
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 40a20d0..83ed4ac 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -277,6 +277,11 @@
 
   ;; For RDPID support
   UNSPECV_RDPID
+
+  ;; For CET support
+  UNSPECV_NOP_ENDBR
+  UNSPECV_NOP_RDSSP
+  UNSPECV_INCSSP
 ])
 
 ;; Constants to represent rounding modes in the ROUND instruction
@@ -19296,6 +19301,32 @@
   [(set_attr "length" "2")
    (set_attr "memory" "unknown")])
 
+;; CET instructions
+(define_insn "rdssp<mode>"
+  [(set (match_operand:SWI48x 0 "register_operand" "+r")
+	(unspec_volatile:SWI48x [(match_dup 0)] UNSPECV_NOP_RDSSP))]
+  "TARGET_CET || flag_cet_shadow_stack"
+  "rdssp<mskmodesuffix>\t%0"
+  [(set_attr "length" "2")
+   (set_attr "type" "other")])
+
+(define_insn "incssp<mode>"
+  [(unspec_volatile [(match_operand:SWI48x 0 "register_operand" "r")]
+		   UNSPECV_INCSSP)]
+  "TARGET_CET || flag_cet_shadow_stack"
+  "incssp<mskmodesuffix>\t%0"
+  [(set_attr "length" "2")
+   (set_attr "type" "other")])
+
+(define_insn "nop_endbr"
+  [(unspec_volatile [(const_int 0)] UNSPECV_NOP_ENDBR)]
+  "TARGET_CET || flag_cet_indbranch_tracking"
+  "*
+{ return (TARGET_64BIT)? \"endbr64\" : \"endbr32\"; }"
+  [(set_attr "length" "4")
+   (set_attr "length_immediate" "0")
+   (set_attr "modrm" "0")])
+
 (define_expand "xbegin"
   [(set (match_operand:SI 0 "register_operand")
 	(unspec_volatile:SI [(const_int 0)] UNSPECV_XBEGIN))]
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 65b2285..d736cec 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -931,3 +931,19 @@ Attempt to avoid generating instruction sequences containing ret bytes.
 mgeneral-regs-only
 Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Var(ix86_target_flags) Save
 Generate code which uses only the general registers.
+
+mcet
+Target Report Mask(ISA_CET) Var(ix86_isa_flags2) Save
+Support CET built-in functions and CET instrumentation.
+
+mcet-switch
+Target Report Var(flag_cet_switch) Init(0)
+Turn on CET instrumentation for switch statements.
+
+mcet-indbranch-tracking
+Target Report Var(flag_cet_indbranch_tracking) Init(0)
+Specifically turn on CET instrumentation with ENDBR and NOTRACK instructions.
+
+mcet-shadow-stack
+Target Report Var(flag_cet_shadow_stack) Init(0)
+Specifically turn on CET codegeneration for shadow stack support.
diff --git a/gcc/config/i386/immintrin.h b/gcc/config/i386/immintrin.h
index b52f58e..696cd20 100644
--- a/gcc/config/i386/immintrin.h
+++ b/gcc/config/i386/immintrin.h
@@ -90,6 +90,8 @@
 
 #include <xtestintrin.h>
 
+#include <cetintrin.h>
+
 #ifndef __RDRND__
 #pragma GCC push_options
 #pragma GCC target("rdrnd")
diff --git a/gcc/final.c b/gcc/final.c
index 356c923..1b0a286 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4787,6 +4787,148 @@ make_pass_clean_state (gcc::context *ctxt)
   return new pass_clean_state (ctxt);
 }
 
+/*  Inserting ENDBRANCH instructions.  */
+
+static unsigned int
+rest_of_handle_cet (void)
+{
+  timevar_push (TV_CET);
+
+  rtx cet_eb;
+  rtx_insn *insn;
+  basic_block bb;
+
+  /* Currently emit EB if it's a noni-tracking function, i.e. 'notrack'
+     is absent among function attributes.  Later an optimization will be
+     introduced to make analysis if an address of a static function is
+     taken.  Such function will get a notrack attribute.  This will allow
+     to reduce the number of EB.  */
+
+  if (!lookup_attribute ("notrack", DECL_ATTRIBUTES (cfun->decl)))
+    {
+      cet_eb = gen_nop_endbr ();
+
+      bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
+      insn = BB_HEAD (bb);
+      emit_insn_before (cet_eb, insn);
+    }
+
+  bb = 0;
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
+	   insn = NEXT_INSN (insn))
+	{
+	  if (INSN_P (insn) && GET_CODE (insn) == CALL_INSN)
+	    {
+	      rtx_insn *next_insn = insn;
+
+	      while ((next_insn != BB_END (bb))
+		      && (DEBUG_INSN_P (NEXT_INSN (next_insn))
+			  || NOTE_P (NEXT_INSN (next_insn))
+			  || BARRIER_P (NEXT_INSN (next_insn))))
+		next_insn = NEXT_INSN (next_insn);
+
+	      /* Generate ENDBRANCH after CALL, which can return more than
+		 twice, setjmp-like functions.  */
+	      if (find_reg_note (insn, REG_SETJMP, NULL) != NULL)
+		{
+		  cet_eb = gen_nop_endbr ();
+		  emit_insn_after (cet_eb, next_insn);
+		}
+	      continue;
+	    }
+
+	  if (INSN_P (insn) && JUMP_P (insn) && flag_cet_switch)
+	    {
+	      rtx target = JUMP_LABEL (insn);
+	      if (target == NULL_RTX || ANY_RETURN_P (target))
+		continue;
+
+	      /* Check the jump is a switch table.  */
+	      rtx_insn *label = as_a<rtx_insn *> (target);
+	      rtx_insn *table = next_insn (label);
+	      if (table == NULL_RTX || !JUMP_TABLE_DATA_P (table))
+		continue;
+
+	      /* For the indirect jump find out all places it jumps and insert
+		 ENDBRANCH there.  It should be done under a special flag to
+		 control ENDBRANCH generation for switch stmts.  */
+	      edge_iterator ei;
+	      edge e;
+	      basic_block dest_blk;
+
+	      FOR_EACH_EDGE (e, ei, bb->succs)
+		{
+		  rtx_insn *insn;
+
+		  dest_blk = e->dest;
+		  insn = BB_HEAD (dest_blk);
+		  gcc_assert (LABEL_P (insn));
+		  cet_eb = gen_nop_endbr ();
+		  emit_insn_after (cet_eb, insn);
+		}
+	      continue;
+	    }
+
+	  if ((LABEL_P (insn) && LABEL_PRESERVE_P (insn))
+	      || (NOTE_P (insn)
+		  && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))
+	    {
+	      cet_eb = gen_nop_endbr ();
+	      emit_insn_after (cet_eb, insn);
+	      continue;
+	    }
+	}
+    }
+
+  timevar_pop (TV_CET);
+  return 0;
+}
+
+namespace {
+
+const pass_data pass_data_handle_cet =
+{
+  RTL_PASS, /* type.  */
+  "cet", /* name.  */
+  OPTGROUP_NONE, /* optinfo_flags.  */
+  TV_CET, /* tv_id.  */
+  0, /* properties_required.  */
+  0, /* properties_provided.  */
+  0, /* properties_destroyed.  */
+  0, /* todo_flags_start.  */
+  0, /* todo_flags_finish.  */
+};
+
+class pass_handle_cet : public rtl_opt_pass
+{
+public:
+  pass_handle_cet (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_handle_cet, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      return (TARGET_CET || flag_cet_indbranch_tracking);
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_cet ();
+    }
+
+}; // class pass_handle_cet
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_handle_cet (gcc::context *ctxt)
+{
+  return new pass_handle_cet (ctxt);
+}
+
 /* Return true if INSN is a call to the current function.  */
 
 static bool
diff --git a/gcc/passes.def b/gcc/passes.def
index c14f6b9..36f49f2 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -497,6 +497,7 @@ along with GCC; see the file COPYING3.  If not see
 	  NEXT_PASS (pass_delay_slots);
 	  NEXT_PASS (pass_split_for_shorten_branches);
 	  NEXT_PASS (pass_convert_to_eh_region_ranges);
+	  NEXT_PASS (pass_handle_cet);
 	  NEXT_PASS (pass_shorten_branches);
 	  NEXT_PASS (pass_set_nothrow_function_flags);
 	  NEXT_PASS (pass_dwarf2_frame);
diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def
index 8734d26..7ece646 100644
--- a/gcc/reg-notes.def
+++ b/gcc/reg-notes.def
@@ -227,3 +227,6 @@ REG_NOTE (RETURNED)
    The decl might not be available in the call due to splitting of the call
    insn.  This note is a SYMBOL_REF.  */
 REG_NOTE (CALL_DECL)
+
+/* Indicate that a call is a NOTRACK call.  */
+REG_NOTE (CALL_NOTRACK)
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin.c b/gcc/testsuite/gcc.target/i386/cet-intrin.c
new file mode 100644
index 0000000..a1d93ec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32|endbr64" 4 } } */
+/* { dg-final { scan-assembler "rdssp\[dq]\[ \t]+(%|)eax" } } */
+/* { dg-final { scan-assembler "rdssp\[dq]\[ \t]+(%|)rax" } } */
+/* { dg-final { scan-assembler "incssp\[dq]\[ \t]+(%|)edi" } } */
+/* { dg-final { scan-assembler "incssp\[dq]\[ \t]+(%|)rdi" } } */
+
+#include <immintrin.h>
+
+unsigned int f1 ()
+{
+  return _rdsspd_u32 ();
+}
+
+unsigned long long f2 ()
+{
+  return _rdsspq_u64 ();
+}
+
+void f3 (unsigned int _a)
+{
+  _incsspd (_a);
+}
+
+void f4 (unsigned long long _a)
+{
+  _incsspq (_a);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-label.c b/gcc/testsuite/gcc.target/i386/cet-label.c
new file mode 100644
index 0000000..701ccc1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-label.c
@@ -0,0 +1,15 @@
+/* Verify that CET works.  */
+/* { dg-do compile } */
+/* { dg-options "-O -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32|endbr64" 3 } } */
+
+int func (int arg)
+{
+  static void *array[] = { &&foo, &&bar };
+
+  goto *array[arg];
+foo:
+  return arg*111;
+bar:
+  return arg*777;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack.c b/gcc/testsuite/gcc.target/i386/cet-notrack.c
new file mode 100644
index 0000000..173ff54
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack.c
@@ -0,0 +1,22 @@
+/* Verify that CET works.  */
+/* { dg-do compile } */
+/* { dg-options "-O -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32|endbr64" 1 } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 3 } } */
+
+int func (int a) __attribute__ ((notrack));
+int (*fptr) (int a) __attribute__ ((notrack));
+
+int foo (int arg)
+{
+int a, b;
+  a = func (arg);
+  b = (*fptr) (arg);
+  return a+b;
+}
+
+int func (int arg)
+{
+int (*fptrl) (int a) __attribute__ ((notrack));
+  return arg*(*fptrl)(arg);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-sjlj.c b/gcc/testsuite/gcc.target/i386/cet-sjlj.c
new file mode 100644
index 0000000..3095c23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-sjlj.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32|endbr64" 4 } } */
+/* { dg-final { scan-assembler-times "rdssp\[dq]" 2 } } */
+/* { dg-final { scan-assembler-times "incssp\[dq]" 1 } } */
+
+#include <stdio.h>
+#include <setjmp.h>
+
+jmp_buf buf;
+int bar (int);
+
+int
+foo (int i)
+{
+  int j = i * 11;
+
+  if (!__builtin_setjmp (buf))
+    {
+      j += 33;
+      printf ("After setjmp: j = %d\n", j);
+      bar (j);
+    }
+
+  return j + i;
+}
+
+int
+bar (int i)
+{
+int j = i;
+
+  j -= 111;
+  printf ("In longjmp: j = %d\n", j);
+  __builtin_longjmp (buf, 1);
+
+  return j;
+}
+
+int
+main ()
+{
+  foo (10);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-switch-1.c b/gcc/testsuite/gcc.target/i386/cet-switch-1.c
new file mode 100644
index 0000000..51a0d63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-switch-1.c
@@ -0,0 +1,25 @@
+/* Verify that CET works.  */
+/* { dg-do compile } */
+/* { dg-options "-O -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32|endbr64" 1 } } */
+/* { dg-final { scan-assembler-times "notrack jmp\[ \t]+\[*].L\[0-9]+" 1 } } */
+
+void func2 (int);
+
+int func1 (int arg)
+{
+  switch (arg)
+  {
+    case 1: func2 (arg*100);
+    case 2: func2 (arg*300);
+    case 5: func2 (arg*500);
+    case 8: func2 (arg*700);
+    case 7: func2 (arg*900);
+    case -1: func2 (arg*-100);
+    case -2: func2 (arg*-300);
+    case -5: func2 (arg*-500);
+    case -7: func2 (arg*-700);
+    case -9: func2 (arg*-900);
+  }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-switch-2.c b/gcc/testsuite/gcc.target/i386/cet-switch-2.c
new file mode 100644
index 0000000..0ac8e8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-switch-2.c
@@ -0,0 +1,25 @@
+/* Verify that CET works.  */
+/* { dg-do compile } */
+/* { dg-options "-O -mcet -mcet-switch" } */
+/* { dg-final { scan-assembler-times "endbr32|endbr64" 12 } } */
+/* { dg-final { scan-assembler-times "\[ \t]+jmp\[ \t]+\[*].L\[0-9]+" 1 } } */
+
+void func2 (int);
+
+int func1 (int arg)
+{
+  switch (arg)
+  {
+    case 1: func2 (arg*100);
+    case 2: func2 (arg*300);
+    case 5: func2 (arg*500);
+    case 8: func2 (arg*700);
+    case 7: func2 (arg*900);
+    case -1: func2 (arg*-100);
+    case -2: func2 (arg*-300);
+    case -5: func2 (arg*-500);
+    case -7: func2 (arg*-700);
+    case -9: func2 (arg*-900);
+  }
+  return 0;
+}
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 9ceda8a..f7fddee 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -273,6 +273,7 @@ DEFTIMEVAR (TV_REORDER_BLOCKS        , "reorder blocks")
 DEFTIMEVAR (TV_SHORTEN_BRANCH        , "shorten branches")
 DEFTIMEVAR (TV_REG_STACK             , "reg stack")
 DEFTIMEVAR (TV_FINAL                 , "final")
+DEFTIMEVAR (TV_CET		     , "cet")
 DEFTIMEVAR (TV_VAROUT                , "variable output")
 DEFTIMEVAR (TV_SYMOUT                , "symout")
 DEFTIMEVAR (TV_VAR_TRACKING          , "variable tracking")
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 34e5c17..d278788 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -96,6 +96,9 @@ struct die_struct;
 /* Nonzero if this is a cold function.  */
 #define ECF_COLD		  (1 << 15)
 
+/* Nonzero if this is a notrack call.  */
+#define ECF_NOTRACK		  (1 << 16)
+
 /* Call argument flags.  */
 /* Nonzero if the argument is not dereferenced recursively, thus only
    directly reachable memory is read or written.  */
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 2863f76..54139e7 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -614,6 +614,7 @@ extern rtl_opt_pass *make_pass_shorten_branches (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_set_nothrow_function_flags (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_dwarf2_frame (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_final (gcc::context *ctxt);
+extern rtl_opt_pass *make_pass_handle_cet (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_rtl_seqabstr (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_release_ssa_names (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_early_inline (gcc::context *ctxt);
-- 
1.8.3.1


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

* Re: [PATCH] [i386] Enable Control-flow Enforcement Technology (CET).
  2017-06-20 20:55 [PATCH] [i386] Enable Control-flow Enforcement Technology (CET) Tsimbalist, Igor V
@ 2017-06-20 21:29 ` Joseph Myers
  2017-06-21 14:07   ` Tsimbalist, Igor V
  0 siblings, 1 reply; 4+ messages in thread
From: Joseph Myers @ 2017-06-20 21:29 UTC (permalink / raw)
  To: Tsimbalist, Igor V; +Cc: gcc-patches, Chupin, Pavel V

This patch is completely missing documentation (in *.texi files) of the 
new options, attribute, built-in functions etc.

You appear to be adding quite target-specific things to the 
architecture-independent compiler.  If the attribute, for example, is to 
be architecture-independent, the documentation needs to define semantics 
for it that make sense on any architecture (or any architecture providing 
such features), not just on x86; the patch submission needs to justify the 
design choices of what is target-specific and what is target-independent.  
(Cf. MPX where there are various architecture-independent features for 
which a software implementation would be logically possible, although 
actually the only implementation of those features in GCC is for MPX 
hardware.)  I don't think this patch would even build for non-x86 targets, 
because you're putting completely x86-specific references such as 
TARGET_CET and gen_nop_endbr in target-independent files.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* RE: [PATCH] [i386] Enable Control-flow Enforcement Technology (CET).
  2017-06-20 21:29 ` Joseph Myers
@ 2017-06-21 14:07   ` Tsimbalist, Igor V
  2017-06-21 18:21     ` Bernhard Reutner-Fischer
  0 siblings, 1 reply; 4+ messages in thread
From: Tsimbalist, Igor V @ 2017-06-21 14:07 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Chupin, Pavel V, Tsimbalist, Igor V

Thanks for the feedback. I'll redo the patch according to your comments.

Igor

-----Original Message-----
From: Joseph Myers [mailto:joseph@codesourcery.com] 
Sent: Tuesday, June 20, 2017 11:30 PM
To: Tsimbalist, Igor V <igor.v.tsimbalist@intel.com>
Cc: gcc-patches@gcc.gnu.org; Chupin, Pavel V <pavel.v.chupin@intel.com>
Subject: Re: [PATCH] [i386] Enable Control-flow Enforcement Technology (CET).
Importance: High

This patch is completely missing documentation (in *.texi files) of the new options, attribute, built-in functions etc.

You appear to be adding quite target-specific things to the architecture-independent compiler.  If the attribute, for example, is to be architecture-independent, the documentation needs to define semantics for it that make sense on any architecture (or any architecture providing such features), not just on x86; the patch submission needs to justify the design choices of what is target-specific and what is target-independent.  
(Cf. MPX where there are various architecture-independent features for which a software implementation would be logically possible, although actually the only implementation of those features in GCC is for MPX
hardware.)  I don't think this patch would even build for non-x86 targets, because you're putting completely x86-specific references such as TARGET_CET and gen_nop_endbr in target-independent files.

--
Joseph S. Myers
joseph@codesourcery.com

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

* RE: [PATCH] [i386] Enable Control-flow Enforcement Technology (CET).
  2017-06-21 14:07   ` Tsimbalist, Igor V
@ 2017-06-21 18:21     ` Bernhard Reutner-Fischer
  0 siblings, 0 replies; 4+ messages in thread
From: Bernhard Reutner-Fischer @ 2017-06-21 18:21 UTC (permalink / raw)
  To: gcc-patches, Tsimbalist, Igor V; +Cc: gcc-patches, Chupin, Pavel V

On 21 June 2017 16:07:29 CEST, "Tsimbalist, Igor V" <igor.v.tsimbalist@intel.com> wrote:
>Thanks for the feedback. I'll redo the patch according to your
>comments.

what is "noni-tracking" ? Surplus i.
"codegeneration" probably lacks a space. 
Thanks,

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

end of thread, other threads:[~2017-06-21 18:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-20 20:55 [PATCH] [i386] Enable Control-flow Enforcement Technology (CET) Tsimbalist, Igor V
2017-06-20 21:29 ` Joseph Myers
2017-06-21 14:07   ` Tsimbalist, Igor V
2017-06-21 18:21     ` Bernhard Reutner-Fischer

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