LLVM: lib/Target/ARM/ARMSLSHardening.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

25#include

26

27using namespace llvm;

28

29#define DEBUG_TYPE "arm-sls-hardening"

30

31#define ARM_SLS_HARDENING_NAME "ARM sls hardening pass"

32

33namespace {

34

36public:

39

40 static char ID;

41

44 }

45

47

49

50 void getAnalysisUsage(AnalysisUsage &AU) const override {

53 }

54

55private:

61};

62

63}

64

65char ARMSLSHardening::ID = 0;

66

69

76 "Must not insert SpeculationBarrierEndBB as only instruction in MBB.");

77 assert(std::prev(MBBI)->isBarrier() &&

78 "SpeculationBarrierEndBB must only follow unconditional control flow "

79 "instructions.");

80 assert(std::prev(MBBI)->isTerminator() &&

81 "SpeculationBarrierEndBB must only follow terminators.");

83 assert(ST->hasDataBarrier() || ST->hasSB());

85 unsigned BarrierOpc =

86 ProduceSB ? (ST->isThumb() ? ARM::t2SpeculationBarrierSBEndBB

87 : ARM::SpeculationBarrierSBEndBB)

88 : (ST->isThumb() ? ARM::t2SpeculationBarrierISBDSBEndBB

89 : ARM::SpeculationBarrierISBDSBEndBB);

92}

93

94bool ARMSLSHardening::runOnMachineFunction(MachineFunction &MF) {

97

99 for (auto &MBB : MF) {

102 }

103

105}

106

107bool ARMSLSHardening::hardenReturnsAndBRs(MachineBasicBlock &MBB) const {

108 if (!ST->hardenSlsRetBr())

109 return false;

114 for (; MBBI != E; MBBI = NextMBBI) {

115 MachineInstr &MI = *MBBI;

116 NextMBBI = std::next(MBBI);

122 }

123 }

125}

126

127static const char SLSBLRNamePrefix[] = "__llvm_slsblr_thunk_";

128

134 {"__llvm_slsblr_thunk_arm_r0", ARM::R0, false},

135 {"__llvm_slsblr_thunk_arm_r1", ARM::R1, false},

136 {"__llvm_slsblr_thunk_arm_r2", ARM::R2, false},

137 {"__llvm_slsblr_thunk_arm_r3", ARM::R3, false},

138 {"__llvm_slsblr_thunk_arm_r4", ARM::R4, false},

139 {"__llvm_slsblr_thunk_arm_r5", ARM::R5, false},

140 {"__llvm_slsblr_thunk_arm_r6", ARM::R6, false},

141 {"__llvm_slsblr_thunk_arm_r7", ARM::R7, false},

142 {"__llvm_slsblr_thunk_arm_r8", ARM::R8, false},

143 {"__llvm_slsblr_thunk_arm_r9", ARM::R9, false},

144 {"__llvm_slsblr_thunk_arm_r10", ARM::R10, false},

145 {"__llvm_slsblr_thunk_arm_r11", ARM::R11, false},

146 {"__llvm_slsblr_thunk_arm_sp", ARM::SP, false},

147 {"__llvm_slsblr_thunk_arm_pc", ARM::PC, false},

148 {"__llvm_slsblr_thunk_thumb_r0", ARM::R0, true},

149 {"__llvm_slsblr_thunk_thumb_r1", ARM::R1, true},

150 {"__llvm_slsblr_thunk_thumb_r2", ARM::R2, true},

151 {"__llvm_slsblr_thunk_thumb_r3", ARM::R3, true},

152 {"__llvm_slsblr_thunk_thumb_r4", ARM::R4, true},

153 {"__llvm_slsblr_thunk_thumb_r5", ARM::R5, true},

154 {"__llvm_slsblr_thunk_thumb_r6", ARM::R6, true},

155 {"__llvm_slsblr_thunk_thumb_r7", ARM::R7, true},

156 {"__llvm_slsblr_thunk_thumb_r8", ARM::R8, true},

157 {"__llvm_slsblr_thunk_thumb_r9", ARM::R9, true},

