LLVM: lib/CodeGen/ShadowStackGCLowering.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

43#include

44#include

45#include

46#include

47

48using namespace llvm;

49

50#define DEBUG_TYPE "shadow-stack-gc-lowering"

51

52namespace {

53

54class ShadowStackGCLoweringImpl {

55

56

58

59

62

63

64

65 std::vector<std::pair<CallInst *, AllocaInst *>> Roots;

66

67public:

68 ShadowStackGCLoweringImpl() = default;

69

70 bool doInitialization(Module &M);

72

73private:

74 bool IsNullValue(Value *V);

78

80 Type *Ty, Value *BasePtr, int Idx1,

81 const char *Name);

83 Type *Ty, Value *BasePtr, int Idx1, int Idx2,

84 const char *Name);

85};

86

87class ShadowStackGCLowering : public FunctionPass {

88 ShadowStackGCLoweringImpl Impl;

89

90public:

91 static char ID;

92

93 ShadowStackGCLowering();

94

98 }

100 std::optional DTU;

101 if (auto *DTWP = getAnalysisIfAvailable())

102 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);

103 return Impl.runOnFunction(F, DTU ? &*DTU : nullptr);

104 }

105};

106

107}

108

112 if (Map.StrategyMap.contains("shadow-stack"))

114

115 ShadowStackGCLoweringImpl Impl;

116 bool Changed = Impl.doInitialization(M);

117 for (auto &F : M) {

118 auto &FAM =

121 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);

122 Changed |= Impl.runOnFunction(F, DT ? &DTU : nullptr);

123 }

124

125 if (!Changed)

129 return PA;

130}

131

132char ShadowStackGCLowering::ID = 0;

134

136 "Shadow Stack GC Lowering", false, false)

141

143

144ShadowStackGCLowering::ShadowStackGCLowering() : FunctionPass(ID) {

146}

147

149

150 Type *VoidPtr = PointerType::getUnqual(F.getContext());

151

152

153 unsigned NumMeta = 0;

155 for (unsigned I = 0; I != Roots.size(); ++I) {

156 Constant *C = cast(Roots[I].first->getArgOperand(1));

157 if (C->isNullValue())

158 NumMeta = I + 1;

160 }

162

164

166 ConstantInt::get(Int32Ty, Roots.size(), false),

167 ConstantInt::get(Int32Ty, NumMeta, false),

168 };

169

170 Constant *DescriptorElts[] = {

173

174 Type *EltTys[] = {DescriptorElts[0]->getType(), DescriptorElts[1]->getType()};

176

178

179

180

181

182

183

184

185

186

187

188

189

190

191

193 GlobalVariable::InternalLinkage, FrameMap,

194 "__gc_" + F.getName());

195

200}

201

202Type *ShadowStackGCLoweringImpl::GetConcreteStackEntryType(Function &F) {

203

204 std::vector<Type *> EltTys;

205 EltTys.push_back(StackEntryTy);

206 for (const std::pair<CallInst *, AllocaInst *> &Root : Roots)

207 EltTys.push_back(Root.second->getAllocatedType());

208

209 return StructType::create(EltTys, ("gc_stackentry." + F.getName()).str());

210}

211

212

213

214bool ShadowStackGCLoweringImpl::doInitialization(Module &M) {

217 if (F.hasGC() && F.getGC() == "shadow-stack") {

219 break;

220 }

221 }

222 if (!Active)

223 return false;

224

225

226

227

228

229

230 std::vector<Type *> EltTys;

231

233

236 PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);

237

238

239

240

241

242

243

244 PointerType *StackEntryPtrTy = PointerType::getUnqual(M.getContext());

245

246 EltTys.clear();

247 EltTys.push_back(StackEntryPtrTy);

248 EltTys.push_back(FrameMapPtrTy);

250

251

252 Head = M.getGlobalVariable("llvm_gc_root_chain");

253 if (!Head) {

254

255

259 } else if (Head->hasExternalLinkage() && Head->isDeclaration()) {

262 }

263

264 return true;

265}

266

267bool ShadowStackGCLoweringImpl::IsNullValue(Value *V) {

268 if (Constant *C = dyn_cast(V))

269 return C->isNullValue();

270 return false;

271}

272

273void ShadowStackGCLoweringImpl::CollectRoots(Function &F) {

274

275

276

277

278 assert(Roots.empty() && "Not cleaned up?");

279

281

285 if (Function *F = CI->getCalledFunction())

286 if (F->getIntrinsicID() == Intrinsic::gcroot) {

287 std::pair<CallInst *, AllocaInst *> Pair = std::make_pair(

288 CI,

289 cast(CI->getArgOperand(0)->stripPointerCasts()));

290 if (IsNullValue(CI->getArgOperand(1)))

291 Roots.push_back(Pair);

292 else

294 }

295

296

297

298 Roots.insert(Roots.begin(), MetaRoots.begin(), MetaRoots.end());

299}

300

304 int Idx2, const char *Name) {

308 Value *Val = B.CreateGEP(Ty, BasePtr, Indices, Name);

309

310 assert(isa(Val) && "Unexpected folded constant");

311

312 return dyn_cast(Val);

313}

314

319 const char *Name) {

322 Value *Val = B.CreateGEP(Ty, BasePtr, Indices, Name);

323

324 assert(isa(Val) && "Unexpected folded constant");

325

326 return dyn_cast(Val);

327}

