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  <wschm...@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  <wschm...@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-" } } */

Reply via email to