37#define DEBUG_TYPE "aarch64-sls-hardening"
39#define AARCH64_SLS_HARDENING_NAME "AArch64 sls hardening pass"
68 static const ThunkKind BR;
69 static const ThunkKind BRAA;
70 static const ThunkKind BRAB;
71 static const ThunkKind BRAAZ;
72 static const ThunkKind BRABZ;
78 static constexpr unsigned NumXRegisters = 32;
81 static unsigned indexOfXReg(
Register Xn);
86 BLRThunks |=
Other.BLRThunks;
87 BLRAAZThunks |=
Other.BLRAAZThunks;
88 BLRABZThunks |=
Other.BLRABZThunks;
89 for (
unsigned I = 0;
I < NumXRegisters; ++
I)
90 BLRAAThunks[
I] |=
Other.BLRAAThunks[
I];
91 for (
unsigned I = 0;
I < NumXRegisters; ++
I)
92 BLRABThunks[
I] |=
Other.BLRABThunks[
I];
98 reg_bitmask_t XnBit = reg_bitmask_t(1) << indexOfXReg(Xn);
99 return getBitmask(Kind, Xm) & XnBit;
103 reg_bitmask_t XnBit = reg_bitmask_t(1) << indexOfXReg(Xn);
104 getBitmask(Kind, Xm) |= XnBit;
109 static_assert(NumXRegisters <=
sizeof(reg_bitmask_t) * CHAR_BIT,
110 "Bitmask is not wide enough to hold all Xn registers");
117 reg_bitmask_t BLRThunks = 0;
118 reg_bitmask_t BLRAAZThunks = 0;
119 reg_bitmask_t BLRABZThunks = 0;
120 reg_bitmask_t BLRAAThunks[NumXRegisters] = {};
121 reg_bitmask_t BLRABThunks[NumXRegisters] = {};
123 reg_bitmask_t &getBitmask(ThunkKind::ThunkKindId Kind,
Register Xm) {
125 case ThunkKind::ThunkBR:
127 case ThunkKind::ThunkBRAAZ:
129 case ThunkKind::ThunkBRABZ:
131 case ThunkKind::ThunkBRAA:
132 return BLRAAThunks[indexOfXReg(Xm)];
133 case ThunkKind::ThunkBRAB:
134 return BLRABThunks[indexOfXReg(Xm)];
153 ThunksSet ExistingThunks);
157 bool ComdatThunks =
true;
168const ThunkKind ThunkKind::BR = {ThunkBR,
"",
false,
170const ThunkKind ThunkKind::BRAA = {ThunkBRAA,
"aa_",
true,
171 true, AArch64::BRAA};
172const ThunkKind ThunkKind::BRAB = {ThunkBRAB,
"ab_",
true,
173 true, AArch64::BRAB};
174const ThunkKind ThunkKind::BRAAZ = {ThunkBRAAZ,
"aaz_",
false,
175 true, AArch64::BRAAZ};
176const ThunkKind ThunkKind::BRABZ = {ThunkBRABZ,
"abz_",
false,
177 true, AArch64::BRABZ};
181 switch (OriginalOpcode) {
183 case AArch64::BLRNoIP:
184 return &ThunkKind::BR;
186 return &ThunkKind::BRAA;
188 return &ThunkKind::BRAB;
189 case AArch64::BLRAAZ:
190 return &ThunkKind::BRAAZ;
191 case AArch64::BLRABZ:
192 return &ThunkKind::BRABZ;
203 assert(
Reg != AArch64::X16 &&
Reg != AArch64::X17 &&
Reg != AArch64::LR);
206 unsigned Result = (unsigned)
Reg - (
unsigned)AArch64::X0;
207 if (
Reg == AArch64::FP)
209 else if (
Reg == AArch64::XZR)
212 assert(Result < NumXRegisters &&
"Internal register numbering changed");
213 assert(AArch64::GPR64RegClass.getRegister(Result).
id() ==
Reg &&
214 "Internal register numbering changed");
219Register ThunksSet::xRegByIndex(
unsigned N) {
220 return AArch64::GPR64RegClass.getRegister(
N);
229 "Must not insert SpeculationBarrierEndBB as only instruction in MBB.");
231 "SpeculationBarrierEndBB must only follow unconditional control flow "
234 "SpeculationBarrierEndBB must only follow terminators.");
237 ? AArch64::SpeculationBarrierSBEndBB
238 : AArch64::SpeculationBarrierISBDSBEndBB;
240 (
MBBI->getOpcode() != AArch64::SpeculationBarrierSBEndBB &&
241 MBBI->getOpcode() != AArch64::SpeculationBarrierISBDSBEndBB))
247 ThunksSet ExistingThunks) {
250 for (
auto &
MBB : MF) {
251 if (ST->hardenSlsRetBr())
252 hardenReturnsAndBRs(MMI,
MBB);
253 if (ST->hardenSlsBlr())
254 hardenBLRs(MMI,
MBB, ExistingThunks);
256 return ExistingThunks;
268 NextMBBI = std::next(
MBBI);
283 unsigned N = ThunksSet::indexOfXReg(Xn);
284 if (!Kind.HasXmOperand)
287 unsigned M = ThunksSet::indexOfXReg(Xm);
291static std::tuple<const ThunkKind &, Register, Register>
294 "Should be filtered out by ThunkInserter");
309 assert(Name.starts_with(
"x") &&
"xN register name expected");
310 bool Fail = Name.drop_front(1).getAsInteger(10,
N);
311 assert(!
Fail &&
N < ThunksSet::NumXRegisters &&
"Unexpected register");
314 return ThunksSet::xRegByIndex(
N);
320 std::tie(XnStr, XmStr) = RegsStr.
split(
'_');
326 return std::make_tuple(std::ref(Kind), Xn, Xm);
331 "ComdatThunks value changed since MF creation");
334 const ThunkKind &Kind = std::get<0>(KindAndRegs);
335 std::tie(std::ignore, Xn, Xm) = KindAndRegs;
344 if (MF.
size() == 1) {
364 Entry->addLiveIn(Xn);
373 Entry->addLiveIn(Xm);
385void SLSHardeningInserter::convertBLRToBL(
428 unsigned NumRegOperands = Kind.HasXmOperand ? 2 : 1;
430 "Expected one or two register inputs");
441 MCSymbol *Sym = Context.getOrCreateSymbol(ThunkName);
443 if (!Thunks.get(Kind.Id, Xn, Xm)) {
444 StringRef TargetAttrs = Kind.NeedsPAuth ?
"+pauth" :
"";
445 Thunks.set(Kind.Id, Xn, Xm);
446 createThunkFunction(MMI, ThunkName, ComdatThunks, TargetAttrs);
462 OpIdx < BL->getNumOperands(); OpIdx++) {
466 if (
Op.getReg() == AArch64::LR &&
Op.isDef())
468 if (
Op.getReg() == AArch64::SP && !
Op.isDef())
473 int FirstOpIdxToRemove = std::max(ImpLROpIdx, ImpSPOpIdx);
474 int SecondOpIdxToRemove = std::min(ImpLROpIdx, ImpSPOpIdx);
482 for (
unsigned OpIdx = 0; OpIdx < NumRegOperands; ++OpIdx) {
491bool SLSHardeningInserter::hardenBLRs(MachineModuleInfo &MMI,
492 MachineBasicBlock &
MBB,
500 NextMBBI = std::next(
MBBI);
502 convertBLRToBL(MMI,
MBB,
MBBI, Thunks);
510class AArch64SLSHardeningLegacy
511 :
public ThunkInserterPass<SLSHardeningInserter> {
515 AArch64SLSHardeningLegacy() : ThunkInserterPass(
ID) {}
522char AArch64SLSHardeningLegacy::ID = 0;
528 return new AArch64SLSHardeningLegacy();
543 .getCachedResult<MachineModuleAnalysis>(
545 assert(MMI &&
"MachineModuleAnalysis must be available");
547 if (Inserter->run(MMI->
getMMI(), MF)) {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define AARCH64_SLS_HARDENING_NAME
static void insertSpeculationBarrier(const AArch64Subtarget *ST, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool AlwaysUseISBDSB=false)
static constexpr StringRef CommonNamePrefix
static SmallString< 32 > createThunkName(const ThunkKind &Kind, Register Xn, Register Xm)
static std::tuple< const ThunkKind &, Register, Register > parseThunkName(StringRef ThunkName)
static const ThunkKind * getThunkKind(unsigned OriginalOpcode)
static bool isBLR(const MachineInstr &MI)
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 ThunkInserter class that simplifies injection of MI thunks as well as a default imple...
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file declares the machine register scavenger class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
~AArch64SLSHardeningPass()
AArch64SLSHardeningPass()
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represents analyses that only rely on functions' control flow.
FunctionPass class - This class is used to implement most global optimizations.
Module * getParent()
Get the module that this global value is contained inside of...
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()
Instructions::iterator instr_iterator
instr_iterator instr_end()
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineInstrBundleIterator< MachineInstr > iterator
void moveAdditionalCallInfo(const MachineInstr *Old, const MachineInstr *New)
Move the call site info from Old to \New call site info.
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)
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
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
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
LLVM_ABI void copyImplicitOps(MachineFunction &MF, const MachineInstr &MI)
Copy implicit register operands from specified instruction to this instruction.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
MachineModuleInfo & getMMI()
This class contains meta information specific to a module.
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 set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
A switch()-like statement whose cases are string literals.
StringSwitch & StartsWith(StringLiteral S, T Value)
TargetInstrInfo - Interface to description of machine instruction set.
virtual const TargetInstrInfo * getInstrInfo() const
This class assists in inserting MI thunk functions into the module and rewriting the existing machine...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
OuterAnalysisManagerProxy< ModuleAnalysisManager, MachineFunction > ModuleAnalysisManagerMachineFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
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 * createAArch64SLSHardeningLegacyPass()
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
DWARFExpression::Operation Op
bool operator|=(SparseBitVector< ElementSize > &LHS, const SparseBitVector< ElementSize > *RHS)
Implement std::hash so that hash_code can be used in STL containers.
const char * getThunkPrefix()
void populateThunk(MachineFunction &MF)
ThunksSet insertThunks(MachineModuleInfo &MMI, MachineFunction &MF, ThunksSet ExistingThunks)
bool mayUseThunk(const MachineFunction &MF)