xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
10b57cec5SDimitry Andric //===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
140b57cec5SDimitry Andric #define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
170b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric namespace llvm {
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric class MemoryBufferRef;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace jitlink {
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric /// Base class for a JIT linker.
280b57cec5SDimitry Andric ///
290b57cec5SDimitry Andric /// A JITLinkerBase instance links one object file into an ongoing JIT
300b57cec5SDimitry Andric /// session. Symbol resolution and finalization operations are pluggable,
310b57cec5SDimitry Andric /// and called using continuation passing (passing a continuation for the
320b57cec5SDimitry Andric /// remaining linker work) to allow them to be performed asynchronously.
330b57cec5SDimitry Andric class JITLinkerBase {
340b57cec5SDimitry Andric public:
350b57cec5SDimitry Andric   JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, PassConfiguration Passes)
360b57cec5SDimitry Andric       : Ctx(std::move(Ctx)), Passes(std::move(Passes)) {
370b57cec5SDimitry Andric     assert(this->Ctx && "Ctx can not be null");
380b57cec5SDimitry Andric   }
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   virtual ~JITLinkerBase();
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric protected:
430b57cec5SDimitry Andric   struct SegmentLayout {
448bcb0991SDimitry Andric     using BlocksList = std::vector<Block *>;
450b57cec5SDimitry Andric 
468bcb0991SDimitry Andric     BlocksList ContentBlocks;
478bcb0991SDimitry Andric     BlocksList ZeroFillBlocks;
480b57cec5SDimitry Andric   };
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   using SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   // Phase 1:
538bcb0991SDimitry Andric   //   1.1: Build link graph
540b57cec5SDimitry Andric   //   1.2: Run pre-prune passes
550b57cec5SDimitry Andric   //   1.2: Prune graph
560b57cec5SDimitry Andric   //   1.3: Run post-prune passes
578bcb0991SDimitry Andric   //   1.4: Sort blocks into segments
580b57cec5SDimitry Andric   //   1.5: Allocate segment memory
590b57cec5SDimitry Andric   //   1.6: Identify externals and make an async call to resolve function
600b57cec5SDimitry Andric   void linkPhase1(std::unique_ptr<JITLinkerBase> Self);
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   // Phase 2:
630b57cec5SDimitry Andric   //   2.1: Apply resolution results
648bcb0991SDimitry Andric   //   2.2: Fix up block contents
650b57cec5SDimitry Andric   //   2.3: Call OnResolved callback
660b57cec5SDimitry Andric   //   2.3: Make an async call to transfer and finalize memory.
670b57cec5SDimitry Andric   void linkPhase2(std::unique_ptr<JITLinkerBase> Self,
688bcb0991SDimitry Andric                   Expected<AsyncLookupResult> LookupResult,
698bcb0991SDimitry Andric                   SegmentLayoutMap Layout);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   // Phase 3:
720b57cec5SDimitry Andric   //   3.1: Call OnFinalized callback, handing off allocation.
730b57cec5SDimitry Andric   void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err);
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   // Build a graph from the given object buffer.
760b57cec5SDimitry Andric   // To be implemented by the client.
778bcb0991SDimitry Andric   virtual Expected<std::unique_ptr<LinkGraph>>
780b57cec5SDimitry Andric   buildGraph(MemoryBufferRef ObjBuffer) = 0;
790b57cec5SDimitry Andric 
808bcb0991SDimitry Andric   // For debug dumping of the link graph.
810b57cec5SDimitry Andric   virtual StringRef getEdgeKindName(Edge::Kind K) const = 0;
820b57cec5SDimitry Andric 
838bcb0991SDimitry Andric   // Alight a JITTargetAddress to conform with block alignment requirements.
848bcb0991SDimitry Andric   static JITTargetAddress alignToBlock(JITTargetAddress Addr, Block &B) {
858bcb0991SDimitry Andric     uint64_t Delta = (B.getAlignmentOffset() - Addr) % B.getAlignment();
868bcb0991SDimitry Andric     return Addr + Delta;
878bcb0991SDimitry Andric   }
888bcb0991SDimitry Andric 
898bcb0991SDimitry Andric   // Alight a pointer to conform with block alignment requirements.
908bcb0991SDimitry Andric   static char *alignToBlock(char *P, Block &B) {
918bcb0991SDimitry Andric     uint64_t PAddr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(P));
928bcb0991SDimitry Andric     uint64_t Delta = (B.getAlignmentOffset() - PAddr) % B.getAlignment();
938bcb0991SDimitry Andric     return P + Delta;
948bcb0991SDimitry Andric   }
958bcb0991SDimitry Andric 
960b57cec5SDimitry Andric private:
970b57cec5SDimitry Andric   // Run all passes in the given pass list, bailing out immediately if any pass
980b57cec5SDimitry Andric   // returns an error.
998bcb0991SDimitry Andric   Error runPasses(LinkGraphPassList &Passes);
1000b57cec5SDimitry Andric 
1018bcb0991SDimitry Andric   // Copy block contents and apply relocations.
1020b57cec5SDimitry Andric   // Implemented in JITLinker.
1030b57cec5SDimitry Andric   virtual Error
1048bcb0991SDimitry Andric   copyAndFixUpBlocks(const SegmentLayoutMap &Layout,
1050b57cec5SDimitry Andric                      JITLinkMemoryManager::Allocation &Alloc) const = 0;
1060b57cec5SDimitry Andric 
1078bcb0991SDimitry Andric   SegmentLayoutMap layOutBlocks();
1080b57cec5SDimitry Andric   Error allocateSegments(const SegmentLayoutMap &Layout);
109*480093f4SDimitry Andric   JITLinkContext::LookupMap getExternalSymbolNames() const;
1100b57cec5SDimitry Andric   void applyLookupResult(AsyncLookupResult LR);
1110b57cec5SDimitry Andric   void deallocateAndBailOut(Error Err);
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   void dumpGraph(raw_ostream &OS);
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   std::unique_ptr<JITLinkContext> Ctx;
1160b57cec5SDimitry Andric   PassConfiguration Passes;
1178bcb0991SDimitry Andric   std::unique_ptr<LinkGraph> G;
1180b57cec5SDimitry Andric   std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc;
1190b57cec5SDimitry Andric };
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric template <typename LinkerImpl> class JITLinker : public JITLinkerBase {
1220b57cec5SDimitry Andric public:
1230b57cec5SDimitry Andric   using JITLinkerBase::JITLinkerBase;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   /// Link constructs a LinkerImpl instance and calls linkPhase1.
1260b57cec5SDimitry Andric   /// Link should be called with the constructor arguments for LinkerImpl, which
1270b57cec5SDimitry Andric   /// will be forwarded to the constructor.
1280b57cec5SDimitry Andric   template <typename... ArgTs> static void link(ArgTs &&... Args) {
1298bcb0991SDimitry Andric     auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric     // Ownership of the linker is passed into the linker's doLink function to
1320b57cec5SDimitry Andric     // allow it to be passed on to async continuations.
1330b57cec5SDimitry Andric     //
1340b57cec5SDimitry Andric     // FIXME: Remove LTmp once we have c++17.
1350b57cec5SDimitry Andric     // C++17 sequencing rules guarantee that function name expressions are
1360b57cec5SDimitry Andric     // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be
1370b57cec5SDimitry Andric     // well formed.
1380b57cec5SDimitry Andric     auto &LTmp = *L;
1390b57cec5SDimitry Andric     LTmp.linkPhase1(std::move(L));
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric private:
1430b57cec5SDimitry Andric   const LinkerImpl &impl() const {
1440b57cec5SDimitry Andric     return static_cast<const LinkerImpl &>(*this);
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   Error
1488bcb0991SDimitry Andric   copyAndFixUpBlocks(const SegmentLayoutMap &Layout,
1490b57cec5SDimitry Andric                      JITLinkMemoryManager::Allocation &Alloc) const override {
1508bcb0991SDimitry Andric     LLVM_DEBUG(dbgs() << "Copying and fixing up blocks:\n");
1510b57cec5SDimitry Andric     for (auto &KV : Layout) {
1520b57cec5SDimitry Andric       auto &Prot = KV.first;
1530b57cec5SDimitry Andric       auto &SegLayout = KV.second;
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric       auto SegMem = Alloc.getWorkingMemory(
1560b57cec5SDimitry Andric           static_cast<sys::Memory::ProtectionFlags>(Prot));
1578bcb0991SDimitry Andric       char *LastBlockEnd = SegMem.data();
1588bcb0991SDimitry Andric       char *BlockDataPtr = LastBlockEnd;
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric       LLVM_DEBUG({
1610b57cec5SDimitry Andric         dbgs() << "  Processing segment "
1620b57cec5SDimitry Andric                << static_cast<sys::Memory::ProtectionFlags>(Prot) << " [ "
1630b57cec5SDimitry Andric                << (const void *)SegMem.data() << " .. "
1640b57cec5SDimitry Andric                << (const void *)((char *)SegMem.data() + SegMem.size())
1650b57cec5SDimitry Andric                << " ]\n    Processing content sections:\n";
1660b57cec5SDimitry Andric       });
1670b57cec5SDimitry Andric 
1688bcb0991SDimitry Andric       for (auto *B : SegLayout.ContentBlocks) {
1698bcb0991SDimitry Andric         LLVM_DEBUG(dbgs() << "    " << *B << ":\n");
1700b57cec5SDimitry Andric 
1718bcb0991SDimitry Andric         // Pad to alignment/alignment-offset.
1728bcb0991SDimitry Andric         BlockDataPtr = alignToBlock(BlockDataPtr, *B);
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric         LLVM_DEBUG({
1758bcb0991SDimitry Andric           dbgs() << "      Bumped block pointer to "
1768bcb0991SDimitry Andric                  << (const void *)BlockDataPtr << " to meet block alignment "
1778bcb0991SDimitry Andric                  << B->getAlignment() << " and alignment offset "
1788bcb0991SDimitry Andric                  << B->getAlignmentOffset() << "\n";
1790b57cec5SDimitry Andric         });
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric         // Zero pad up to alignment.
1820b57cec5SDimitry Andric         LLVM_DEBUG({
1838bcb0991SDimitry Andric           if (LastBlockEnd != BlockDataPtr)
1848bcb0991SDimitry Andric             dbgs() << "      Zero padding from " << (const void *)LastBlockEnd
1858bcb0991SDimitry Andric                    << " to " << (const void *)BlockDataPtr << "\n";
1860b57cec5SDimitry Andric         });
1870b57cec5SDimitry Andric 
1888bcb0991SDimitry Andric         while (LastBlockEnd != BlockDataPtr)
1898bcb0991SDimitry Andric           *LastBlockEnd++ = 0;
1908bcb0991SDimitry Andric 
1918bcb0991SDimitry Andric         // Copy initial block content.
1920b57cec5SDimitry Andric         LLVM_DEBUG({
1938bcb0991SDimitry Andric           dbgs() << "      Copying block " << *B << " content, "
1948bcb0991SDimitry Andric                  << B->getContent().size() << " bytes, from "
1958bcb0991SDimitry Andric                  << (const void *)B->getContent().data() << " to "
1968bcb0991SDimitry Andric                  << (const void *)BlockDataPtr << "\n";
1970b57cec5SDimitry Andric         });
1988bcb0991SDimitry Andric         memcpy(BlockDataPtr, B->getContent().data(), B->getContent().size());
1990b57cec5SDimitry Andric 
2008bcb0991SDimitry Andric         // Copy Block data and apply fixups.
2010b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "      Applying fixups.\n");
2028bcb0991SDimitry Andric         for (auto &E : B->edges()) {
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric           // Skip non-relocation edges.
2050b57cec5SDimitry Andric           if (!E.isRelocation())
2060b57cec5SDimitry Andric             continue;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric           // Dispatch to LinkerImpl for fixup.
2098bcb0991SDimitry Andric           if (auto Err = impl().applyFixup(*B, E, BlockDataPtr))
2100b57cec5SDimitry Andric             return Err;
2110b57cec5SDimitry Andric         }
2120b57cec5SDimitry Andric 
2138bcb0991SDimitry Andric         // Point the block's content to the fixed up buffer.
2148bcb0991SDimitry Andric         B->setContent(StringRef(BlockDataPtr, B->getContent().size()));
2150b57cec5SDimitry Andric 
2168bcb0991SDimitry Andric         // Update block end pointer.
2178bcb0991SDimitry Andric         LastBlockEnd = BlockDataPtr + B->getContent().size();
2188bcb0991SDimitry Andric         BlockDataPtr = LastBlockEnd;
2190b57cec5SDimitry Andric       }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric       // Zero pad the rest of the segment.
2220b57cec5SDimitry Andric       LLVM_DEBUG({
2230b57cec5SDimitry Andric         dbgs() << "    Zero padding end of segment from "
2248bcb0991SDimitry Andric                << (const void *)LastBlockEnd << " to "
2250b57cec5SDimitry Andric                << (const void *)((char *)SegMem.data() + SegMem.size()) << "\n";
2260b57cec5SDimitry Andric       });
2278bcb0991SDimitry Andric       while (LastBlockEnd != SegMem.data() + SegMem.size())
2288bcb0991SDimitry Andric         *LastBlockEnd++ = 0;
2290b57cec5SDimitry Andric     }
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric     return Error::success();
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric };
2340b57cec5SDimitry Andric 
2358bcb0991SDimitry Andric /// Removes dead symbols/blocks/addressables.
2360b57cec5SDimitry Andric ///
2378bcb0991SDimitry Andric /// Finds the set of symbols and addressables reachable from any symbol
2388bcb0991SDimitry Andric /// initially marked live. All symbols/addressables not marked live at the end
2398bcb0991SDimitry Andric /// of this process are removed.
2408bcb0991SDimitry Andric void prune(LinkGraph &G);
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric } // end namespace jitlink
2430b57cec5SDimitry Andric } // end namespace llvm
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric #undef DEBUG_TYPE // "jitlink"
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
248