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