xref: /llvm-project/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h (revision d02c1676d75a6bab1252b48da9a955fc7dc1251f)
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