| File: | build/source/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp |
| Warning: | line 120, column 7 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | //===---- ExecutionUtils.cpp - Utilities for executing functions in Orc ---===// | ||||
| 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-exception | ||||
| 6 | // | ||||
| 7 | //===----------------------------------------------------------------------===// | ||||
| 8 | |||||
| 9 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" | ||||
| 10 | #include "llvm/ExecutionEngine/JITLink/x86_64.h" | ||||
| 11 | #include "llvm/ExecutionEngine/Orc/Layer.h" | ||||
| 12 | #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" | ||||
| 13 | #include "llvm/IR/Constants.h" | ||||
| 14 | #include "llvm/IR/Function.h" | ||||
| 15 | #include "llvm/IR/GlobalVariable.h" | ||||
| 16 | #include "llvm/IR/Module.h" | ||||
| 17 | #include "llvm/MC/TargetRegistry.h" | ||||
| 18 | #include "llvm/Object/MachOUniversal.h" | ||||
| 19 | #include "llvm/Support/FormatVariadic.h" | ||||
| 20 | #include "llvm/Target/TargetMachine.h" | ||||
| 21 | #include <string> | ||||
| 22 | |||||
| 23 | namespace llvm { | ||||
| 24 | namespace orc { | ||||
| 25 | |||||
| 26 | CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End) | ||||
| 27 | : InitList( | ||||
| 28 | GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr), | ||||
| 29 | I((InitList && End) ? InitList->getNumOperands() : 0) { | ||||
| 30 | } | ||||
| 31 | |||||
| 32 | bool CtorDtorIterator::operator==(const CtorDtorIterator &Other) const { | ||||
| 33 | assert(InitList == Other.InitList && "Incomparable iterators.")(static_cast <bool> (InitList == Other.InitList && "Incomparable iterators.") ? void (0) : __assert_fail ("InitList == Other.InitList && \"Incomparable iterators.\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 33, __extension__ __PRETTY_FUNCTION__)); | ||||
| 34 | return I == Other.I; | ||||
| 35 | } | ||||
| 36 | |||||
| 37 | bool CtorDtorIterator::operator!=(const CtorDtorIterator &Other) const { | ||||
| 38 | return !(*this == Other); | ||||
| 39 | } | ||||
| 40 | |||||
| 41 | CtorDtorIterator& CtorDtorIterator::operator++() { | ||||
| 42 | ++I; | ||||
| 43 | return *this; | ||||
| 44 | } | ||||
| 45 | |||||
| 46 | CtorDtorIterator CtorDtorIterator::operator++(int) { | ||||
| 47 | CtorDtorIterator Temp = *this; | ||||
| 48 | ++I; | ||||
| 49 | return Temp; | ||||
| 50 | } | ||||
| 51 | |||||
| 52 | CtorDtorIterator::Element CtorDtorIterator::operator*() const { | ||||
| 53 | ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I)); | ||||
| 54 | assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors")(static_cast <bool> (CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors" ) ? void (0) : __assert_fail ("CS && \"Unrecognized type in llvm.global_ctors/llvm.global_dtors\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 54, __extension__ __PRETTY_FUNCTION__)); | ||||
| 55 | |||||
| 56 | Constant *FuncC = CS->getOperand(1); | ||||
| 57 | Function *Func = nullptr; | ||||
| 58 | |||||
| 59 | // Extract function pointer, pulling off any casts. | ||||
| 60 | while (FuncC) { | ||||
| 61 | if (Function *F = dyn_cast_or_null<Function>(FuncC)) { | ||||
| 62 | Func = F; | ||||
| 63 | break; | ||||
| 64 | } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) { | ||||
| 65 | if (CE->isCast()) | ||||
| 66 | FuncC = CE->getOperand(0); | ||||
| 67 | else | ||||
| 68 | break; | ||||
| 69 | } else { | ||||
| 70 | // This isn't anything we recognize. Bail out with Func left set to null. | ||||
| 71 | break; | ||||
| 72 | } | ||||
| 73 | } | ||||
| 74 | |||||
| 75 | auto *Priority = cast<ConstantInt>(CS->getOperand(0)); | ||||
| 76 | Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr; | ||||
| 77 | if (Data
| ||||
| 78 | Data = nullptr; | ||||
| 79 | return Element(Priority->getZExtValue(), Func, Data); | ||||
| 80 | } | ||||
| 81 | |||||
| 82 | iterator_range<CtorDtorIterator> getConstructors(const Module &M) { | ||||
| 83 | const GlobalVariable *CtorsList = M.getNamedGlobal("llvm.global_ctors"); | ||||
| 84 | return make_range(CtorDtorIterator(CtorsList, false), | ||||
| 85 | CtorDtorIterator(CtorsList, true)); | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | iterator_range<CtorDtorIterator> getDestructors(const Module &M) { | ||||
| 89 | const GlobalVariable *DtorsList = M.getNamedGlobal("llvm.global_dtors"); | ||||
| 90 | return make_range(CtorDtorIterator(DtorsList, false), | ||||
| 91 | CtorDtorIterator(DtorsList, true)); | ||||
| 92 | } | ||||
| 93 | |||||
| 94 | bool StaticInitGVIterator::isStaticInitGlobal(GlobalValue &GV) { | ||||
| 95 | if (GV.isDeclaration()) | ||||
| 96 | return false; | ||||
| 97 | |||||
| 98 | if (GV.hasName() && (GV.getName() == "llvm.global_ctors" || | ||||
| 99 | GV.getName() == "llvm.global_dtors")) | ||||
| 100 | return true; | ||||
| 101 | |||||
| 102 | if (ObjFmt == Triple::MachO) { | ||||
| 103 | // FIXME: These section checks are too strict: We should match first and | ||||
| 104 | // second word split by comma. | ||||
| 105 | if (GV.hasSection() && | ||||
| 106 | (GV.getSection().startswith("__DATA,__objc_classlist") || | ||||
| 107 | GV.getSection().startswith("__DATA,__objc_selrefs"))) | ||||
| 108 | return true; | ||||
| 109 | } | ||||
| 110 | |||||
| 111 | return false; | ||||
| 112 | } | ||||
| 113 | |||||
| 114 | void CtorDtorRunner::add(iterator_range<CtorDtorIterator> CtorDtors) { | ||||
| 115 | if (CtorDtors.empty()) | ||||
| |||||
| 116 | return; | ||||
| 117 | |||||
| 118 | MangleAndInterner Mangle( | ||||
| 119 | JD.getExecutionSession(), | ||||
| 120 | (*CtorDtors.begin()).Func->getParent()->getDataLayout()); | ||||
| |||||
| 121 | |||||
| 122 | for (auto CtorDtor : CtorDtors) { | ||||
| 123 | assert(CtorDtor.Func && CtorDtor.Func->hasName() &&(static_cast <bool> (CtorDtor.Func && CtorDtor. Func->hasName() && "Ctor/Dtor function must be named to be runnable under the JIT" ) ? void (0) : __assert_fail ("CtorDtor.Func && CtorDtor.Func->hasName() && \"Ctor/Dtor function must be named to be runnable under the JIT\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 124, __extension__ __PRETTY_FUNCTION__)) | ||||
| 124 | "Ctor/Dtor function must be named to be runnable under the JIT")(static_cast <bool> (CtorDtor.Func && CtorDtor. Func->hasName() && "Ctor/Dtor function must be named to be runnable under the JIT" ) ? void (0) : __assert_fail ("CtorDtor.Func && CtorDtor.Func->hasName() && \"Ctor/Dtor function must be named to be runnable under the JIT\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 124, __extension__ __PRETTY_FUNCTION__)); | ||||
| 125 | |||||
| 126 | // FIXME: Maybe use a symbol promoter here instead. | ||||
| 127 | if (CtorDtor.Func->hasLocalLinkage()) { | ||||
| 128 | CtorDtor.Func->setLinkage(GlobalValue::ExternalLinkage); | ||||
| 129 | CtorDtor.Func->setVisibility(GlobalValue::HiddenVisibility); | ||||
| 130 | } | ||||
| 131 | |||||
| 132 | if (CtorDtor.Data && cast<GlobalValue>(CtorDtor.Data)->isDeclaration()) { | ||||
| 133 | dbgs() << " Skipping because why now?\n"; | ||||
| 134 | continue; | ||||
| 135 | } | ||||
| 136 | |||||
| 137 | CtorDtorsByPriority[CtorDtor.Priority].push_back( | ||||
| 138 | Mangle(CtorDtor.Func->getName())); | ||||
| 139 | } | ||||
| 140 | } | ||||
| 141 | |||||
| 142 | Error CtorDtorRunner::run() { | ||||
| 143 | using CtorDtorTy = void (*)(); | ||||
| 144 | |||||
| 145 | SymbolLookupSet LookupSet; | ||||
| 146 | for (auto &KV : CtorDtorsByPriority) | ||||
| 147 | for (auto &Name : KV.second) | ||||
| 148 | LookupSet.add(Name); | ||||
| 149 | assert(!LookupSet.containsDuplicates() &&(static_cast <bool> (!LookupSet.containsDuplicates() && "Ctor/Dtor list contains duplicates") ? void (0) : __assert_fail ("!LookupSet.containsDuplicates() && \"Ctor/Dtor list contains duplicates\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 150, __extension__ __PRETTY_FUNCTION__)) | ||||
| 150 | "Ctor/Dtor list contains duplicates")(static_cast <bool> (!LookupSet.containsDuplicates() && "Ctor/Dtor list contains duplicates") ? void (0) : __assert_fail ("!LookupSet.containsDuplicates() && \"Ctor/Dtor list contains duplicates\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 150, __extension__ __PRETTY_FUNCTION__)); | ||||
| 151 | |||||
| 152 | auto &ES = JD.getExecutionSession(); | ||||
| 153 | if (auto CtorDtorMap = ES.lookup( | ||||
| 154 | makeJITDylibSearchOrder(&JD, JITDylibLookupFlags::MatchAllSymbols), | ||||
| 155 | std::move(LookupSet))) { | ||||
| 156 | for (auto &KV : CtorDtorsByPriority) { | ||||
| 157 | for (auto &Name : KV.second) { | ||||
| 158 | assert(CtorDtorMap->count(Name) && "No entry for Name")(static_cast <bool> (CtorDtorMap->count(Name) && "No entry for Name") ? void (0) : __assert_fail ("CtorDtorMap->count(Name) && \"No entry for Name\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 158, __extension__ __PRETTY_FUNCTION__)); | ||||
| 159 | auto CtorDtor = (*CtorDtorMap)[Name].getAddress().toPtr<CtorDtorTy>(); | ||||
| 160 | CtorDtor(); | ||||
| 161 | } | ||||
| 162 | } | ||||
| 163 | CtorDtorsByPriority.clear(); | ||||
| 164 | return Error::success(); | ||||
| 165 | } else | ||||
| 166 | return CtorDtorMap.takeError(); | ||||
| 167 | } | ||||
| 168 | |||||
| 169 | void LocalCXXRuntimeOverridesBase::runDestructors() { | ||||
| 170 | auto& CXXDestructorDataPairs = DSOHandleOverride; | ||||
| 171 | for (auto &P : CXXDestructorDataPairs) | ||||
| 172 | P.first(P.second); | ||||
| 173 | CXXDestructorDataPairs.clear(); | ||||
| 174 | } | ||||
| 175 | |||||
| 176 | int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor, | ||||
| 177 | void *Arg, | ||||
| 178 | void *DSOHandle) { | ||||
| 179 | auto& CXXDestructorDataPairs = | ||||
| 180 | *reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle); | ||||
| 181 | CXXDestructorDataPairs.push_back(std::make_pair(Destructor, Arg)); | ||||
| 182 | return 0; | ||||
| 183 | } | ||||
| 184 | |||||
| 185 | Error LocalCXXRuntimeOverrides::enable(JITDylib &JD, | ||||
| 186 | MangleAndInterner &Mangle) { | ||||
| 187 | SymbolMap RuntimeInterposes; | ||||
| 188 | RuntimeInterposes[Mangle("__dso_handle")] = { | ||||
| 189 | ExecutorAddr::fromPtr(&DSOHandleOverride), JITSymbolFlags::Exported}; | ||||
| 190 | RuntimeInterposes[Mangle("__cxa_atexit")] = { | ||||
| 191 | ExecutorAddr::fromPtr(&CXAAtExitOverride), JITSymbolFlags::Exported}; | ||||
| 192 | |||||
| 193 | return JD.define(absoluteSymbols(std::move(RuntimeInterposes))); | ||||
| 194 | } | ||||
| 195 | |||||
| 196 | void ItaniumCXAAtExitSupport::registerAtExit(void (*F)(void *), void *Ctx, | ||||
| 197 | void *DSOHandle) { | ||||
| 198 | std::lock_guard<std::mutex> Lock(AtExitsMutex); | ||||
| 199 | AtExitRecords[DSOHandle].push_back({F, Ctx}); | ||||
| 200 | } | ||||
| 201 | |||||
| 202 | void ItaniumCXAAtExitSupport::runAtExits(void *DSOHandle) { | ||||
| 203 | std::vector<AtExitRecord> AtExitsToRun; | ||||
| 204 | |||||
| 205 | { | ||||
| 206 | std::lock_guard<std::mutex> Lock(AtExitsMutex); | ||||
| 207 | auto I = AtExitRecords.find(DSOHandle); | ||||
| 208 | if (I != AtExitRecords.end()) { | ||||
| 209 | AtExitsToRun = std::move(I->second); | ||||
| 210 | AtExitRecords.erase(I); | ||||
| 211 | } | ||||
| 212 | } | ||||
| 213 | |||||
| 214 | while (!AtExitsToRun.empty()) { | ||||
| 215 | AtExitsToRun.back().F(AtExitsToRun.back().Ctx); | ||||
| 216 | AtExitsToRun.pop_back(); | ||||
| 217 | } | ||||
| 218 | } | ||||
| 219 | |||||
| 220 | DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator( | ||||
| 221 | sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow) | ||||
| 222 | : Dylib(std::move(Dylib)), Allow(std::move(Allow)), | ||||
| 223 | GlobalPrefix(GlobalPrefix) {} | ||||
| 224 | |||||
| 225 | Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> | ||||
| 226 | DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix, | ||||
| 227 | SymbolPredicate Allow) { | ||||
| 228 | std::string ErrMsg; | ||||
| 229 | auto Lib = sys::DynamicLibrary::getPermanentLibrary(FileName, &ErrMsg); | ||||
| 230 | if (!Lib.isValid()) | ||||
| 231 | return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); | ||||
| 232 | return std::make_unique<DynamicLibrarySearchGenerator>( | ||||
| 233 | std::move(Lib), GlobalPrefix, std::move(Allow)); | ||||
| 234 | } | ||||
| 235 | |||||
| 236 | Error DynamicLibrarySearchGenerator::tryToGenerate( | ||||
| 237 | LookupState &LS, LookupKind K, JITDylib &JD, | ||||
| 238 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { | ||||
| 239 | orc::SymbolMap NewSymbols; | ||||
| 240 | |||||
| 241 | bool HasGlobalPrefix = (GlobalPrefix != '\0'); | ||||
| 242 | |||||
| 243 | for (auto &KV : Symbols) { | ||||
| 244 | auto &Name = KV.first; | ||||
| 245 | |||||
| 246 | if ((*Name).empty()) | ||||
| 247 | continue; | ||||
| 248 | |||||
| 249 | if (Allow && !Allow(Name)) | ||||
| 250 | continue; | ||||
| 251 | |||||
| 252 | if (HasGlobalPrefix && (*Name).front() != GlobalPrefix) | ||||
| 253 | continue; | ||||
| 254 | |||||
| 255 | std::string Tmp((*Name).data() + HasGlobalPrefix, | ||||
| 256 | (*Name).size() - HasGlobalPrefix); | ||||
| 257 | if (void *P = Dylib.getAddressOfSymbol(Tmp.c_str())) | ||||
| 258 | NewSymbols[Name] = {ExecutorAddr::fromPtr(P), JITSymbolFlags::Exported}; | ||||
| 259 | } | ||||
| 260 | |||||
| 261 | if (NewSymbols.empty()) | ||||
| 262 | return Error::success(); | ||||
| 263 | |||||
| 264 | return JD.define(absoluteSymbols(std::move(NewSymbols))); | ||||
| 265 | } | ||||
| 266 | |||||
| 267 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> | ||||
| 268 | StaticLibraryDefinitionGenerator::Load( | ||||
| 269 | ObjectLayer &L, const char *FileName, | ||||
| 270 | GetObjectFileInterface GetObjFileInterface) { | ||||
| 271 | |||||
| 272 | auto B = object::createBinary(FileName); | ||||
| 273 | if (!B) | ||||
| 274 | return createFileError(FileName, B.takeError()); | ||||
| 275 | |||||
| 276 | // If this is a regular archive then create an instance from it. | ||||
| 277 | if (isa<object::Archive>(B->getBinary())) { | ||||
| 278 | auto [Archive, ArchiveBuffer] = B->takeBinary(); | ||||
| 279 | return Create(L, std::move(ArchiveBuffer), | ||||
| 280 | std::unique_ptr<object::Archive>( | ||||
| 281 | static_cast<object::Archive *>(Archive.release())), | ||||
| 282 | std::move(GetObjFileInterface)); | ||||
| 283 | } | ||||
| 284 | |||||
| 285 | // If this is a universal binary then search for a slice matching the given | ||||
| 286 | // Triple. | ||||
| 287 | if (auto *UB = cast<object::MachOUniversalBinary>(B->getBinary())) { | ||||
| 288 | |||||
| 289 | const auto &TT = L.getExecutionSession().getTargetTriple(); | ||||
| 290 | |||||
| 291 | auto SliceRange = getSliceRangeForArch(*UB, TT); | ||||
| 292 | if (!SliceRange) | ||||
| 293 | return SliceRange.takeError(); | ||||
| 294 | |||||
| 295 | auto SliceBuffer = MemoryBuffer::getFileSlice(FileName, SliceRange->second, | ||||
| 296 | SliceRange->first); | ||||
| 297 | if (!SliceBuffer) | ||||
| 298 | return make_error<StringError>( | ||||
| 299 | Twine("Could not create buffer for ") + TT.str() + " slice of " + | ||||
| 300 | FileName + ": [ " + formatv("{0:x}", SliceRange->first) + " .. " + | ||||
| 301 | formatv("{0:x}", SliceRange->first + SliceRange->second) + ": " + | ||||
| 302 | SliceBuffer.getError().message(), | ||||
| 303 | SliceBuffer.getError()); | ||||
| 304 | |||||
| 305 | return Create(L, std::move(*SliceBuffer), std::move(GetObjFileInterface)); | ||||
| 306 | } | ||||
| 307 | |||||
| 308 | return make_error<StringError>(Twine("Unrecognized file type for ") + | ||||
| 309 | FileName, | ||||
| 310 | inconvertibleErrorCode()); | ||||
| 311 | } | ||||
| 312 | |||||
| 313 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> | ||||
| 314 | StaticLibraryDefinitionGenerator::Create( | ||||
| 315 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, | ||||
| 316 | std::unique_ptr<object::Archive> Archive, | ||||
| 317 | GetObjectFileInterface GetObjFileInterface) { | ||||
| 318 | |||||
| 319 | Error Err = Error::success(); | ||||
| 320 | |||||
| 321 | std::unique_ptr<StaticLibraryDefinitionGenerator> ADG( | ||||
| 322 | new StaticLibraryDefinitionGenerator( | ||||
| 323 | L, std::move(ArchiveBuffer), std::move(Archive), | ||||
| 324 | std::move(GetObjFileInterface), Err)); | ||||
| 325 | |||||
| 326 | if (Err) | ||||
| 327 | return std::move(Err); | ||||
| 328 | |||||
| 329 | return std::move(ADG); | ||||
| 330 | } | ||||
| 331 | |||||
| 332 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> | ||||
| 333 | StaticLibraryDefinitionGenerator::Create( | ||||
| 334 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, | ||||
| 335 | GetObjectFileInterface GetObjFileInterface) { | ||||
| 336 | |||||
| 337 | auto B = object::createBinary(ArchiveBuffer->getMemBufferRef()); | ||||
| 338 | if (!B) | ||||
| 339 | return B.takeError(); | ||||
| 340 | |||||
| 341 | // If this is a regular archive then create an instance from it. | ||||
| 342 | if (isa<object::Archive>(*B)) | ||||
| 343 | return Create(L, std::move(ArchiveBuffer), | ||||
| 344 | std::unique_ptr<object::Archive>( | ||||
| 345 | static_cast<object::Archive *>(B->release())), | ||||
| 346 | std::move(GetObjFileInterface)); | ||||
| 347 | |||||
| 348 | // If this is a universal binary then search for a slice matching the given | ||||
| 349 | // Triple. | ||||
| 350 | if (auto *UB = cast<object::MachOUniversalBinary>(B->get())) { | ||||
| 351 | |||||
| 352 | const auto &TT = L.getExecutionSession().getTargetTriple(); | ||||
| 353 | |||||
| 354 | auto SliceRange = getSliceRangeForArch(*UB, TT); | ||||
| 355 | if (!SliceRange) | ||||
| 356 | return SliceRange.takeError(); | ||||
| 357 | |||||
| 358 | MemoryBufferRef SliceRef( | ||||
| 359 | StringRef(ArchiveBuffer->getBufferStart() + SliceRange->first, | ||||
| 360 | SliceRange->second), | ||||
| 361 | ArchiveBuffer->getBufferIdentifier()); | ||||
| 362 | |||||
| 363 | auto Archive = object::Archive::create(SliceRef); | ||||
| 364 | if (!Archive) | ||||
| 365 | return Archive.takeError(); | ||||
| 366 | |||||
| 367 | return Create(L, std::move(ArchiveBuffer), std::move(*Archive), | ||||
| 368 | std::move(GetObjFileInterface)); | ||||
| 369 | } | ||||
| 370 | |||||
| 371 | return make_error<StringError>(Twine("Unrecognized file type for ") + | ||||
| 372 | ArchiveBuffer->getBufferIdentifier(), | ||||
| 373 | inconvertibleErrorCode()); | ||||
| 374 | } | ||||
| 375 | |||||
| 376 | Error StaticLibraryDefinitionGenerator::tryToGenerate( | ||||
| 377 | LookupState &LS, LookupKind K, JITDylib &JD, | ||||
| 378 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { | ||||
| 379 | // Don't materialize symbols from static archives unless this is a static | ||||
| 380 | // lookup. | ||||
| 381 | if (K != LookupKind::Static) | ||||
| 382 | return Error::success(); | ||||
| 383 | |||||
| 384 | // Bail out early if we've already freed the archive. | ||||
| 385 | if (!Archive) | ||||
| 386 | return Error::success(); | ||||
| 387 | |||||
| 388 | DenseSet<std::pair<StringRef, StringRef>> ChildBufferInfos; | ||||
| 389 | |||||
| 390 | for (const auto &KV : Symbols) { | ||||
| 391 | const auto &Name = KV.first; | ||||
| 392 | if (!ObjectFilesMap.count(Name)) | ||||
| 393 | continue; | ||||
| 394 | auto ChildBuffer = ObjectFilesMap[Name]; | ||||
| 395 | ChildBufferInfos.insert( | ||||
| 396 | {ChildBuffer.getBuffer(), ChildBuffer.getBufferIdentifier()}); | ||||
| 397 | } | ||||
| 398 | |||||
| 399 | for (auto ChildBufferInfo : ChildBufferInfos) { | ||||
| 400 | MemoryBufferRef ChildBufferRef(ChildBufferInfo.first, | ||||
| 401 | ChildBufferInfo.second); | ||||
| 402 | |||||
| 403 | auto I = GetObjFileInterface(L.getExecutionSession(), ChildBufferRef); | ||||
| 404 | if (!I) | ||||
| 405 | return I.takeError(); | ||||
| 406 | |||||
| 407 | if (auto Err = L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef, false), | ||||
| 408 | std::move(*I))) | ||||
| 409 | return Err; | ||||
| 410 | } | ||||
| 411 | |||||
| 412 | return Error::success(); | ||||
| 413 | } | ||||
| 414 | |||||
| 415 | Error StaticLibraryDefinitionGenerator::buildObjectFilesMap() { | ||||
| 416 | DenseMap<uint64_t, MemoryBufferRef> MemoryBuffers; | ||||
| 417 | DenseSet<uint64_t> Visited; | ||||
| 418 | DenseSet<uint64_t> Excluded; | ||||
| 419 | for (auto &S : Archive->symbols()) { | ||||
| 420 | StringRef SymName = S.getName(); | ||||
| 421 | auto Member = S.getMember(); | ||||
| 422 | if (!Member) | ||||
| 423 | return Member.takeError(); | ||||
| 424 | auto DataOffset = Member->getDataOffset(); | ||||
| 425 | if (!Visited.count(DataOffset)) { | ||||
| 426 | Visited.insert(DataOffset); | ||||
| 427 | auto Child = Member->getAsBinary(); | ||||
| 428 | if (!Child) | ||||
| 429 | return Child.takeError(); | ||||
| 430 | if ((*Child)->isCOFFImportFile()) { | ||||
| 431 | ImportedDynamicLibraries.insert((*Child)->getFileName().str()); | ||||
| 432 | Excluded.insert(DataOffset); | ||||
| 433 | continue; | ||||
| 434 | } | ||||
| 435 | MemoryBuffers[DataOffset] = (*Child)->getMemoryBufferRef(); | ||||
| 436 | } | ||||
| 437 | if (!Excluded.count(DataOffset)) | ||||
| 438 | ObjectFilesMap[L.getExecutionSession().intern(SymName)] = | ||||
| 439 | MemoryBuffers[DataOffset]; | ||||
| 440 | } | ||||
| 441 | |||||
| 442 | return Error::success(); | ||||
| 443 | } | ||||
| 444 | |||||
| 445 | Expected<std::pair<size_t, size_t>> | ||||
| 446 | StaticLibraryDefinitionGenerator::getSliceRangeForArch( | ||||
| 447 | object::MachOUniversalBinary &UB, const Triple &TT) { | ||||
| 448 | |||||
| 449 | for (const auto &Obj : UB.objects()) { | ||||
| 450 | auto ObjTT = Obj.getTriple(); | ||||
| 451 | if (ObjTT.getArch() == TT.getArch() && | ||||
| 452 | ObjTT.getSubArch() == TT.getSubArch() && | ||||
| 453 | (TT.getVendor() == Triple::UnknownVendor || | ||||
| 454 | ObjTT.getVendor() == TT.getVendor())) { | ||||
| 455 | // We found a match. Return the range for the slice. | ||||
| 456 | return std::make_pair(Obj.getOffset(), Obj.getSize()); | ||||
| 457 | } | ||||
| 458 | } | ||||
| 459 | |||||
| 460 | return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() + | ||||
| 461 | " does not contain a slice for " + | ||||
| 462 | TT.str(), | ||||
| 463 | inconvertibleErrorCode()); | ||||
| 464 | } | ||||
| 465 | |||||
| 466 | StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator( | ||||
| 467 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, | ||||
| 468 | std::unique_ptr<object::Archive> Archive, | ||||
| 469 | GetObjectFileInterface GetObjFileInterface, Error &Err) | ||||
| 470 | : L(L), GetObjFileInterface(std::move(GetObjFileInterface)), | ||||
| 471 | ArchiveBuffer(std::move(ArchiveBuffer)), Archive(std::move(Archive)) { | ||||
| 472 | ErrorAsOutParameter _(&Err); | ||||
| 473 | if (!this->GetObjFileInterface) | ||||
| 474 | this->GetObjFileInterface = getObjectFileInterface; | ||||
| 475 | if (!Err) | ||||
| 476 | Err = buildObjectFilesMap(); | ||||
| 477 | } | ||||
| 478 | |||||
| 479 | std::unique_ptr<DLLImportDefinitionGenerator> | ||||
| 480 | DLLImportDefinitionGenerator::Create(ExecutionSession &ES, | ||||
| 481 | ObjectLinkingLayer &L) { | ||||
| 482 | return std::unique_ptr<DLLImportDefinitionGenerator>( | ||||
| 483 | new DLLImportDefinitionGenerator(ES, L)); | ||||
| 484 | } | ||||
| 485 | |||||
| 486 | Error DLLImportDefinitionGenerator::tryToGenerate( | ||||
| 487 | LookupState &LS, LookupKind K, JITDylib &JD, | ||||
| 488 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { | ||||
| 489 | JITDylibSearchOrder LinkOrder; | ||||
| 490 | JD.withLinkOrderDo([&](const JITDylibSearchOrder &LO) { | ||||
| 491 | LinkOrder.reserve(LO.size()); | ||||
| 492 | for (auto &KV : LO) { | ||||
| 493 | if (KV.first == &JD) | ||||
| 494 | continue; | ||||
| 495 | LinkOrder.push_back(KV); | ||||
| 496 | } | ||||
| 497 | }); | ||||
| 498 | |||||
| 499 | // FIXME: if regular symbol name start with __imp_ we have to issue lookup of | ||||
| 500 | // both __imp_ and stripped name and use the lookup information to resolve the | ||||
| 501 | // real symbol name. | ||||
| 502 | SymbolLookupSet LookupSet; | ||||
| 503 | DenseMap<StringRef, SymbolLookupFlags> ToLookUpSymbols; | ||||
| 504 | for (auto &KV : Symbols) { | ||||
| 505 | StringRef Deinterned = *KV.first; | ||||
| 506 | if (Deinterned.startswith(getImpPrefix())) | ||||
| 507 | Deinterned = Deinterned.drop_front(StringRef(getImpPrefix()).size()); | ||||
| 508 | // Don't degrade the required state | ||||
| 509 | if (ToLookUpSymbols.count(Deinterned) && | ||||
| 510 | ToLookUpSymbols[Deinterned] == SymbolLookupFlags::RequiredSymbol) | ||||
| 511 | continue; | ||||
| 512 | ToLookUpSymbols[Deinterned] = KV.second; | ||||
| 513 | } | ||||
| 514 | |||||
| 515 | for (auto &KV : ToLookUpSymbols) | ||||
| 516 | LookupSet.add(ES.intern(KV.first), KV.second); | ||||
| 517 | |||||
| 518 | auto Resolved = | ||||
| 519 | ES.lookup(LinkOrder, LookupSet, LookupKind::DLSym, SymbolState::Resolved); | ||||
| 520 | if (!Resolved) | ||||
| 521 | return Resolved.takeError(); | ||||
| 522 | |||||
| 523 | auto G = createStubsGraph(*Resolved); | ||||
| 524 | if (!G) | ||||
| 525 | return G.takeError(); | ||||
| 526 | return L.add(JD, std::move(*G)); | ||||
| 527 | } | ||||
| 528 | |||||
| 529 | Expected<unsigned> | ||||
| 530 | DLLImportDefinitionGenerator::getTargetPointerSize(const Triple &TT) { | ||||
| 531 | switch (TT.getArch()) { | ||||
| 532 | case Triple::x86_64: | ||||
| 533 | return 8; | ||||
| 534 | default: | ||||
| 535 | return make_error<StringError>( | ||||
| 536 | "architecture unsupported by DLLImportDefinitionGenerator", | ||||
| 537 | inconvertibleErrorCode()); | ||||
| 538 | } | ||||
| 539 | } | ||||
| 540 | |||||
| 541 | Expected<support::endianness> | ||||
| 542 | DLLImportDefinitionGenerator::getTargetEndianness(const Triple &TT) { | ||||
| 543 | switch (TT.getArch()) { | ||||
| 544 | case Triple::x86_64: | ||||
| 545 | return support::endianness::little; | ||||
| 546 | default: | ||||
| 547 | return make_error<StringError>( | ||||
| 548 | "architecture unsupported by DLLImportDefinitionGenerator", | ||||
| 549 | inconvertibleErrorCode()); | ||||
| 550 | } | ||||
| 551 | } | ||||
| 552 | |||||
| 553 | Expected<std::unique_ptr<jitlink::LinkGraph>> | ||||
| 554 | DLLImportDefinitionGenerator::createStubsGraph(const SymbolMap &Resolved) { | ||||
| 555 | Triple TT = ES.getTargetTriple(); | ||||
| 556 | auto PointerSize = getTargetEndianness(TT); | ||||
| 557 | if (!PointerSize) | ||||
| 558 | return PointerSize.takeError(); | ||||
| 559 | auto Endianness = getTargetEndianness(TT); | ||||
| 560 | if (!Endianness) | ||||
| 561 | return Endianness.takeError(); | ||||
| 562 | |||||
| 563 | auto G = std::make_unique<jitlink::LinkGraph>( | ||||
| 564 | "<DLLIMPORT_STUBS>", TT, *PointerSize, *Endianness, | ||||
| 565 | jitlink::getGenericEdgeKindName); | ||||
| 566 | jitlink::Section &Sec = | ||||
| 567 | G->createSection(getSectionName(), MemProt::Read | MemProt::Exec); | ||||
| 568 | |||||
| 569 | for (auto &KV : Resolved) { | ||||
| 570 | jitlink::Symbol &Target = G->addAbsoluteSymbol( | ||||
| 571 | *KV.first, KV.second.getAddress(), *PointerSize, | ||||
| 572 | jitlink::Linkage::Strong, jitlink::Scope::Local, false); | ||||
| 573 | |||||
| 574 | // Create __imp_ symbol | ||||
| 575 | jitlink::Symbol &Ptr = | ||||
| 576 | jitlink::x86_64::createAnonymousPointer(*G, Sec, &Target); | ||||
| 577 | auto NameCopy = G->allocateContent(Twine(getImpPrefix()) + *KV.first); | ||||
| 578 | StringRef NameCopyRef = StringRef(NameCopy.data(), NameCopy.size()); | ||||
| 579 | Ptr.setName(NameCopyRef); | ||||
| 580 | Ptr.setLinkage(jitlink::Linkage::Strong); | ||||
| 581 | Ptr.setScope(jitlink::Scope::Default); | ||||
| 582 | |||||
| 583 | // Create PLT stub | ||||
| 584 | // FIXME: check PLT stub of data symbol is not accessed | ||||
| 585 | jitlink::Block &StubBlock = | ||||
| 586 | jitlink::x86_64::createPointerJumpStubBlock(*G, Sec, Ptr); | ||||
| 587 | G->addDefinedSymbol(StubBlock, 0, *KV.first, StubBlock.getSize(), | ||||
| 588 | jitlink::Linkage::Strong, jitlink::Scope::Default, true, | ||||
| 589 | false); | ||||
| 590 | } | ||||
| 591 | |||||
| 592 | return std::move(G); | ||||
| 593 | } | ||||
| 594 | |||||
| 595 | } // End namespace orc. | ||||
| 596 | } // End namespace llvm. |
| 1 | //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===// |
| 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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Contains utilities for executing code in Orc. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H |
| 14 | #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H |
| 15 | |
| 16 | #include "llvm/ADT/StringMap.h" |
| 17 | #include "llvm/ADT/iterator_range.h" |
| 18 | #include "llvm/ExecutionEngine/JITSymbol.h" |
| 19 | #include "llvm/ExecutionEngine/Orc/Core.h" |
| 20 | #include "llvm/ExecutionEngine/Orc/Mangling.h" |
| 21 | #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" |
| 22 | #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h" |
| 23 | #include "llvm/ExecutionEngine/RuntimeDyld.h" |
| 24 | #include "llvm/Object/Archive.h" |
| 25 | #include "llvm/Support/DynamicLibrary.h" |
| 26 | #include <algorithm> |
| 27 | #include <cstdint> |
| 28 | #include <utility> |
| 29 | #include <vector> |
| 30 | |
| 31 | namespace llvm { |
| 32 | |
| 33 | class ConstantArray; |
| 34 | class GlobalVariable; |
| 35 | class Function; |
| 36 | class Module; |
| 37 | class Value; |
| 38 | |
| 39 | namespace object { |
| 40 | class MachOUniversalBinary; |
| 41 | } |
| 42 | |
| 43 | namespace orc { |
| 44 | |
| 45 | class ObjectLayer; |
| 46 | |
| 47 | /// This iterator provides a convenient way to iterate over the elements |
| 48 | /// of an llvm.global_ctors/llvm.global_dtors instance. |
| 49 | /// |
| 50 | /// The easiest way to get hold of instances of this class is to use the |
| 51 | /// getConstructors/getDestructors functions. |
| 52 | class CtorDtorIterator { |
| 53 | public: |
| 54 | /// Accessor for an element of the global_ctors/global_dtors array. |
| 55 | /// |
| 56 | /// This class provides a read-only view of the element with any casts on |
| 57 | /// the function stripped away. |
| 58 | struct Element { |
| 59 | Element(unsigned Priority, Function *Func, Value *Data) |
| 60 | : Priority(Priority), Func(Func), Data(Data) {} |
| 61 | |
| 62 | unsigned Priority; |
| 63 | Function *Func; |
| 64 | Value *Data; |
| 65 | }; |
| 66 | |
| 67 | /// Construct an iterator instance. If End is true then this iterator |
| 68 | /// acts as the end of the range, otherwise it is the beginning. |
| 69 | CtorDtorIterator(const GlobalVariable *GV, bool End); |
| 70 | |
| 71 | /// Test iterators for equality. |
| 72 | bool operator==(const CtorDtorIterator &Other) const; |
| 73 | |
| 74 | /// Test iterators for inequality. |
| 75 | bool operator!=(const CtorDtorIterator &Other) const; |
| 76 | |
| 77 | /// Pre-increment iterator. |
| 78 | CtorDtorIterator& operator++(); |
| 79 | |
| 80 | /// Post-increment iterator. |
| 81 | CtorDtorIterator operator++(int); |
| 82 | |
| 83 | /// Dereference iterator. The resulting value provides a read-only view |
| 84 | /// of this element of the global_ctors/global_dtors list. |
| 85 | Element operator*() const; |
| 86 | |
| 87 | private: |
| 88 | const ConstantArray *InitList; |
| 89 | unsigned I; |
| 90 | }; |
| 91 | |
| 92 | /// Create an iterator range over the entries of the llvm.global_ctors |
| 93 | /// array. |
| 94 | iterator_range<CtorDtorIterator> getConstructors(const Module &M); |
| 95 | |
| 96 | /// Create an iterator range over the entries of the llvm.global_ctors |
| 97 | /// array. |
| 98 | iterator_range<CtorDtorIterator> getDestructors(const Module &M); |
| 99 | |
| 100 | /// This iterator provides a convenient way to iterate over GlobalValues that |
| 101 | /// have initialization effects. |
| 102 | class StaticInitGVIterator { |
| 103 | public: |
| 104 | StaticInitGVIterator() = default; |
| 105 | |
| 106 | StaticInitGVIterator(Module &M) |
| 107 | : I(M.global_values().begin()), E(M.global_values().end()), |
| 108 | ObjFmt(Triple(M.getTargetTriple()).getObjectFormat()) { |
| 109 | if (I != E) { |
| 110 | if (!isStaticInitGlobal(*I)) |
| 111 | moveToNextStaticInitGlobal(); |
| 112 | } else |
| 113 | I = E = Module::global_value_iterator(); |
| 114 | } |
| 115 | |
| 116 | bool operator==(const StaticInitGVIterator &O) const { return I == O.I; } |
| 117 | bool operator!=(const StaticInitGVIterator &O) const { return I != O.I; } |
| 118 | |
| 119 | StaticInitGVIterator &operator++() { |
| 120 | assert(I != E && "Increment past end of range")(static_cast <bool> (I != E && "Increment past end of range" ) ? void (0) : __assert_fail ("I != E && \"Increment past end of range\"" , "llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h", 120 , __extension__ __PRETTY_FUNCTION__)); |
| 121 | moveToNextStaticInitGlobal(); |
| 122 | return *this; |
| 123 | } |
| 124 | |
| 125 | GlobalValue &operator*() { return *I; } |
| 126 | |
| 127 | private: |
| 128 | bool isStaticInitGlobal(GlobalValue &GV); |
| 129 | void moveToNextStaticInitGlobal() { |
| 130 | ++I; |
| 131 | while (I != E && !isStaticInitGlobal(*I)) |
| 132 | ++I; |
| 133 | if (I == E) |
| 134 | I = E = Module::global_value_iterator(); |
| 135 | } |
| 136 | |
| 137 | Module::global_value_iterator I, E; |
| 138 | Triple::ObjectFormatType ObjFmt; |
| 139 | }; |
| 140 | |
| 141 | /// Create an iterator range over the GlobalValues that contribute to static |
| 142 | /// initialization. |
| 143 | inline iterator_range<StaticInitGVIterator> getStaticInitGVs(Module &M) { |
| 144 | return make_range(StaticInitGVIterator(M), StaticInitGVIterator()); |
| 145 | } |
| 146 | |
| 147 | class CtorDtorRunner { |
| 148 | public: |
| 149 | CtorDtorRunner(JITDylib &JD) : JD(JD) {} |
| 150 | void add(iterator_range<CtorDtorIterator> CtorDtors); |
| 151 | Error run(); |
| 152 | |
| 153 | private: |
| 154 | using CtorDtorList = std::vector<SymbolStringPtr>; |
| 155 | using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>; |
| 156 | |
| 157 | JITDylib &JD; |
| 158 | CtorDtorPriorityMap CtorDtorsByPriority; |
| 159 | }; |
| 160 | |
| 161 | /// Support class for static dtor execution. For hosted (in-process) JITs |
| 162 | /// only! |
| 163 | /// |
| 164 | /// If a __cxa_atexit function isn't found C++ programs that use static |
| 165 | /// destructors will fail to link. However, we don't want to use the host |
| 166 | /// process's __cxa_atexit, because it will schedule JIT'd destructors to run |
| 167 | /// after the JIT has been torn down, which is no good. This class makes it easy |
| 168 | /// to override __cxa_atexit (and the related __dso_handle). |
| 169 | /// |
| 170 | /// To use, clients should manually call searchOverrides from their symbol |
| 171 | /// resolver. This should generally be done after attempting symbol resolution |
| 172 | /// inside the JIT, but before searching the host process's symbol table. When |
| 173 | /// the client determines that destructors should be run (generally at JIT |
| 174 | /// teardown or after a return from main), the runDestructors method should be |
| 175 | /// called. |
| 176 | class LocalCXXRuntimeOverridesBase { |
| 177 | public: |
| 178 | /// Run any destructors recorded by the overriden __cxa_atexit function |
| 179 | /// (CXAAtExitOverride). |
| 180 | void runDestructors(); |
| 181 | |
| 182 | protected: |
| 183 | using DestructorPtr = void (*)(void *); |
| 184 | using CXXDestructorDataPair = std::pair<DestructorPtr, void *>; |
| 185 | using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>; |
| 186 | CXXDestructorDataPairList DSOHandleOverride; |
| 187 | static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, |
| 188 | void *DSOHandle); |
| 189 | }; |
| 190 | |
| 191 | class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { |
| 192 | public: |
| 193 | Error enable(JITDylib &JD, MangleAndInterner &Mangler); |
| 194 | }; |
| 195 | |
| 196 | /// An interface for Itanium __cxa_atexit interposer implementations. |
| 197 | class ItaniumCXAAtExitSupport { |
| 198 | public: |
| 199 | struct AtExitRecord { |
| 200 | void (*F)(void *); |
| 201 | void *Ctx; |
| 202 | }; |
| 203 | |
| 204 | void registerAtExit(void (*F)(void *), void *Ctx, void *DSOHandle); |
| 205 | void runAtExits(void *DSOHandle); |
| 206 | |
| 207 | private: |
| 208 | std::mutex AtExitsMutex; |
| 209 | DenseMap<void *, std::vector<AtExitRecord>> AtExitRecords; |
| 210 | }; |
| 211 | |
| 212 | /// A utility class to expose symbols found via dlsym to the JIT. |
| 213 | /// |
| 214 | /// If an instance of this class is attached to a JITDylib as a fallback |
| 215 | /// definition generator, then any symbol found in the given DynamicLibrary that |
| 216 | /// passes the 'Allow' predicate will be added to the JITDylib. |
| 217 | class DynamicLibrarySearchGenerator : public DefinitionGenerator { |
| 218 | public: |
| 219 | using SymbolPredicate = std::function<bool(const SymbolStringPtr &)>; |
| 220 | |
| 221 | /// Create a DynamicLibrarySearchGenerator that searches for symbols in the |
| 222 | /// given sys::DynamicLibrary. |
| 223 | /// |
| 224 | /// If the Allow predicate is given then only symbols matching the predicate |
| 225 | /// will be searched for. If the predicate is not given then all symbols will |
| 226 | /// be searched for. |
| 227 | DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix, |
| 228 | SymbolPredicate Allow = SymbolPredicate()); |
| 229 | |
| 230 | /// Permanently loads the library at the given path and, on success, returns |
| 231 | /// a DynamicLibrarySearchGenerator that will search it for symbol definitions |
| 232 | /// in the library. On failure returns the reason the library failed to load. |
| 233 | static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> |
| 234 | Load(const char *FileName, char GlobalPrefix, |
| 235 | SymbolPredicate Allow = SymbolPredicate()); |
| 236 | |
| 237 | /// Creates a DynamicLibrarySearchGenerator that searches for symbols in |
| 238 | /// the current process. |
| 239 | static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> |
| 240 | GetForCurrentProcess(char GlobalPrefix, |
| 241 | SymbolPredicate Allow = SymbolPredicate()) { |
| 242 | return Load(nullptr, GlobalPrefix, std::move(Allow)); |
| 243 | } |
| 244 | |
| 245 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
| 246 | JITDylibLookupFlags JDLookupFlags, |
| 247 | const SymbolLookupSet &Symbols) override; |
| 248 | |
| 249 | private: |
| 250 | sys::DynamicLibrary Dylib; |
| 251 | SymbolPredicate Allow; |
| 252 | char GlobalPrefix; |
| 253 | }; |
| 254 | |
| 255 | /// A utility class to expose symbols from a static library. |
| 256 | /// |
| 257 | /// If an instance of this class is attached to a JITDylib as a fallback |
| 258 | /// definition generator, then any symbol found in the archive will result in |
| 259 | /// the containing object being added to the JITDylib. |
| 260 | class StaticLibraryDefinitionGenerator : public DefinitionGenerator { |
| 261 | public: |
| 262 | // Interface builder function for objects loaded from this archive. |
| 263 | using GetObjectFileInterface = |
| 264 | unique_function<Expected<MaterializationUnit::Interface>( |
| 265 | ExecutionSession &ES, MemoryBufferRef ObjBuffer)>; |
| 266 | |
| 267 | /// Try to create a StaticLibraryDefinitionGenerator from the given path. |
| 268 | /// |
| 269 | /// This call will succeed if the file at the given path is a static library |
| 270 | /// or a MachO universal binary containing a static library that is compatible |
| 271 | /// with the ExecutionSession's triple. Otherwise it will return an error. |
| 272 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
| 273 | Load(ObjectLayer &L, const char *FileName, |
| 274 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
| 275 | |
| 276 | /// Try to create a StaticLibrarySearchGenerator from the given memory buffer |
| 277 | /// and Archive object. |
| 278 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
| 279 | Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
| 280 | std::unique_ptr<object::Archive> Archive, |
| 281 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
| 282 | |
| 283 | /// Try to create a StaticLibrarySearchGenerator from the given memory buffer. |
| 284 | /// This call will succeed if the buffer contains a valid archive, otherwise |
| 285 | /// it will return an error. |
| 286 | /// |
| 287 | /// This call will succeed if the buffer contains a valid static library or a |
| 288 | /// MachO universal binary containing a static library that is compatible |
| 289 | /// with the ExecutionSession's triple. Otherwise it will return an error. |
| 290 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
| 291 | Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
| 292 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
| 293 | |
| 294 | /// Returns a list of filenames of dynamic libraries that this archive has |
| 295 | /// imported. This class does not load these libraries by itself. User is |
| 296 | /// responsible for making sure these libraries are avaliable to the JITDylib. |
| 297 | const std::set<std::string> &getImportedDynamicLibraries() const { |
| 298 | return ImportedDynamicLibraries; |
| 299 | } |
| 300 | |
| 301 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
| 302 | JITDylibLookupFlags JDLookupFlags, |
| 303 | const SymbolLookupSet &Symbols) override; |
| 304 | |
| 305 | private: |
| 306 | StaticLibraryDefinitionGenerator(ObjectLayer &L, |
| 307 | std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
| 308 | std::unique_ptr<object::Archive> Archive, |
| 309 | GetObjectFileInterface GetObjFileInterface, |
| 310 | Error &Err); |
| 311 | Error buildObjectFilesMap(); |
| 312 | |
| 313 | static Expected<std::pair<size_t, size_t>> |
| 314 | getSliceRangeForArch(object::MachOUniversalBinary &UB, const Triple &TT); |
| 315 | |
| 316 | ObjectLayer &L; |
| 317 | GetObjectFileInterface GetObjFileInterface; |
| 318 | std::set<std::string> ImportedDynamicLibraries; |
| 319 | std::unique_ptr<MemoryBuffer> ArchiveBuffer; |
| 320 | std::unique_ptr<object::Archive> Archive; |
| 321 | DenseMap<SymbolStringPtr, MemoryBufferRef> ObjectFilesMap; |
| 322 | }; |
| 323 | |
| 324 | /// A utility class to create COFF dllimport GOT symbols (__imp_*) and PLT |
| 325 | /// stubs. |
| 326 | /// |
| 327 | /// If an instance of this class is attached to a JITDylib as a fallback |
| 328 | /// definition generator, PLT stubs and dllimport __imp_ symbols will be |
| 329 | /// generated for external symbols found outside the given jitdylib. Currently |
| 330 | /// only supports x86_64 architecture. |
| 331 | class DLLImportDefinitionGenerator : public DefinitionGenerator { |
| 332 | public: |
| 333 | /// Creates a DLLImportDefinitionGenerator instance. |
| 334 | static std::unique_ptr<DLLImportDefinitionGenerator> |
| 335 | Create(ExecutionSession &ES, ObjectLinkingLayer &L); |
| 336 | |
| 337 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
| 338 | JITDylibLookupFlags JDLookupFlags, |
| 339 | const SymbolLookupSet &Symbols) override; |
| 340 | |
| 341 | private: |
| 342 | DLLImportDefinitionGenerator(ExecutionSession &ES, ObjectLinkingLayer &L) |
| 343 | : ES(ES), L(L) {} |
| 344 | |
| 345 | static Expected<unsigned> getTargetPointerSize(const Triple &TT); |
| 346 | static Expected<support::endianness> getTargetEndianness(const Triple &TT); |
| 347 | Expected<std::unique_ptr<jitlink::LinkGraph>> |
| 348 | createStubsGraph(const SymbolMap &Resolved); |
| 349 | |
| 350 | static StringRef getImpPrefix() { return "__imp_"; } |
| 351 | |
| 352 | static StringRef getSectionName() { return "$__DLLIMPORT_STUBS"; } |
| 353 | |
| 354 | ExecutionSession &ES; |
| 355 | ObjectLinkingLayer &L; |
| 356 | }; |
| 357 | |
| 358 | } // end namespace orc |
| 359 | } // end namespace llvm |
| 360 | |
| 361 | #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H |