Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
35266 views
//===---- ExecutionUtils.cpp - Utilities for executing functions in Orc ---===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"9#include "llvm/ExecutionEngine/JITLink/x86_64.h"10#include "llvm/ExecutionEngine/Orc/Layer.h"11#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"12#include "llvm/IR/Constants.h"13#include "llvm/IR/Function.h"14#include "llvm/IR/GlobalVariable.h"15#include "llvm/IR/Module.h"16#include "llvm/MC/TargetRegistry.h"17#include "llvm/Object/MachOUniversal.h"18#include "llvm/Support/FormatVariadic.h"19#include "llvm/Support/StringSaver.h"20#include "llvm/Target/TargetMachine.h"21#include <string>2223namespace llvm {24namespace orc {2526CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End)27: InitList(28GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr),29I((InitList && End) ? InitList->getNumOperands() : 0) {30}3132bool CtorDtorIterator::operator==(const CtorDtorIterator &Other) const {33assert(InitList == Other.InitList && "Incomparable iterators.");34return I == Other.I;35}3637bool CtorDtorIterator::operator!=(const CtorDtorIterator &Other) const {38return !(*this == Other);39}4041CtorDtorIterator& CtorDtorIterator::operator++() {42++I;43return *this;44}4546CtorDtorIterator CtorDtorIterator::operator++(int) {47CtorDtorIterator Temp = *this;48++I;49return Temp;50}5152CtorDtorIterator::Element CtorDtorIterator::operator*() const {53ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I));54assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors");5556Constant *FuncC = CS->getOperand(1);57Function *Func = nullptr;5859// Extract function pointer, pulling off any casts.60while (FuncC) {61if (Function *F = dyn_cast_or_null<Function>(FuncC)) {62Func = F;63break;64} else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) {65if (CE->isCast())66FuncC = CE->getOperand(0);67else68break;69} else {70// This isn't anything we recognize. Bail out with Func left set to null.71break;72}73}7475auto *Priority = cast<ConstantInt>(CS->getOperand(0));76Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr;77if (Data && !isa<GlobalValue>(Data))78Data = nullptr;79return Element(Priority->getZExtValue(), Func, Data);80}8182iterator_range<CtorDtorIterator> getConstructors(const Module &M) {83const GlobalVariable *CtorsList = M.getNamedGlobal("llvm.global_ctors");84return make_range(CtorDtorIterator(CtorsList, false),85CtorDtorIterator(CtorsList, true));86}8788iterator_range<CtorDtorIterator> getDestructors(const Module &M) {89const GlobalVariable *DtorsList = M.getNamedGlobal("llvm.global_dtors");90return make_range(CtorDtorIterator(DtorsList, false),91CtorDtorIterator(DtorsList, true));92}9394bool StaticInitGVIterator::isStaticInitGlobal(GlobalValue &GV) {95if (GV.isDeclaration())96return false;9798if (GV.hasName() && (GV.getName() == "llvm.global_ctors" ||99GV.getName() == "llvm.global_dtors"))100return true;101102if (ObjFmt == Triple::MachO) {103// FIXME: These section checks are too strict: We should match first and104// second word split by comma.105if (GV.hasSection() &&106(GV.getSection().starts_with("__DATA,__objc_classlist") ||107GV.getSection().starts_with("__DATA,__objc_selrefs")))108return true;109}110111return false;112}113114void CtorDtorRunner::add(iterator_range<CtorDtorIterator> CtorDtors) {115if (CtorDtors.empty())116return;117118MangleAndInterner Mangle(119JD.getExecutionSession(),120(*CtorDtors.begin()).Func->getDataLayout());121122for (auto CtorDtor : CtorDtors) {123assert(CtorDtor.Func && CtorDtor.Func->hasName() &&124"Ctor/Dtor function must be named to be runnable under the JIT");125126// FIXME: Maybe use a symbol promoter here instead.127if (CtorDtor.Func->hasLocalLinkage()) {128CtorDtor.Func->setLinkage(GlobalValue::ExternalLinkage);129CtorDtor.Func->setVisibility(GlobalValue::HiddenVisibility);130}131132if (CtorDtor.Data && cast<GlobalValue>(CtorDtor.Data)->isDeclaration()) {133dbgs() << " Skipping because why now?\n";134continue;135}136137CtorDtorsByPriority[CtorDtor.Priority].push_back(138Mangle(CtorDtor.Func->getName()));139}140}141142Error CtorDtorRunner::run() {143using CtorDtorTy = void (*)();144145SymbolLookupSet LookupSet;146for (auto &KV : CtorDtorsByPriority)147for (auto &Name : KV.second)148LookupSet.add(Name);149assert(!LookupSet.containsDuplicates() &&150"Ctor/Dtor list contains duplicates");151152auto &ES = JD.getExecutionSession();153if (auto CtorDtorMap = ES.lookup(154makeJITDylibSearchOrder(&JD, JITDylibLookupFlags::MatchAllSymbols),155std::move(LookupSet))) {156for (auto &KV : CtorDtorsByPriority) {157for (auto &Name : KV.second) {158assert(CtorDtorMap->count(Name) && "No entry for Name");159auto CtorDtor = (*CtorDtorMap)[Name].getAddress().toPtr<CtorDtorTy>();160CtorDtor();161}162}163CtorDtorsByPriority.clear();164return Error::success();165} else166return CtorDtorMap.takeError();167}168169void LocalCXXRuntimeOverridesBase::runDestructors() {170auto& CXXDestructorDataPairs = DSOHandleOverride;171for (auto &P : CXXDestructorDataPairs)172P.first(P.second);173CXXDestructorDataPairs.clear();174}175176int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor,177void *Arg,178void *DSOHandle) {179auto& CXXDestructorDataPairs =180*reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle);181CXXDestructorDataPairs.push_back(std::make_pair(Destructor, Arg));182return 0;183}184185Error LocalCXXRuntimeOverrides::enable(JITDylib &JD,186MangleAndInterner &Mangle) {187SymbolMap RuntimeInterposes;188RuntimeInterposes[Mangle("__dso_handle")] = {189ExecutorAddr::fromPtr(&DSOHandleOverride), JITSymbolFlags::Exported};190RuntimeInterposes[Mangle("__cxa_atexit")] = {191ExecutorAddr::fromPtr(&CXAAtExitOverride), JITSymbolFlags::Exported};192193return JD.define(absoluteSymbols(std::move(RuntimeInterposes)));194}195196void ItaniumCXAAtExitSupport::registerAtExit(void (*F)(void *), void *Ctx,197void *DSOHandle) {198std::lock_guard<std::mutex> Lock(AtExitsMutex);199AtExitRecords[DSOHandle].push_back({F, Ctx});200}201202void ItaniumCXAAtExitSupport::runAtExits(void *DSOHandle) {203std::vector<AtExitRecord> AtExitsToRun;204205{206std::lock_guard<std::mutex> Lock(AtExitsMutex);207auto I = AtExitRecords.find(DSOHandle);208if (I != AtExitRecords.end()) {209AtExitsToRun = std::move(I->second);210AtExitRecords.erase(I);211}212}213214while (!AtExitsToRun.empty()) {215AtExitsToRun.back().F(AtExitsToRun.back().Ctx);216AtExitsToRun.pop_back();217}218}219220DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator(221sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow,222AddAbsoluteSymbolsFn AddAbsoluteSymbols)223: Dylib(std::move(Dylib)), Allow(std::move(Allow)),224AddAbsoluteSymbols(std::move(AddAbsoluteSymbols)),225GlobalPrefix(GlobalPrefix) {}226227Expected<std::unique_ptr<DynamicLibrarySearchGenerator>>228DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix,229SymbolPredicate Allow,230AddAbsoluteSymbolsFn AddAbsoluteSymbols) {231std::string ErrMsg;232auto Lib = sys::DynamicLibrary::getPermanentLibrary(FileName, &ErrMsg);233if (!Lib.isValid())234return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());235return std::make_unique<DynamicLibrarySearchGenerator>(236std::move(Lib), GlobalPrefix, std::move(Allow),237std::move(AddAbsoluteSymbols));238}239240Error DynamicLibrarySearchGenerator::tryToGenerate(241LookupState &LS, LookupKind K, JITDylib &JD,242JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {243orc::SymbolMap NewSymbols;244245bool HasGlobalPrefix = (GlobalPrefix != '\0');246247for (auto &KV : Symbols) {248auto &Name = KV.first;249250if ((*Name).empty())251continue;252253if (Allow && !Allow(Name))254continue;255256if (HasGlobalPrefix && (*Name).front() != GlobalPrefix)257continue;258259std::string Tmp((*Name).data() + HasGlobalPrefix,260(*Name).size() - HasGlobalPrefix);261if (void *P = Dylib.getAddressOfSymbol(Tmp.c_str()))262NewSymbols[Name] = {ExecutorAddr::fromPtr(P), JITSymbolFlags::Exported};263}264265if (NewSymbols.empty())266return Error::success();267268if (AddAbsoluteSymbols)269return AddAbsoluteSymbols(JD, std::move(NewSymbols));270return JD.define(absoluteSymbols(std::move(NewSymbols)));271}272273Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>>274StaticLibraryDefinitionGenerator::Load(275ObjectLayer &L, const char *FileName,276GetObjectFileInterface GetObjFileInterface) {277278auto B = object::createBinary(FileName);279if (!B)280return createFileError(FileName, B.takeError());281282// If this is a regular archive then create an instance from it.283if (isa<object::Archive>(B->getBinary())) {284auto [Archive, ArchiveBuffer] = B->takeBinary();285return Create(L, std::move(ArchiveBuffer),286std::unique_ptr<object::Archive>(287static_cast<object::Archive *>(Archive.release())),288std::move(GetObjFileInterface));289}290291// If this is a universal binary then search for a slice matching the given292// Triple.293if (auto *UB = dyn_cast<object::MachOUniversalBinary>(B->getBinary())) {294295const auto &TT = L.getExecutionSession().getTargetTriple();296297auto SliceRange = getSliceRangeForArch(*UB, TT);298if (!SliceRange)299return SliceRange.takeError();300301auto SliceBuffer = MemoryBuffer::getFileSlice(FileName, SliceRange->second,302SliceRange->first);303if (!SliceBuffer)304return make_error<StringError>(305Twine("Could not create buffer for ") + TT.str() + " slice of " +306FileName + ": [ " + formatv("{0:x}", SliceRange->first) + " .. " +307formatv("{0:x}", SliceRange->first + SliceRange->second) + ": " +308SliceBuffer.getError().message(),309SliceBuffer.getError());310311return Create(L, std::move(*SliceBuffer), std::move(GetObjFileInterface));312}313314return make_error<StringError>(Twine("Unrecognized file type for ") +315FileName,316inconvertibleErrorCode());317}318319Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>>320StaticLibraryDefinitionGenerator::Create(321ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer,322std::unique_ptr<object::Archive> Archive,323GetObjectFileInterface GetObjFileInterface) {324325Error Err = Error::success();326327std::unique_ptr<StaticLibraryDefinitionGenerator> ADG(328new StaticLibraryDefinitionGenerator(329L, std::move(ArchiveBuffer), std::move(Archive),330std::move(GetObjFileInterface), Err));331332if (Err)333return std::move(Err);334335return std::move(ADG);336}337338Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>>339StaticLibraryDefinitionGenerator::Create(340ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer,341GetObjectFileInterface GetObjFileInterface) {342343auto B = object::createBinary(ArchiveBuffer->getMemBufferRef());344if (!B)345return B.takeError();346347// If this is a regular archive then create an instance from it.348if (isa<object::Archive>(*B))349return Create(L, std::move(ArchiveBuffer),350std::unique_ptr<object::Archive>(351static_cast<object::Archive *>(B->release())),352std::move(GetObjFileInterface));353354// If this is a universal binary then search for a slice matching the given355// Triple.356if (auto *UB = dyn_cast<object::MachOUniversalBinary>(B->get())) {357358const auto &TT = L.getExecutionSession().getTargetTriple();359360auto SliceRange = getSliceRangeForArch(*UB, TT);361if (!SliceRange)362return SliceRange.takeError();363364MemoryBufferRef SliceRef(365StringRef(ArchiveBuffer->getBufferStart() + SliceRange->first,366SliceRange->second),367ArchiveBuffer->getBufferIdentifier());368369auto Archive = object::Archive::create(SliceRef);370if (!Archive)371return Archive.takeError();372373return Create(L, std::move(ArchiveBuffer), std::move(*Archive),374std::move(GetObjFileInterface));375}376377return make_error<StringError>(Twine("Unrecognized file type for ") +378ArchiveBuffer->getBufferIdentifier(),379inconvertibleErrorCode());380}381382Error StaticLibraryDefinitionGenerator::tryToGenerate(383LookupState &LS, LookupKind K, JITDylib &JD,384JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {385// Don't materialize symbols from static archives unless this is a static386// lookup.387if (K != LookupKind::Static)388return Error::success();389390// Bail out early if we've already freed the archive.391if (!Archive)392return Error::success();393394DenseSet<std::pair<StringRef, StringRef>> ChildBufferInfos;395396for (const auto &KV : Symbols) {397const auto &Name = KV.first;398if (!ObjectFilesMap.count(Name))399continue;400auto ChildBuffer = ObjectFilesMap[Name];401ChildBufferInfos.insert(402{ChildBuffer.getBuffer(), ChildBuffer.getBufferIdentifier()});403}404405for (auto ChildBufferInfo : ChildBufferInfos) {406MemoryBufferRef ChildBufferRef(ChildBufferInfo.first,407ChildBufferInfo.second);408409auto I = GetObjFileInterface(L.getExecutionSession(), ChildBufferRef);410if (!I)411return I.takeError();412413if (auto Err = L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef, false),414std::move(*I)))415return Err;416}417418return Error::success();419}420421Error StaticLibraryDefinitionGenerator::buildObjectFilesMap() {422DenseMap<uint64_t, MemoryBufferRef> MemoryBuffers;423DenseSet<uint64_t> Visited;424DenseSet<uint64_t> Excluded;425StringSaver FileNames(ObjFileNameStorage);426for (auto &S : Archive->symbols()) {427StringRef SymName = S.getName();428auto Member = S.getMember();429if (!Member)430return Member.takeError();431auto DataOffset = Member->getDataOffset();432if (!Visited.count(DataOffset)) {433Visited.insert(DataOffset);434auto Child = Member->getAsBinary();435if (!Child)436return Child.takeError();437if ((*Child)->isCOFFImportFile()) {438ImportedDynamicLibraries.insert((*Child)->getFileName().str());439Excluded.insert(DataOffset);440continue;441}442443// Give members of the archive a name that contains the archive path so444// that they can be differentiated from a member with the same name in a445// different archive. This also ensure initializer symbols names will be446// unique within a JITDylib.447StringRef FullName = FileNames.save(Archive->getFileName() + "(" +448(*Child)->getFileName() + ")");449MemoryBufferRef MemBuffer((*Child)->getMemoryBufferRef().getBuffer(),450FullName);451452MemoryBuffers[DataOffset] = MemBuffer;453}454if (!Excluded.count(DataOffset))455ObjectFilesMap[L.getExecutionSession().intern(SymName)] =456MemoryBuffers[DataOffset];457}458459return Error::success();460}461462Expected<std::pair<size_t, size_t>>463StaticLibraryDefinitionGenerator::getSliceRangeForArch(464object::MachOUniversalBinary &UB, const Triple &TT) {465466for (const auto &Obj : UB.objects()) {467auto ObjTT = Obj.getTriple();468if (ObjTT.getArch() == TT.getArch() &&469ObjTT.getSubArch() == TT.getSubArch() &&470(TT.getVendor() == Triple::UnknownVendor ||471ObjTT.getVendor() == TT.getVendor())) {472// We found a match. Return the range for the slice.473return std::make_pair(Obj.getOffset(), Obj.getSize());474}475}476477return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +478" does not contain a slice for " +479TT.str(),480inconvertibleErrorCode());481}482483StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator(484ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer,485std::unique_ptr<object::Archive> Archive,486GetObjectFileInterface GetObjFileInterface, Error &Err)487: L(L), GetObjFileInterface(std::move(GetObjFileInterface)),488ArchiveBuffer(std::move(ArchiveBuffer)), Archive(std::move(Archive)) {489ErrorAsOutParameter _(&Err);490if (!this->GetObjFileInterface)491this->GetObjFileInterface = getObjectFileInterface;492if (!Err)493Err = buildObjectFilesMap();494}495496std::unique_ptr<DLLImportDefinitionGenerator>497DLLImportDefinitionGenerator::Create(ExecutionSession &ES,498ObjectLinkingLayer &L) {499return std::unique_ptr<DLLImportDefinitionGenerator>(500new DLLImportDefinitionGenerator(ES, L));501}502503Error DLLImportDefinitionGenerator::tryToGenerate(504LookupState &LS, LookupKind K, JITDylib &JD,505JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {506JITDylibSearchOrder LinkOrder;507JD.withLinkOrderDo([&](const JITDylibSearchOrder &LO) {508LinkOrder.reserve(LO.size());509for (auto &KV : LO) {510if (KV.first == &JD)511continue;512LinkOrder.push_back(KV);513}514});515516// FIXME: if regular symbol name start with __imp_ we have to issue lookup of517// both __imp_ and stripped name and use the lookup information to resolve the518// real symbol name.519SymbolLookupSet LookupSet;520DenseMap<StringRef, SymbolLookupFlags> ToLookUpSymbols;521for (auto &KV : Symbols) {522StringRef Deinterned = *KV.first;523if (Deinterned.starts_with(getImpPrefix()))524Deinterned = Deinterned.drop_front(StringRef(getImpPrefix()).size());525// Don't degrade the required state526if (ToLookUpSymbols.count(Deinterned) &&527ToLookUpSymbols[Deinterned] == SymbolLookupFlags::RequiredSymbol)528continue;529ToLookUpSymbols[Deinterned] = KV.second;530}531532for (auto &KV : ToLookUpSymbols)533LookupSet.add(ES.intern(KV.first), KV.second);534535auto Resolved =536ES.lookup(LinkOrder, LookupSet, LookupKind::DLSym, SymbolState::Resolved);537if (!Resolved)538return Resolved.takeError();539540auto G = createStubsGraph(*Resolved);541if (!G)542return G.takeError();543return L.add(JD, std::move(*G));544}545546Expected<unsigned>547DLLImportDefinitionGenerator::getTargetPointerSize(const Triple &TT) {548switch (TT.getArch()) {549case Triple::x86_64:550return 8;551default:552return make_error<StringError>(553"architecture unsupported by DLLImportDefinitionGenerator",554inconvertibleErrorCode());555}556}557558Expected<llvm::endianness>559DLLImportDefinitionGenerator::getEndianness(const Triple &TT) {560switch (TT.getArch()) {561case Triple::x86_64:562return llvm::endianness::little;563default:564return make_error<StringError>(565"architecture unsupported by DLLImportDefinitionGenerator",566inconvertibleErrorCode());567}568}569570Expected<std::unique_ptr<jitlink::LinkGraph>>571DLLImportDefinitionGenerator::createStubsGraph(const SymbolMap &Resolved) {572Triple TT = ES.getTargetTriple();573auto PointerSize = getTargetPointerSize(TT);574if (!PointerSize)575return PointerSize.takeError();576auto Endianness = getEndianness(TT);577if (!Endianness)578return Endianness.takeError();579580auto G = std::make_unique<jitlink::LinkGraph>(581"<DLLIMPORT_STUBS>", TT, *PointerSize, *Endianness,582jitlink::getGenericEdgeKindName);583jitlink::Section &Sec =584G->createSection(getSectionName(), MemProt::Read | MemProt::Exec);585586for (auto &KV : Resolved) {587jitlink::Symbol &Target = G->addAbsoluteSymbol(588*KV.first, KV.second.getAddress(), *PointerSize,589jitlink::Linkage::Strong, jitlink::Scope::Local, false);590591// Create __imp_ symbol592jitlink::Symbol &Ptr =593jitlink::x86_64::createAnonymousPointer(*G, Sec, &Target);594auto NameCopy = G->allocateContent(Twine(getImpPrefix()) + *KV.first);595StringRef NameCopyRef = StringRef(NameCopy.data(), NameCopy.size());596Ptr.setName(NameCopyRef);597Ptr.setLinkage(jitlink::Linkage::Strong);598Ptr.setScope(jitlink::Scope::Default);599600// Create PLT stub601// FIXME: check PLT stub of data symbol is not accessed602jitlink::Block &StubBlock =603jitlink::x86_64::createPointerJumpStubBlock(*G, Sec, Ptr);604G->addDefinedSymbol(StubBlock, 0, *KV.first, StubBlock.getSize(),605jitlink::Linkage::Strong, jitlink::Scope::Default, true,606false);607}608609return std::move(G);610}611612} // End namespace orc.613} // End namespace llvm.614615616