[rs6000] Add -msafe-indirect-jumps option and implement safe bctrl

Message ID 0d2655b0-d226-7791-0795-2217ec2b5f4f@linux.vnet.ibm.com
State New
Headers show
Series
  • [rs6000] Add -msafe-indirect-jumps option and implement safe bctrl
Related show

Commit Message

Bill Schmidt Jan. 12, 2018, 10:33 p.m.
Hi,

This patch adds a new option for the compiler to produce only "safe" indirect
jumps, in the sense that these jumps are deliberately mispredicted to inhibit
speculative execution.  For now, this option is undocumented; this may change
at some future date.  It is intended eventually for the linker to also honor
this flag when creating PLT stubs, for example.

In addition to the new option, I've included changes to indirect calls for
the ELFv2 ABI when the option is specified.  In place of bctrl, we generate
a seteq followed by a beqctrl-.  Using the CR0.eq bit is safe since CR0 is
volatile over the call.

Future patches will address uses of the bctr instruction, which will require
a virtual condition register, since no assumptions can be made about CR
availability at bctr locations.

Bootstrapped and tested on powerpc64le-linux-gnu with no regressions.  Is this
okay for trunk?

Thanks,
Bill


[gcc]

2018-01-12  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	* config/rs6000/rs6000.c (rs6000_opt_vars): Add entry for
	safe-indirect-jumps.
	* config/rs6000/rs6000.md (*call_indirect_elfv2<mode>): Restrict
	to case where -msafe-indirect-jumps is not in effect.
	(*call_indirect_elf2<mode>_safe): New define_insn.
	(*call_value_indirect_elfv2<mode>): Restrict to case where
	-msafe-indirect-jumps is not in effect.
	(*call_value_indirect_elfv2<mode>_safe): New define_insn.
	* config/rs6000/rs6000.opt (msafe-indirect-jumps): New option.

[gcc/testsuite]

2018-01-12  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	* gcc.target/powerpc/safe-indirect-jump-1.c: New file.

Comments

Bill Schmidt Jan. 14, 2018, 4:55 a.m. | #1
Hi, 

This is now superceded by https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01204.html.
Sorry for the noise.

Thanks,
Bill

> On Jan 12, 2018, at 4:33 PM, Bill Schmidt <wschmidt@linux.vnet.ibm.com> wrote:
> 
> Hi,
> 
> This patch adds a new option for the compiler to produce only "safe" indirect
> jumps, in the sense that these jumps are deliberately mispredicted to inhibit
> speculative execution.  For now, this option is undocumented; this may change
> at some future date.  It is intended eventually for the linker to also honor
> this flag when creating PLT stubs, for example.
> 
> In addition to the new option, I've included changes to indirect calls for
> the ELFv2 ABI when the option is specified.  In place of bctrl, we generate
> a seteq followed by a beqctrl-.  Using the CR0.eq bit is safe since CR0 is
> volatile over the call.
> 
> Future patches will address uses of the bctr instruction, which will require
> a virtual condition register, since no assumptions can be made about CR
> availability at bctr locations.
> 
> Bootstrapped and tested on powerpc64le-linux-gnu with no regressions.  Is this
> okay for trunk?
> 
> Thanks,
> Bill
> 
> 
> [gcc]
> 
> 2018-01-12  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	* config/rs6000/rs6000.c (rs6000_opt_vars): Add entry for
> 	safe-indirect-jumps.
> 	* config/rs6000/rs6000.md (*call_indirect_elfv2<mode>): Restrict
> 	to case where -msafe-indirect-jumps is not in effect.
> 	(*call_indirect_elf2<mode>_safe): New define_insn.
> 	(*call_value_indirect_elfv2<mode>): Restrict to case where
> 	-msafe-indirect-jumps is not in effect.
> 	(*call_value_indirect_elfv2<mode>_safe): New define_insn.
> 	* config/rs6000/rs6000.opt (msafe-indirect-jumps): New option.
> 
> [gcc/testsuite]
> 
> 2018-01-12  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	* gcc.target/powerpc/safe-indirect-jump-1.c: New file.
> 
> 
> Index: gcc/config/rs6000/rs6000.c
> ===================================================================
> --- gcc/config/rs6000/rs6000.c	(revision 256364)
> +++ gcc/config/rs6000/rs6000.c	(working copy)
> @@ -36726,6 +36726,9 @@ static struct rs6000_opt_var const rs6000_opt_vars
>   { "sched-epilog",
>     offsetof (struct gcc_options, x_TARGET_SCHED_PROLOG),
>     offsetof (struct cl_target_option, x_TARGET_SCHED_PROLOG), },
> +  { "safe-indirect-jumps",
> +    offsetof (struct gcc_options, x_rs6000_safe_indirect_jumps),
> +    offsetof (struct cl_target_option, x_rs6000_safe_indirect_jumps), },
> };
> 
> /* Inner function to handle attribute((target("..."))) and #pragma GCC target
> Index: gcc/config/rs6000/rs6000.md
> ===================================================================
> --- gcc/config/rs6000/rs6000.md	(revision 256364)
> +++ gcc/config/rs6000/rs6000.md	(working copy)
> @@ -11222,11 +11222,22 @@
> 	 (match_operand 1 "" "g,g"))
>    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
>    (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_ELFv2"
> +  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps"
>   "b%T0l\;<ptrload> 2,%2(1)"
>   [(set_attr "type" "jmpreg")
>    (set_attr "length" "8")])
> 
> +;; Variant with deliberate misprediction.
> +(define_insn "*call_indirect_elfv2<mode>_safe"
> +  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
> +	 (match_operand 1 "" "g,g"))
> +   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps"
> +  "seteq\;beq%T0l-\;<ptrload> 2,%2(1)"
> +  [(set_attr "type" "jmpreg")
> +   (set_attr "length" "12")])
> +
> (define_insn "*call_value_indirect_elfv2<mode>"
>   [(set (match_operand 0 "" "")
> 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> @@ -11233,11 +11244,22 @@
> 	      (match_operand 2 "" "g,g")))
>    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
>    (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_ELFv2"
> +  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps"
>   "b%T1l\;<ptrload> 2,%3(1)"
>   [(set_attr "type" "jmpreg")
>    (set_attr "length" "8")])
> 
> +; Variant with deliberate misprediction.
> +(define_insn "*call_value_indirect_elfv2<mode>_safe"
> +  [(set (match_operand 0 "" "")
> +	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> +	      (match_operand 2 "" "g,g")))
> +   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps"
> +  "seteq\;beq%T1l-\;<ptrload> 2,%3(1)"
> +  [(set_attr "type" "jmpreg")
> +   (set_attr "length" "12")])
> 
> ;; Call subroutine returning any type.
> (define_expand "untyped_call"
> Index: gcc/config/rs6000/rs6000.opt
> ===================================================================
> --- gcc/config/rs6000/rs6000.opt	(revision 256364)
> +++ gcc/config/rs6000/rs6000.opt	(working copy)
> @@ -617,3 +617,8 @@ Use the given offset for addressing the stack-prot
> 
> TargetVariable
> long rs6000_stack_protector_guard_offset = 0
> +
> +;; -msafe-indirect-jumps adds deliberate misprediction to indirect
> +;; branches via the CTR.
> +msafe-indirect-jumps
> +Target Undocumented Var(rs6000_safe_indirect_jumps) Init(0) Save
> Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c	(nonexistent)
> +++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c	(working copy)
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target { powerpc64le-*-* } } } */
> +/* { dg-options "-msafe-indirect-jumps" } */
> +
> +/* Test for deliberate misprediction of indirect calls for ELFv2.  */
> +
> +extern int (*f)();
> +
> +int bar ()
> +{
> +  return (*f) ();
> +}
> +
> +/* { dg-final { scan-assembler "seteq" } } */
> +/* { dg-final { scan-assembler "beqctrl-" } } */
>

