60#define PASS_KEY "x86-slh"
61#define DEBUG_TYPE PASS_KEY
63STATISTIC(NumCondBranchesTraced,
"Number of conditional branches traced");
64STATISTIC(NumBranchesUntraced,
"Number of branches unable to trace");
66 "Number of address mode used registers hardened");
68 "Number of post-load register values hardened");
70 "Number of calls or jumps requiring extra hardening");
71STATISTIC(NumInstsInserted,
"Number of instructions inserted");
72STATISTIC(NumLFENCEsInserted,
"Number of lfence instructions inserted");
76constexpr StringRef X86SLHPassName =
"X86 speculative load hardening";
82 StringRef getPassName()
const override {
return X86SLHPassName; }
84 void getAnalysisUsage(AnalysisUsage &AU)
const override;
90class X86SpeculativeLoadHardeningImpl {
92 X86SpeculativeLoadHardeningImpl() =
default;
99 struct BlockCondInfo {
100 MachineBasicBlock *MBB;
104 SmallVector<MachineInstr *, 2> CondBrs;
106 MachineInstr *UncondBr;
115 MachineSSAUpdater SSA;
121 const X86Subtarget *Subtarget =
nullptr;
122 MachineRegisterInfo *MRI =
nullptr;
123 const X86InstrInfo *TII =
nullptr;
124 const TargetRegisterInfo *TRI =
nullptr;
126 std::optional<PredState> PS;
145 void restoreEFLAGS(MachineBasicBlock &
MBB,
149 void mergePredStateIntoSP(MachineBasicBlock &
MBB,
152 Register extractPredStateFromSP(MachineBasicBlock &
MBB,
157 hardenLoadAddr(MachineInstr &
MI, MachineOperand &BaseMO,
158 MachineOperand &IndexMO,
159 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg);
161 sinkPostLoadHardenedInst(MachineInstr &
MI,
162 SmallPtrSetImpl<MachineInstr *> &HardenedInstrs);
168 void hardenReturnInstr(MachineInstr &
MI);
169 void tracePredStateThroughCall(MachineInstr &
MI);
170 void hardenIndirectCallOrJumpInstr(
172 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg);
177bool X86SpeculativeLoadHardeningLegacy::runOnMachineFunction(
179 X86SpeculativeLoadHardeningImpl Impl;
186char X86SpeculativeLoadHardeningLegacy::ID = 0;
188void X86SpeculativeLoadHardeningLegacy::getAnalysisUsage(
189 AnalysisUsage &AU)
const {
198 assert(!Succ.
isEHPad() &&
"Shouldn't get edges to EH pads!");
212 "Didn't start with the right target!");
221 assert(
MBB.isSuccessor(&OldLayoutSucc) &&
222 "Without an unconditional branch, the old layout successor should "
223 "be an actual successor!");
227 UncondBr = &*BrBuilder;
238 "Cannot have a branchless successor and an unconditional branch!");
240 "A non-branch successor must have been a layout successor before "
241 "and now is a layout successor of the new block.");
247 if (SuccCount == 1) {
248 MBB.replaceSuccessor(&Succ, &NewMBB);
250 MBB.splitSuccessor(&Succ, &NewMBB);
264 assert(OpMBB.
isMBB() &&
"Block operand to a PHI is not a block!");
269 if (SuccCount == 1) {
275 MI.addOperand(MF, OpV);
282 for (
auto &LI : Succ.
liveins())
302 for (
auto &
MI :
MBB) {
311 if (!Preds.
insert(
MI.getOperand(OpIdx + 1).getMBB()).second)
324 while (!DupIndices.
empty()) {
328 MI.removeOperand(OpIdx + 1);
329 MI.removeOperand(OpIdx);
347 if (
MI.getOpcode() == X86::LFENCE)
355 if (
MI.getOpcode() == X86::MFENCE)
374 const X86Options &CLOpts = Subtarget->
getCLOpts();
375 if (!CLOpts.speculative_load_hardening &&
384 PS.emplace(MF, &X86::GR64_NOSPRegClass);
391 if (CLOpts.slh_lfence) {
392 hardenEdgesWithLFENCE(MF);
400 auto EntryInsertPt =
Entry.SkipPHIsLabelsAndDebug(
Entry.begin());
410 if (!HasVulnerableLoad && Infos.
empty())
415 const int PoisonVal = -1;
417 BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::MOV64ri32), PS->PoisonReg)
423 if (HasVulnerableLoad && CLOpts.slh_fence_call_and_ret) {
430 BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::LFENCE));
432 ++NumLFENCEsInserted;
437 if (CLOpts.slh_fence_call_and_ret && Infos.
empty())
442 if (CLOpts.slh_ip && !CLOpts.slh_fence_call_and_ret) {
445 PS->InitialReg = extractPredStateFromSP(Entry, EntryInsertPt, Loc);
451 auto ZeroI =
BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::MOV32r0),
454 MachineOperand *ZeroEFLAGSDefOp =
455 ZeroI->findRegisterDefOperand(X86::EFLAGS,
nullptr);
457 "Must have an implicit def of EFLAGS!");
459 BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::SUBREG_TO_REG),
472 PS->SSA.Initialize(PS->InitialReg);
473 PS->SSA.AddAvailableValue(&Entry, PS->InitialReg);
476 auto CMovs = tracePredStateThroughCFG(MF, Infos);
486 for (MachineBasicBlock &
MBB : MF) {
492 PS->SSA.AddAvailableValue(
498 if (CLOpts.slh_indirect) {
501 unfoldCallAndJumpLoads(MF);
504 auto IndirectBrCMovs = tracePredStateThroughIndirectBranches(MF);
505 CMovs.append(IndirectBrCMovs.begin(), IndirectBrCMovs.end());
511 tracePredStateThroughBlocksAndHarden(MF);
515 for (MachineInstr *CMovI : CMovs)
516 for (MachineOperand &
Op : CMovI->operands()) {
517 if (!
Op.isReg() ||
Op.getReg() != PS->InitialReg)
520 PS->SSA.RewriteUse(
Op);
532void X86SpeculativeLoadHardeningImpl::hardenEdgesWithLFENCE(
536 SmallSetVector<MachineBasicBlock *, 8> Blocks;
537 for (MachineBasicBlock &
MBB : MF) {
545 if (TermIt ==
MBB.
end() || !TermIt->isBranch())
552 if (!SuccMBB->isEHPad())
556 for (MachineBasicBlock *
MBB : Blocks) {
560 ++NumLFENCEsInserted;
565X86SpeculativeLoadHardeningImpl::collectBlockCondInfo(
MachineFunction &MF) {
570 for (MachineBasicBlock &
MBB : MF) {
595 BlockCondInfo
Info = {&
MBB, {},
nullptr};
601 if (!
MI.isTerminator())
605 if (!
MI.isBranch()) {
606 Info.CondBrs.clear();
612 if (
MI.getOpcode() == X86::JMP_1) {
613 Info.CondBrs.clear();
628 Info.CondBrs.clear();
634 Info.CondBrs.push_back(&
MI);
636 if (
Info.CondBrs.empty()) {
637 ++NumBranchesUntraced;
638 LLVM_DEBUG(
dbgs() <<
"WARNING: unable to secure successors of block:\n";
657X86SpeculativeLoadHardeningImpl::tracePredStateThroughCFG(
665 for (
const BlockCondInfo &Info : Infos) {
666 MachineBasicBlock &
MBB = *
Info.MBB;
667 const SmallVectorImpl<MachineInstr *> &CondBrs =
Info.CondBrs;
668 MachineInstr *UncondBr =
Info.UncondBr;
672 ++NumCondBranchesTraced;
676 MachineBasicBlock *UncondSucc =
677 UncondBr ? (UncondBr->
getOpcode() == X86::JMP_1
683 SmallDenseMap<MachineBasicBlock *, int> SuccCounts;
685 ++SuccCounts[UncondSucc];
686 for (
auto *CondBr : CondBrs)
687 ++SuccCounts[CondBr->getOperand(0).getMBB()];
691 auto BuildCheckingBlockForSuccAndConds =
692 [&](MachineBasicBlock &
MBB, MachineBasicBlock &Succ,
int SuccCount,
693 MachineInstr *Br, MachineInstr *&UncondBr,
698 (SuccCount == 1 && Succ.pred_size() == 1)
700 : splitEdge(MBB, Succ, SuccCount, Br, UncondBr, *TII);
702 bool LiveEFLAGS = Succ.isLiveIn(X86::EFLAGS);
704 CheckingMBB.addLiveIn(X86::EFLAGS);
707 auto InsertPt = CheckingMBB.begin();
708 assert((InsertPt == CheckingMBB.end() || !InsertPt->isPHI()) &&
709 "Should never have a PHI in the initial checking block as it "
710 "always has a single predecessor!");
714 Register CurStateReg = PS->InitialReg;
716 for (X86::CondCode Cond : Conds) {
717 int PredStateSizeInBytes = TRI->getRegSizeInBits(*PS->RC) / 8;
718 auto CMovOp = X86::getCMovOpcode(PredStateSizeInBytes);
720 Register UpdatedStateReg = MRI->createVirtualRegister(PS->RC);
723 auto CMovI = BuildMI(CheckingMBB, InsertPt, DebugLoc(),
724 TII->get(CMovOp), UpdatedStateReg)
726 .addReg(PS->PoisonReg)
730 if (!LiveEFLAGS && Cond == Conds.back())
731 CMovI->findRegisterUseOperand(X86::EFLAGS, nullptr)
735 LLVM_DEBUG(dbgs() <<
" Inserting cmov: "; CMovI->dump();
740 if (CurStateReg == PS->InitialReg)
741 CMovs.push_back(&*CMovI);
744 CurStateReg = UpdatedStateReg;
749 PS->SSA.AddAvailableValue(&CheckingMBB, CurStateReg);
752 std::vector<X86::CondCode> UncondCodeSeq;
753 for (
auto *CondBr : CondBrs) {
754 MachineBasicBlock &Succ = *CondBr->getOperand(0).getMBB();
755 int &SuccCount = SuccCounts[&Succ];
759 UncondCodeSeq.push_back(
Cond);
761 BuildCheckingBlockForSuccAndConds(
MBB, Succ, SuccCount, CondBr, UncondBr,
784 assert(SuccCounts[UncondSucc] == 1 &&
785 "We should never have more than one edge to the unconditional "
786 "successor at this point because every other edge must have been "
791 UncondCodeSeq.erase(
llvm::unique(UncondCodeSeq), UncondCodeSeq.end());
794 BuildCheckingBlockForSuccAndConds(
MBB, *UncondSucc, 1,
795 UncondBr, UncondBr, UncondCodeSeq);
809 unsigned UnfoldedOpc =
TII.getOpcodeAfterMemoryUnfold(
810 Opcode,
true,
false, &Index);
812 return TII.getRegClass(
MCID, Index);
815void X86SpeculativeLoadHardeningImpl::unfoldCallAndJumpLoads(
817 for (MachineBasicBlock &
MBB : MF)
822 if (!
MI.isCall() && !
MI.isBranch())
828 switch (
MI.getOpcode()) {
831 dbgs() <<
"ERROR: Found an unexpected loading branch or call "
833 MI.dump();
dbgs() <<
"\n");
837 case X86::FARCALL16m:
838 case X86::FARCALL32m:
839 case X86::FARCALL64m:
848 case X86::CALL16m_NT:
850 case X86::CALL32m_NT:
852 case X86::CALL64m_NT:
859 case X86::TAILJMPm64:
860 case X86::TAILJMPm64_REX:
862 case X86::TCRETURNmi64:
863 case X86::TCRETURN_WINmi64:
864 case X86::TCRETURNmi: {
871 <<
"ERROR: Unable to unfold load from instruction:\n";
872 MI.dump();
dbgs() <<
"\n");
876 SmallVector<MachineInstr *, 2> NewMIs;
880 TII->unfoldMemoryOperand(MF,
MI,
Reg,
true,
884 "Computed unfolded register class but failed to unfold");
886 for (
auto *NewMI : NewMIs)
890 if (
MI.isCandidateForAdditionalCallInfo())
891 MF.eraseAdditionalCallInfo(&
MI);
893 MI.eraseFromParent();
895 dbgs() <<
"Unfolded load successfully into:\n";
896 for (
auto *NewMI : NewMIs) {
926X86SpeculativeLoadHardeningImpl::tracePredStateThroughIndirectBranches(
932 MachineSSAUpdater TargetAddrSSA(MF);
936 SmallPtrSet<MachineBasicBlock *, 4> IndirectTerminatedMBBs;
941 SmallPtrSet<MachineBasicBlock *, 4> IndirectTargetMBBs;
945 for (MachineBasicBlock &
MBB : MF) {
952 MachineInstr &TI = *MII;
982 "Support for 16-bit indirect branches is not implemented.");
985 "Support for 32-bit indirect branches is not implemented.");
994 return !OtherTI.isDebugInstr() && &OtherTI != &TI;
997 dbgs() <<
"ERROR: Found other terminators in a block with an indirect "
998 "branch! This is not yet supported! Terminator sequence:\n";
1008 TargetAddrSSA.AddAvailableValue(&
MBB, TargetReg);
1019 if (IndirectTargetMBBs.
empty())
1025 for (MachineBasicBlock &
MBB : MF) {
1027 if (!IndirectTargetMBBs.
count(&
MBB))
1034 "Unexpected EH pad as target of an indirect branch!");
1042 "Cannot check within a block that already has live-in EFLAGS!");
1049 if (IndirectTerminatedMBBs.
count(Pred))
1057 if (!
llvm::all_of(Pred->successors(), [&](MachineBasicBlock *Succ) {
1058 return Succ->isEHPad() || Succ == &MBB;
1061 dbgs() <<
"ERROR: Found conditional entry to target of indirect "
1067 "an indirect branch!");
1073 auto InsertPt = Pred->getFirstTerminator();
1079 TII->get(X86::MOV64ri32), TargetReg)
1099 TargetAddrSSA.AddAvailableValue(Pred, TargetReg);
1107 Register TargetReg = TargetAddrSSA.GetValueInMiddleOfBlock(&
MBB);
1118 .
addReg(TargetReg, RegState::Kill)
1137 .
addReg(TargetReg, RegState::Kill)
1138 .
addReg(AddrReg, RegState::Kill);
1145 int PredStateSizeInBytes =
TRI->getRegSizeInBits(*PS->RC) / 8;
1161 PS->SSA.AddAvailableValue(&
MBB, UpdatedStateReg);
1172 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr)) {
1173 return !DefOp->isDead();
1184 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr)) {
1186 if (DefOp->isDead())
1194 if (
MI.killsRegister(X86::EFLAGS, &
TRI))
1200 return MBB.isLiveIn(X86::EFLAGS);
1230void X86SpeculativeLoadHardeningImpl::tracePredStateThroughBlocksAndHarden(
1232 const X86Options &CLOpts = Subtarget->
getCLOpts();
1233 SmallPtrSet<MachineInstr *, 16> HardenPostLoad;
1234 SmallPtrSet<MachineInstr *, 16> HardenLoadAddr;
1236 SmallSet<Register, 16> HardenedAddrRegs;
1238 SmallDenseMap<Register, Register, 32> AddrRegToHardenedReg;
1243 SparseBitVector<> LoadDepRegs;
1245 for (MachineBasicBlock &
MBB : MF) {
1261 if (CLOpts.slh_loads)
1262 for (MachineInstr &
MI :
MBB) {
1268 return Op.isReg() && LoadDepRegs.test(Op.getReg().id());
1270 for (MachineOperand &Def :
MI.defs())
1272 LoadDepRegs.
set(
Def.getReg().id());
1277 if (
MI.getOpcode() == X86::LFENCE)
1285 if (
MI.getOpcode() == X86::MFENCE)
1290 if (MemRefBeginIdx < 0) {
1292 <<
"WARNING: unable to harden loading instruction: ";
1297 MachineOperand &BaseMO =
1299 MachineOperand &IndexMO =
1305 if (!BaseMO.
isFI() && BaseMO.
getReg() != X86::RIP &&
1309 IndexReg = IndexMO.
getReg();
1311 if (!BaseReg && !IndexReg)
1319 if ((BaseReg && LoadDepRegs.
test(
BaseReg.id())) ||
1320 (IndexReg && LoadDepRegs.
test(IndexReg.
id())))
1330 MI.getOperand(0).isReg() &&
1331 canHardenRegister(
MI.getOperand(0).getReg()) &&
1332 !HardenedAddrRegs.
count(BaseReg) &&
1333 !HardenedAddrRegs.
count(IndexReg)) {
1335 HardenedAddrRegs.
insert(
MI.getOperand(0).getReg());
1343 HardenedAddrRegs.
insert(BaseReg);
1345 HardenedAddrRegs.
insert(IndexReg);
1347 for (MachineOperand &Def :
MI.defs())
1349 LoadDepRegs.
set(
Def.getReg().id());
1357 for (MachineInstr &
MI :
MBB) {
1358 if (CLOpts.slh_loads) {
1361 "Requested to harden both the address and def of a load!");
1364 if (HardenLoadAddr.
erase(&
MI)) {
1366 assert(MemRefBeginIdx >= 0 &&
"Cannot have an invalid index here!");
1368 MachineOperand &BaseMO =
1370 MachineOperand &IndexMO =
1372 hardenLoadAddr(
MI, BaseMO, IndexMO, AddrRegToHardenedReg);
1378 if (HardenPostLoad.
erase(&
MI)) {
1379 assert(!
MI.isCall() &&
"Must not try to post-load harden a call!");
1387 MachineInstr *SunkMI = sinkPostLoadHardenedInst(
MI, HardenPostLoad);
1392 if (SunkMI != &
MI) {
1399 HardenPostLoad.
insert(SunkMI);
1407 AddrRegToHardenedReg[HardenedReg] = HardenedReg;
1417 if ((
MI.isCall() ||
MI.isBranch()) && CLOpts.slh_indirect)
1418 hardenIndirectCallOrJumpInstr(
MI, AddrRegToHardenedReg);
1425 if (!
MI.isCall() && !
MI.isReturn())
1430 if (
MI.isReturn() && !
MI.isCall()) {
1431 hardenReturnInstr(
MI);
1438 assert(
MI.isCall() &&
"Should only reach here for calls!");
1439 tracePredStateThroughCall(
MI);
1442 HardenPostLoad.
clear();
1443 HardenLoadAddr.
clear();
1444 HardenedAddrRegs.
clear();
1445 AddrRegToHardenedReg.
clear();
1450 LoadDepRegs.
clear();
1460Register X86SpeculativeLoadHardeningImpl::saveEFLAGS(
1478void X86SpeculativeLoadHardeningImpl::restoreEFLAGS(
1489void X86SpeculativeLoadHardeningImpl::mergePredStateIntoSP(
1496 auto ShiftI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::SHL64ri), TmpReg)
1497 .
addReg(PredStateReg, RegState::Kill)
1501 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::OR64rr), X86::RSP)
1503 .
addReg(TmpReg, RegState::Kill);
1509Register X86SpeculativeLoadHardeningImpl::extractPredStateFromSP(
1518 BuildMI(
MBB, InsertPt, Loc,
TII->get(TargetOpcode::COPY), TmpReg)
1521 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::SAR64ri), PredStateReg)
1522 .
addReg(TmpReg, RegState::Kill)
1523 .
addImm(
TRI->getRegSizeInBits(*PS->RC) - 1);
1527 return PredStateReg;
1530void X86SpeculativeLoadHardeningImpl::hardenLoadAddr(
1531 MachineInstr &
MI, MachineOperand &BaseMO, MachineOperand &IndexMO,
1532 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg) {
1542 if (BaseMO.
isFI()) {
1546 dbgs() <<
" Skipping hardening base of explicit stack frame load: ";
1547 MI.dump();
dbgs() <<
"\n");
1548 }
else if (BaseMO.
getReg() == X86::RSP) {
1553 "Explicit RSP access with dynamic index!");
1555 dbgs() <<
" Cannot harden base of explicit RSP offset in a load!");
1556 }
else if (BaseMO.
getReg() == X86::RIP ||
1557 BaseMO.
getReg() == X86::NoRegister) {
1567 dbgs() <<
" Cannot harden base of "
1568 << (BaseMO.
getReg() == X86::RIP ?
"RIP-relative" :
"no-base")
1569 <<
" address in a load!");
1572 "Only allowed to have a frame index or register base.");
1576 if (IndexMO.
getReg() != X86::NoRegister &&
1577 (HardenOpRegs.
empty() ||
1578 HardenOpRegs.
front()->getReg() != IndexMO.
getReg()))
1582 "Should have exactly one or two registers to harden!");
1584 HardenOpRegs[0]->getReg() != HardenOpRegs[1]->getReg()) &&
1585 "Should not have two of the same registers!");
1590 auto It = AddrRegToHardenedReg.
find(
Op->getReg());
1591 if (It == AddrRegToHardenedReg.
end())
1596 Op->setReg(It->second);
1600 if (HardenOpRegs.
empty())
1604 Register StateReg = PS->SSA.GetValueAtEndOfBlock(&
MBB);
1606 auto InsertPt =
MI.getIterator();
1612 if (EFLAGSLive && !Subtarget->hasBMI2()) {
1614 FlagsReg = saveEFLAGS(
MBB, InsertPt, Loc);
1617 for (MachineOperand *
Op : HardenOpRegs) {
1624 if (!Subtarget->hasVLX() && (OpRC->hasSuperClassEq(&X86::VR128RegClass) ||
1625 OpRC->hasSuperClassEq(&X86::VR256RegClass))) {
1626 assert(Subtarget->
hasAVX2() &&
"AVX2-specific register classes!");
1627 bool Is128Bit = OpRC->hasSuperClassEq(&X86::VR128RegClass);
1634 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::VMOV64toPQIrr), VStateReg)
1642 auto BroadcastI =
BuildMI(
MBB, InsertPt, Loc,
1643 TII->get(Is128Bit ? X86::VPBROADCASTQrr
1644 : X86::VPBROADCASTQYrr),
1649 LLVM_DEBUG(
dbgs() <<
" Inserting broadcast: "; BroadcastI->dump();
1655 TII->get(Is128Bit ? X86::VPORrr : X86::VPORYrr), TmpReg)
1661 }
else if (OpRC->hasSuperClassEq(&X86::VR128XRegClass) ||
1662 OpRC->hasSuperClassEq(&X86::VR256XRegClass) ||
1663 OpRC->hasSuperClassEq(&X86::VR512RegClass)) {
1664 assert(Subtarget->
hasAVX512() &&
"AVX512-specific register classes!");
1665 bool Is128Bit = OpRC->hasSuperClassEq(&X86::VR128XRegClass);
1666 bool Is256Bit = OpRC->hasSuperClassEq(&X86::VR256XRegClass);
1667 if (Is128Bit || Is256Bit)
1668 assert(Subtarget->hasVLX() &&
"AVX512VL-specific register classes!");
1672 unsigned BroadcastOp =
Is128Bit ? X86::VPBROADCASTQrZ128rr
1673 : Is256Bit ? X86::VPBROADCASTQrZ256rr
1674 : X86::VPBROADCASTQrZrr;
1676 BuildMI(
MBB, InsertPt, Loc,
TII->get(BroadcastOp), VStateReg)
1680 LLVM_DEBUG(
dbgs() <<
" Inserting broadcast: "; BroadcastI->dump();
1684 unsigned OrOp =
Is128Bit ? X86::VPORQZ128rr
1685 : Is256Bit ? X86::VPORQZ256rr : X86::VPORQZrr;
1686 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(OrOp), TmpReg)
1694 assert(OpRC->hasSuperClassEq(&X86::GR64RegClass) &&
1695 "Not a supported register class for address hardening!");
1699 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::OR64rr), TmpReg)
1709 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::SHRX64rr), TmpReg)
1721 "Should not have checked this register yet!");
1722 AddrRegToHardenedReg[
Op->getReg()] = TmpReg;
1724 ++NumAddrRegsHardened;
1729 restoreEFLAGS(
MBB, InsertPt, Loc, FlagsReg);
1732MachineInstr *X86SpeculativeLoadHardeningImpl::sinkPostLoadHardenedInst(
1733 MachineInstr &InitialMI, SmallPtrSetImpl<MachineInstr *> &HardenedInstrs) {
1735 "Cannot get here with a non-invariant load!");
1737 "Cannot get here with a data invariant load "
1738 "that interferes with EFLAGS!");
1741 auto SinkCheckToSingleUse =
1742 [&](MachineInstr &
MI) -> std::optional<MachineInstr *> {
1748 MachineInstr *SingleUseMI =
nullptr;
1758 "Data variant instruction being hardened!");
1765 assert(MemRefBeginIdx >= 0 &&
1766 "Should always have mem references here!");
1768 MachineOperand &BaseMO =
1770 MachineOperand &IndexMO =
1772 if ((BaseMO.
isReg() && BaseMO.
getReg() == DefReg) ||
1793 if (
UseMI.getDesc().getNumDefs() > 1)
1800 if (!canHardenRegister(UseDefReg))
1803 SingleUseMI = &
UseMI;
1808 return {SingleUseMI};
1811 MachineInstr *
MI = &InitialMI;
1812 while (std::optional<MachineInstr *> SingleUse = SinkCheckToSingleUse(*
MI)) {
1822bool X86SpeculativeLoadHardeningImpl::canHardenRegister(
Register Reg) {
1828 int RegBytes =
TRI->getRegSizeInBits(*RC) / 8;
1833 unsigned RegIdx =
Log2_32(RegBytes);
1834 assert(RegIdx < 4 &&
"Unsupported register size");
1844 &X86::GR8_NOREXRegClass, &X86::GR16_NOREXRegClass,
1845 &X86::GR32_NOREXRegClass, &X86::GR64_NOREXRegClass};
1846 if (RC == NOREXRegClasses[RegIdx])
1850 &X86::GR8RegClass, &X86::GR16RegClass, &X86::GR32RegClass,
1851 &X86::GR64RegClass};
1869Register X86SpeculativeLoadHardeningImpl::hardenValueInRegister(
1872 assert(canHardenRegister(
Reg) &&
"Cannot harden this register!");
1875 int Bytes =
TRI->getRegSizeInBits(*RC) / 8;
1876 Register StateReg = PS->SSA.GetValueAtEndOfBlock(&
MBB);
1877 assert((Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8) &&
1878 "Unknown register size");
1882 unsigned SubRegImms[] = {X86::sub_8bit, X86::sub_16bit, X86::sub_32bit};
1883 unsigned SubRegImm = SubRegImms[
Log2_32(Bytes)];
1885 BuildMI(
MBB, InsertPt, Loc,
TII->get(TargetOpcode::COPY), NarrowStateReg)
1886 .
addReg(StateReg, {}, SubRegImm);
1887 StateReg = NarrowStateReg;
1892 FlagsReg = saveEFLAGS(
MBB, InsertPt, Loc);
1895 unsigned OrOpCodes[] = {X86::OR8rr, X86::OR16rr, X86::OR32rr, X86::OR64rr};
1896 unsigned OrOpCode = OrOpCodes[
Log2_32(Bytes)];
1897 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(OrOpCode), NewReg)
1905 restoreEFLAGS(
MBB, InsertPt, Loc, FlagsReg);
1919Register X86SpeculativeLoadHardeningImpl::hardenPostLoad(MachineInstr &
MI) {
1923 auto &DefOp =
MI.getOperand(0);
1924 Register OldDefReg = DefOp.getReg();
1931 DefOp.setReg(UnhardenedReg);
1936 Register HardenedReg = hardenValueInRegister(
1937 UnhardenedReg,
MBB, std::next(
MI.getIterator()), Loc);
1943 ++NumPostLoadRegsHardened;
1970void X86SpeculativeLoadHardeningImpl::hardenReturnInstr(MachineInstr &
MI) {
1973 auto InsertPt =
MI.getIterator();
1975 if (Subtarget->
getCLOpts().slh_fence_call_and_ret)
1983 mergePredStateIntoSP(
MBB, InsertPt, Loc, PS->SSA.GetValueAtEndOfBlock(&
MBB));
2016void X86SpeculativeLoadHardeningImpl::tracePredStateThroughCall(
2020 auto InsertPt =
MI.getIterator();
2023 if (Subtarget->
getCLOpts().slh_fence_call_and_ret) {
2033 BuildMI(
MBB, std::next(InsertPt), Loc,
TII->get(X86::LFENCE));
2035 ++NumLFENCEsInserted;
2041 Register StateReg = PS->SSA.GetValueAtEndOfBlock(&
MBB);
2042 mergePredStateIntoSP(
MBB, InsertPt, Loc, StateReg);
2057 MI.setPostInstrSymbol(MF, RetSymbol);
2088 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::MOV64ri32), ExpectedRetAddrReg)
2091 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::LEA64r), ExpectedRetAddrReg)
2107 if (!ExpectedRetAddrReg) {
2109 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::MOV64rm), ExpectedRetAddrReg)
2119 Register NewStateReg = extractPredStateFromSP(
MBB, InsertPt, Loc);
2129 .
addReg(ExpectedRetAddrReg, RegState::Kill)
2133 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::LEA64r), ActualRetAddrReg)
2140 .
addReg(ExpectedRetAddrReg, RegState::Kill)
2141 .
addReg(ActualRetAddrReg, RegState::Kill);
2146 int PredStateSizeInBytes =
TRI->getRegSizeInBits(*PS->RC) / 8;
2150 auto CMovI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(CMovOp), UpdatedStateReg)
2151 .
addReg(NewStateReg, RegState::Kill)
2158 PS->SSA.AddAvailableValue(&
MBB, UpdatedStateReg);
2176void X86SpeculativeLoadHardeningImpl::hardenIndirectCallOrJumpInstr(
2178 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg) {
2179 switch (
MI.getOpcode()) {
2180 case X86::FARCALL16m:
2181 case X86::FARCALL32m:
2182 case X86::FARCALL64m:
2183 case X86::FARJMP16m:
2184 case X86::FARJMP32m:
2185 case X86::FARJMP64m:
2196 assert(!
MI.mayLoad() &&
"Found a lingering loading instruction!");
2200 if (!
MI.getOperand(0).isReg())
2205 auto &TargetOp =
MI.getOperand(0);
2206 Register OldTargetReg = TargetOp.getReg();
2211 Register &HardenedTargetReg = AddrRegToHardenedReg[OldTargetReg];
2220 if (!HardenedTargetReg)
2221 HardenedTargetReg = hardenValueInRegister(
2222 OldTargetReg, *
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc());
2225 TargetOp.setReg(HardenedTargetReg);
2227 ++NumCallsOrJumpsHardened;
2233 X86SpeculativeLoadHardeningImpl Impl;
2234 const bool Changed = Impl.run(MF);
2243 "X86 speculative load hardener",
false,
false)
2248 return new X86SpeculativeLoadHardeningLegacy();
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the DenseMap class.
const HexagonInstrInfo * TII
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the SparseBitVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static MachineBasicBlock & splitEdge(MachineBasicBlock &MBB, MachineBasicBlock &Succ, int SuccCount, MachineInstr *Br, MachineInstr *&UncondBr, const X86InstrInfo &TII)
static void canonicalizePHIOperands(MachineFunction &MF)
Removing duplicate PHI operands to leave the PHI in a canonical and predictable form.
static bool isEFLAGSLive(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const TargetRegisterInfo &TRI)
static const TargetRegisterClass * getRegClassForUnfoldedLoad(const X86InstrInfo &TII, unsigned Opcode)
Compute the register class for the unfolded load.
static bool hasVulnerableLoad(MachineFunction &MF)
Helper to scan a function for loads vulnerable to misspeculation that we want to harden.
static bool isEFLAGSDefLive(const MachineInstr &MI)
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Represents analyses that only rely on functions' control flow.
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
iterator find(const_arg_type_t< KeyT > Val)
FunctionPass class - This class is used to implement most global optimizations.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Describe properties that are true of each instruction in the target description file.
bool hasSuperClassEq(const MCRegisterClass *RC) const
Returns true if RC is a super-class of or equal to this class.
void normalizeSuccProbs()
Normalize probabilities of all successors so that the sum of them becomes one.
bool isEHPad() const
Returns true if the block is a landing pad.
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
iterator_range< livein_iterator > liveins() const
reverse_instr_iterator instr_rbegin()
LLVM_ABI iterator SkipPHIsAndLabels(iterator I)
Return the first instruction in MBB after I that is not a PHI or a label.
LLVM_ABI iterator SkipPHIsLabelsAndDebug(iterator I, Register Reg=Register(), bool SkipPseudoOp=true)
Return the first instruction in MBB after I that is not a PHI, label or debug.
bool isEHFuncletEntry() const
Returns true if this is the entry block of an EH funclet.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned succ_size() const
LLVM_ABI void dump() const
bool isEHScopeEntry() const
Returns true if this is the entry block of an EH scope, i.e., the block that used to have a catchpad ...
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
reverse_instr_iterator instr_rend()
LLVM_ABI bool isLayoutSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB will be emitted immediately after this block, such that if this bloc...
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< iterator > terminators()
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
void setMachineBlockAddressTaken()
Set this block to indicate that its address is used as something other than the target of a terminato...
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
bool isCleanupFuncletEntry() const
Returns true if this is the entry block of a cleanup funclet.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
void dump() const
dump - Print the current MachineFunction to cerr, useful for debugger use.
bool exposesReturnsTwice() const
exposesReturnsTwice - Returns true if the function calls setjmp or any other similar functions with a...
MCContext & getContext() const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
bool verify(Pass *p=nullptr, const char *Banner=nullptr, raw_ostream *OS=nullptr, bool AbortOnError=true) const
Run the current MachineFunction through the machine code verifier, useful for debugger use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isTerminator(QueryType Type=AnyInBundle) const
Returns true if this instruction part of the terminator for a basic block.
bool isBranch(QueryType Type=AnyInBundle) const
Returns true if this is a conditional, unconditional, or indirect branch.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI bool addRegisterDead(Register Reg, const TargetRegisterInfo *RegInfo, bool AddIfNotFound=false)
We have determined MI defined a register without a use.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
void setIsDead(bool Val=true)
void setIsKill(bool Val=true)
void setMBB(MachineBasicBlock *MBB)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr unsigned id() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void insert_range(Range &&R)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool test(unsigned Idx) const
Represent a constant reference to a string, i.e.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool has128ByteRedZone(const MachineFunction &MF) const
Return true if the function has a redzone (accessible bytes past the frame of the top of stack functi...
static bool isDataInvariantLoad(MachineInstr &MI)
Returns true if the instruction has no behavior (specified or otherwise) that is based on the value l...
static bool isDataInvariant(MachineInstr &MI)
Returns true if the instruction has no behavior (specified or otherwise) that is based on the value o...
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const X86InstrInfo * getInstrInfo() const override
bool isPositionIndependent() const
const X86RegisterInfo * getRegisterInfo() const override
const X86Options & getCLOpts() const
const X86FrameLowering * getFrameLowering() const override
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
CondCode getCondFromBranch(const MachineInstr &MI)
int getFirstAddrOperandIdx(const MachineInstr &MI)
Return the index of the instruction's first address operand, if it has a memory reference,...
CondCode GetOppositeBranchCondition(CondCode CC)
GetOppositeBranchCondition - Return the inverse of the specified cond, e.g.
unsigned getCMovOpcode(unsigned RegBytes, bool HasMemoryOperand=false, bool HasNDD=false)
Return a cmov opcode for the given register size in bytes, and operand type.
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
NodeAddr< DefNode * > Def
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
auto unique(Range &&R, Predicate P)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionPass * createX86SpeculativeLoadHardeningLegacyPass()
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
MCRegisterClass TargetRegisterClass