brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.7 KiB · 596849e Raw
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