158 {"__llvm_slsblr_thunk_thumb_r10", ARM::R10, true},

159 {"__llvm_slsblr_thunk_thumb_r11", ARM::R11, true},

160 {"__llvm_slsblr_thunk_thumb_sp", ARM::SP, true},

161 {"__llvm_slsblr_thunk_thumb_pc", ARM::PC, true},

163

164

165

167

172

173namespace {

174struct SLSBLRThunkInserter

175 : ThunkInserter<SLSBLRThunkInserter, ArmInsertedThunks> {

176 const char *getThunkPrefix() { return SLSBLRNamePrefix; }

177 bool mayUseThunk(const MachineFunction &MF) {

178 ComdatThunks &= !MF.getSubtarget().hardenSlsNoComdat();

179 return MF.getSubtarget().hardenSlsBlr();

180 }

181 ArmInsertedThunks insertThunks(MachineModuleInfo &MMI, MachineFunction &MF,

183 void populateThunk(MachineFunction &MF);

184

185private:

186 bool ComdatThunks = true;

187};

188}

189

191SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI, MachineFunction &MF,

193 if ((InsertedThunks & ArmThunk &&

194 !MF.getSubtarget().isThumb()) ||

198

199

200

201 const ARMSubtarget *ST = &MF.getSubtarget();

203 if (ST->isThumb() == T.isThumb)

204 createThunkFunction(MMI, T.Name, ComdatThunks,

205 T.isThumb ? "+thumb-mode" : "");

207}

208

209void SLSBLRThunkInserter::populateThunk(MachineFunction &MF) {

211 "ComdatThunks value changed since MF creation");

212

213

218 Register ThunkReg = ThunkIt->Reg;

219 bool isThumb = ThunkIt->isThumb;

220

221 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();

222 MachineBasicBlock *Entry = &MF.front();

224

225

226

227

228

229 Entry->addLiveIn(ThunkReg);

234 else

237

238

239

240

241

243 Entry->end(), DebugLoc(), true );

244}

245

246MachineBasicBlock &ARMSLSHardening::ConvertIndirectCallToIndirectJump(

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

279 int RegOpIdxOnIndirectCall = -1;

282 case ARM::BLX:

283 case ARM::BLX_noip:

285 RegOpIdxOnIndirectCall = 0;

286 break;

287 case ARM::tBLXr:

288 case ARM::tBLXr_noip:

290 RegOpIdxOnIndirectCall = 2;

291 break;

292 default:

294 }

295

297

298

299

300

301

302

304 bool RegIsKilled = IndirectCall.getOperand(RegOpIdxOnIndirectCall).isKill();

305

307

308 MachineFunction &MF = *MBBI->getMF();

311 });

314 const GlobalValue *GV = cast(M->getNamedValue(ThunkIt->Name));

315

316 MachineInstr *BL =

322

323

324

325

326

327

328

329

330

331 int ImpLROpIdx = -1;

332 int ImpSPOpIdx = -1;

336 if (Op.isReg())

337 continue;

338 if (Op.getReg() == ARM::LR && Op.isDef())

339 ImpLROpIdx = OpIdx;

340 if (Op.getReg() == ARM::SP && Op.isDef())

341 ImpSPOpIdx = OpIdx;

342 }

343 assert(ImpLROpIdx != -1);

344 assert(ImpSPOpIdx != -1);

345 int FirstOpIdxToRemove = std::max(ImpLROpIdx, ImpSPOpIdx);

346 int SecondOpIdxToRemove = std::min(ImpLROpIdx, ImpSPOpIdx);

349

352

353

355 RegIsKilled ));

356

358 return MBB;

359}

360

361bool ARMSLSHardening::hardenIndirectCalls(MachineBasicBlock &MBB) const {

362 if (ST->hardenSlsBlr())

363 return false;

367 for (; MBBI != E; MBBI = NextMBBI) {

368 MachineInstr &MI = *MBBI;

369 NextMBBI = std::next(MBBI);

370

371

372

374 ConvertIndirectCallToIndirectJump(MBB, MBBI);

376 }

377 }

