36#define DEBUG_TYPE "aarch64-sls-hardening"
38#define AARCH64_SLS_HARDENING_NAME "AArch64 sls hardening pass"
67char AArch64SLSHardening::ID = 0;
78 "Must not insert SpeculationBarrierEndBB as only instruction in MBB.");
80 "SpeculationBarrierEndBB must only follow unconditional control flow "
83 "SpeculationBarrierEndBB must only follow terminators.");
86 ? AArch64::SpeculationBarrierSBEndBB
87 : AArch64::SpeculationBarrierISBDSBEndBB;
89 (
MBBI->getOpcode() != AArch64::SpeculationBarrierSBEndBB &&
90 MBBI->getOpcode() != AArch64::SpeculationBarrierISBDSBEndBB))
100 for (
auto &
MBB : MF) {
109 switch (
MI.getOpcode()) {
111 case AArch64::BLRNoIP:
115 case AArch64::BLRAAZ:
116 case AArch64::BLRABZ:
118 "producing BLRA* instructions. Therefore, there's no "
119 "support in this pass for those instructions.");
125 if (!
ST->hardenSlsRetBr())
132 NextMBBI = std::next(
MBBI);
135 insertSpeculationBarrier(ST,
MBB, std::next(
MBBI),
MI.getDebugLoc());
142static const char SLSBLRNamePrefix[] =
"__llvm_slsblr_thunk_";
148 {
"__llvm_slsblr_thunk_x0", AArch64::X0},
149 {
"__llvm_slsblr_thunk_x1", AArch64::X1},
150 {
"__llvm_slsblr_thunk_x2", AArch64::X2},
151 {
"__llvm_slsblr_thunk_x3", AArch64::X3},
152 {
"__llvm_slsblr_thunk_x4", AArch64::X4},
153 {
"__llvm_slsblr_thunk_x5", AArch64::X5},
154 {
"__llvm_slsblr_thunk_x6", AArch64::X6},
155 {
"__llvm_slsblr_thunk_x7", AArch64::X7},
156 {
"__llvm_slsblr_thunk_x8", AArch64::X8},
157 {
"__llvm_slsblr_thunk_x9", AArch64::X9},
158 {
"__llvm_slsblr_thunk_x10", AArch64::X10},
159 {
"__llvm_slsblr_thunk_x11", AArch64::X11},
160 {
"__llvm_slsblr_thunk_x12", AArch64::X12},
161 {
"__llvm_slsblr_thunk_x13", AArch64::X13},
162 {
"__llvm_slsblr_thunk_x14", AArch64::X14},
163 {
"__llvm_slsblr_thunk_x15", AArch64::X15},
167 {
"__llvm_slsblr_thunk_x18", AArch64::X18},
168 {
"__llvm_slsblr_thunk_x19", AArch64::X19},
169 {
"__llvm_slsblr_thunk_x20", AArch64::X20},
170 {
"__llvm_slsblr_thunk_x21", AArch64::X21},
171 {
"__llvm_slsblr_thunk_x22", AArch64::X22},
172 {
"__llvm_slsblr_thunk_x23", AArch64::X23},
173 {
"__llvm_slsblr_thunk_x24", AArch64::X24},
174 {
"__llvm_slsblr_thunk_x25", AArch64::X25},
175 {
"__llvm_slsblr_thunk_x26", AArch64::X26},
176 {
"__llvm_slsblr_thunk_x27", AArch64::X27},
177 {
"__llvm_slsblr_thunk_x28", AArch64::X28},
178 {
"__llvm_slsblr_thunk_x29", AArch64::FP},
181 {
"__llvm_slsblr_thunk_x31", AArch64::XZR},
185struct SLSBLRThunkInserter :
ThunkInserter<SLSBLRThunkInserter> {
186 const char *getThunkPrefix() {
return SLSBLRNamePrefix; }
199 bool ComdatThunks =
true;
209 createThunkFunction(MMI,
T.Name, ComdatThunks);
232 Entry->addLiveIn(ThunkReg);
290 case AArch64::BLRNoIP:
291 BLOpcode = AArch64::BL;
293 assert(Reg != AArch64::X16 && Reg != AArch64::X17 && Reg != AArch64::LR);
298 case AArch64::BLRAAZ:
299 case AArch64::BLRABZ:
301 "therefore there is no need to support them for now.");
351 for (
unsigned OpIdx =
BL->getNumExplicitOperands();
352 OpIdx < BL->getNumOperands(); OpIdx++) {
356 if (
Op.getReg() == AArch64::LR &&
Op.isDef())
358 if (
Op.getReg() == AArch64::SP && !
Op.isDef())
363 int FirstOpIdxToRemove = std::max(ImpLROpIdx, ImpSPOpIdx);
364 int SecondOpIdxToRemove = std::min(ImpLROpIdx, ImpSPOpIdx);
365 BL->removeOperand(FirstOpIdxToRemove);
366 BL->removeOperand(SecondOpIdxToRemove);
368 BL->copyImplicitOps(MF, BLR);
380 if (!
ST->hardenSlsBlr())
388 NextMBBI = std::next(
MBBI);
398 return new AArch64SLSHardening();
414 std::tuple<SLSBLRThunkInserter> TIs;
417 template <
typename... ThunkInserterT>
418 static void initTIs(
Module &M,
419 std::tuple<ThunkInserterT...> &ThunkInserters) {
420 (void)std::initializer_list<int>{
421 (std::get<ThunkInserterT>(ThunkInserters).init(M), 0)...};
423 template <
typename... ThunkInserterT>
425 std::tuple<ThunkInserterT...> &ThunkInserters) {
427 (void)std::initializer_list<int>{
428 Modified |= std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF)...};
435char AArch64IndirectThunks::ID = 0;
438 return new AArch64IndirectThunks();
441bool AArch64IndirectThunks::doInitialization(
Module &M) {
448 auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
449 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 file defines the SmallVector class.
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.
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.
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 startswith(StringRef Prefix) const
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.
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.