Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:53

0001 //===- IndirectionUtils.h - Utilities for adding indirections ---*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Contains utilities for adding indirections and breaking up modules.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
0014 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
0015 
0016 #include "llvm/ADT/StringMap.h"
0017 #include "llvm/ADT/StringRef.h"
0018 #include "llvm/ExecutionEngine/JITSymbol.h"
0019 #include "llvm/ExecutionEngine/Orc/Core.h"
0020 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
0021 #include "llvm/ExecutionEngine/Orc/RedirectionManager.h"
0022 #include "llvm/Support/Error.h"
0023 #include "llvm/Support/Memory.h"
0024 #include "llvm/Support/Process.h"
0025 #include "llvm/Transforms/Utils/ValueMapper.h"
0026 #include <algorithm>
0027 #include <cassert>
0028 #include <cstdint>
0029 #include <functional>
0030 #include <future>
0031 #include <map>
0032 #include <memory>
0033 #include <system_error>
0034 #include <utility>
0035 #include <vector>
0036 
0037 namespace llvm {
0038 
0039 class Constant;
0040 class Function;
0041 class FunctionType;
0042 class GlobalAlias;
0043 class GlobalVariable;
0044 class Module;
0045 class PointerType;
0046 class Triple;
0047 class Twine;
0048 class Value;
0049 class MCDisassembler;
0050 class MCInstrAnalysis;
0051 
0052 namespace jitlink {
0053 class LinkGraph;
0054 class Symbol;
0055 } // namespace jitlink
0056 
0057 namespace orc {
0058 
0059 /// Base class for pools of compiler re-entry trampolines.
0060 /// These trampolines are callable addresses that save all register state
0061 /// before calling a supplied function to return the trampoline landing
0062 /// address, then restore all state before jumping to that address. They
0063 /// are used by various ORC APIs to support lazy compilation
0064 class TrampolinePool {
0065 public:
0066   using NotifyLandingResolvedFunction =
0067       unique_function<void(ExecutorAddr) const>;
0068 
0069   using ResolveLandingFunction = unique_function<void(
0070       ExecutorAddr TrampolineAddr,
0071       NotifyLandingResolvedFunction OnLandingResolved) const>;
0072 
0073   virtual ~TrampolinePool();
0074 
0075   /// Get an available trampoline address.
0076   /// Returns an error if no trampoline can be created.
0077   Expected<ExecutorAddr> getTrampoline() {
0078     std::lock_guard<std::mutex> Lock(TPMutex);
0079     if (AvailableTrampolines.empty()) {
0080       if (auto Err = grow())
0081         return std::move(Err);
0082     }
0083     assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool");
0084     auto TrampolineAddr = AvailableTrampolines.back();
0085     AvailableTrampolines.pop_back();
0086     return TrampolineAddr;
0087   }
0088 
0089   /// Returns the given trampoline to the pool for re-use.
0090   void releaseTrampoline(ExecutorAddr TrampolineAddr) {
0091     std::lock_guard<std::mutex> Lock(TPMutex);
0092     AvailableTrampolines.push_back(TrampolineAddr);
0093   }
0094 
0095 protected:
0096   virtual Error grow() = 0;
0097 
0098   std::mutex TPMutex;
0099   std::vector<ExecutorAddr> AvailableTrampolines;
0100 };
0101 
0102 /// A trampoline pool for trampolines within the current process.
0103 template <typename ORCABI> class LocalTrampolinePool : public TrampolinePool {
0104 public:
0105   /// Creates a LocalTrampolinePool with the given RunCallback function.
0106   /// Returns an error if this function is unable to correctly allocate, write
0107   /// and protect the resolver code block.
0108   static Expected<std::unique_ptr<LocalTrampolinePool>>
0109   Create(ResolveLandingFunction ResolveLanding) {
0110     Error Err = Error::success();
0111 
0112     auto LTP = std::unique_ptr<LocalTrampolinePool>(
0113         new LocalTrampolinePool(std::move(ResolveLanding), Err));
0114 
0115     if (Err)
0116       return std::move(Err);
0117     return std::move(LTP);
0118   }
0119 
0120 private:
0121   static JITTargetAddress reenter(void *TrampolinePoolPtr, void *TrampolineId) {
0122     LocalTrampolinePool<ORCABI> *TrampolinePool =
0123         static_cast<LocalTrampolinePool *>(TrampolinePoolPtr);
0124 
0125     std::promise<ExecutorAddr> LandingAddressP;
0126     auto LandingAddressF = LandingAddressP.get_future();
0127 
0128     TrampolinePool->ResolveLanding(ExecutorAddr::fromPtr(TrampolineId),
0129                                    [&](ExecutorAddr LandingAddress) {
0130                                      LandingAddressP.set_value(LandingAddress);
0131                                    });
0132     return LandingAddressF.get().getValue();
0133   }
0134 
0135   LocalTrampolinePool(ResolveLandingFunction ResolveLanding, Error &Err)
0136       : ResolveLanding(std::move(ResolveLanding)) {
0137 
0138     ErrorAsOutParameter _(Err);
0139 
0140     /// Try to set up the resolver block.
0141     std::error_code EC;
0142     ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
0143         ORCABI::ResolverCodeSize, nullptr,
0144         sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
0145     if (EC) {
0146       Err = errorCodeToError(EC);
0147       return;
0148     }
0149 
0150     ORCABI::writeResolverCode(static_cast<char *>(ResolverBlock.base()),
0151                               ExecutorAddr::fromPtr(ResolverBlock.base()),
0152                               ExecutorAddr::fromPtr(&reenter),
0153                               ExecutorAddr::fromPtr(this));
0154 
0155     EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
0156                                           sys::Memory::MF_READ |
0157                                               sys::Memory::MF_EXEC);
0158     if (EC) {
0159       Err = errorCodeToError(EC);
0160       return;
0161     }
0162   }
0163 
0164   Error grow() override {
0165     assert(AvailableTrampolines.empty() && "Growing prematurely?");
0166 
0167     std::error_code EC;
0168     auto TrampolineBlock =
0169         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
0170             sys::Process::getPageSizeEstimate(), nullptr,
0171             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
0172     if (EC)
0173       return errorCodeToError(EC);
0174 
0175     unsigned NumTrampolines =
0176         (sys::Process::getPageSizeEstimate() - ORCABI::PointerSize) /
0177         ORCABI::TrampolineSize;
0178 
0179     char *TrampolineMem = static_cast<char *>(TrampolineBlock.base());
0180     ORCABI::writeTrampolines(
0181         TrampolineMem, ExecutorAddr::fromPtr(TrampolineMem),
0182         ExecutorAddr::fromPtr(ResolverBlock.base()), NumTrampolines);
0183 
0184     for (unsigned I = 0; I < NumTrampolines; ++I)
0185       AvailableTrampolines.push_back(
0186           ExecutorAddr::fromPtr(TrampolineMem + (I * ORCABI::TrampolineSize)));
0187 
0188     if (auto EC = sys::Memory::protectMappedMemory(
0189                     TrampolineBlock.getMemoryBlock(),
0190                     sys::Memory::MF_READ | sys::Memory::MF_EXEC))
0191       return errorCodeToError(EC);
0192 
0193     TrampolineBlocks.push_back(std::move(TrampolineBlock));
0194     return Error::success();
0195   }
0196 
0197   ResolveLandingFunction ResolveLanding;
0198 
0199   sys::OwningMemoryBlock ResolverBlock;
0200   std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
0201 };
0202 
0203 /// Target-independent base class for compile callback management.
0204 class JITCompileCallbackManager {
0205 public:
0206   using CompileFunction = std::function<ExecutorAddr()>;
0207 
0208   virtual ~JITCompileCallbackManager() = default;
0209 
0210   /// Reserve a compile callback.
0211   Expected<ExecutorAddr> getCompileCallback(CompileFunction Compile);
0212 
0213   /// Execute the callback for the given trampoline id. Called by the JIT
0214   ///        to compile functions on demand.
0215   ExecutorAddr executeCompileCallback(ExecutorAddr TrampolineAddr);
0216 
0217 protected:
0218   /// Construct a JITCompileCallbackManager.
0219   JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP,
0220                             ExecutionSession &ES,
0221                             ExecutorAddr ErrorHandlerAddress)
0222       : TP(std::move(TP)), ES(ES),
0223         CallbacksJD(ES.createBareJITDylib("<Callbacks>")),
0224         ErrorHandlerAddress(ErrorHandlerAddress) {}
0225 
0226   void setTrampolinePool(std::unique_ptr<TrampolinePool> TP) {
0227     this->TP = std::move(TP);
0228   }
0229 
0230 private:
0231   std::mutex CCMgrMutex;
0232   std::unique_ptr<TrampolinePool> TP;
0233   ExecutionSession &ES;
0234   JITDylib &CallbacksJD;
0235   ExecutorAddr ErrorHandlerAddress;
0236   std::map<ExecutorAddr, SymbolStringPtr> AddrToSymbol;
0237   size_t NextCallbackId = 0;
0238 };
0239 
0240 /// Manage compile callbacks for in-process JITs.
0241 template <typename ORCABI>
0242 class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
0243 public:
0244   /// Create a new LocalJITCompileCallbackManager.
0245   static Expected<std::unique_ptr<LocalJITCompileCallbackManager>>
0246   Create(ExecutionSession &ES, ExecutorAddr ErrorHandlerAddress) {
0247     Error Err = Error::success();
0248     auto CCMgr = std::unique_ptr<LocalJITCompileCallbackManager>(
0249         new LocalJITCompileCallbackManager(ES, ErrorHandlerAddress, Err));
0250     if (Err)
0251       return std::move(Err);
0252     return std::move(CCMgr);
0253   }
0254 
0255 private:
0256   /// Construct a InProcessJITCompileCallbackManager.
0257   /// @param ErrorHandlerAddress The address of an error handler in the target
0258   ///                            process to be used if a compile callback fails.
0259   LocalJITCompileCallbackManager(ExecutionSession &ES,
0260                                  ExecutorAddr ErrorHandlerAddress, Error &Err)
0261       : JITCompileCallbackManager(nullptr, ES, ErrorHandlerAddress) {
0262     using NotifyLandingResolvedFunction =
0263         TrampolinePool::NotifyLandingResolvedFunction;
0264 
0265     ErrorAsOutParameter _(Err);
0266     auto TP = LocalTrampolinePool<ORCABI>::Create(
0267         [this](ExecutorAddr TrampolineAddr,
0268                NotifyLandingResolvedFunction NotifyLandingResolved) {
0269           NotifyLandingResolved(executeCompileCallback(TrampolineAddr));
0270         });
0271 
0272     if (!TP) {
0273       Err = TP.takeError();
0274       return;
0275     }
0276 
0277     setTrampolinePool(std::move(*TP));
0278   }
0279 };
0280 
0281 /// Base class for managing collections of named indirect stubs.
0282 class IndirectStubsManager : public RedirectableSymbolManager {
0283 public:
0284   /// Map type for initializing the manager. See init.
0285   using StubInitsMap = StringMap<std::pair<ExecutorAddr, JITSymbolFlags>>;
0286 
0287   virtual ~IndirectStubsManager() = default;
0288 
0289   /// Create a single stub with the given name, target address and flags.
0290   virtual Error createStub(StringRef StubName, ExecutorAddr StubAddr,
0291                            JITSymbolFlags StubFlags) = 0;
0292 
0293   /// Create StubInits.size() stubs with the given names, target
0294   ///        addresses, and flags.
0295   virtual Error createStubs(const StubInitsMap &StubInits) = 0;
0296 
0297   /// Find the stub with the given name. If ExportedStubsOnly is true,
0298   ///        this will only return a result if the stub's flags indicate that it
0299   ///        is exported.
0300   virtual ExecutorSymbolDef findStub(StringRef Name,
0301                                      bool ExportedStubsOnly) = 0;
0302 
0303   /// Find the implementation-pointer for the stub.
0304   virtual ExecutorSymbolDef findPointer(StringRef Name) = 0;
0305 
0306   /// Change the value of the implementation pointer for the stub.
0307   virtual Error updatePointer(StringRef Name, ExecutorAddr NewAddr) = 0;
0308 
0309   /// --- RedirectableSymbolManager implementation ---
0310   Error redirect(JITDylib &JD, const SymbolMap &NewDests) override;
0311 
0312   void
0313   emitRedirectableSymbols(std::unique_ptr<MaterializationResponsibility> MR,
0314                           SymbolMap InitialDests) override;
0315 
0316 private:
0317   void anchor() override;
0318 };
0319 
0320 template <typename ORCABI> class LocalIndirectStubsInfo {
0321 public:
0322   LocalIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
0323       : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
0324 
0325   static Expected<LocalIndirectStubsInfo> create(unsigned MinStubs,
0326                                                  unsigned PageSize) {
0327     auto ISAS = getIndirectStubsBlockSizes<ORCABI>(MinStubs, PageSize);
0328 
0329     assert((ISAS.StubBytes % PageSize == 0) &&
0330            "StubBytes is not a page size multiple");
0331     uint64_t PointerAlloc = alignTo(ISAS.PointerBytes, PageSize);
0332 
0333     // Allocate memory for stubs and pointers in one call.
0334     std::error_code EC;
0335     auto StubsAndPtrsMem =
0336         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
0337             ISAS.StubBytes + PointerAlloc, nullptr,
0338             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
0339     if (EC)
0340       return errorCodeToError(EC);
0341 
0342     sys::MemoryBlock StubsBlock(StubsAndPtrsMem.base(), ISAS.StubBytes);
0343     auto StubsBlockMem = static_cast<char *>(StubsAndPtrsMem.base());
0344     auto PtrBlockAddress =
0345         ExecutorAddr::fromPtr(StubsBlockMem) + ISAS.StubBytes;
0346 
0347     ORCABI::writeIndirectStubsBlock(StubsBlockMem,
0348                                     ExecutorAddr::fromPtr(StubsBlockMem),
0349                                     PtrBlockAddress, ISAS.NumStubs);
0350 
0351     if (auto EC = sys::Memory::protectMappedMemory(
0352             StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
0353       return errorCodeToError(EC);
0354 
0355     return LocalIndirectStubsInfo(ISAS.NumStubs, std::move(StubsAndPtrsMem));
0356   }
0357 
0358   unsigned getNumStubs() const { return NumStubs; }
0359 
0360   void *getStub(unsigned Idx) const {
0361     return static_cast<char *>(StubsMem.base()) + Idx * ORCABI::StubSize;
0362   }
0363 
0364   void **getPtr(unsigned Idx) const {
0365     char *PtrsBase =
0366         static_cast<char *>(StubsMem.base()) + NumStubs * ORCABI::StubSize;
0367     return reinterpret_cast<void **>(PtrsBase) + Idx;
0368   }
0369 
0370 private:
0371   unsigned NumStubs = 0;
0372   sys::OwningMemoryBlock StubsMem;
0373 };
0374 
0375 /// IndirectStubsManager implementation for the host architecture, e.g.
0376 ///        OrcX86_64. (See OrcArchitectureSupport.h).
0377 template <typename TargetT>
0378 class LocalIndirectStubsManager : public IndirectStubsManager {
0379 public:
0380   Error createStub(StringRef StubName, ExecutorAddr StubAddr,
0381                    JITSymbolFlags StubFlags) override {
0382     std::lock_guard<std::mutex> Lock(StubsMutex);
0383     if (auto Err = reserveStubs(1))
0384       return Err;
0385 
0386     createStubInternal(StubName, StubAddr, StubFlags);
0387 
0388     return Error::success();
0389   }
0390 
0391   Error createStubs(const StubInitsMap &StubInits) override {
0392     std::lock_guard<std::mutex> Lock(StubsMutex);
0393     if (auto Err = reserveStubs(StubInits.size()))
0394       return Err;
0395 
0396     for (const auto &Entry : StubInits)
0397       createStubInternal(Entry.first(), Entry.second.first,
0398                          Entry.second.second);
0399 
0400     return Error::success();
0401   }
0402 
0403   ExecutorSymbolDef findStub(StringRef Name, bool ExportedStubsOnly) override {
0404     std::lock_guard<std::mutex> Lock(StubsMutex);
0405     auto I = StubIndexes.find(Name);
0406     if (I == StubIndexes.end())
0407       return ExecutorSymbolDef();
0408     auto Key = I->second.first;
0409     void *StubPtr = IndirectStubsInfos[Key.first].getStub(Key.second);
0410     assert(StubPtr && "Missing stub address");
0411     auto StubAddr = ExecutorAddr::fromPtr(StubPtr);
0412     auto StubSymbol = ExecutorSymbolDef(StubAddr, I->second.second);
0413     if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
0414       return ExecutorSymbolDef();
0415     return StubSymbol;
0416   }
0417 
0418   ExecutorSymbolDef findPointer(StringRef Name) override {
0419     std::lock_guard<std::mutex> Lock(StubsMutex);
0420     auto I = StubIndexes.find(Name);
0421     if (I == StubIndexes.end())
0422       return ExecutorSymbolDef();
0423     auto Key = I->second.first;
0424     void *PtrPtr = IndirectStubsInfos[Key.first].getPtr(Key.second);
0425     assert(PtrPtr && "Missing pointer address");
0426     auto PtrAddr = ExecutorAddr::fromPtr(PtrPtr);
0427     return ExecutorSymbolDef(PtrAddr, I->second.second);
0428   }
0429 
0430   Error updatePointer(StringRef Name, ExecutorAddr NewAddr) override {
0431     using AtomicIntPtr = std::atomic<uintptr_t>;
0432 
0433     std::lock_guard<std::mutex> Lock(StubsMutex);
0434     auto I = StubIndexes.find(Name);
0435     assert(I != StubIndexes.end() && "No stub pointer for symbol");
0436     auto Key = I->second.first;
0437     AtomicIntPtr *AtomicStubPtr = reinterpret_cast<AtomicIntPtr *>(
0438         IndirectStubsInfos[Key.first].getPtr(Key.second));
0439     *AtomicStubPtr = static_cast<uintptr_t>(NewAddr.getValue());
0440     return Error::success();
0441   }
0442 
0443 private:
0444   Error reserveStubs(unsigned NumStubs) {
0445     if (NumStubs <= FreeStubs.size())
0446       return Error::success();
0447 
0448     unsigned NewStubsRequired = NumStubs - FreeStubs.size();
0449     unsigned NewBlockId = IndirectStubsInfos.size();
0450     auto ISI =
0451         LocalIndirectStubsInfo<TargetT>::create(NewStubsRequired, PageSize);
0452     if (!ISI)
0453       return ISI.takeError();
0454     for (unsigned I = 0; I < ISI->getNumStubs(); ++I)
0455       FreeStubs.push_back(std::make_pair(NewBlockId, I));
0456     IndirectStubsInfos.push_back(std::move(*ISI));
0457     return Error::success();
0458   }
0459 
0460   void createStubInternal(StringRef StubName, ExecutorAddr InitAddr,
0461                           JITSymbolFlags StubFlags) {
0462     auto Key = FreeStubs.back();
0463     FreeStubs.pop_back();
0464     *IndirectStubsInfos[Key.first].getPtr(Key.second) =
0465         InitAddr.toPtr<void *>();
0466     StubIndexes[StubName] = std::make_pair(Key, StubFlags);
0467   }
0468 
0469   unsigned PageSize = sys::Process::getPageSizeEstimate();
0470   std::mutex StubsMutex;
0471   std::vector<LocalIndirectStubsInfo<TargetT>> IndirectStubsInfos;
0472   using StubKey = std::pair<uint16_t, uint16_t>;
0473   std::vector<StubKey> FreeStubs;
0474   StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
0475 };
0476 
0477 /// Create a local compile callback manager.
0478 ///
0479 /// The given target triple will determine the ABI, and the given
0480 /// ErrorHandlerAddress will be used by the resulting compile callback
0481 /// manager if a compile callback fails.
0482 Expected<std::unique_ptr<JITCompileCallbackManager>>
0483 createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
0484                                   ExecutorAddr ErrorHandlerAddress);
0485 
0486 /// Create a local indirect stubs manager builder.
0487 ///
0488 /// The given target triple will determine the ABI.
0489 std::function<std::unique_ptr<IndirectStubsManager>()>
0490 createLocalIndirectStubsManagerBuilder(const Triple &T);
0491 
0492 /// Build a function pointer of FunctionType with the given constant
0493 ///        address.
0494 ///
0495 ///   Usage example: Turn a trampoline address into a function pointer constant
0496 /// for use in a stub.
0497 Constant *createIRTypedAddress(FunctionType &FT, ExecutorAddr Addr);
0498 
0499 /// Create a function pointer with the given type, name, and initializer
0500 ///        in the given Module.
0501 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
0502                                   Constant *Initializer);
0503 
0504 /// Turn a function declaration into a stub function that makes an
0505 ///        indirect call using the given function pointer.
0506 void makeStub(Function &F, Value &ImplPointer);
0507 
0508 /// Promotes private symbols to global hidden, and renames to prevent clashes
0509 /// with other promoted symbols. The same SymbolPromoter instance should be
0510 /// used for all symbols to be added to a single JITDylib.
0511 class SymbolLinkagePromoter {
0512 public:
0513   /// Promote symbols in the given module. Returns the set of global values
0514   /// that have been renamed/promoted.
0515   std::vector<GlobalValue *> operator()(Module &M);
0516 
0517 private:
0518   unsigned NextId = 0;
0519 };
0520 
0521 /// Clone a function declaration into a new module.
0522 ///
0523 ///   This function can be used as the first step towards creating a callback
0524 /// stub (see makeStub).
0525 ///
0526 ///   If the VMap argument is non-null, a mapping will be added between F and
0527 /// the new declaration, and between each of F's arguments and the new
0528 /// declaration's arguments. This map can then be passed in to moveFunction to
0529 /// move the function body if required. Note: When moving functions between
0530 /// modules with these utilities, all decls should be cloned (and added to a
0531 /// single VMap) before any bodies are moved. This will ensure that references
0532 /// between functions all refer to the versions in the new module.
0533 Function *cloneFunctionDecl(Module &Dst, const Function &F,
0534                             ValueToValueMapTy *VMap = nullptr);
0535 
0536 /// Clone a global variable declaration into a new module.
0537 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
0538                                         ValueToValueMapTy *VMap = nullptr);
0539 
0540 /// Clone a global alias declaration into a new module.
0541 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
0542                                   ValueToValueMapTy &VMap);
0543 
0544 /// Introduce relocations to \p Sym in its own definition if there are any
0545 /// pointers formed via PC-relative address that do not already have a
0546 /// relocation.
0547 ///
0548 /// This is useful when introducing indirection via a stub function at link time
0549 /// without compiler support. If a function pointer is formed without a
0550 /// relocation, e.g. in the definition of \c foo
0551 ///
0552 /// \code
0553 /// _foo:
0554 ///   leaq -7(%rip), rax # form pointer to _foo without relocation
0555 /// _bar:
0556 ///   leaq (%rip), %rax  # uses X86_64_RELOC_SIGNED to '_foo'
0557 /// \endcode
0558 ///
0559 /// the pointer to \c _foo computed by \c _foo and \c _bar may differ if we
0560 /// introduce a stub for _foo. If the pointer is used as a key, this may be
0561 /// observable to the program. This pass will attempt to introduce the missing
0562 /// "self-relocation" on the leaq instruction.
0563 ///
0564 /// This is based on disassembly and should be considered "best effort". It may
0565 /// silently fail to add relocations.
0566 Error addFunctionPointerRelocationsToCurrentSymbol(jitlink::Symbol &Sym,
0567                                                    jitlink::LinkGraph &G,
0568                                                    MCDisassembler &Disassembler,
0569                                                    MCInstrAnalysis &MIA);
0570 
0571 } // end namespace orc
0572 
0573 } // end namespace llvm
0574 
0575 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H