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

95 bool doInitialization(Module &M) override { return Impl.doInitialization(M); }

96 void getAnalysisUsage(AnalysisUsage &AU) const override {

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

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) {

157 if (C->isNullValue())

158 NumMeta = I + 1;

160 }

162

163 Type *Int32Ty = Type::getInt32Ty(F.getContext());

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

192 Constant *GV = new GlobalVariable(*F.getParent(), FrameMap->getType(), true,

193 GlobalVariable::InternalLinkage, FrameMap,

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

195

197 ConstantInt::get(Type::getInt32Ty(F.getContext()), 0),

198 ConstantInt::get(Type::getInt32Ty(F.getContext()), 0)};

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) {

216 for (Function &F : 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

232 EltTys.push_back(Type::getInt32Ty(M.getContext()));

233

234 EltTys.push_back(Type::getInt32Ty(M.getContext()));

236 PointerType *FrameMapPtrTy = PointerType::getUnqual(M.getContext());

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

256 Head = new GlobalVariable(

262 }

263

264 return true;

265}

266

267bool ShadowStackGCLoweringImpl::IsNullValue(Value *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

282 for (BasicBlock &BB : F)

283 for (Instruction &I : BB)

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

301GetElementPtrInst *

302ShadowStackGCLoweringImpl::CreateGEP(LLVMContext &Context, IRBuilder<> &B,

303 Type *Ty, Value *BasePtr, int Idx,

304 int Idx2, const char *Name) {

305 Value *Indices[] = {ConstantInt::get(Type::getInt32Ty(Context), 0),

306 ConstantInt::get(Type::getInt32Ty(Context), Idx),

307 ConstantInt::get(Type::getInt32Ty(Context), Idx2)};

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

309

311

313}

314

315GetElementPtrInst *ShadowStackGCLoweringImpl::CreateGEP(LLVMContext &Context,

318 Value *BasePtr, int Idx,

319 const char *Name) {

320 Value *Indices[] = {ConstantInt::get(Type::getInt32Ty(Context), 0),

321 ConstantInt::get(Type::getInt32Ty(Context), Idx)};

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

323

325

327}

328

329

330bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,

331 DomTreeUpdater *DTU) {

332

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

334 return false;

335

336 LLVMContext &Context = F.getContext();

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

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}

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

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

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

static bool runOnFunction(Function &F, bool PostInlining)

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

Machine Check Debug Module

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)

This file defines the SmallVector class.

Represent the analysis usage information of a pass.

AnalysisUsage & addPreserved()

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

InstListType::iterator iterator

Instruction iterators...

static LLVM_ABI 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 LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)

This is an important base class in LLVM.

static LLVM_ABI 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.

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

An analysis pass which caches information about the entire Module.

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

bool hasExternalLinkage() const

LLVM_ABI bool isDeclaration() const

Return true if the primary definition of this global value is outside of the current translation unit...

void setLinkage(LinkageTypes LT)

@ LinkOnceAnyLinkage

Keep one copy of function when linking (inline)

LLVM_ABI void setInitializer(Constant *InitVal)

setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...

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

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 LLVM_ABI PassRegistry * getPassRegistry()

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

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 & preserve()

Mark an analysis as preserved.

PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)

Definition ShadowStackGCLowering.cpp:109

void push_back(const T &Elt)

Class to represent struct types.

static LLVM_ABI 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.

LLVM Value Representation.

Type * getType() const

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

LLVM_ABI void replaceAllUsesWith(Value *V)

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

LLVM_ABI void takeName(Value *V)

Transfer the name from V to this value.

unsigned ID

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

@ C

The default llvm calling convention, compatible with C.

friend class Instruction

Iterator for Instructions in a `BasicBlock.

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

decltype(auto) dyn_cast(const From &Val)

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

FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty

InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy

Provide the FunctionAnalysisManager to Module proxy.

std::string utostr(uint64_t X, bool isNeg=false)

LLVM_ABI char & ShadowStackGCLoweringID

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

Definition ShadowStackGCLowering.cpp:133

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

LLVM_ABI void initializeShadowStackGCLoweringPass(PassRegistry &)

IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >

decltype(auto) cast(const From &Val)

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

LLVM_ABI FunctionPass * createShadowStackGCLoweringPass()

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

Definition ShadowStackGCLowering.cpp:142

AnalysisManager< Module > ModuleAnalysisManager

Convenience typedef for the Module analysis manager.