1 //===- IndirectionUtils.h - Utilities for adding indirections ---*- 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 adding indirections and breaking up modules. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H 14 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H 15 16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ExecutionEngine/JITSymbol.h" 19 #include "llvm/ExecutionEngine/Orc/Core.h" 20 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h" 21 #include "llvm/ExecutionEngine/Orc/RedirectionManager.h" 22 #include "llvm/Support/Error.h" 23 #include "llvm/Support/Memory.h" 24 #include "llvm/Support/Process.h" 25 #include "llvm/Transforms/Utils/ValueMapper.h" 26 #include <algorithm> 27 #include <cassert> 28 #include <cstdint> 29 #include <functional> 30 #include <future> 31 #include <map> 32 #include <memory> 33 #include <system_error> 34 #include <utility> 35 #include <vector> 36 37 namespace llvm { 38 39 class Constant; 40 class Function; 41 class FunctionType; 42 class GlobalAlias; 43 class GlobalVariable; 44 class Module; 45 class PointerType; 46 class Triple; 47 class Twine; 48 class Value; 49 class MCDisassembler; 50 class MCInstrAnalysis; 51 52 namespace jitlink { 53 class LinkGraph; 54 class Symbol; 55 } // namespace jitlink 56 57 namespace orc { 58 59 /// Base class for pools of compiler re-entry trampolines. 60 /// These trampolines are callable addresses that save all register state 61 /// before calling a supplied function to return the trampoline landing 62 /// address, then restore all state before jumping to that address. They 63 /// are used by various ORC APIs to support lazy compilation 64 class TrampolinePool { 65 public: 66 using NotifyLandingResolvedFunction = 67 unique_function<void(ExecutorAddr) const>; 68 69 using ResolveLandingFunction = unique_function<void( 70 ExecutorAddr TrampolineAddr, 71 NotifyLandingResolvedFunction OnLandingResolved) const>; 72 73 virtual ~TrampolinePool(); 74 75 /// Get an available trampoline address. 76 /// Returns an error if no trampoline can be created. 77 Expected<ExecutorAddr> getTrampoline() { 78 std::lock_guard<std::mutex> Lock(TPMutex); 79 if (AvailableTrampolines.empty()) { 80 if (auto Err = grow()) 81 return std::move(Err); 82 } 83 assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool"); 84 auto TrampolineAddr = AvailableTrampolines.back(); 85 AvailableTrampolines.pop_back(); 86 return TrampolineAddr; 87 } 88 89 /// Returns the given trampoline to the pool for re-use. 90 void releaseTrampoline(ExecutorAddr TrampolineAddr) { 91 std::lock_guard<std::mutex> Lock(TPMutex); 92 AvailableTrampolines.push_back(TrampolineAddr); 93 } 94 95 protected: 96 virtual Error grow() = 0; 97 98 std::mutex TPMutex; 99 std::vector<ExecutorAddr> AvailableTrampolines; 100 }; 101 102 /// A trampoline pool for trampolines within the current process. 103 template <typename ORCABI> class LocalTrampolinePool : public TrampolinePool { 104 public: 105 /// Creates a LocalTrampolinePool with the given RunCallback function. 106 /// Returns an error if this function is unable to correctly allocate, write 107 /// and protect the resolver code block. 108 static Expected<std::unique_ptr<LocalTrampolinePool>> 109 Create(ResolveLandingFunction ResolveLanding) { 110 Error Err = Error::success(); 111 112 auto LTP = std::unique_ptr<LocalTrampolinePool>( 113 new LocalTrampolinePool(std::move(ResolveLanding), Err)); 114 115 if (Err) 116 return std::move(Err); 117 return std::move(LTP); 118 } 119 120 private: 121 static JITTargetAddress reenter(void *TrampolinePoolPtr, void *TrampolineId) { 122 LocalTrampolinePool<ORCABI> *TrampolinePool = 123 static_cast<LocalTrampolinePool *>(TrampolinePoolPtr); 124 125 std::promise<ExecutorAddr> LandingAddressP; 126 auto LandingAddressF = LandingAddressP.get_future(); 127 128 TrampolinePool->ResolveLanding(ExecutorAddr::fromPtr(TrampolineId), 129 [&](ExecutorAddr LandingAddress) { 130 LandingAddressP.set_value(LandingAddress); 131 }); 132 return LandingAddressF.get().getValue(); 133 } 134 135 LocalTrampolinePool(ResolveLandingFunction ResolveLanding, Error &Err) 136 : ResolveLanding(std::move(ResolveLanding)) { 137 138 ErrorAsOutParameter _(Err); 139 140 /// Try to set up the resolver block. 141 std::error_code EC; 142 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 143 ORCABI::ResolverCodeSize, nullptr, 144 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 145 if (EC) { 146 Err = errorCodeToError(EC); 147 return; 148 } 149 150 ORCABI::writeResolverCode(static_cast<char *>(ResolverBlock.base()), 151 ExecutorAddr::fromPtr(ResolverBlock.base()), 152 ExecutorAddr::fromPtr(&reenter), 153 ExecutorAddr::fromPtr(this)); 154 155 EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(), 156 sys::Memory::MF_READ | 157 sys::Memory::MF_EXEC); 158 if (EC) { 159 Err = errorCodeToError(EC); 160 return; 161 } 162 } 163 164 Error grow() override { 165 assert(AvailableTrampolines.empty() && "Growing prematurely?"); 166 167 std::error_code EC; 168 auto TrampolineBlock = 169 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 170 sys::Process::getPageSizeEstimate(), nullptr, 171 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 172 if (EC) 173 return errorCodeToError(EC); 174 175 unsigned NumTrampolines = 176 (sys::Process::getPageSizeEstimate() - ORCABI::PointerSize) / 177 ORCABI::TrampolineSize; 178 179 char *TrampolineMem = static_cast<char *>(TrampolineBlock.base()); 180 ORCABI::writeTrampolines( 181 TrampolineMem, ExecutorAddr::fromPtr(TrampolineMem), 182 ExecutorAddr::fromPtr(ResolverBlock.base()), NumTrampolines); 183 184 for (unsigned I = 0; I < NumTrampolines; ++I) 185 AvailableTrampolines.push_back( 186 ExecutorAddr::fromPtr(TrampolineMem + (I * ORCABI::TrampolineSize))); 187 188 if (auto EC = sys::Memory::protectMappedMemory( 189 TrampolineBlock.getMemoryBlock(), 190 sys::Memory::MF_READ | sys::Memory::MF_EXEC)) 191 return errorCodeToError(EC); 192 193 TrampolineBlocks.push_back(std::move(TrampolineBlock)); 194 return Error::success(); 195 } 196 197 ResolveLandingFunction ResolveLanding; 198 199 sys::OwningMemoryBlock ResolverBlock; 200 std::vector<sys::OwningMemoryBlock> TrampolineBlocks; 201 }; 202 203 /// Target-independent base class for compile callback management. 204 class JITCompileCallbackManager { 205 public: 206 using CompileFunction = std::function<ExecutorAddr()>; 207 208 virtual ~JITCompileCallbackManager() = default; 209 210 /// Reserve a compile callback. 211 Expected<ExecutorAddr> getCompileCallback(CompileFunction Compile); 212 213 /// Execute the callback for the given trampoline id. Called by the JIT 214 /// to compile functions on demand. 215 ExecutorAddr executeCompileCallback(ExecutorAddr TrampolineAddr); 216 217 protected: 218 /// Construct a JITCompileCallbackManager. 219 JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP, 220 ExecutionSession &ES, 221 ExecutorAddr ErrorHandlerAddress) 222 : TP(std::move(TP)), ES(ES), 223 CallbacksJD(ES.createBareJITDylib("<Callbacks>")), 224 ErrorHandlerAddress(ErrorHandlerAddress) {} 225 226 void setTrampolinePool(std::unique_ptr<TrampolinePool> TP) { 227 this->TP = std::move(TP); 228 } 229 230 private: 231 std::mutex CCMgrMutex; 232 std::unique_ptr<TrampolinePool> TP; 233 ExecutionSession &ES; 234 JITDylib &CallbacksJD; 235 ExecutorAddr ErrorHandlerAddress; 236 std::map<ExecutorAddr, SymbolStringPtr> AddrToSymbol; 237 size_t NextCallbackId = 0; 238 }; 239 240 /// Manage compile callbacks for in-process JITs. 241 template <typename ORCABI> 242 class LocalJITCompileCallbackManager : public JITCompileCallbackManager { 243 public: 244 /// Create a new LocalJITCompileCallbackManager. 245 static Expected<std::unique_ptr<LocalJITCompileCallbackManager>> 246 Create(ExecutionSession &ES, ExecutorAddr ErrorHandlerAddress) { 247 Error Err = Error::success(); 248 auto CCMgr = std::unique_ptr<LocalJITCompileCallbackManager>( 249 new LocalJITCompileCallbackManager(ES, ErrorHandlerAddress, Err)); 250 if (Err) 251 return std::move(Err); 252 return std::move(CCMgr); 253 } 254 255 private: 256 /// Construct a InProcessJITCompileCallbackManager. 257 /// @param ErrorHandlerAddress The address of an error handler in the target 258 /// process to be used if a compile callback fails. 259 LocalJITCompileCallbackManager(ExecutionSession &ES, 260 ExecutorAddr ErrorHandlerAddress, Error &Err) 261 : JITCompileCallbackManager(nullptr, ES, ErrorHandlerAddress) { 262 using NotifyLandingResolvedFunction = 263 TrampolinePool::NotifyLandingResolvedFunction; 264 265 ErrorAsOutParameter _(Err); 266 auto TP = LocalTrampolinePool<ORCABI>::Create( 267 [this](ExecutorAddr TrampolineAddr, 268 NotifyLandingResolvedFunction NotifyLandingResolved) { 269 NotifyLandingResolved(executeCompileCallback(TrampolineAddr)); 270 }); 271 272 if (!TP) { 273 Err = TP.takeError(); 274 return; 275 } 276 277 setTrampolinePool(std::move(*TP)); 278 } 279 }; 280 281 /// Base class for managing collections of named indirect stubs. 282 class IndirectStubsManager : public RedirectableSymbolManager { 283 public: 284 /// Map type for initializing the manager. See init. 285 using StubInitsMap = StringMap<std::pair<ExecutorAddr, JITSymbolFlags>>; 286 287 virtual ~IndirectStubsManager() = default; 288 289 /// Create a single stub with the given name, target address and flags. 290 virtual Error createStub(StringRef StubName, ExecutorAddr StubAddr, 291 JITSymbolFlags StubFlags) = 0; 292 293 /// Create StubInits.size() stubs with the given names, target 294 /// addresses, and flags. 295 virtual Error createStubs(const StubInitsMap &StubInits) = 0; 296 297 /// Find the stub with the given name. If ExportedStubsOnly is true, 298 /// this will only return a result if the stub's flags indicate that it 299 /// is exported. 300 virtual ExecutorSymbolDef findStub(StringRef Name, 301 bool ExportedStubsOnly) = 0; 302 303 /// Find the implementation-pointer for the stub. 304 virtual ExecutorSymbolDef findPointer(StringRef Name) = 0; 305 306 /// Change the value of the implementation pointer for the stub. 307 virtual Error updatePointer(StringRef Name, ExecutorAddr NewAddr) = 0; 308 309 /// --- RedirectableSymbolManager implementation --- 310 Error redirect(JITDylib &JD, const SymbolMap &NewDests) override; 311 312 void 313 emitRedirectableSymbols(std::unique_ptr<MaterializationResponsibility> MR, 314 SymbolMap InitialDests) override; 315 316 private: 317 void anchor() override; 318 }; 319 320 template <typename ORCABI> class LocalIndirectStubsInfo { 321 public: 322 LocalIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem) 323 : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {} 324 325 static Expected<LocalIndirectStubsInfo> create(unsigned MinStubs, 326 unsigned PageSize) { 327 auto ISAS = getIndirectStubsBlockSizes<ORCABI>(MinStubs, PageSize); 328 329 assert((ISAS.StubBytes % PageSize == 0) && 330 "StubBytes is not a page size multiple"); 331 uint64_t PointerAlloc = alignTo(ISAS.PointerBytes, PageSize); 332 333 // Allocate memory for stubs and pointers in one call. 334 std::error_code EC; 335 auto StubsAndPtrsMem = 336 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 337 ISAS.StubBytes + PointerAlloc, nullptr, 338 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 339 if (EC) 340 return errorCodeToError(EC); 341 342 sys::MemoryBlock StubsBlock(StubsAndPtrsMem.base(), ISAS.StubBytes); 343 auto StubsBlockMem = static_cast<char *>(StubsAndPtrsMem.base()); 344 auto PtrBlockAddress = 345 ExecutorAddr::fromPtr(StubsBlockMem) + ISAS.StubBytes; 346 347 ORCABI::writeIndirectStubsBlock(StubsBlockMem, 348 ExecutorAddr::fromPtr(StubsBlockMem), 349 PtrBlockAddress, ISAS.NumStubs); 350 351 if (auto EC = sys::Memory::protectMappedMemory( 352 StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC)) 353 return errorCodeToError(EC); 354 355 return LocalIndirectStubsInfo(ISAS.NumStubs, std::move(StubsAndPtrsMem)); 356 } 357 358 unsigned getNumStubs() const { return NumStubs; } 359 360 void *getStub(unsigned Idx) const { 361 return static_cast<char *>(StubsMem.base()) + Idx * ORCABI::StubSize; 362 } 363 364 void **getPtr(unsigned Idx) const { 365 char *PtrsBase = 366 static_cast<char *>(StubsMem.base()) + NumStubs * ORCABI::StubSize; 367 return reinterpret_cast<void **>(PtrsBase) + Idx; 368 } 369 370 private: 371 unsigned NumStubs = 0; 372 sys::OwningMemoryBlock StubsMem; 373 }; 374 375 /// IndirectStubsManager implementation for the host architecture, e.g. 376 /// OrcX86_64. (See OrcArchitectureSupport.h). 377 template <typename TargetT> 378 class LocalIndirectStubsManager : public IndirectStubsManager { 379 public: 380 Error createStub(StringRef StubName, ExecutorAddr StubAddr, 381 JITSymbolFlags StubFlags) override { 382 std::lock_guard<std::mutex> Lock(StubsMutex); 383 if (auto Err = reserveStubs(1)) 384 return Err; 385 386 createStubInternal(StubName, StubAddr, StubFlags); 387 388 return Error::success(); 389 } 390 391 Error createStubs(const StubInitsMap &StubInits) override { 392 std::lock_guard<std::mutex> Lock(StubsMutex); 393 if (auto Err = reserveStubs(StubInits.size())) 394 return Err; 395 396 for (const auto &Entry : StubInits) 397 createStubInternal(Entry.first(), Entry.second.first, 398 Entry.second.second); 399 400 return Error::success(); 401 } 402 403 ExecutorSymbolDef findStub(StringRef Name, bool ExportedStubsOnly) override { 404 std::lock_guard<std::mutex> Lock(StubsMutex); 405 auto I = StubIndexes.find(Name); 406 if (I == StubIndexes.end()) 407 return ExecutorSymbolDef(); 408 auto Key = I->second.first; 409 void *StubPtr = IndirectStubsInfos[Key.first].getStub(Key.second); 410 assert(StubPtr && "Missing stub address"); 411 auto StubAddr = ExecutorAddr::fromPtr(StubPtr); 412 auto StubSymbol = ExecutorSymbolDef(StubAddr, I->second.second); 413 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported()) 414 return ExecutorSymbolDef(); 415 return StubSymbol; 416 } 417 418 ExecutorSymbolDef findPointer(StringRef Name) override { 419 std::lock_guard<std::mutex> Lock(StubsMutex); 420 auto I = StubIndexes.find(Name); 421 if (I == StubIndexes.end()) 422 return ExecutorSymbolDef(); 423 auto Key = I->second.first; 424 void *PtrPtr = IndirectStubsInfos[Key.first].getPtr(Key.second); 425 assert(PtrPtr && "Missing pointer address"); 426 auto PtrAddr = ExecutorAddr::fromPtr(PtrPtr); 427 return ExecutorSymbolDef(PtrAddr, I->second.second); 428 } 429 430 Error updatePointer(StringRef Name, ExecutorAddr NewAddr) override { 431 using AtomicIntPtr = std::atomic<uintptr_t>; 432 433 std::lock_guard<std::mutex> Lock(StubsMutex); 434 auto I = StubIndexes.find(Name); 435 assert(I != StubIndexes.end() && "No stub pointer for symbol"); 436 auto Key = I->second.first; 437 AtomicIntPtr *AtomicStubPtr = reinterpret_cast<AtomicIntPtr *>( 438 IndirectStubsInfos[Key.first].getPtr(Key.second)); 439 *AtomicStubPtr = static_cast<uintptr_t>(NewAddr.getValue()); 440 return Error::success(); 441 } 442 443 private: 444 Error reserveStubs(unsigned NumStubs) { 445 if (NumStubs <= FreeStubs.size()) 446 return Error::success(); 447 448 unsigned NewStubsRequired = NumStubs - FreeStubs.size(); 449 unsigned NewBlockId = IndirectStubsInfos.size(); 450 auto ISI = 451 LocalIndirectStubsInfo<TargetT>::create(NewStubsRequired, PageSize); 452 if (!ISI) 453 return ISI.takeError(); 454 for (unsigned I = 0; I < ISI->getNumStubs(); ++I) 455 FreeStubs.push_back(std::make_pair(NewBlockId, I)); 456 IndirectStubsInfos.push_back(std::move(*ISI)); 457 return Error::success(); 458 } 459 460 void createStubInternal(StringRef StubName, ExecutorAddr InitAddr, 461 JITSymbolFlags StubFlags) { 462 auto Key = FreeStubs.back(); 463 FreeStubs.pop_back(); 464 *IndirectStubsInfos[Key.first].getPtr(Key.second) = 465 InitAddr.toPtr<void *>(); 466 StubIndexes[StubName] = std::make_pair(Key, StubFlags); 467 } 468 469 unsigned PageSize = sys::Process::getPageSizeEstimate(); 470 std::mutex StubsMutex; 471 std::vector<LocalIndirectStubsInfo<TargetT>> IndirectStubsInfos; 472 using StubKey = std::pair<uint16_t, uint16_t>; 473 std::vector<StubKey> FreeStubs; 474 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; 475 }; 476 477 /// Create a local compile callback manager. 478 /// 479 /// The given target triple will determine the ABI, and the given 480 /// ErrorHandlerAddress will be used by the resulting compile callback 481 /// manager if a compile callback fails. 482 Expected<std::unique_ptr<JITCompileCallbackManager>> 483 createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES, 484 ExecutorAddr ErrorHandlerAddress); 485 486 /// Create a local indirect stubs manager builder. 487 /// 488 /// The given target triple will determine the ABI. 489 std::function<std::unique_ptr<IndirectStubsManager>()> 490 createLocalIndirectStubsManagerBuilder(const Triple &T); 491 492 /// Build a function pointer of FunctionType with the given constant 493 /// address. 494 /// 495 /// Usage example: Turn a trampoline address into a function pointer constant 496 /// for use in a stub. 497 Constant *createIRTypedAddress(FunctionType &FT, ExecutorAddr Addr); 498 499 /// Create a function pointer with the given type, name, and initializer 500 /// in the given Module. 501 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name, 502 Constant *Initializer); 503 504 /// Turn a function declaration into a stub function that makes an 505 /// indirect call using the given function pointer. 506 void makeStub(Function &F, Value &ImplPointer); 507 508 /// Promotes private symbols to global hidden, and renames to prevent clashes 509 /// with other promoted symbols. The same SymbolPromoter instance should be 510 /// used for all symbols to be added to a single JITDylib. 511 class SymbolLinkagePromoter { 512 public: 513 /// Promote symbols in the given module. Returns the set of global values 514 /// that have been renamed/promoted. 515 std::vector<GlobalValue *> operator()(Module &M); 516 517 private: 518 unsigned NextId = 0; 519 }; 520 521 /// Clone a function declaration into a new module. 522 /// 523 /// This function can be used as the first step towards creating a callback 524 /// stub (see makeStub). 525 /// 526 /// If the VMap argument is non-null, a mapping will be added between F and 527 /// the new declaration, and between each of F's arguments and the new 528 /// declaration's arguments. This map can then be passed in to moveFunction to 529 /// move the function body if required. Note: When moving functions between 530 /// modules with these utilities, all decls should be cloned (and added to a 531 /// single VMap) before any bodies are moved. This will ensure that references 532 /// between functions all refer to the versions in the new module. 533 Function *cloneFunctionDecl(Module &Dst, const Function &F, 534 ValueToValueMapTy *VMap = nullptr); 535 536 /// Clone a global variable declaration into a new module. 537 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, 538 ValueToValueMapTy *VMap = nullptr); 539 540 /// Clone a global alias declaration into a new module. 541 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, 542 ValueToValueMapTy &VMap); 543 544 /// Introduce relocations to \p Sym in its own definition if there are any 545 /// pointers formed via PC-relative address that do not already have a 546 /// relocation. 547 /// 548 /// This is useful when introducing indirection via a stub function at link time 549 /// without compiler support. If a function pointer is formed without a 550 /// relocation, e.g. in the definition of \c foo 551 /// 552 /// \code 553 /// _foo: 554 /// leaq -7(%rip), rax # form pointer to _foo without relocation 555 /// _bar: 556 /// leaq (%rip), %rax # uses X86_64_RELOC_SIGNED to '_foo' 557 /// \endcode 558 /// 559 /// the pointer to \c _foo computed by \c _foo and \c _bar may differ if we 560 /// introduce a stub for _foo. If the pointer is used as a key, this may be 561 /// observable to the program. This pass will attempt to introduce the missing 562 /// "self-relocation" on the leaq instruction. 563 /// 564 /// This is based on disassembly and should be considered "best effort". It may 565 /// silently fail to add relocations. 566 Error addFunctionPointerRelocationsToCurrentSymbol(jitlink::Symbol &Sym, 567 jitlink::LinkGraph &G, 568 MCDisassembler &Disassembler, 569 MCInstrAnalysis &MIA); 570 571 } // end namespace orc 572 573 } // end namespace llvm 574 575 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H 576