From 551e1ae81fde9401820b6d2b51d4d897d1cd2f26 Mon Sep 17 00:00:00 2001
From: Igor Tsimbalist <igor.v.tsimbalist@intel.com>
Date: Tue, 30 Jan 2018 16:42:42 +0300
Subject: [PATCH] PR84066 Wrong shadow stack register size is saved for x32

x32 is a 64-bit process with 32-bit software pointer and kernel may
place x32 shadow stack above 4GB.  We need to save and restore 64-bit
shadow stack register for x32. builtin jmp buf size is 5 pointers.  We
have space to save 64-bit shadow stack pointers: 32-bit SP, 32-bit FP,
32-bit IP, 64-bit SSP for x32.

	PR target/84066
	* gcc/config/i386/i386.md: Replace Pmode with word_mode in
	builtin_setjmp_setup and builtin_longjmp to support x32.
	* gcc/testsuite/gcc.target/i386/cet-sjlj-6.c: New test.
---
 gcc/ChangeLog                              |  6 +++++
 gcc/config/i386/i386.md                    | 40 ++++++++++++++++--------------
 gcc/testsuite/ChangeLog                    |  5 ++++
 gcc/testsuite/gcc.target/i386/cet-sjlj-6.c | 19 ++++++++++++++
 4 files changed, 51 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-sjlj-6.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ac75869..728c9fd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2018-01-30  Igor Tsimbalist  <igor.v.tsimbalist@intel.com>
+
+	PR target/84066
+	* config/i386/i386.md: Replace Pmode with word_mode in
+	builtin_setjmp_setup and builtin_longjmp to support x32.
+
 2018-01-29  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84057
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index fe9649d..a168c94 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -18385,13 +18385,14 @@
     {
       rtx mem, reg_ssp;
 
-      mem = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0],
-					       3 * GET_MODE_SIZE (Pmode)));
-      reg_ssp = gen_reg_rtx (Pmode);
+      mem = gen_rtx_MEM (word_mode,
+			 plus_constant (ptr_mode, operands[0],
+					3 * GET_MODE_SIZE (ptr_mode)));
+      reg_ssp = gen_reg_rtx (word_mode);
       emit_insn (gen_rtx_SET (reg_ssp, const0_rtx));
-      emit_insn ((Pmode == SImode)
-		  ? gen_rdsspsi (reg_ssp, reg_ssp)
-		  : gen_rdsspdi (reg_ssp, reg_ssp));
+      emit_insn ((word_mode == SImode)
+		 ? gen_rdsspsi (reg_ssp, reg_ssp)
+		 : gen_rdsspdi (reg_ssp, reg_ssp));
       emit_move_insn (mem, reg_ssp);
     }
   DONE;
@@ -18433,18 +18434,18 @@
       /* Get the current shadow stack pointer.  The code below will check if
 	 SHSTK feature is enabled.  If it is not enabled the RDSSP instruction
 	 is a NOP.  */
-      reg_ssp = gen_reg_rtx (Pmode);
+      reg_ssp = gen_reg_rtx (word_mode);
       emit_insn (gen_rtx_SET (reg_ssp, const0_rtx));
-      emit_insn ((Pmode == SImode)
+      emit_insn ((word_mode == SImode)
 		 ? gen_rdsspsi (reg_ssp, reg_ssp)
 		 : gen_rdsspdi (reg_ssp, reg_ssp));
-      mem_buf = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0],
-						   3 * GET_MODE_SIZE (Pmode)));
+      mem_buf = gen_rtx_MEM (word_mode,
+			     plus_constant (ptr_mode, operands[0],
+					    3 * GET_MODE_SIZE (ptr_mode)));
 
       /* Compare through substraction the saved and the current ssp to decide
 	 if ssp has to be adjusted.  */
-      reg_adj = gen_reg_rtx (Pmode);
-      tmp = gen_rtx_SET (reg_adj, gen_rtx_MINUS (Pmode, reg_ssp, mem_buf));
+      tmp = gen_rtx_SET (reg_ssp, gen_rtx_MINUS (word_mode, 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);
@@ -18460,9 +18461,10 @@
       JUMP_LABEL (jump) = noadj_label;
 
       /* Compute the numebr of frames to adjust.  */
+      reg_adj = gen_rtx_SUBREG (Pmode, reg_ssp, 0);
       tmp = gen_rtx_SET (reg_adj,
 			 gen_rtx_LSHIFTRT (Pmode, negate_rtx (Pmode, reg_adj),
-					   GEN_INT ((Pmode == SImode)
+					   GEN_INT ((word_mode == SImode)
 						    ? 2
 						    : 3)));
       clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
@@ -18487,9 +18489,9 @@
       emit_label (loop_label);
       LABEL_NUSES (loop_label) = 1;
 
-      emit_insn ((Pmode == SImode)
-		 ? gen_incsspsi (reg_adj)
-		 : gen_incsspdi (reg_adj));
+      emit_insn ((word_mode == SImode)
+		 ? gen_incsspsi (reg_ssp)
+		 : gen_incsspdi (reg_ssp));
       tmp = gen_rtx_SET (reg_adj, gen_rtx_MINUS (Pmode,
 						 reg_adj,
 						 GEN_INT (255)));
@@ -18511,9 +18513,9 @@
 
       emit_label (inc_label);
       LABEL_NUSES (inc_label) = 1;
-      emit_insn ((Pmode == SImode)
-		 ? gen_incsspsi (reg_adj)
-		 : gen_incsspdi (reg_adj));
+      emit_insn ((word_mode == SImode)
+		 ? gen_incsspsi (reg_ssp)
+		 : gen_incsspdi (reg_ssp));
 
       emit_label (noadj_label);
       LABEL_NUSES (noadj_label) = 1;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 18e19af..1575650 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2018-01-30  Igor Tsimbalist  <igor.v.tsimbalist@intel.com>
+
+	PR target/84066
+	* gcc.target/i386/cet-sjlj-6.c: New test.
+
 2018-01-29  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/84057
diff --git a/gcc/testsuite/gcc.target/i386/cet-sjlj-6.c b/gcc/testsuite/gcc.target/i386/cet-sjlj-6.c
new file mode 100644
index 0000000..df9d89b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-sjlj-6.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet -mx32" } */
+/* { dg-final { scan-assembler-times "endbr64" 2 } } */
+/* { dg-final { scan-assembler-times "movq\t.*buf\\+12" 1 } } */
+/* { dg-final { scan-assembler-times "subq\tbuf\\+12" 1 } } */
+/* { dg-final { scan-assembler-times "rdsspq" 2 } } */
+/* { dg-final { scan-assembler-times "incsspq" 2 } } */
+
+void *buf[5];
+
+void raise0(void)
+{
+  __builtin_longjmp (buf, 1);
+}
+
+void execute(int cmd)
+{
+  __builtin_setjmp (buf);
+}
-- 
1.8.3.1