Patch

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 256364)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -36726,6 +36726,9 @@  static struct rs6000_opt_var const rs6000_opt_vars
   { "sched-epilog",
     offsetof (struct gcc_options, x_TARGET_SCHED_PROLOG),
     offsetof (struct cl_target_option, x_TARGET_SCHED_PROLOG), },
+  { "safe-indirect-jumps",
+    offsetof (struct gcc_options, x_rs6000_safe_indirect_jumps),
+    offsetof (struct cl_target_option, x_rs6000_safe_indirect_jumps), },
 };
 
 /* Inner function to handle attribute((target("..."))) and #pragma GCC target
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 256364)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -11222,11 +11222,22 @@ 
 	 (match_operand 1 "" "g,g"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2"
+  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps"
   "b%T0l\;<ptrload> 2,%2(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
 
+;; Variant with deliberate misprediction.
+(define_insn "*call_indirect_elfv2<mode>_safe"
+  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+	 (match_operand 1 "" "g,g"))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps"
+  "seteq\;beq%T0l-\;<ptrload> 2,%2(1)"
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
@@ -11233,11 +11244,22 @@ 
 	      (match_operand 2 "" "g,g")))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2"
+  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps"
   "b%T1l\;<ptrload> 2,%3(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
 
+; Variant with deliberate misprediction.
+(define_insn "*call_value_indirect_elfv2<mode>_safe"
+  [(set (match_operand 0 "" "")
+	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+	      (match_operand 2 "" "g,g")))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps"
+  "seteq\;beq%T1l-\;<ptrload> 2,%3(1)"
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
 
 ;; Call subroutine returning any type.
 (define_expand "untyped_call"
Index: gcc/config/rs6000/rs6000.opt
===================================================================
--- gcc/config/rs6000/rs6000.opt	(revision 256364)
+++ gcc/config/rs6000/rs6000.opt	(working copy)
@@ -617,3 +617,8 @@  Use the given offset for addressing the stack-prot
 
 TargetVariable
 long rs6000_stack_protector_guard_offset = 0
+
+;; -msafe-indirect-jumps adds deliberate misprediction to indirect
+;; branches via the CTR.
+msafe-indirect-jumps
+Target Undocumented Var(rs6000_safe_indirect_jumps) Init(0) Save
Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c	(working copy)
@@ -0,0 +1,14 @@ 
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-options "-msafe-indirect-jumps" } */
+
+/* Test for deliberate misprediction of indirect calls for ELFv2.  */
+
+extern int (*f)();
+
+int bar ()
+{
+  return (*f) ();
+}
+
+/* { dg-final { scan-assembler "seteq" } } */
+/* { dg-final { scan-assembler "beqctrl-" } } */