494 lines · cpp
1//===-- ModuleUtils.cpp - Functions to manipulate Modules -----------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This family of functions perform manipulations on Modules.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/Transforms/Utils/ModuleUtils.h"14#include "llvm/Analysis/VectorUtils.h"15#include "llvm/ADT/SmallString.h"16#include "llvm/IR/DerivedTypes.h"17#include "llvm/IR/Function.h"18#include "llvm/IR/IRBuilder.h"19#include "llvm/IR/MDBuilder.h"20#include "llvm/IR/Module.h"21#include "llvm/Support/Casting.h"22#include "llvm/Support/MD5.h"23#include "llvm/Support/raw_ostream.h"24#include "llvm/Support/xxhash.h"25 26using namespace llvm;27 28#define DEBUG_TYPE "moduleutils"29 30static void appendToGlobalArray(StringRef ArrayName, Module &M, Function *F,31 int Priority, Constant *Data) {32 IRBuilder<> IRB(M.getContext());33 34 // Get the current set of static global constructors and add the new ctor35 // to the list.36 SmallVector<Constant *, 16> CurrentCtors;37 StructType *EltTy;38 if (GlobalVariable *GVCtor = M.getNamedGlobal(ArrayName)) {39 EltTy = cast<StructType>(GVCtor->getValueType()->getArrayElementType());40 if (Constant *Init = GVCtor->getInitializer()) {41 unsigned n = Init->getNumOperands();42 CurrentCtors.reserve(n + 1);43 for (unsigned i = 0; i != n; ++i)44 CurrentCtors.push_back(cast<Constant>(Init->getOperand(i)));45 }46 GVCtor->eraseFromParent();47 } else {48 EltTy = StructType::get(49 IRB.getInt32Ty(),50 PointerType::get(M.getContext(), F->getAddressSpace()), IRB.getPtrTy());51 }52 53 // Build a 3 field global_ctor entry. We don't take a comdat key.54 Constant *CSVals[3];55 CSVals[0] = IRB.getInt32(Priority);56 CSVals[1] = F;57 CSVals[2] = Data ? ConstantExpr::getPointerCast(Data, IRB.getPtrTy())58 : Constant::getNullValue(IRB.getPtrTy());59 Constant *RuntimeCtorInit =60 ConstantStruct::get(EltTy, ArrayRef(CSVals, EltTy->getNumElements()));61 62 CurrentCtors.push_back(RuntimeCtorInit);63 64 // Create a new initializer.65 ArrayType *AT = ArrayType::get(EltTy, CurrentCtors.size());66 Constant *NewInit = ConstantArray::get(AT, CurrentCtors);67 68 // Create the new global variable and replace all uses of69 // the old global variable with the new one.70 (void)new GlobalVariable(M, NewInit->getType(), false,71 GlobalValue::AppendingLinkage, NewInit, ArrayName);72}73 74void llvm::appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data) {75 appendToGlobalArray("llvm.global_ctors", M, F, Priority, Data);76}77 78void llvm::appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *Data) {79 appendToGlobalArray("llvm.global_dtors", M, F, Priority, Data);80}81 82static void transformGlobalArray(StringRef ArrayName, Module &M,83 const GlobalCtorTransformFn &Fn) {84 GlobalVariable *GVCtor = M.getNamedGlobal(ArrayName);85 if (!GVCtor)86 return;87 88 IRBuilder<> IRB(M.getContext());89 SmallVector<Constant *, 16> CurrentCtors;90 bool Changed = false;91 StructType *EltTy =92 cast<StructType>(GVCtor->getValueType()->getArrayElementType());93 if (Constant *Init = GVCtor->getInitializer()) {94 CurrentCtors.reserve(Init->getNumOperands());95 for (Value *OP : Init->operands()) {96 Constant *C = cast<Constant>(OP);97 Constant *NewC = Fn(C);98 Changed |= (!NewC || NewC != C);99 if (NewC)100 CurrentCtors.push_back(NewC);101 }102 }103 if (!Changed)104 return;105 106 GVCtor->eraseFromParent();107 108 // Create a new initializer.109 ArrayType *AT = ArrayType::get(EltTy, CurrentCtors.size());110 Constant *NewInit = ConstantArray::get(AT, CurrentCtors);111 112 // Create the new global variable and replace all uses of113 // the old global variable with the new one.114 (void)new GlobalVariable(M, NewInit->getType(), false,115 GlobalValue::AppendingLinkage, NewInit, ArrayName);116}117 118void llvm::transformGlobalCtors(Module &M, const GlobalCtorTransformFn &Fn) {119 transformGlobalArray("llvm.global_ctors", M, Fn);120}121 122void llvm::transformGlobalDtors(Module &M, const GlobalCtorTransformFn &Fn) {123 transformGlobalArray("llvm.global_dtors", M, Fn);124}125 126static void collectUsedGlobals(GlobalVariable *GV,127 SmallSetVector<Constant *, 16> &Init) {128 if (!GV || !GV->hasInitializer())129 return;130 131 auto *CA = cast<ConstantArray>(GV->getInitializer());132 for (Use &Op : CA->operands())133 Init.insert(cast<Constant>(Op));134}135 136static void appendToUsedList(Module &M, StringRef Name, ArrayRef<GlobalValue *> Values) {137 GlobalVariable *GV = M.getGlobalVariable(Name);138 139 SmallSetVector<Constant *, 16> Init;140 collectUsedGlobals(GV, Init);141 if (GV)142 GV->eraseFromParent();143 144 Type *ArrayEltTy = llvm::PointerType::getUnqual(M.getContext());145 for (auto *V : Values)146 Init.insert(ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, ArrayEltTy));147 148 if (Init.empty())149 return;150 151 ArrayType *ATy = ArrayType::get(ArrayEltTy, Init.size());152 GV = new llvm::GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,153 ConstantArray::get(ATy, Init.getArrayRef()),154 Name);155 GV->setSection("llvm.metadata");156}157 158void llvm::appendToUsed(Module &M, ArrayRef<GlobalValue *> Values) {159 appendToUsedList(M, "llvm.used", Values);160}161 162void llvm::appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values) {163 appendToUsedList(M, "llvm.compiler.used", Values);164}165 166static void removeFromUsedList(Module &M, StringRef Name,167 function_ref<bool(Constant *)> ShouldRemove) {168 GlobalVariable *GV = M.getNamedGlobal(Name);169 if (!GV)170 return;171 172 SmallSetVector<Constant *, 16> Init;173 collectUsedGlobals(GV, Init);174 175 Type *ArrayEltTy = cast<ArrayType>(GV->getValueType())->getElementType();176 177 SmallVector<Constant *, 16> NewInit;178 for (Constant *MaybeRemoved : Init) {179 if (!ShouldRemove(MaybeRemoved->stripPointerCasts()))180 NewInit.push_back(MaybeRemoved);181 }182 183 if (!NewInit.empty()) {184 ArrayType *ATy = ArrayType::get(ArrayEltTy, NewInit.size());185 GlobalVariable *NewGV =186 new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,187 ConstantArray::get(ATy, NewInit), "", GV,188 GV->getThreadLocalMode(), GV->getAddressSpace());189 NewGV->setSection(GV->getSection());190 NewGV->takeName(GV);191 }192 193 GV->eraseFromParent();194}195 196void llvm::removeFromUsedLists(Module &M,197 function_ref<bool(Constant *)> ShouldRemove) {198 removeFromUsedList(M, "llvm.used", ShouldRemove);199 removeFromUsedList(M, "llvm.compiler.used", ShouldRemove);200}201 202void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {203 if (!M.getModuleFlag("kcfi"))204 return;205 // Matches CodeGenModule::CreateKCFITypeId in Clang.206 LLVMContext &Ctx = M.getContext();207 MDBuilder MDB(Ctx);208 std::string Type = MangledType.str();209 if (M.getModuleFlag("cfi-normalize-integers"))210 Type += ".normalized";211 F.setMetadata(LLVMContext::MD_kcfi_type,212 MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(213 Type::getInt32Ty(Ctx),214 static_cast<uint32_t>(xxHash64(Type))))));215 // If the module was compiled with -fpatchable-function-entry, ensure216 // we use the same patchable-function-prefix.217 if (auto *MD = mdconst::extract_or_null<ConstantInt>(218 M.getModuleFlag("kcfi-offset"))) {219 if (unsigned Offset = MD->getZExtValue())220 F.addFnAttr("patchable-function-prefix", std::to_string(Offset));221 }222}223 224FunctionCallee llvm::declareSanitizerInitFunction(Module &M, StringRef InitName,225 ArrayRef<Type *> InitArgTypes,226 bool Weak) {227 assert(!InitName.empty() && "Expected init function name");228 auto *VoidTy = Type::getVoidTy(M.getContext());229 auto *FnTy = FunctionType::get(VoidTy, InitArgTypes, false);230 auto FnCallee = M.getOrInsertFunction(InitName, FnTy);231 auto *Fn = cast<Function>(FnCallee.getCallee());232 if (Weak && Fn->isDeclaration())233 Fn->setLinkage(Function::ExternalWeakLinkage);234 return FnCallee;235}236 237Function *llvm::createSanitizerCtor(Module &M, StringRef CtorName) {238 Function *Ctor = Function::createWithDefaultAttr(239 FunctionType::get(Type::getVoidTy(M.getContext()), false),240 GlobalValue::InternalLinkage, M.getDataLayout().getProgramAddressSpace(),241 CtorName, &M);242 Ctor->addFnAttr(Attribute::NoUnwind);243 setKCFIType(M, *Ctor, "_ZTSFvvE"); // void (*)(void)244 BasicBlock *CtorBB = BasicBlock::Create(M.getContext(), "", Ctor);245 ReturnInst::Create(M.getContext(), CtorBB);246 // Ensure Ctor cannot be discarded, even if in a comdat.247 appendToUsed(M, {Ctor});248 return Ctor;249}250 251std::pair<Function *, FunctionCallee> llvm::createSanitizerCtorAndInitFunctions(252 Module &M, StringRef CtorName, StringRef InitName,253 ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs,254 StringRef VersionCheckName, bool Weak) {255 assert(!InitName.empty() && "Expected init function name");256 assert(InitArgs.size() == InitArgTypes.size() &&257 "Sanitizer's init function expects different number of arguments");258 FunctionCallee InitFunction =259 declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak);260 Function *Ctor = createSanitizerCtor(M, CtorName);261 IRBuilder<> IRB(M.getContext());262 263 BasicBlock *RetBB = &Ctor->getEntryBlock();264 if (Weak) {265 RetBB->setName("ret");266 auto *EntryBB = BasicBlock::Create(M.getContext(), "entry", Ctor, RetBB);267 auto *CallInitBB =268 BasicBlock::Create(M.getContext(), "callfunc", Ctor, RetBB);269 auto *InitFn = cast<Function>(InitFunction.getCallee());270 auto *InitFnPtr =271 PointerType::get(M.getContext(), InitFn->getAddressSpace());272 IRB.SetInsertPoint(EntryBB);273 Value *InitNotNull =274 IRB.CreateICmpNE(InitFn, ConstantPointerNull::get(InitFnPtr));275 IRB.CreateCondBr(InitNotNull, CallInitBB, RetBB);276 IRB.SetInsertPoint(CallInitBB);277 } else {278 IRB.SetInsertPoint(RetBB->getTerminator());279 }280 281 IRB.CreateCall(InitFunction, InitArgs);282 if (!VersionCheckName.empty()) {283 FunctionCallee VersionCheckFunction = M.getOrInsertFunction(284 VersionCheckName, FunctionType::get(IRB.getVoidTy(), {}, false),285 AttributeList());286 IRB.CreateCall(VersionCheckFunction, {});287 }288 289 if (Weak)290 IRB.CreateBr(RetBB);291 292 return std::make_pair(Ctor, InitFunction);293}294 295std::pair<Function *, FunctionCallee>296llvm::getOrCreateSanitizerCtorAndInitFunctions(297 Module &M, StringRef CtorName, StringRef InitName,298 ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs,299 function_ref<void(Function *, FunctionCallee)> FunctionsCreatedCallback,300 StringRef VersionCheckName, bool Weak) {301 assert(!CtorName.empty() && "Expected ctor function name");302 303 if (Function *Ctor = M.getFunction(CtorName))304 // FIXME: Sink this logic into the module, similar to the handling of305 // globals. This will make moving to a concurrent model much easier.306 if (Ctor->arg_empty() ||307 Ctor->getReturnType() == Type::getVoidTy(M.getContext()))308 return {Ctor,309 declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak)};310 311 Function *Ctor;312 FunctionCallee InitFunction;313 std::tie(Ctor, InitFunction) = llvm::createSanitizerCtorAndInitFunctions(314 M, CtorName, InitName, InitArgTypes, InitArgs, VersionCheckName, Weak);315 FunctionsCreatedCallback(Ctor, InitFunction);316 return std::make_pair(Ctor, InitFunction);317}318 319void llvm::filterDeadComdatFunctions(320 SmallVectorImpl<Function *> &DeadComdatFunctions) {321 SmallPtrSet<Function *, 32> MaybeDeadFunctions;322 SmallPtrSet<Comdat *, 32> MaybeDeadComdats;323 for (Function *F : DeadComdatFunctions) {324 MaybeDeadFunctions.insert(F);325 if (Comdat *C = F->getComdat())326 MaybeDeadComdats.insert(C);327 }328 329 // Find comdats for which all users are dead now.330 SmallPtrSet<Comdat *, 32> DeadComdats;331 for (Comdat *C : MaybeDeadComdats) {332 auto IsUserDead = [&](GlobalObject *GO) {333 auto *F = dyn_cast<Function>(GO);334 return F && MaybeDeadFunctions.contains(F);335 };336 if (all_of(C->getUsers(), IsUserDead))337 DeadComdats.insert(C);338 }339 340 // Only keep functions which have no comdat or a dead comdat.341 erase_if(DeadComdatFunctions, [&](Function *F) {342 Comdat *C = F->getComdat();343 return C && !DeadComdats.contains(C);344 });345}346 347std::string llvm::getUniqueModuleId(Module *M) {348 MD5 Md5;349 350 auto *UniqueSourceFileIdentifier = dyn_cast_or_null<MDNode>(351 M->getModuleFlag("Unique Source File Identifier"));352 if (UniqueSourceFileIdentifier) {353 Md5.update(354 cast<MDString>(UniqueSourceFileIdentifier->getOperand(0))->getString());355 } else {356 bool ExportsSymbols = false;357 for (auto &GV : M->global_values()) {358 if (GV.isDeclaration() || GV.getName().starts_with("llvm.") ||359 !GV.hasExternalLinkage() || GV.hasComdat())360 continue;361 ExportsSymbols = true;362 Md5.update(GV.getName());363 Md5.update(ArrayRef<uint8_t>{0});364 }365 366 if (!ExportsSymbols)367 return "";368 }369 370 MD5::MD5Result R;371 Md5.final(R);372 373 SmallString<32> Str;374 MD5::stringifyResult(R, Str);375 return ("." + Str).str();376}377 378void llvm::embedBufferInModule(Module &M, MemoryBufferRef Buf,379 StringRef SectionName, Align Alignment) {380 // Embed the memory buffer into the module.381 Constant *ModuleConstant = ConstantDataArray::get(382 M.getContext(), ArrayRef(Buf.getBufferStart(), Buf.getBufferSize()));383 GlobalVariable *GV = new GlobalVariable(384 M, ModuleConstant->getType(), true, GlobalValue::PrivateLinkage,385 ModuleConstant, "llvm.embedded.object");386 GV->setSection(SectionName);387 GV->setAlignment(Alignment);388 389 LLVMContext &Ctx = M.getContext();390 NamedMDNode *MD = M.getOrInsertNamedMetadata("llvm.embedded.objects");391 Metadata *MDVals[] = {ConstantAsMetadata::get(GV),392 MDString::get(Ctx, SectionName)};393 394 MD->addOperand(llvm::MDNode::get(Ctx, MDVals));395 GV->setMetadata(LLVMContext::MD_exclude, llvm::MDNode::get(Ctx, {}));396 397 appendToCompilerUsed(M, GV);398}399 400bool llvm::lowerGlobalIFuncUsersAsGlobalCtor(401 Module &M, ArrayRef<GlobalIFunc *> FilteredIFuncsToLower) {402 SmallVector<GlobalIFunc *, 32> AllIFuncs;403 ArrayRef<GlobalIFunc *> IFuncsToLower = FilteredIFuncsToLower;404 if (FilteredIFuncsToLower.empty()) { // Default to lowering all ifuncs405 for (GlobalIFunc &GI : M.ifuncs())406 AllIFuncs.push_back(&GI);407 IFuncsToLower = AllIFuncs;408 }409 410 bool UnhandledUsers = false;411 LLVMContext &Ctx = M.getContext();412 const DataLayout &DL = M.getDataLayout();413 414 PointerType *TableEntryTy =415 PointerType::get(Ctx, DL.getProgramAddressSpace());416 417 ArrayType *FuncPtrTableTy =418 ArrayType::get(TableEntryTy, IFuncsToLower.size());419 420 Align PtrAlign = DL.getABITypeAlign(TableEntryTy);421 422 // Create a global table of function pointers we'll initialize in a global423 // constructor.424 auto *FuncPtrTable = new GlobalVariable(425 M, FuncPtrTableTy, false, GlobalValue::InternalLinkage,426 PoisonValue::get(FuncPtrTableTy), "", nullptr,427 GlobalVariable::NotThreadLocal, DL.getDefaultGlobalsAddressSpace());428 FuncPtrTable->setAlignment(PtrAlign);429 430 // Create a function to initialize the function pointer table.431 Function *NewCtor = Function::Create(432 FunctionType::get(Type::getVoidTy(Ctx), false), Function::InternalLinkage,433 DL.getProgramAddressSpace(), "", &M);434 435 BasicBlock *BB = BasicBlock::Create(Ctx, "", NewCtor);436 IRBuilder<> InitBuilder(BB);437 438 size_t TableIndex = 0;439 for (GlobalIFunc *GI : IFuncsToLower) {440 Function *ResolvedFunction = GI->getResolverFunction();441 442 // We don't know what to pass to a resolver function taking arguments443 //444 // FIXME: Is this even valid? clang and gcc don't complain but this445 // probably should be invalid IR. We could just pass through undef.446 if (!std::empty(ResolvedFunction->getFunctionType()->params())) {447 LLVM_DEBUG(dbgs() << "Not lowering ifunc resolver function "448 << ResolvedFunction->getName() << " with parameters\n");449 UnhandledUsers = true;450 continue;451 }452 453 // Initialize the function pointer table.454 CallInst *ResolvedFunc = InitBuilder.CreateCall(ResolvedFunction);455 Value *Casted = InitBuilder.CreatePointerCast(ResolvedFunc, TableEntryTy);456 Constant *GEP = cast<Constant>(InitBuilder.CreateConstInBoundsGEP2_32(457 FuncPtrTableTy, FuncPtrTable, 0, TableIndex++));458 InitBuilder.CreateAlignedStore(Casted, GEP, PtrAlign);459 460 // Update all users to load a pointer from the global table.461 for (User *User : make_early_inc_range(GI->users())) {462 Instruction *UserInst = dyn_cast<Instruction>(User);463 if (!UserInst) {464 // TODO: Should handle constantexpr casts in user instructions. Probably465 // can't do much about constant initializers.466 UnhandledUsers = true;467 continue;468 }469 470 IRBuilder<> UseBuilder(UserInst);471 LoadInst *ResolvedTarget =472 UseBuilder.CreateAlignedLoad(TableEntryTy, GEP, PtrAlign);473 Value *ResolvedCast =474 UseBuilder.CreatePointerCast(ResolvedTarget, GI->getType());475 UserInst->replaceUsesOfWith(GI, ResolvedCast);476 }477 478 // If we handled all users, erase the ifunc.479 if (GI->use_empty())480 GI->eraseFromParent();481 }482 483 InitBuilder.CreateRetVoid();484 485 PointerType *ConstantDataTy = PointerType::get(Ctx, 0);486 487 // TODO: Is this the right priority? Probably should be before any other488 // constructors?489 const int Priority = 10;490 appendToGlobalCtors(M, NewCtor, Priority,491 ConstantPointerNull::get(ConstantDataTy));492 return UnhandledUsers;493}494