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