35#define DEBUG_TYPE "aarch64-sls-hardening"
37#define AARCH64_SLS_HARDENING_NAME "AArch64 sls hardening pass"
66char AArch64SLSHardening::ID = 0;
77 "Must not insert SpeculationBarrierEndBB as only instruction in MBB.");
79 "SpeculationBarrierEndBB must only follow unconditional control flow "
82 "SpeculationBarrierEndBB must only follow terminators.");
85 ? AArch64::SpeculationBarrierSBEndBB
86 : AArch64::SpeculationBarrierISBDSBEndBB;
88 (
MBBI->getOpcode() != AArch64::SpeculationBarrierSBEndBB &&
89 MBBI->getOpcode() != AArch64::SpeculationBarrierISBDSBEndBB))
99 for (
auto &
MBB : MF) {
108 switch (
MI.getOpcode()) {
110 case AArch64::BLRNoIP:
114 case AArch64::BLRAAZ:
115 case AArch64::BLRABZ:
117 "producing BLRA* instructions. Therefore, there's no "
118 "support in this pass for those instructions.");
124 if (!
ST->hardenSlsRetBr())
131 NextMBBI = std::next(
MBBI);
134 insertSpeculationBarrier(ST,
MBB, std::next(
MBBI),
MI.getDebugLoc());
141static const char SLSBLRNamePrefix[] =
"__llvm_slsblr_thunk_";
147 {
"__llvm_slsblr_thunk_x0", AArch64::X0},
148 {
"__llvm_slsblr_thunk_x1", AArch64::X1},
149 {
"__llvm_slsblr_thunk_x2", AArch64::X2},
150 {
"__llvm_slsblr_thunk_x3", AArch64::X3},
151 {
"__llvm_slsblr_thunk_x4", AArch64::X4},
152 {
"__llvm_slsblr_thunk_x5", AArch64::X5},
153 {
"__llvm_slsblr_thunk_x6", AArch64::X6},
154 {
"__llvm_slsblr_thunk_x7", AArch64::X7},
155 {
"__llvm_slsblr_thunk_x8", AArch64::X8},
156 {
"__llvm_slsblr_thunk_x9", AArch64::X9},
157 {
"__llvm_slsblr_thunk_x10", AArch64::X10},
158 {
"__llvm_slsblr_thunk_x11", AArch64::X11},
159 {
"__llvm_slsblr_thunk_x12", AArch64::X12},
160 {
"__llvm_slsblr_thunk_x13", AArch64::X13},
161 {
"__llvm_slsblr_thunk_x14", AArch64::X14},
162 {
"__llvm_slsblr_thunk_x15", AArch64::X15},
166 {
"__llvm_slsblr_thunk_x18", AArch64::X18},
167 {
"__llvm_slsblr_thunk_x19", AArch64::X19},
168 {
"__llvm_slsblr_thunk_x20", AArch64::X20},
169 {
"__llvm_slsblr_thunk_x21", AArch64::X21},
170 {
"__llvm_slsblr_thunk_x22", AArch64::X22},
171 {
"__llvm_slsblr_thunk_x23", AArch64::X23},
172 {
"__llvm_slsblr_thunk_x24", AArch64::X24},
173 {
"__llvm_slsblr_thunk_x25", AArch64::X25},
174 {
"__llvm_slsblr_thunk_x26", AArch64::X26},
175 {
"__llvm_slsblr_thunk_x27", AArch64::X27},
176 {
"__llvm_slsblr_thunk_x28", AArch64::X28},
177 {
"__llvm_slsblr_thunk_x29", AArch64::FP},
180 {
"__llvm_slsblr_thunk_x31", AArch64::XZR},
184struct SLSBLRThunkInserter :
ThunkInserter<SLSBLRThunkInserter> {
185 const char *getThunkPrefix() {
return SLSBLRNamePrefix; }
198 bool ComdatThunks =
true;
208 createThunkFunction(MMI,
T.Name, ComdatThunks);
228 if (MF.
size() == 1) {
244 Entry->addLiveIn(ThunkReg);
302 case AArch64::BLRNoIP:
303 BLOpcode = AArch64::BL;
305 assert(Reg != AArch64::X16 && Reg != AArch64::X17 && Reg != AArch64::LR);
310 case AArch64::BLRAAZ:
311 case AArch64::BLRABZ:
313 "therefore there is no need to support them for now.");
363 for (
unsigned OpIdx =
BL->getNumExplicitOperands();
364 OpIdx < BL->getNumOperands(); OpIdx++) {
368 if (
Op.getReg() == AArch64::LR &&
Op.isDef())
370 if (
Op.getReg() == AArch64::SP && !
Op.isDef())
375 int FirstOpIdxToRemove = std::max(ImpLROpIdx, ImpSPOpIdx);
376 int SecondOpIdxToRemove = std::min(ImpLROpIdx, ImpSPOpIdx);
377 BL->removeOperand(FirstOpIdxToRemove);
378 BL->removeOperand(SecondOpIdxToRemove);
380 BL->copyImplicitOps(MF, BLR);
392 if (!
ST->hardenSlsBlr())
400 NextMBBI = std::next(
MBBI);
410 return new AArch64SLSHardening();
426 std::tuple<SLSBLRThunkInserter> TIs;
428 template <
typename... ThunkInserterT>
429 static void initTIs(
Module &M,
430 std::tuple<ThunkInserterT...> &ThunkInserters) {
431 (..., std::get<ThunkInserterT>(ThunkInserters).init(M));
433 template <
typename... ThunkInserterT>
435 std::tuple<ThunkInserterT...> &ThunkInserters) {
436 return (0 | ... | std::get<ThunkInserterT>(ThunkInserters).
run(MMI, MF));
442char AArch64IndirectThunks::ID = 0;
445 return new AArch64IndirectThunks();
448bool AArch64IndirectThunks::doInitialization(
Module &M) {
455 auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
456 return runTIs(MMI, MF, TIs);
#define AARCH64_SLS_HARDENING_NAME
static const struct ThunkNameAndReg SLSBLRThunks[]
MachineBasicBlock MachineBasicBlock::iterator DebugLoc bool AlwaysUseISBDSB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
Contains a base class for Passes that inject an MI thunk.
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file declares the machine register scavenger class.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Context object for machine code objects.
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
instr_iterator instr_begin()
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
Instructions::iterator instr_iterator
instr_iterator instr_end()
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
bool doInitialization(Module &) override
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
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 push_back(MachineBasicBlock *MBB)
MCContext & getContext() const
const MachineBasicBlock & front() const
void moveCallSiteInfo(const MachineInstr *Old, const MachineInstr *New)
Move the call site info from Old to \New call site info.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
This class contains meta information specific to a module.
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
A Module instance is used to store all the information related to an LLVM module.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
StringRef - Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
virtual const TargetInstrInfo * getInstrInfo() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Reg
All possible values of the reg field in the ModR/M byte.
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
static bool isIndirectBranchOpcode(int Opc)
FunctionPass * createAArch64IndirectThunks()
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void initializeAArch64SLSHardeningPass(PassRegistry &)
FunctionPass * createAArch64SLSHardeningPass()
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.