xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
14*0b57cec5SDimitry Andric #define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
17*0b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18*0b57cec5SDimitry Andric 
19*0b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink"
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric namespace llvm {
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric class MemoryBufferRef;
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric namespace jitlink {
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric /// Base class for a JIT linker.
28*0b57cec5SDimitry Andric ///
29*0b57cec5SDimitry Andric /// A JITLinkerBase instance links one object file into an ongoing JIT
30*0b57cec5SDimitry Andric /// session. Symbol resolution and finalization operations are pluggable,
31*0b57cec5SDimitry Andric /// and called using continuation passing (passing a continuation for the
32*0b57cec5SDimitry Andric /// remaining linker work) to allow them to be performed asynchronously.
33*0b57cec5SDimitry Andric class JITLinkerBase {
34*0b57cec5SDimitry Andric public:
35*0b57cec5SDimitry Andric   JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, PassConfiguration Passes)
36*0b57cec5SDimitry Andric       : Ctx(std::move(Ctx)), Passes(std::move(Passes)) {
37*0b57cec5SDimitry Andric     assert(this->Ctx && "Ctx can not be null");
38*0b57cec5SDimitry Andric   }
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric   virtual ~JITLinkerBase();
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric protected:
43*0b57cec5SDimitry Andric   struct SegmentLayout {
44*0b57cec5SDimitry Andric     using SectionAtomsList = std::vector<DefinedAtom *>;
45*0b57cec5SDimitry Andric     struct SectionLayout {
46*0b57cec5SDimitry Andric       SectionLayout(Section &S) : S(&S) {}
47*0b57cec5SDimitry Andric 
48*0b57cec5SDimitry Andric       Section *S;
49*0b57cec5SDimitry Andric       SectionAtomsList Atoms;
50*0b57cec5SDimitry Andric     };
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric     using SectionLayoutList = std::vector<SectionLayout>;
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric     SectionLayoutList ContentSections;
55*0b57cec5SDimitry Andric     SectionLayoutList ZeroFillSections;
56*0b57cec5SDimitry Andric   };
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric   using SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>;
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric   // Phase 1:
61*0b57cec5SDimitry Andric   //   1.1: Build atom graph
62*0b57cec5SDimitry Andric   //   1.2: Run pre-prune passes
63*0b57cec5SDimitry Andric   //   1.2: Prune graph
64*0b57cec5SDimitry Andric   //   1.3: Run post-prune passes
65*0b57cec5SDimitry Andric   //   1.4: Sort atoms into segments
66*0b57cec5SDimitry Andric   //   1.5: Allocate segment memory
67*0b57cec5SDimitry Andric   //   1.6: Identify externals and make an async call to resolve function
68*0b57cec5SDimitry Andric   void linkPhase1(std::unique_ptr<JITLinkerBase> Self);
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric   // Phase 2:
71*0b57cec5SDimitry Andric   //   2.1: Apply resolution results
72*0b57cec5SDimitry Andric   //   2.2: Fix up atom contents
73*0b57cec5SDimitry Andric   //   2.3: Call OnResolved callback
74*0b57cec5SDimitry Andric   //   2.3: Make an async call to transfer and finalize memory.
75*0b57cec5SDimitry Andric   void linkPhase2(std::unique_ptr<JITLinkerBase> Self,
76*0b57cec5SDimitry Andric                   Expected<AsyncLookupResult> LookupResult);
77*0b57cec5SDimitry Andric 
78*0b57cec5SDimitry Andric   // Phase 3:
79*0b57cec5SDimitry Andric   //   3.1: Call OnFinalized callback, handing off allocation.
80*0b57cec5SDimitry Andric   void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err);
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric   // Build a graph from the given object buffer.
83*0b57cec5SDimitry Andric   // To be implemented by the client.
84*0b57cec5SDimitry Andric   virtual Expected<std::unique_ptr<AtomGraph>>
85*0b57cec5SDimitry Andric   buildGraph(MemoryBufferRef ObjBuffer) = 0;
86*0b57cec5SDimitry Andric 
87*0b57cec5SDimitry Andric   // For debug dumping of the atom graph.
88*0b57cec5SDimitry Andric   virtual StringRef getEdgeKindName(Edge::Kind K) const = 0;
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric private:
91*0b57cec5SDimitry Andric   // Run all passes in the given pass list, bailing out immediately if any pass
92*0b57cec5SDimitry Andric   // returns an error.
93*0b57cec5SDimitry Andric   Error runPasses(AtomGraphPassList &Passes, AtomGraph &G);
94*0b57cec5SDimitry Andric 
95*0b57cec5SDimitry Andric   // Copy atom contents and apply relocations.
96*0b57cec5SDimitry Andric   // Implemented in JITLinker.
97*0b57cec5SDimitry Andric   virtual Error
98*0b57cec5SDimitry Andric   copyAndFixUpAllAtoms(const SegmentLayoutMap &Layout,
99*0b57cec5SDimitry Andric                        JITLinkMemoryManager::Allocation &Alloc) const = 0;
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric   void layOutAtoms();
102*0b57cec5SDimitry Andric   Error allocateSegments(const SegmentLayoutMap &Layout);
103*0b57cec5SDimitry Andric   DenseSet<StringRef> getExternalSymbolNames() const;
104*0b57cec5SDimitry Andric   void applyLookupResult(AsyncLookupResult LR);
105*0b57cec5SDimitry Andric   void deallocateAndBailOut(Error Err);
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric   void dumpGraph(raw_ostream &OS);
108*0b57cec5SDimitry Andric 
109*0b57cec5SDimitry Andric   std::unique_ptr<JITLinkContext> Ctx;
110*0b57cec5SDimitry Andric   PassConfiguration Passes;
111*0b57cec5SDimitry Andric   std::unique_ptr<AtomGraph> G;
112*0b57cec5SDimitry Andric   SegmentLayoutMap Layout;
113*0b57cec5SDimitry Andric   std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc;
114*0b57cec5SDimitry Andric };
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric template <typename LinkerImpl> class JITLinker : public JITLinkerBase {
117*0b57cec5SDimitry Andric public:
118*0b57cec5SDimitry Andric   using JITLinkerBase::JITLinkerBase;
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric   /// Link constructs a LinkerImpl instance and calls linkPhase1.
121*0b57cec5SDimitry Andric   /// Link should be called with the constructor arguments for LinkerImpl, which
122*0b57cec5SDimitry Andric   /// will be forwarded to the constructor.
123*0b57cec5SDimitry Andric   template <typename... ArgTs> static void link(ArgTs &&... Args) {
124*0b57cec5SDimitry Andric     auto L = llvm::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...);
125*0b57cec5SDimitry Andric 
126*0b57cec5SDimitry Andric     // Ownership of the linker is passed into the linker's doLink function to
127*0b57cec5SDimitry Andric     // allow it to be passed on to async continuations.
128*0b57cec5SDimitry Andric     //
129*0b57cec5SDimitry Andric     // FIXME: Remove LTmp once we have c++17.
130*0b57cec5SDimitry Andric     // C++17 sequencing rules guarantee that function name expressions are
131*0b57cec5SDimitry Andric     // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be
132*0b57cec5SDimitry Andric     // well formed.
133*0b57cec5SDimitry Andric     auto &LTmp = *L;
134*0b57cec5SDimitry Andric     LTmp.linkPhase1(std::move(L));
135*0b57cec5SDimitry Andric   }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric private:
138*0b57cec5SDimitry Andric   const LinkerImpl &impl() const {
139*0b57cec5SDimitry Andric     return static_cast<const LinkerImpl &>(*this);
140*0b57cec5SDimitry Andric   }
141*0b57cec5SDimitry Andric 
142*0b57cec5SDimitry Andric   Error
143*0b57cec5SDimitry Andric   copyAndFixUpAllAtoms(const SegmentLayoutMap &Layout,
144*0b57cec5SDimitry Andric                        JITLinkMemoryManager::Allocation &Alloc) const override {
145*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Copying and fixing up atoms:\n");
146*0b57cec5SDimitry Andric     for (auto &KV : Layout) {
147*0b57cec5SDimitry Andric       auto &Prot = KV.first;
148*0b57cec5SDimitry Andric       auto &SegLayout = KV.second;
149*0b57cec5SDimitry Andric 
150*0b57cec5SDimitry Andric       auto SegMem = Alloc.getWorkingMemory(
151*0b57cec5SDimitry Andric           static_cast<sys::Memory::ProtectionFlags>(Prot));
152*0b57cec5SDimitry Andric       char *LastAtomEnd = SegMem.data();
153*0b57cec5SDimitry Andric       char *AtomDataPtr = LastAtomEnd;
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric       LLVM_DEBUG({
156*0b57cec5SDimitry Andric         dbgs() << "  Processing segment "
157*0b57cec5SDimitry Andric                << static_cast<sys::Memory::ProtectionFlags>(Prot) << " [ "
158*0b57cec5SDimitry Andric                << (const void *)SegMem.data() << " .. "
159*0b57cec5SDimitry Andric                << (const void *)((char *)SegMem.data() + SegMem.size())
160*0b57cec5SDimitry Andric                << " ]\n    Processing content sections:\n";
161*0b57cec5SDimitry Andric       });
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric       for (auto &SI : SegLayout.ContentSections) {
164*0b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "    " << SI.S->getName() << ":\n");
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric         AtomDataPtr += alignmentAdjustment(AtomDataPtr, SI.S->getAlignment());
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric         LLVM_DEBUG({
169*0b57cec5SDimitry Andric           dbgs() << "      Bumped atom pointer to " << (const void *)AtomDataPtr
170*0b57cec5SDimitry Andric                  << " to meet section alignment "
171*0b57cec5SDimitry Andric                  << " of " << SI.S->getAlignment() << "\n";
172*0b57cec5SDimitry Andric         });
173*0b57cec5SDimitry Andric 
174*0b57cec5SDimitry Andric         for (auto *DA : SI.Atoms) {
175*0b57cec5SDimitry Andric 
176*0b57cec5SDimitry Andric           // Align.
177*0b57cec5SDimitry Andric           AtomDataPtr += alignmentAdjustment(AtomDataPtr, DA->getAlignment());
178*0b57cec5SDimitry Andric           LLVM_DEBUG({
179*0b57cec5SDimitry Andric             dbgs() << "      Bumped atom pointer to "
180*0b57cec5SDimitry Andric                    << (const void *)AtomDataPtr << " to meet alignment of "
181*0b57cec5SDimitry Andric                    << DA->getAlignment() << "\n";
182*0b57cec5SDimitry Andric           });
183*0b57cec5SDimitry Andric 
184*0b57cec5SDimitry Andric           // Zero pad up to alignment.
185*0b57cec5SDimitry Andric           LLVM_DEBUG({
186*0b57cec5SDimitry Andric             if (LastAtomEnd != AtomDataPtr)
187*0b57cec5SDimitry Andric               dbgs() << "      Zero padding from " << (const void *)LastAtomEnd
188*0b57cec5SDimitry Andric                      << " to " << (const void *)AtomDataPtr << "\n";
189*0b57cec5SDimitry Andric           });
190*0b57cec5SDimitry Andric           while (LastAtomEnd != AtomDataPtr)
191*0b57cec5SDimitry Andric             *LastAtomEnd++ = 0;
192*0b57cec5SDimitry Andric 
193*0b57cec5SDimitry Andric           // Copy initial atom content.
194*0b57cec5SDimitry Andric           LLVM_DEBUG({
195*0b57cec5SDimitry Andric             dbgs() << "      Copying atom " << *DA << " content, "
196*0b57cec5SDimitry Andric                    << DA->getContent().size() << " bytes, from "
197*0b57cec5SDimitry Andric                    << (const void *)DA->getContent().data() << " to "
198*0b57cec5SDimitry Andric                    << (const void *)AtomDataPtr << "\n";
199*0b57cec5SDimitry Andric           });
200*0b57cec5SDimitry Andric           memcpy(AtomDataPtr, DA->getContent().data(), DA->getContent().size());
201*0b57cec5SDimitry Andric 
202*0b57cec5SDimitry Andric           // Copy atom data and apply fixups.
203*0b57cec5SDimitry Andric           LLVM_DEBUG(dbgs() << "      Applying fixups.\n");
204*0b57cec5SDimitry Andric           for (auto &E : DA->edges()) {
205*0b57cec5SDimitry Andric 
206*0b57cec5SDimitry Andric             // Skip non-relocation edges.
207*0b57cec5SDimitry Andric             if (!E.isRelocation())
208*0b57cec5SDimitry Andric               continue;
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric             // Dispatch to LinkerImpl for fixup.
211*0b57cec5SDimitry Andric             if (auto Err = impl().applyFixup(*DA, E, AtomDataPtr))
212*0b57cec5SDimitry Andric               return Err;
213*0b57cec5SDimitry Andric           }
214*0b57cec5SDimitry Andric 
215*0b57cec5SDimitry Andric           // Point the atom's content to the fixed up buffer.
216*0b57cec5SDimitry Andric           DA->setContent(StringRef(AtomDataPtr, DA->getContent().size()));
217*0b57cec5SDimitry Andric 
218*0b57cec5SDimitry Andric           // Update atom end pointer.
219*0b57cec5SDimitry Andric           LastAtomEnd = AtomDataPtr + DA->getContent().size();
220*0b57cec5SDimitry Andric           AtomDataPtr = LastAtomEnd;
221*0b57cec5SDimitry Andric         }
222*0b57cec5SDimitry Andric       }
223*0b57cec5SDimitry Andric 
224*0b57cec5SDimitry Andric       // Zero pad the rest of the segment.
225*0b57cec5SDimitry Andric       LLVM_DEBUG({
226*0b57cec5SDimitry Andric         dbgs() << "    Zero padding end of segment from "
227*0b57cec5SDimitry Andric                << (const void *)LastAtomEnd << " to "
228*0b57cec5SDimitry Andric                << (const void *)((char *)SegMem.data() + SegMem.size()) << "\n";
229*0b57cec5SDimitry Andric       });
230*0b57cec5SDimitry Andric       while (LastAtomEnd != SegMem.data() + SegMem.size())
231*0b57cec5SDimitry Andric         *LastAtomEnd++ = 0;
232*0b57cec5SDimitry Andric     }
233*0b57cec5SDimitry Andric 
234*0b57cec5SDimitry Andric     return Error::success();
235*0b57cec5SDimitry Andric   }
236*0b57cec5SDimitry Andric };
237*0b57cec5SDimitry Andric 
238*0b57cec5SDimitry Andric /// Dead strips and replaces discarded definitions with external atoms.
239*0b57cec5SDimitry Andric ///
240*0b57cec5SDimitry Andric /// Finds the set of nodes reachable from any node initially marked live
241*0b57cec5SDimitry Andric /// (nodes marked should-discard are treated as not live, even if they are
242*0b57cec5SDimitry Andric /// reachable). All nodes not marked as live at the end of this process,
243*0b57cec5SDimitry Andric /// are deleted. Nodes that are live, but marked should-discard are replaced
244*0b57cec5SDimitry Andric /// with external atoms and all edges to them are re-written.
245*0b57cec5SDimitry Andric void prune(AtomGraph &G);
246*0b57cec5SDimitry Andric 
247*0b57cec5SDimitry Andric Error addEHFrame(AtomGraph &G, Section &EHFrameSection,
248*0b57cec5SDimitry Andric                  StringRef EHFrameContent, JITTargetAddress EHFrameAddress,
249*0b57cec5SDimitry Andric                  Edge::Kind FDEToCIERelocKind, Edge::Kind FDEToTargetRelocKind);
250*0b57cec5SDimitry Andric 
251*0b57cec5SDimitry Andric } // end namespace jitlink
252*0b57cec5SDimitry Andric } // end namespace llvm
253*0b57cec5SDimitry Andric 
254*0b57cec5SDimitry Andric #undef DEBUG_TYPE // "jitlink"
255*0b57cec5SDimitry Andric 
256*0b57cec5SDimitry Andric #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
257