379}

380

381

382

384 return new ARMSLSHardening();

385}

386

387namespace {

388class ARMIndirectThunks : public ThunkInserterPass {

389public:

390 static char ID;

391

393

394 StringRef getPassName() const override { return "ARM Indirect Thunks"; }

395};

396}

397

398char ARMIndirectThunks::ID = 0;

399

401 return new ARMIndirectThunks();

402}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

const TargetInstrInfo & TII

static void insertSpeculationBarrier(const AArch64Subtarget *ST, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool AlwaysUseISBDSB=false)

static bool isThumb(const MCSubtargetInfo &STI)

MachineBasicBlock & MBB

Definition ARMSLSHardening.cpp:71

MachineBasicBlock MachineBasicBlock::iterator DebugLoc bool AlwaysUseISBDSB

Definition ARMSLSHardening.cpp:74

#define ARM_SLS_HARDENING_NAME

Definition ARMSLSHardening.cpp:31

ArmInsertedThunks

Definition ARMSLSHardening.cpp:166

@ NoThunk

Definition ARMSLSHardening.cpp:166

@ ArmThunk

Definition ARMSLSHardening.cpp:166

@ ThumbThunk

Definition ARMSLSHardening.cpp:166

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Definition ARMSLSHardening.cpp:73

MachineBasicBlock MachineBasicBlock::iterator MBBI

Definition ARMSLSHardening.cpp:72

static const struct ThunkNameRegMode SLSBLRThunks[]

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

Contains a base ThunkInserter class that simplifies injection of MI thunks as well as a default imple...

Machine Check Debug Module

Promote Memory to Register

MachineInstr unsigned OpIdx

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")

static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")

bool isThumb1Only() const

Represent the analysis usage information of a pass.

LLVM_ABI void setPreservesCFG()

This function should be called by the pass, iff they do not:

FunctionPass class - This class is used to implement most global optimizations.

Module * getParent()

Get the module that this global value is contained inside of...

const MCInstrDesc & get(unsigned Opcode) const

Return the machine instruction descriptor that corresponds to the specified instruction opcode.

LLVM_ABI iterator getFirstTerminator()

Returns an iterator to the first terminator instruction of this basic block.

LLVM_ABI instr_iterator erase(instr_iterator I)

Remove an instruction from the instruction list and delete it.

MachineInstrBundleIterator< MachineInstr > iterator

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.

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.

Function & getFunction()

Return the LLVM function that this machine code represents.

const MachineBasicBlock & front() const

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & add(const MachineOperand &MO) const

const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const

const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const

Add a new virtual register operand.

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.

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

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)

static LLVM_ABI PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

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.

virtual bool isPredicated(const MachineInstr &MI) const

Returns true if the instruction is already predicated.

virtual const TargetInstrInfo * getInstrInfo() const

Basic implementation of MachineFunctionPass wrapping one or more ThunkInserters passed as type parame...

#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.

This is an optimization pass for GlobalISel generic memory operations.

static bool isIndirectCall(const MachineInstr &MI)

MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)

Builder interface. Specify how to create the initial instruction itself.

static std::array< MachineOperand, 2 > predOps(ARMCC::CondCodes Pred, unsigned PredReg=0)

Get the operands corresponding to the given Pred value.

void initializeARMSLSHardeningPass(PassRegistry &)

FunctionPass * createARMSLSHardeningPass()

Definition ARMSLSHardening.cpp:383

static bool isIndirectControlFlowNotComingBack(const MachineInstr &MI)

DWARFExpression::Operation Op

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

auto find_if(R &&Range, UnaryPredicate P)

Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.

FunctionPass * createARMIndirectThunks()

Definition ARMSLSHardening.cpp:400

bool operator|=(SparseBitVector< ElementSize > &LHS, const SparseBitVector< ElementSize > *RHS)

static bool isSpeculationBarrierEndBBOpcode(int Opc)

bool isThumb

Definition ARMSLSHardening.cpp:132

Register Reg

Definition ARMSLSHardening.cpp:131

const char * Name

Definition ARMSLSHardening.cpp:130