173471bf0Spatrick //===- ARMSLSHardening.cpp - Harden Straight Line Missspeculation ---------===//
273471bf0Spatrick //
373471bf0Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
473471bf0Spatrick // See https://llvm.org/LICENSE.txt for license information.
573471bf0Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673471bf0Spatrick //
773471bf0Spatrick //===----------------------------------------------------------------------===//
873471bf0Spatrick //
973471bf0Spatrick // This file contains a pass to insert code to mitigate against side channel
1073471bf0Spatrick // vulnerabilities that may happen under straight line miss-speculation.
1173471bf0Spatrick //
1273471bf0Spatrick //===----------------------------------------------------------------------===//
1373471bf0Spatrick
1473471bf0Spatrick #include "ARM.h"
1573471bf0Spatrick #include "ARMInstrInfo.h"
1673471bf0Spatrick #include "ARMSubtarget.h"
1773471bf0Spatrick #include "llvm/CodeGen/IndirectThunks.h"
1873471bf0Spatrick #include "llvm/CodeGen/MachineBasicBlock.h"
1973471bf0Spatrick #include "llvm/CodeGen/MachineFunction.h"
2073471bf0Spatrick #include "llvm/CodeGen/MachineFunctionPass.h"
2173471bf0Spatrick #include "llvm/CodeGen/MachineInstr.h"
2273471bf0Spatrick #include "llvm/CodeGen/MachineInstrBuilder.h"
2373471bf0Spatrick #include "llvm/CodeGen/MachineOperand.h"
2473471bf0Spatrick #include "llvm/IR/DebugLoc.h"
2573471bf0Spatrick #include <cassert>
2673471bf0Spatrick
2773471bf0Spatrick using namespace llvm;
2873471bf0Spatrick
2973471bf0Spatrick #define DEBUG_TYPE "arm-sls-hardening"
3073471bf0Spatrick
3173471bf0Spatrick #define ARM_SLS_HARDENING_NAME "ARM sls hardening pass"
3273471bf0Spatrick
3373471bf0Spatrick namespace {
3473471bf0Spatrick
3573471bf0Spatrick class ARMSLSHardening : public MachineFunctionPass {
3673471bf0Spatrick public:
3773471bf0Spatrick const TargetInstrInfo *TII;
3873471bf0Spatrick const ARMSubtarget *ST;
3973471bf0Spatrick
4073471bf0Spatrick static char ID;
4173471bf0Spatrick
ARMSLSHardening()4273471bf0Spatrick ARMSLSHardening() : MachineFunctionPass(ID) {
4373471bf0Spatrick initializeARMSLSHardeningPass(*PassRegistry::getPassRegistry());
4473471bf0Spatrick }
4573471bf0Spatrick
4673471bf0Spatrick bool runOnMachineFunction(MachineFunction &Fn) override;
4773471bf0Spatrick
getPassName() const4873471bf0Spatrick StringRef getPassName() const override { return ARM_SLS_HARDENING_NAME; }
4973471bf0Spatrick
getAnalysisUsage(AnalysisUsage & AU) const5073471bf0Spatrick void getAnalysisUsage(AnalysisUsage &AU) const override {
5173471bf0Spatrick AU.setPreservesCFG();
5273471bf0Spatrick MachineFunctionPass::getAnalysisUsage(AU);
5373471bf0Spatrick }
5473471bf0Spatrick
5573471bf0Spatrick private:
5673471bf0Spatrick bool hardenReturnsAndBRs(MachineBasicBlock &MBB) const;
5773471bf0Spatrick bool hardenIndirectCalls(MachineBasicBlock &MBB) const;
5873471bf0Spatrick MachineBasicBlock &
5973471bf0Spatrick ConvertIndirectCallToIndirectJump(MachineBasicBlock &MBB,
6073471bf0Spatrick MachineBasicBlock::iterator) const;
6173471bf0Spatrick };
6273471bf0Spatrick
6373471bf0Spatrick } // end anonymous namespace
6473471bf0Spatrick
6573471bf0Spatrick char ARMSLSHardening::ID = 0;
6673471bf0Spatrick
6773471bf0Spatrick INITIALIZE_PASS(ARMSLSHardening, "arm-sls-hardening",
6873471bf0Spatrick ARM_SLS_HARDENING_NAME, false, false)
6973471bf0Spatrick
insertSpeculationBarrier(const ARMSubtarget * ST,MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,DebugLoc DL,bool AlwaysUseISBDSB=false)7073471bf0Spatrick static void insertSpeculationBarrier(const ARMSubtarget *ST,
7173471bf0Spatrick MachineBasicBlock &MBB,
7273471bf0Spatrick MachineBasicBlock::iterator MBBI,
7373471bf0Spatrick DebugLoc DL,
7473471bf0Spatrick bool AlwaysUseISBDSB = false) {
7573471bf0Spatrick assert(MBBI != MBB.begin() &&
7673471bf0Spatrick "Must not insert SpeculationBarrierEndBB as only instruction in MBB.");
7773471bf0Spatrick assert(std::prev(MBBI)->isBarrier() &&
7873471bf0Spatrick "SpeculationBarrierEndBB must only follow unconditional control flow "
7973471bf0Spatrick "instructions.");
8073471bf0Spatrick assert(std::prev(MBBI)->isTerminator() &&
8173471bf0Spatrick "SpeculationBarrierEndBB must only follow terminators.");
8273471bf0Spatrick const TargetInstrInfo *TII = ST->getInstrInfo();
8373471bf0Spatrick assert(ST->hasDataBarrier() || ST->hasSB());
8473471bf0Spatrick bool ProduceSB = ST->hasSB() && !AlwaysUseISBDSB;
8573471bf0Spatrick unsigned BarrierOpc =
8673471bf0Spatrick ProduceSB ? (ST->isThumb() ? ARM::t2SpeculationBarrierSBEndBB
8773471bf0Spatrick : ARM::SpeculationBarrierSBEndBB)
8873471bf0Spatrick : (ST->isThumb() ? ARM::t2SpeculationBarrierISBDSBEndBB
8973471bf0Spatrick : ARM::SpeculationBarrierISBDSBEndBB);
9073471bf0Spatrick if (MBBI == MBB.end() || !isSpeculationBarrierEndBBOpcode(MBBI->getOpcode()))
9173471bf0Spatrick BuildMI(MBB, MBBI, DL, TII->get(BarrierOpc));
9273471bf0Spatrick }
9373471bf0Spatrick
runOnMachineFunction(MachineFunction & MF)9473471bf0Spatrick bool ARMSLSHardening::runOnMachineFunction(MachineFunction &MF) {
9573471bf0Spatrick ST = &MF.getSubtarget<ARMSubtarget>();
9673471bf0Spatrick TII = MF.getSubtarget().getInstrInfo();
9773471bf0Spatrick
9873471bf0Spatrick bool Modified = false;
9973471bf0Spatrick for (auto &MBB : MF) {
10073471bf0Spatrick Modified |= hardenReturnsAndBRs(MBB);
10173471bf0Spatrick Modified |= hardenIndirectCalls(MBB);
10273471bf0Spatrick }
10373471bf0Spatrick
10473471bf0Spatrick return Modified;
10573471bf0Spatrick }
10673471bf0Spatrick
hardenReturnsAndBRs(MachineBasicBlock & MBB) const10773471bf0Spatrick bool ARMSLSHardening::hardenReturnsAndBRs(MachineBasicBlock &MBB) const {
10873471bf0Spatrick if (!ST->hardenSlsRetBr())
10973471bf0Spatrick return false;
11073471bf0Spatrick assert(!ST->isThumb1Only());
11173471bf0Spatrick bool Modified = false;
11273471bf0Spatrick MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(), E = MBB.end();
11373471bf0Spatrick MachineBasicBlock::iterator NextMBBI;
11473471bf0Spatrick for (; MBBI != E; MBBI = NextMBBI) {
11573471bf0Spatrick MachineInstr &MI = *MBBI;
11673471bf0Spatrick NextMBBI = std::next(MBBI);
11773471bf0Spatrick if (isIndirectControlFlowNotComingBack(MI)) {
11873471bf0Spatrick assert(MI.isTerminator());
11973471bf0Spatrick assert(!TII->isPredicated(MI));
12073471bf0Spatrick insertSpeculationBarrier(ST, MBB, std::next(MBBI), MI.getDebugLoc());
12173471bf0Spatrick Modified = true;
12273471bf0Spatrick }
12373471bf0Spatrick }
12473471bf0Spatrick return Modified;
12573471bf0Spatrick }
12673471bf0Spatrick
12773471bf0Spatrick static const char SLSBLRNamePrefix[] = "__llvm_slsblr_thunk_";
12873471bf0Spatrick
12973471bf0Spatrick static const struct ThunkNameRegMode {
13073471bf0Spatrick const char* Name;
13173471bf0Spatrick Register Reg;
13273471bf0Spatrick bool isThumb;
13373471bf0Spatrick } SLSBLRThunks[] = {
13473471bf0Spatrick {"__llvm_slsblr_thunk_arm_r0", ARM::R0, false},
13573471bf0Spatrick {"__llvm_slsblr_thunk_arm_r1", ARM::R1, false},
13673471bf0Spatrick {"__llvm_slsblr_thunk_arm_r2", ARM::R2, false},
13773471bf0Spatrick {"__llvm_slsblr_thunk_arm_r3", ARM::R3, false},
13873471bf0Spatrick {"__llvm_slsblr_thunk_arm_r4", ARM::R4, false},
13973471bf0Spatrick {"__llvm_slsblr_thunk_arm_r5", ARM::R5, false},
14073471bf0Spatrick {"__llvm_slsblr_thunk_arm_r6", ARM::R6, false},
14173471bf0Spatrick {"__llvm_slsblr_thunk_arm_r7", ARM::R7, false},
14273471bf0Spatrick {"__llvm_slsblr_thunk_arm_r8", ARM::R8, false},
14373471bf0Spatrick {"__llvm_slsblr_thunk_arm_r9", ARM::R9, false},
14473471bf0Spatrick {"__llvm_slsblr_thunk_arm_r10", ARM::R10, false},
14573471bf0Spatrick {"__llvm_slsblr_thunk_arm_r11", ARM::R11, false},
14673471bf0Spatrick {"__llvm_slsblr_thunk_arm_sp", ARM::SP, false},
14773471bf0Spatrick {"__llvm_slsblr_thunk_arm_pc", ARM::PC, false},
14873471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r0", ARM::R0, true},
14973471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r1", ARM::R1, true},
15073471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r2", ARM::R2, true},
15173471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r3", ARM::R3, true},
15273471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r4", ARM::R4, true},
15373471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r5", ARM::R5, true},
15473471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r6", ARM::R6, true},
15573471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r7", ARM::R7, true},
15673471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r8", ARM::R8, true},
15773471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r9", ARM::R9, true},
15873471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r10", ARM::R10, true},
15973471bf0Spatrick {"__llvm_slsblr_thunk_thumb_r11", ARM::R11, true},
16073471bf0Spatrick {"__llvm_slsblr_thunk_thumb_sp", ARM::SP, true},
16173471bf0Spatrick {"__llvm_slsblr_thunk_thumb_pc", ARM::PC, true},
16273471bf0Spatrick };
16373471bf0Spatrick
164*d415bd75Srobert // An enum for tracking whether Arm and Thumb thunks have been inserted into the
165*d415bd75Srobert // current module so far.
166*d415bd75Srobert enum ArmInsertedThunks { ArmThunk = 1, ThumbThunk = 2 };
167*d415bd75Srobert
operator |=(ArmInsertedThunks & X,ArmInsertedThunks Y)168*d415bd75Srobert inline ArmInsertedThunks &operator|=(ArmInsertedThunks &X,
169*d415bd75Srobert ArmInsertedThunks Y) {
170*d415bd75Srobert return X = static_cast<ArmInsertedThunks>(X | Y);
171*d415bd75Srobert }
172*d415bd75Srobert
17373471bf0Spatrick namespace {
174*d415bd75Srobert struct SLSBLRThunkInserter
175*d415bd75Srobert : ThunkInserter<SLSBLRThunkInserter, ArmInsertedThunks> {
getThunkPrefix__anona645888e0211::SLSBLRThunkInserter17673471bf0Spatrick const char *getThunkPrefix() { return SLSBLRNamePrefix; }
mayUseThunk__anona645888e0211::SLSBLRThunkInserter177*d415bd75Srobert bool mayUseThunk(const MachineFunction &MF,
178*d415bd75Srobert ArmInsertedThunks InsertedThunks) {
179*d415bd75Srobert if ((InsertedThunks & ArmThunk &&
180*d415bd75Srobert !MF.getSubtarget<ARMSubtarget>().isThumb()) ||
181*d415bd75Srobert (InsertedThunks & ThumbThunk &&
182*d415bd75Srobert MF.getSubtarget<ARMSubtarget>().isThumb()))
183*d415bd75Srobert return false;
18473471bf0Spatrick ComdatThunks &= !MF.getSubtarget<ARMSubtarget>().hardenSlsNoComdat();
18573471bf0Spatrick // FIXME: This could also check if there are any indirect calls in the
18673471bf0Spatrick // function to more accurately reflect if a thunk will be needed.
18773471bf0Spatrick return MF.getSubtarget<ARMSubtarget>().hardenSlsBlr();
18873471bf0Spatrick }
189*d415bd75Srobert ArmInsertedThunks insertThunks(MachineModuleInfo &MMI, MachineFunction &MF);
19073471bf0Spatrick void populateThunk(MachineFunction &MF);
19173471bf0Spatrick
19273471bf0Spatrick private:
19373471bf0Spatrick bool ComdatThunks = true;
19473471bf0Spatrick };
19573471bf0Spatrick } // namespace
19673471bf0Spatrick
insertThunks(MachineModuleInfo & MMI,MachineFunction & MF)197*d415bd75Srobert ArmInsertedThunks SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI,
198*d415bd75Srobert MachineFunction &MF) {
19973471bf0Spatrick // FIXME: It probably would be possible to filter which thunks to produce
20073471bf0Spatrick // based on which registers are actually used in indirect calls in this
20173471bf0Spatrick // function. But would that be a worthwhile optimization?
202*d415bd75Srobert const ARMSubtarget *ST = &MF.getSubtarget<ARMSubtarget>();
20373471bf0Spatrick for (auto T : SLSBLRThunks)
204*d415bd75Srobert if (ST->isThumb() == T.isThumb)
20573471bf0Spatrick createThunkFunction(MMI, T.Name, ComdatThunks);
206*d415bd75Srobert return ST->isThumb() ? ThumbThunk : ArmThunk;
20773471bf0Spatrick }
20873471bf0Spatrick
populateThunk(MachineFunction & MF)20973471bf0Spatrick void SLSBLRThunkInserter::populateThunk(MachineFunction &MF) {
21073471bf0Spatrick // FIXME: How to better communicate Register number, rather than through
21173471bf0Spatrick // name and lookup table?
21273471bf0Spatrick assert(MF.getName().startswith(getThunkPrefix()));
21373471bf0Spatrick auto ThunkIt = llvm::find_if(
21473471bf0Spatrick SLSBLRThunks, [&MF](auto T) { return T.Name == MF.getName(); });
21573471bf0Spatrick assert(ThunkIt != std::end(SLSBLRThunks));
21673471bf0Spatrick Register ThunkReg = ThunkIt->Reg;
21773471bf0Spatrick bool isThumb = ThunkIt->isThumb;
21873471bf0Spatrick
21973471bf0Spatrick const TargetInstrInfo *TII = MF.getSubtarget<ARMSubtarget>().getInstrInfo();
22073471bf0Spatrick MachineBasicBlock *Entry = &MF.front();
22173471bf0Spatrick Entry->clear();
22273471bf0Spatrick
22373471bf0Spatrick // These thunks need to consist of the following instructions:
22473471bf0Spatrick // __llvm_slsblr_thunk_(arm/thumb)_rN:
22573471bf0Spatrick // bx rN
22673471bf0Spatrick // barrierInsts
22773471bf0Spatrick Entry->addLiveIn(ThunkReg);
22873471bf0Spatrick if (isThumb)
22973471bf0Spatrick BuildMI(Entry, DebugLoc(), TII->get(ARM::tBX))
23073471bf0Spatrick .addReg(ThunkReg)
23173471bf0Spatrick .add(predOps(ARMCC::AL));
23273471bf0Spatrick else
23373471bf0Spatrick BuildMI(Entry, DebugLoc(), TII->get(ARM::BX))
23473471bf0Spatrick .addReg(ThunkReg);
23573471bf0Spatrick
23673471bf0Spatrick // Make sure the thunks do not make use of the SB extension in case there is
23773471bf0Spatrick // a function somewhere that will call to it that for some reason disabled
23873471bf0Spatrick // the SB extension locally on that function, even though it's enabled for
23973471bf0Spatrick // the module otherwise. Therefore set AlwaysUseISBSDB to true.
24073471bf0Spatrick insertSpeculationBarrier(&MF.getSubtarget<ARMSubtarget>(), *Entry,
24173471bf0Spatrick Entry->end(), DebugLoc(), true /*AlwaysUseISBDSB*/);
24273471bf0Spatrick }
24373471bf0Spatrick
ConvertIndirectCallToIndirectJump(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI) const24473471bf0Spatrick MachineBasicBlock &ARMSLSHardening::ConvertIndirectCallToIndirectJump(
24573471bf0Spatrick MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const {
24673471bf0Spatrick // Transform an indirect call to an indirect jump as follows:
24773471bf0Spatrick // Before:
24873471bf0Spatrick // |-----------------------------|
24973471bf0Spatrick // | ... |
25073471bf0Spatrick // | instI |
25173471bf0Spatrick // | BLX rN |
25273471bf0Spatrick // | instJ |
25373471bf0Spatrick // | ... |
25473471bf0Spatrick // |-----------------------------|
25573471bf0Spatrick //
25673471bf0Spatrick // After:
25773471bf0Spatrick // |---------- -------------------------|
25873471bf0Spatrick // | ... |
25973471bf0Spatrick // | instI |
26073471bf0Spatrick // | *call* __llvm_slsblr_thunk_mode_xN |
26173471bf0Spatrick // | instJ |
26273471bf0Spatrick // | ... |
26373471bf0Spatrick // |--------------------------------------|
26473471bf0Spatrick //
26573471bf0Spatrick // __llvm_slsblr_thunk_mode_xN:
26673471bf0Spatrick // |-----------------------------|
26773471bf0Spatrick // | BX rN |
26873471bf0Spatrick // | barrierInsts |
26973471bf0Spatrick // |-----------------------------|
27073471bf0Spatrick //
27173471bf0Spatrick // The __llvm_slsblr_thunk_mode_xN thunks are created by the
27273471bf0Spatrick // SLSBLRThunkInserter.
27373471bf0Spatrick // This function merely needs to transform an indirect call to a direct call
27473471bf0Spatrick // to __llvm_slsblr_thunk_xN.
27573471bf0Spatrick MachineInstr &IndirectCall = *MBBI;
27673471bf0Spatrick assert(isIndirectCall(IndirectCall) && !IndirectCall.isReturn());
27773471bf0Spatrick int RegOpIdxOnIndirectCall = -1;
27873471bf0Spatrick bool isThumb;
27973471bf0Spatrick switch (IndirectCall.getOpcode()) {
28073471bf0Spatrick case ARM::BLX: // !isThumb2
28173471bf0Spatrick case ARM::BLX_noip: // !isThumb2
28273471bf0Spatrick isThumb = false;
28373471bf0Spatrick RegOpIdxOnIndirectCall = 0;
28473471bf0Spatrick break;
28573471bf0Spatrick case ARM::tBLXr: // isThumb2
28673471bf0Spatrick case ARM::tBLXr_noip: // isThumb2
28773471bf0Spatrick isThumb = true;
28873471bf0Spatrick RegOpIdxOnIndirectCall = 2;
28973471bf0Spatrick break;
29073471bf0Spatrick default:
29173471bf0Spatrick llvm_unreachable("unhandled Indirect Call");
29273471bf0Spatrick }
29373471bf0Spatrick
29473471bf0Spatrick Register Reg = IndirectCall.getOperand(RegOpIdxOnIndirectCall).getReg();
29573471bf0Spatrick // Since linkers are allowed to clobber R12 on function calls, the above
29673471bf0Spatrick // mitigation only works if the original indirect call instruction was not
29773471bf0Spatrick // using R12. Code generation before must make sure that no indirect call
29873471bf0Spatrick // using R12 was produced if the mitigation is enabled.
29973471bf0Spatrick // Also, the transformation is incorrect if the indirect call uses LR, so
30073471bf0Spatrick // also have to avoid that.
30173471bf0Spatrick assert(Reg != ARM::R12 && Reg != ARM::LR);
30273471bf0Spatrick bool RegIsKilled = IndirectCall.getOperand(RegOpIdxOnIndirectCall).isKill();
30373471bf0Spatrick
30473471bf0Spatrick DebugLoc DL = IndirectCall.getDebugLoc();
30573471bf0Spatrick
30673471bf0Spatrick MachineFunction &MF = *MBBI->getMF();
30773471bf0Spatrick auto ThunkIt = llvm::find_if(SLSBLRThunks, [Reg, isThumb](auto T) {
30873471bf0Spatrick return T.Reg == Reg && T.isThumb == isThumb;
30973471bf0Spatrick });
31073471bf0Spatrick assert(ThunkIt != std::end(SLSBLRThunks));
31173471bf0Spatrick Module *M = MF.getFunction().getParent();
31273471bf0Spatrick const GlobalValue *GV = cast<GlobalValue>(M->getNamedValue(ThunkIt->Name));
31373471bf0Spatrick
31473471bf0Spatrick MachineInstr *BL =
31573471bf0Spatrick isThumb ? BuildMI(MBB, MBBI, DL, TII->get(ARM::tBL))
31673471bf0Spatrick .addImm(IndirectCall.getOperand(0).getImm())
31773471bf0Spatrick .addReg(IndirectCall.getOperand(1).getReg())
31873471bf0Spatrick .addGlobalAddress(GV)
31973471bf0Spatrick : BuildMI(MBB, MBBI, DL, TII->get(ARM::BL)).addGlobalAddress(GV);
32073471bf0Spatrick
32173471bf0Spatrick // Now copy the implicit operands from IndirectCall to BL and copy other
32273471bf0Spatrick // necessary info.
32373471bf0Spatrick // However, both IndirectCall and BL instructions implictly use SP and
32473471bf0Spatrick // implicitly define LR. Blindly copying implicit operands would result in SP
32573471bf0Spatrick // and LR operands to be present multiple times. While this may not be too
32673471bf0Spatrick // much of an issue, let's avoid that for cleanliness, by removing those
32773471bf0Spatrick // implicit operands from the BL created above before we copy over all
32873471bf0Spatrick // implicit operands from the IndirectCall.
32973471bf0Spatrick int ImpLROpIdx = -1;
33073471bf0Spatrick int ImpSPOpIdx = -1;
33173471bf0Spatrick for (unsigned OpIdx = BL->getNumExplicitOperands();
33273471bf0Spatrick OpIdx < BL->getNumOperands(); OpIdx++) {
33373471bf0Spatrick MachineOperand Op = BL->getOperand(OpIdx);
33473471bf0Spatrick if (!Op.isReg())
33573471bf0Spatrick continue;
33673471bf0Spatrick if (Op.getReg() == ARM::LR && Op.isDef())
33773471bf0Spatrick ImpLROpIdx = OpIdx;
33873471bf0Spatrick if (Op.getReg() == ARM::SP && !Op.isDef())
33973471bf0Spatrick ImpSPOpIdx = OpIdx;
34073471bf0Spatrick }
34173471bf0Spatrick assert(ImpLROpIdx != -1);
34273471bf0Spatrick assert(ImpSPOpIdx != -1);
34373471bf0Spatrick int FirstOpIdxToRemove = std::max(ImpLROpIdx, ImpSPOpIdx);
34473471bf0Spatrick int SecondOpIdxToRemove = std::min(ImpLROpIdx, ImpSPOpIdx);
345*d415bd75Srobert BL->removeOperand(FirstOpIdxToRemove);
346*d415bd75Srobert BL->removeOperand(SecondOpIdxToRemove);
34773471bf0Spatrick // Now copy over the implicit operands from the original IndirectCall
34873471bf0Spatrick BL->copyImplicitOps(MF, IndirectCall);
34973471bf0Spatrick MF.moveCallSiteInfo(&IndirectCall, BL);
35073471bf0Spatrick // Also add the register called in the IndirectCall as being used in the
35173471bf0Spatrick // called thunk.
35273471bf0Spatrick BL->addOperand(MachineOperand::CreateReg(Reg, false /*isDef*/, true /*isImp*/,
35373471bf0Spatrick RegIsKilled /*isKill*/));
35473471bf0Spatrick // Remove IndirectCallinstruction
35573471bf0Spatrick MBB.erase(MBBI);
35673471bf0Spatrick return MBB;
35773471bf0Spatrick }
35873471bf0Spatrick
hardenIndirectCalls(MachineBasicBlock & MBB) const35973471bf0Spatrick bool ARMSLSHardening::hardenIndirectCalls(MachineBasicBlock &MBB) const {
36073471bf0Spatrick if (!ST->hardenSlsBlr())
36173471bf0Spatrick return false;
36273471bf0Spatrick bool Modified = false;
36373471bf0Spatrick MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
36473471bf0Spatrick MachineBasicBlock::iterator NextMBBI;
36573471bf0Spatrick for (; MBBI != E; MBBI = NextMBBI) {
36673471bf0Spatrick MachineInstr &MI = *MBBI;
36773471bf0Spatrick NextMBBI = std::next(MBBI);
36873471bf0Spatrick // Tail calls are both indirect calls and "returns".
36973471bf0Spatrick // They are also indirect jumps, so should be handled by sls-harden-retbr,
37073471bf0Spatrick // rather than sls-harden-blr.
37173471bf0Spatrick if (isIndirectCall(MI) && !MI.isReturn()) {
37273471bf0Spatrick ConvertIndirectCallToIndirectJump(MBB, MBBI);
37373471bf0Spatrick Modified = true;
37473471bf0Spatrick }
37573471bf0Spatrick }
37673471bf0Spatrick return Modified;
37773471bf0Spatrick }
37873471bf0Spatrick
37973471bf0Spatrick
38073471bf0Spatrick
createARMSLSHardeningPass()38173471bf0Spatrick FunctionPass *llvm::createARMSLSHardeningPass() {
38273471bf0Spatrick return new ARMSLSHardening();
38373471bf0Spatrick }
38473471bf0Spatrick
38573471bf0Spatrick namespace {
38673471bf0Spatrick class ARMIndirectThunks : public MachineFunctionPass {
38773471bf0Spatrick public:
38873471bf0Spatrick static char ID;
38973471bf0Spatrick
ARMIndirectThunks()39073471bf0Spatrick ARMIndirectThunks() : MachineFunctionPass(ID) {}
39173471bf0Spatrick
getPassName() const39273471bf0Spatrick StringRef getPassName() const override { return "ARM Indirect Thunks"; }
39373471bf0Spatrick
39473471bf0Spatrick bool doInitialization(Module &M) override;
39573471bf0Spatrick bool runOnMachineFunction(MachineFunction &MF) override;
39673471bf0Spatrick
getAnalysisUsage(AnalysisUsage & AU) const39773471bf0Spatrick void getAnalysisUsage(AnalysisUsage &AU) const override {
39873471bf0Spatrick MachineFunctionPass::getAnalysisUsage(AU);
39973471bf0Spatrick AU.addRequired<MachineModuleInfoWrapperPass>();
40073471bf0Spatrick AU.addPreserved<MachineModuleInfoWrapperPass>();
40173471bf0Spatrick }
40273471bf0Spatrick
40373471bf0Spatrick private:
40473471bf0Spatrick std::tuple<SLSBLRThunkInserter> TIs;
40573471bf0Spatrick
40673471bf0Spatrick // FIXME: When LLVM moves to C++17, these can become folds
40773471bf0Spatrick template <typename... ThunkInserterT>
initTIs(Module & M,std::tuple<ThunkInserterT...> & ThunkInserters)40873471bf0Spatrick static void initTIs(Module &M,
40973471bf0Spatrick std::tuple<ThunkInserterT...> &ThunkInserters) {
41073471bf0Spatrick (void)std::initializer_list<int>{
41173471bf0Spatrick (std::get<ThunkInserterT>(ThunkInserters).init(M), 0)...};
41273471bf0Spatrick }
41373471bf0Spatrick template <typename... ThunkInserterT>
runTIs(MachineModuleInfo & MMI,MachineFunction & MF,std::tuple<ThunkInserterT...> & ThunkInserters)41473471bf0Spatrick static bool runTIs(MachineModuleInfo &MMI, MachineFunction &MF,
41573471bf0Spatrick std::tuple<ThunkInserterT...> &ThunkInserters) {
41673471bf0Spatrick bool Modified = false;
41773471bf0Spatrick (void)std::initializer_list<int>{
41873471bf0Spatrick Modified |= std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF)...};
41973471bf0Spatrick return Modified;
42073471bf0Spatrick }
42173471bf0Spatrick };
42273471bf0Spatrick
42373471bf0Spatrick } // end anonymous namespace
42473471bf0Spatrick
42573471bf0Spatrick char ARMIndirectThunks::ID = 0;
42673471bf0Spatrick
createARMIndirectThunks()42773471bf0Spatrick FunctionPass *llvm::createARMIndirectThunks() {
42873471bf0Spatrick return new ARMIndirectThunks();
42973471bf0Spatrick }
43073471bf0Spatrick
doInitialization(Module & M)43173471bf0Spatrick bool ARMIndirectThunks::doInitialization(Module &M) {
43273471bf0Spatrick initTIs(M, TIs);
43373471bf0Spatrick return false;
43473471bf0Spatrick }
43573471bf0Spatrick
runOnMachineFunction(MachineFunction & MF)43673471bf0Spatrick bool ARMIndirectThunks::runOnMachineFunction(MachineFunction &MF) {
43773471bf0Spatrick LLVM_DEBUG(dbgs() << getPassName() << '\n');
43873471bf0Spatrick auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
43973471bf0Spatrick return runTIs(MMI, MF, TIs);
44073471bf0Spatrick }
441