328

329

330bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,

332

333 if (F.hasGC() || F.getGC() != "shadow-stack")

334 return false;

335

337

338

339 CollectRoots(F);

340

341

342

343 if (Roots.empty())

344 return false;

345

346

347 Value *FrameMap = GetFrameMap(F);

348 Type *ConcreteStackEntryTy = GetConcreteStackEntryType(F);

349

350

352 IRBuilder<> AtEntry(IP->getParent(), IP);

353

355 AtEntry.CreateAlloca(ConcreteStackEntryTy, nullptr, "gc_frame");

356

357 AtEntry.SetInsertPointPastAllocas(&F);

358 IP = AtEntry.GetInsertPoint();

359

360

362 AtEntry.CreateLoad(AtEntry.getPtrTy(), Head, "gc_currhead");

363 Instruction *EntryMapPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,

364 StackEntry, 0, 1, "gc_frame.map");

365 AtEntry.CreateStore(FrameMap, EntryMapPtr);

366

367

368 for (unsigned I = 0, E = Roots.size(); I != E; ++I) {

369

370 Value *SlotPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,

371 StackEntry, 1 + I, "gc_root");

372

373

374 AllocaInst *OriginalAlloca = Roots[I].second;

375 SlotPtr->takeName(OriginalAlloca);

377 }

378

379

380

381

382

383 while (isa(IP))

384 ++IP;

385 AtEntry.SetInsertPoint(IP->getParent(), IP);

386

387

388 Instruction *EntryNextPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,

389 StackEntry, 0, 0, "gc_frame.next");

390 Instruction *NewHeadVal = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,

391 StackEntry, 0, "gc_newhead");

392 AtEntry.CreateStore(CurrentHead, EntryNextPtr);

393 AtEntry.CreateStore(NewHeadVal, Head);

394

395

396 EscapeEnumerator EE(F, "gc_cleanup", true, DTU);

397 while (IRBuilder<> *AtExit = EE.Next()) {

398

399

401 CreateGEP(Context, *AtExit, ConcreteStackEntryTy, StackEntry, 0, 0,

402 "gc_frame.next");

403 Value *SavedHead =

404 AtExit->CreateLoad(AtExit->getPtrTy(), EntryNextPtr2, "gc_savedhead");

405 AtExit->CreateStore(SavedHead, Head);

406 }

407

408

409

410

411 for (std::pair<CallInst *, AllocaInst *> &Root : Roots) {

412 Root.first->eraseFromParent();

413 Root.second->eraseFromParent();

414 }

415

416 Roots.clear();

417 return true;

418}

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

This file contains the declarations for the subclasses of Constant, which represent the different fla...

Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx

static bool runOnFunction(Function &F, bool PostInlining)

Module.h This file contains the declarations for the Module class.

FunctionAnalysisManager FAM

ModuleAnalysisManager MAM

#define INITIALIZE_PASS_DEPENDENCY(depName)

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

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

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SmallVector class.

an instruction to allocate memory on the stack

A container for analyses that lazily runs them and caches their results.

PassT::Result * getCachedResult(IRUnitT &IR) const

Get the cached result of an analysis pass for a given IR unit.

PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)

Get the result of an analysis pass for a given IR unit.

Represent the analysis usage information of a pass.

AnalysisUsage & addPreserved()

Add the specified Pass class to the set of analyses preserved by this pass.

LLVM Basic Block Representation.

InstListType::iterator iterator

Instruction iterators...

static Constant * get(ArrayType *T, ArrayRef< Constant * > V)

static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)

Getelementptr form.

static Constant * get(StructType *T, ArrayRef< Constant * > V)

This is an important base class in LLVM.

static Constant * getNullValue(Type *Ty)

Constructor to create a '0' constant of arbitrary type.

Analysis pass which computes a DominatorTree.

Legacy analysis pass which computes a DominatorTree.

EscapeEnumerator - This is a little algorithm to find all escape points from a function so that "fina...

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

virtual bool runOnFunction(Function &F)=0

runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.

An analysis pass which caches information about the entire Module.

an instruction for type-safe pointer arithmetic to access elements of arrays and structs

@ LinkOnceAnyLinkage

Keep one copy of function when linking (inline)

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...

A wrapper class for inspecting calls to intrinsic functions.

This is an important class for using LLVM in a threaded context.

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 void getAnalysisUsage(AnalysisUsage &) const

getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...

virtual bool doInitialization(Module &)

doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...

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.

void preserve()

Mark an analysis as preserved.

PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

Class to represent struct types.

static StructType * create(LLVMContext &Context, StringRef Name)

This creates an identified struct.

The instances of the Type class are immutable: once they are created, they are never changed.

static IntegerType * getInt32Ty(LLVMContext &C)

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

void takeName(Value *V)

Transfer the name from V to this value.

@ C

The default llvm calling convention, compatible with C.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

This is an optimization pass for GlobalISel generic memory operations.

char & ShadowStackGCLoweringID

ShadowStackGCLowering - Implements the custom lowering mechanism used by the shadow stack GC.

void initializeShadowStackGCLoweringPass(PassRegistry &)

FunctionPass * createShadowStackGCLoweringPass()

ShadowStackGCLowering - Implements the custom lowering mechanism used by the shadow stack GC.