From f8de876d8c7323cbf4c51cbe38e7ea2ac2b4e4e2 Mon Sep 17 00:00:00 2001 From: Igor Tsimbalist Date: Wed, 14 Feb 2018 16:06:21 +0100 Subject: [PATCH] Reimplement CET intrinsics for rdssp/incssp insn. Introduce a couple of new CET intrinsics for reading and updating a shadow stack pointer (_get_ssp and _inc_ssp). They replace the existing _rdssp[d|q] and _incssp[d|q] instrinsics. PR target/84239 * gcc/config/i386/cetintrin.h: Remove _rdssp[d|q] and add _get_ssp intrinsics. Remove argument from __builtin_ia32_rdssp[d|q]. * gcc/config/i386/i386-builtin-types.def: Add UINT_FTYPE_VOID. * gcc/config/i386/i386-builtin.def: Remove argument from __builtin_ia32_rdssp[d|q]. * gcc/config/i386/i386.c: Use UINT_FTYPE_VOID. Use ix86_expand_special_args_builtin for _rdssp[d|q]. * gcc/config/i386/i386.md: Remove argument from rdssp[si|di] insn. Clear register before usage. * doc/extend.texi: Remove argument from __builtin_ia32_rdssp[d|q]. Add documentation for new _get_ssp and _inc_ssp intrinsics. * testsuite/gcc.target/i386/cet-intrin-3.c: Use new _get_ssp and _inc_ssp intrinsics. * testsuite/gcc.target/i386/cet-intrin-4.c: Likewise. * testsuite/gcc.target/i386/cet-rdssp-1.c: Remove argument from __builtin_ia32_rdssp[d|q]. * libgcc/config/i386/shadow-stack-unwind.hi (_Unwind_Frames_Extra): Use new _get_ssp and _inc_ssp intrinsics. From-SVN: r257660 --- gcc/ChangeLog | 16 +++++ gcc/config/i386/cetintrin.h | 33 +++++------ gcc/config/i386/i386-builtin-types.def | 1 + gcc/config/i386/i386-builtin.def | 4 +- gcc/config/i386/i386.c | 3 +- gcc/config/i386/i386.md | 16 +++-- gcc/doc/extend.texi | 62 ++++++++++++++++++-- gcc/testsuite/ChangeLog | 9 +++ gcc/testsuite/gcc.target/i386/cet-intrin-3.c | 10 ++-- gcc/testsuite/gcc.target/i386/cet-intrin-4.c | 25 +------- gcc/testsuite/gcc.target/i386/cet-rdssp-1.c | 8 +-- libgcc/ChangeLog | 6 ++ libgcc/config/i386/shadow-stack-unwind.h | 17 ++---- 13 files changed, 127 insertions(+), 83 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cc294407691..b2bec8b574f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2018-02-14 Igor Tsimbalist + + PR target/84239 + * config/i386/cetintrin.h: Remove _rdssp[d|q] and + add _get_ssp intrinsics. Remove argument from + __builtin_ia32_rdssp[d|q]. + * config/i386/i386-builtin-types.def: Add UINT_FTYPE_VOID. + * config/i386/i386-builtin.def: Remove argument from + __builtin_ia32_rdssp[d|q]. + * config/i386/i386.c: Use UINT_FTYPE_VOID. Use + ix86_expand_special_args_builtin for _rdssp[d|q]. + * config/i386/i386.md: Remove argument from rdssp[si|di] insn. + Clear register before usage. + * doc/extend.texi: Remove argument from __builtin_ia32_rdssp[d|q]. + Add documentation for new _get_ssp and _inc_ssp intrinsics. + 2018-02-14 Richard Sandiford PR tree-optimization/84357 diff --git a/gcc/config/i386/cetintrin.h b/gcc/config/i386/cetintrin.h index 7a4b4d8bf24..e9abcf3c580 100644 --- a/gcc/config/i386/cetintrin.h +++ b/gcc/config/i386/cetintrin.h @@ -34,37 +34,32 @@ #define __DISABLE_SHSTK__ #endif /* __SHSTK__ */ -extern __inline unsigned int -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_rdsspd (unsigned int __B) -{ - return __builtin_ia32_rdsspd (__B); -} - #ifdef __x86_64__ extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_rdsspq (unsigned long long __B) +_get_ssp (void) { - return __builtin_ia32_rdsspq (__B); + return __builtin_ia32_rdsspq (); +} +#else +extern __inline unsigned int +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_get_ssp (void) +{ + return __builtin_ia32_rdsspd (); } #endif extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_incsspd (unsigned int __B) +_inc_ssp (unsigned int __B) { - __builtin_ia32_incsspd (__B); -} - #ifdef __x86_64__ -extern __inline void -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_incsspq (unsigned long long __B) -{ - __builtin_ia32_incsspq (__B); -} + __builtin_ia32_incsspq ((unsigned long long) __B); +#else + __builtin_ia32_incsspd (__B); #endif +} extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) diff --git a/gcc/config/i386/i386-builtin-types.def b/gcc/config/i386/i386-builtin-types.def index ba335490489..08360d23cbb 100644 --- a/gcc/config/i386/i386-builtin-types.def +++ b/gcc/config/i386/i386-builtin-types.def @@ -192,6 +192,7 @@ DEF_POINTER_TYPE (PCV64QI, V64QI, CONST) DEF_FUNCTION_TYPE (FLOAT128) DEF_FUNCTION_TYPE (UINT64) DEF_FUNCTION_TYPE (UNSIGNED) +DEF_FUNCTION_TYPE (UINT) DEF_FUNCTION_TYPE (USHORT) DEF_FUNCTION_TYPE (INT) DEF_FUNCTION_TYPE (VOID) diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def index 169189d962c..a48019499bd 100644 --- a/gcc/config/i386/i386-builtin.def +++ b/gcc/config/i386/i386-builtin.def @@ -3043,7 +3043,7 @@ BDESC (OPTION_MASK_ISA_SHSTK, CODE_FOR_clrssbsy, "__builtin_ia32_clrssbsy", IX86 BDESC_END (CET, CET_NORMAL) BDESC_FIRST (cet_rdssp, CET_NORMAL, - OPTION_MASK_ISA_SHSTK, CODE_FOR_rdsspsi, "__builtin_ia32_rdsspd", IX86_BUILTIN_RDSSPD, UNKNOWN, (int) UINT_FTYPE_UINT) -BDESC (OPTION_MASK_ISA_SHSTK | OPTION_MASK_ISA_64BIT, CODE_FOR_rdsspdi, "__builtin_ia32_rdsspq", IX86_BUILTIN_RDSSPQ, UNKNOWN, (int) UINT64_FTYPE_UINT64) + OPTION_MASK_ISA_SHSTK, CODE_FOR_rdsspsi, "__builtin_ia32_rdsspd", IX86_BUILTIN_RDSSPD, UNKNOWN, (int) UINT_FTYPE_VOID) +BDESC (OPTION_MASK_ISA_SHSTK | OPTION_MASK_ISA_64BIT, CODE_FOR_rdsspdi, "__builtin_ia32_rdsspq", IX86_BUILTIN_RDSSPQ, UNKNOWN, (int) UINT64_FTYPE_VOID) BDESC_END (CET_NORMAL, MAX) diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 020eef9fd7b..fa31f94d3e0 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -35708,6 +35708,7 @@ ix86_expand_special_args_builtin (const struct builtin_description *d, case INT_FTYPE_VOID: case USHORT_FTYPE_VOID: case UINT64_FTYPE_VOID: + case UINT_FTYPE_VOID: case UNSIGNED_FTYPE_VOID: nargs = 0; klass = load; @@ -38497,7 +38498,7 @@ s4fma_expand: && fcode <= IX86_BUILTIN__BDESC_CET_NORMAL_LAST) { i = fcode - IX86_BUILTIN__BDESC_CET_NORMAL_FIRST; - return ix86_expand_args_builtin (bdesc_cet_rdssp + i, exp, + return ix86_expand_special_args_builtin (bdesc_cet_rdssp + i, exp, target); } diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index a4832bf696f..3998053a506 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -18391,8 +18391,8 @@ reg_ssp = gen_reg_rtx (word_mode); emit_insn (gen_rtx_SET (reg_ssp, const0_rtx)); emit_insn ((word_mode == SImode) - ? gen_rdsspsi (reg_ssp, reg_ssp) - : gen_rdsspdi (reg_ssp, reg_ssp)); + ? gen_rdsspsi (reg_ssp) + : gen_rdsspdi (reg_ssp)); emit_move_insn (mem, reg_ssp); } DONE; @@ -18437,8 +18437,8 @@ reg_ssp = gen_reg_rtx (word_mode); emit_insn (gen_rtx_SET (reg_ssp, const0_rtx)); emit_insn ((word_mode == SImode) - ? gen_rdsspsi (reg_ssp, reg_ssp) - : gen_rdsspdi (reg_ssp, reg_ssp)); + ? gen_rdsspsi (reg_ssp) + : gen_rdsspdi (reg_ssp)); mem_buf = gen_rtx_MEM (word_mode, plus_constant (Pmode, operands[0], 3 * GET_MODE_SIZE (ptr_mode))); @@ -20167,12 +20167,10 @@ ;; CET instructions (define_insn "rdssp" [(set (match_operand:SWI48x 0 "register_operand" "=r") - (unspec_volatile:SWI48x - [(match_operand:SWI48x 1 "register_operand" "0")] - UNSPECV_NOP_RDSSP))] + (unspec_volatile:SWI48x [(const_int 0)] UNSPECV_NOP_RDSSP))] "TARGET_SHSTK" - "rdssp\t%0" - [(set_attr "length" "4") + "xor{l}\t%k0, %k0\n\trdssp\t%0" + [(set_attr "length" "6") (set_attr "type" "other")]) (define_insn "incssp" diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4f79a92fc1d..5c3c5ec2dc8 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -12461,6 +12461,7 @@ instructions, but allow the compiler to schedule those calls. * TILEPro Built-in Functions:: * x86 Built-in Functions:: * x86 transactional memory intrinsics:: +* x86 control-flow protection intrinsics:: @end menu @node AArch64 Built-in Functions @@ -21772,13 +21773,17 @@ void __builtin_ia32_wrpkru (unsigned int) unsigned int __builtin_ia32_rdpkru () @end smallexample -The following built-in functions are available when @option{-mcet} is used. -They are used to support Intel Control-flow Enforcment Technology (CET). -Each built-in function generates the machine instruction that is part of the -function's name. +The following built-in functions are available when @option{-mcet} or +@option{-mshstk} option is used. They support shadow stack +machine instructions from Intel Control-flow Enforcement Technology (CET). +Each built-in function generates the machine instruction that is part +of the function's name. These are the internal low-level functions. +Normally the functions in @ref{x86 control-flow protection intrinsics} +should be used instead. + @smallexample -unsigned int __builtin_ia32_rdsspd (unsigned int) -unsigned long long __builtin_ia32_rdsspq (unsigned long long) +unsigned int __builtin_ia32_rdsspd (void) +unsigned long long __builtin_ia32_rdsspq (void) void __builtin_ia32_incsspd (unsigned int) void __builtin_ia32_incsspq (unsigned long long) void __builtin_ia32_saveprevssp(void); @@ -21885,6 +21890,51 @@ else Note that, in most cases, the transactional and non-transactional code must synchronize together to ensure consistency. +@node x86 control-flow protection intrinsics +@subsection x86 Control-Flow Protection Intrinsics + +@deftypefn {CET Function} {ret_type} _get_ssp (void) +Get the current value of shadow stack pointer if shadow stack support +from Intel CET is enabled in the hardware or @code{0} otherwise. +The @code{ret_type} is @code{unsigned long long} for 64-bit targets +and @code{unsigned int} for 32-bit targets. +@end deftypefn + +@deftypefn {CET Function} void _inc_ssp (unsigned int) +Increment the current shadow stack pointer by the size specified by the +function argument. The argument is masked to a byte value for security +reasons, so to increment by more than 255 bytes you must call the function +multiple times. +@end deftypefn + +The shadow stack unwind code looks like: + +@smallexample +#include + +/* Unwind the shadow stack for EH. */ +#define _Unwind_Frames_Extra(x) \ + do \ + @{ \ + _Unwind_Word ssp = _get_ssp (); \ + if (ssp != 0) \ + @{ \ + _Unwind_Word tmp = (x); \ + while (tmp > 255) \ + @{ \ + _inc_ssp (tmp); \ + tmp -= 255; \ + @} \ + _inc_ssp (tmp); \ + @} \ + @} \ + while (0) +@end smallexample + +@noindent +This code runs unconditionally on all 64-bit processors. For 32-bit +processors the code runs on those that support multi-byte NOP instructions. + @node Target Format Checks @section Format Checks Specific to Particular Target Machines diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 473a2723012..51aeba332d3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2018-02-14 Igor Tsimbalist + + PR target/84239 + * gcc.target/i386/cet-intrin-3.c: Use new _get_ssp and + _inc_ssp intrinsics. + * gcc.target/i386/cet-intrin-4.c: Likewise. + * gcc.target/i386/cet-rdssp-1.c: Remove argument from + __builtin_ia32_rdssp[d|q]. + 2018-02-14 Richard Sandiford PR tree-optimization/84357 diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-3.c b/gcc/testsuite/gcc.target/i386/cet-intrin-3.c index bcd7203fdb4..b98c1e928d5 100644 --- a/gcc/testsuite/gcc.target/i386/cet-intrin-3.c +++ b/gcc/testsuite/gcc.target/i386/cet-intrin-3.c @@ -10,24 +10,22 @@ unsigned int f1 () { - unsigned int x = 0; - return _rdsspd (x); + return _get_ssp (); } void f3 (unsigned int _a) { - _incsspd (_a); + _inc_ssp (_a); } #ifdef __x86_64__ unsigned long long f2 () { - unsigned long long x = 0; - return _rdsspq (x); + return _get_ssp (); } void f4 (unsigned int _a) { - _incsspq (_a); + _inc_ssp (_a); } #endif diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-4.c b/gcc/testsuite/gcc.target/i386/cet-intrin-4.c index 437a4cd690c..86957b2eebe 100644 --- a/gcc/testsuite/gcc.target/i386/cet-intrin-4.c +++ b/gcc/testsuite/gcc.target/i386/cet-intrin-4.c @@ -5,27 +5,4 @@ /* { dg-final { scan-assembler "incssp\[dq]\[ \t]+(%|)\[re]di" { target { ! ia32 } } } } */ #include - -unsigned int f1 () -{ - unsigned int x = 0; - return _rdsspd (x); -} - -void f3 (unsigned int _a) -{ - _incsspd (_a); -} - -#ifdef __x86_64__ -unsigned long long f2 () -{ - unsigned long long x = 0; - return _rdsspq (x); -} - -void f4 (unsigned int _a) -{ - _incsspq (_a); -} -#endif +#include "cet-intrin-3.c" diff --git a/gcc/testsuite/gcc.target/i386/cet-rdssp-1.c b/gcc/testsuite/gcc.target/i386/cet-rdssp-1.c index fb50ff43504..6cd24f63384 100644 --- a/gcc/testsuite/gcc.target/i386/cet-rdssp-1.c +++ b/gcc/testsuite/gcc.target/i386/cet-rdssp-1.c @@ -5,18 +5,18 @@ void _exit(int status) __attribute__ ((__noreturn__)); #ifdef __x86_64__ # define incssp(x) __builtin_ia32_incsspq (x) -# define rdssp(x) __builtin_ia32_rdsspq (x) +# define rdssp() __builtin_ia32_rdsspq () #else # define incssp(x) __builtin_ia32_incsspd (x) -# define rdssp(x) __builtin_ia32_rdsspd (x) +# define rdssp() __builtin_ia32_rdsspd () #endif static void __attribute__ ((noinline, noclone)) test (unsigned long frames) { - unsigned long ssp = 0; - ssp = rdssp (ssp); + unsigned long ssp; + ssp = rdssp (); if (ssp != 0) { unsigned long tmp = frames; diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 1eb16631e03..692773d7d2d 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,9 @@ +2018-02-08 Igor Tsimbalist + + PR target/84239 + * config/i386/shadow-stack-unwind.hi (_Unwind_Frames_Extra): + Use new _get_ssp and _inc_ssp intrinsics. + 2018-02-02 Julia Koval * config/i386/cpuinfo.h (processor_subtypes): Add INTEL_COREI7_ICELAKE. diff --git a/libgcc/config/i386/shadow-stack-unwind.h b/libgcc/config/i386/shadow-stack-unwind.h index ef75d97aa2f..416e061dd46 100644 --- a/libgcc/config/i386/shadow-stack-unwind.h +++ b/libgcc/config/i386/shadow-stack-unwind.h @@ -22,30 +22,23 @@ a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ -#ifdef __x86_64__ -# define incssp(x) __builtin_ia32_incsspq ((x)) -# define rdssp(x) __builtin_ia32_rdsspq (x) -#else -# define incssp(x) __builtin_ia32_incsspd ((x)) -# define rdssp(x) __builtin_ia32_rdsspd (x) -#endif +#include /* Unwind the shadow stack for EH. */ #undef _Unwind_Frames_Extra #define _Unwind_Frames_Extra(x) \ do \ { \ - unsigned long ssp = 0; \ - ssp = rdssp (ssp); \ + _Unwind_Word ssp = _get_ssp (); \ if (ssp != 0) \ { \ - unsigned long tmp = (x); \ + _Unwind_Word tmp = (x); \ while (tmp > 255) \ { \ - incssp (tmp); \ + _inc_ssp (tmp); \ tmp -= 255; \ } \ - incssp (tmp); \ + _inc_ssp (tmp); \ } \ } \ while (0)