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: Bill Schmidt <wschmidt at linux dot vnet dot ibm dot com>
- To: Segher Boessenkool <segher at kernel dot crashing dot org>
- 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 11:54:41 -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> <20180115163834.GZ21977@gate.crashing.org>
Hi Segher,
Thanks for the quick review!
> On Jan 15, 2018, at 10:38 AM, Segher Boessenkool <segher@kernel.crashing.org> wrote:
>
> 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 :-)
Looks like we are now looking at -m[no-]speculate-indirect-jumps with
default to true. LLVM folks are in agreement too.
>
>> 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.
Yeah, that's the plan. Everything that uses bctr[l]. I used too loose of language.
>
>> 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?
An indirect jump is expected to be of the form (set (pc) (...other stuff));
otherwise it might get missed and blocks that are only reachable from
an indirect jump can get deleted. I found this out when I tried to do
something involving a parallel that was not very bright; that doesn't
actually prevent anything if you are doing things right. And the
clobber solution you suggest should be just fine.
tldr: Ignore my lunatic ravings. ;-)
Thanks,
Bill
>
>> (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
>