This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH v2, rs6000] Add -msafe-indirect-jumps option and implement safe bctr / bctrl
- From: Segher Boessenkool <segher at kernel dot crashing dot org>
- To: Bill Schmidt <wschmidt at linux dot vnet dot ibm dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>, amodra at gmail dot com, David Edelsohn <dje dot gcc at gmail dot com>
- Date: Mon, 15 Jan 2018 10:38:34 -0600
- Subject: Re: [PATCH v2, rs6000] Add -msafe-indirect-jumps option and implement safe bctr / bctrl
- Authentication-results: sourceware.org; auth=none
- References: <b8d0b56c-4958-0545-beba-5016403f2a5f@linux.vnet.ibm.com>
Hi!
On Sat, Jan 13, 2018 at 10:53:57PM -0600, Bill Schmidt wrote:
> 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.
I think we settled on calling the option -mmispredict-indirect-jumps;
please let me know if you still agree with that. Or have thought of a
better name :-)
> 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 "crset eq" followed by a beqctrl-. Using the CR0.eq bit is safe since CR0
> is volatile over the call.
And CR0 is unused by the call; compare to CR1 (on older ABIs) for example.
> I've also added code to replace uses of bctr when the new option is specified,
> with the sequence
>
> crset 4x[CRb]+2
> beqctr- CRb
> b .
>
> where CRb is an available condition register field. This applies to all
> subtargets, and in particular is not restricted to ELFv2. The use cases
> covered here are computed gotos and switch statements.
>
> NOT yet covered by this patch: indirect calls for ELFv1. That will come later.
Would be nice to have it for all ABIs, even.
> Please let me know if there is a better way to represent the crset without
> an unspec.
See the various patterns using cr%q. I'm not sure they can generate creqv
(i.e. crset) currently, but that could be added (like crnot is there already,
for example). If you don't use unspec (or maybe unspec_volatile) it can be
optimised away though.
Maybe it is best not to put the crset into its own insn, just make it part
of the bigger pattern, with an appropriate clobber?
> For the indirect jump, I don't see a way around it due to the
> expected form of indirect jumps in cfganal.c.
I'm not sure what you are getting at here, could you explain a bit?
> (define_expand "indirect_jump"
> - [(set (pc) (match_operand 0 "register_operand"))])
> + [(set (pc) (match_operand 0 "register_operand"))]
> + ""
> +{
> + /* We need to reserve a CR when forcing a mispredicted jump. */
> + if (rs6000_safe_indirect_jumps) {
> + rtx ccreg = gen_reg_rtx (CCmode);
> + emit_insn (gen_rtx_SET (ccreg,
> + gen_rtx_UNSPEC (CCmode,
> + gen_rtvec (1, const0_rtx),
> + UNSPEC_CRSET_EQ)));
> + rtvec v = rtvec_alloc (2);
> + RTVEC_ELT (v, 0) = operands[0];
> + RTVEC_ELT (v, 1) = ccreg;
> + emit_jump_insn (gen_rtx_SET (pc_rtx,
> + gen_rtx_UNSPEC (Pmode, v,
> + UNSPEC_COMP_GOTO_CR)));
> + DONE;
> + }
> +})
>
> (define_insn "*indirect_jump<mode>"
> [(set (pc)
> (match_operand:P 0 "register_operand" "c,*l"))]
> - ""
> + "!rs6000_safe_indirect_jumps"
> "b%T0"
> [(set_attr "type" "jmpreg")])
>
> +(define_insn "*indirect_jump<mode>_safe"
> + [(set (pc)
> + (unspec:P [(match_operand:P 0 "register_operand" "c,*l")
> + (match_operand:CC 1 "cc_reg_operand" "y,y")]
> + UNSPEC_COMP_GOTO_CR))]
> + "rs6000_safe_indirect_jumps"
> + "beq%T0- %1\;b ."
> + [(set_attr "type" "jmpreg")
> + (set_attr "length" "8")])
> +
> +(define_insn "*set_cr_eq"
> + [(set (match_operand:CC 0 "cc_reg_operand" "=y")
> + (unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ))]
> + "rs6000_safe_indirect_jumps"
> + "crset %E0"
> + [(set_attr "type" "cr_logical")])
So merge this latter insn into the previous, making the CC a clobber?
Like (not tested):
+(define_insn "indirect_jump<mode>_mispredict"
+ [(set (pc)
+ (match_operand:P 0 "register_operand" "c,*l")
+ (clobber (match_operand:CC 1 "cc_reg_operand" "y,y"))]
+ "rs6000_safe_indirect_jumps"
+ "crset %E1\;beq%T0- %1\;b ."
+ [(set_attr "type" "jmpreg")
+ (set_attr "length" "12")])
and then change the indirect_jump pattern to simply select between the normal
and mispredict patterns?
> +(define_expand "tablejumpsi_safe"
And then similar for tablejump.
Segher