121
|
1 //===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking ---*- C++ -*-===//
|
|
2 //
|
|
3 // The LLVM Compiler Infrastructure
|
|
4 //
|
|
5 // This file is distributed under the University of Illinois Open Source
|
|
6 // License. See LICENSE.TXT for details.
|
|
7 //
|
|
8 //===----------------------------------------------------------------------===//
|
|
9 //
|
|
10 // Contains the definition for an RTDyld-based, in-process object linking layer.
|
|
11 //
|
|
12 //===----------------------------------------------------------------------===//
|
|
13
|
|
14 #ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
|
|
15 #define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
|
|
16
|
|
17 #include "llvm/ADT/STLExtras.h"
|
|
18 #include "llvm/ADT/StringMap.h"
|
|
19 #include "llvm/ADT/StringRef.h"
|
|
20 #include "llvm/ExecutionEngine/JITSymbol.h"
|
|
21 #include "llvm/ExecutionEngine/RuntimeDyld.h"
|
|
22 #include "llvm/Object/ObjectFile.h"
|
|
23 #include "llvm/Support/Error.h"
|
|
24 #include <algorithm>
|
|
25 #include <cassert>
|
|
26 #include <functional>
|
|
27 #include <list>
|
|
28 #include <memory>
|
|
29 #include <string>
|
|
30 #include <utility>
|
|
31 #include <vector>
|
|
32
|
|
33 namespace llvm {
|
|
34 namespace orc {
|
|
35
|
|
36 class RTDyldObjectLinkingLayerBase {
|
|
37 public:
|
|
38
|
|
39 using ObjectPtr =
|
|
40 std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
|
|
41
|
|
42 protected:
|
|
43
|
|
44 /// @brief Holds an object to be allocated/linked as a unit in the JIT.
|
|
45 ///
|
|
46 /// An instance of this class will be created for each object added
|
|
47 /// via JITObjectLayer::addObject. Deleting the instance (via
|
|
48 /// removeObject) frees its memory, removing all symbol definitions that
|
|
49 /// had been provided by this instance. Higher level layers are responsible
|
|
50 /// for taking any action required to handle the missing symbols.
|
|
51 class LinkedObject {
|
|
52 public:
|
|
53 LinkedObject() = default;
|
|
54 LinkedObject(const LinkedObject&) = delete;
|
|
55 void operator=(const LinkedObject&) = delete;
|
|
56 virtual ~LinkedObject() = default;
|
|
57
|
|
58 virtual void finalize() = 0;
|
|
59
|
|
60 virtual JITSymbol::GetAddressFtor
|
|
61 getSymbolMaterializer(std::string Name) = 0;
|
|
62
|
|
63 virtual void mapSectionAddress(const void *LocalAddress,
|
|
64 JITTargetAddress TargetAddr) const = 0;
|
|
65
|
|
66 JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
|
|
67 auto SymEntry = SymbolTable.find(Name);
|
|
68 if (SymEntry == SymbolTable.end())
|
|
69 return nullptr;
|
|
70 if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
|
|
71 return nullptr;
|
|
72 if (!Finalized)
|
|
73 return JITSymbol(getSymbolMaterializer(Name),
|
|
74 SymEntry->second.getFlags());
|
|
75 return JITSymbol(SymEntry->second);
|
|
76 }
|
|
77
|
|
78 protected:
|
|
79 StringMap<JITEvaluatedSymbol> SymbolTable;
|
|
80 bool Finalized = false;
|
|
81 };
|
|
82
|
|
83 using LinkedObjectListT = std::list<std::unique_ptr<LinkedObject>>;
|
|
84
|
|
85 public:
|
|
86 /// @brief Handle to a loaded object.
|
|
87 using ObjHandleT = LinkedObjectListT::iterator;
|
|
88 };
|
|
89
|
|
90 /// @brief Bare bones object linking layer.
|
|
91 ///
|
|
92 /// This class is intended to be used as the base layer for a JIT. It allows
|
|
93 /// object files to be loaded into memory, linked, and the addresses of their
|
|
94 /// symbols queried. All objects added to this layer can see each other's
|
|
95 /// symbols.
|
|
96 class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase {
|
|
97 public:
|
|
98
|
|
99 using RTDyldObjectLinkingLayerBase::ObjectPtr;
|
|
100
|
|
101 /// @brief Functor for receiving object-loaded notifications.
|
|
102 using NotifyLoadedFtor =
|
|
103 std::function<void(ObjHandleT, const ObjectPtr &Obj,
|
|
104 const RuntimeDyld::LoadedObjectInfo &)>;
|
|
105
|
|
106 /// @brief Functor for receiving finalization notifications.
|
|
107 using NotifyFinalizedFtor = std::function<void(ObjHandleT)>;
|
|
108
|
|
109 private:
|
|
110
|
|
111
|
|
112 template <typename MemoryManagerPtrT, typename SymbolResolverPtrT,
|
|
113 typename FinalizerFtor>
|
|
114 class ConcreteLinkedObject : public LinkedObject {
|
|
115 public:
|
|
116 ConcreteLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr,
|
|
117 SymbolResolverPtrT Resolver,
|
|
118 FinalizerFtor Finalizer,
|
|
119 bool ProcessAllSections)
|
|
120 : MemMgr(std::move(MemMgr)),
|
|
121 PFC(llvm::make_unique<PreFinalizeContents>(std::move(Obj),
|
|
122 std::move(Resolver),
|
|
123 std::move(Finalizer),
|
|
124 ProcessAllSections)) {
|
|
125 buildInitialSymbolTable(PFC->Obj);
|
|
126 }
|
|
127
|
|
128 ~ConcreteLinkedObject() override {
|
|
129 MemMgr->deregisterEHFrames();
|
|
130 }
|
|
131
|
|
132 void setHandle(ObjHandleT H) {
|
|
133 PFC->Handle = H;
|
|
134 }
|
|
135
|
|
136 void finalize() override {
|
|
137 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
|
|
138
|
|
139 RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver);
|
|
140 RTDyld.setProcessAllSections(PFC->ProcessAllSections);
|
|
141 PFC->RTDyld = &RTDyld;
|
|
142
|
|
143 this->Finalized = true;
|
|
144 PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Obj),
|
|
145 [&]() {
|
|
146 this->updateSymbolTable(RTDyld);
|
|
147 });
|
|
148
|
|
149 // Release resources.
|
|
150 PFC = nullptr;
|
|
151 }
|
|
152
|
|
153 JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
|
|
154 return
|
|
155 [this, Name]() {
|
|
156 // The symbol may be materialized between the creation of this lambda
|
|
157 // and its execution, so we need to double check.
|
|
158 if (!this->Finalized)
|
|
159 this->finalize();
|
|
160 return this->getSymbol(Name, false).getAddress();
|
|
161 };
|
|
162 }
|
|
163
|
|
164 void mapSectionAddress(const void *LocalAddress,
|
|
165 JITTargetAddress TargetAddr) const override {
|
|
166 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
|
|
167 assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
|
|
168 PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
|
|
169 }
|
|
170
|
|
171 private:
|
|
172
|
|
173 void buildInitialSymbolTable(const ObjectPtr &Obj) {
|
|
174 for (auto &Symbol : Obj->getBinary()->symbols()) {
|
|
175 if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
|
|
176 continue;
|
|
177 Expected<StringRef> SymbolName = Symbol.getName();
|
|
178 // FIXME: Raise an error for bad symbols.
|
|
179 if (!SymbolName) {
|
|
180 consumeError(SymbolName.takeError());
|
|
181 continue;
|
|
182 }
|
|
183 auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
|
|
184 SymbolTable.insert(
|
|
185 std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
|
|
186 }
|
|
187 }
|
|
188
|
|
189 void updateSymbolTable(const RuntimeDyld &RTDyld) {
|
|
190 for (auto &SymEntry : SymbolTable)
|
|
191 SymEntry.second = RTDyld.getSymbol(SymEntry.first());
|
|
192 }
|
|
193
|
|
194 // Contains the information needed prior to finalization: the object files,
|
|
195 // memory manager, resolver, and flags needed for RuntimeDyld.
|
|
196 struct PreFinalizeContents {
|
|
197 PreFinalizeContents(ObjectPtr Obj, SymbolResolverPtrT Resolver,
|
|
198 FinalizerFtor Finalizer, bool ProcessAllSections)
|
|
199 : Obj(std::move(Obj)), Resolver(std::move(Resolver)),
|
|
200 Finalizer(std::move(Finalizer)),
|
|
201 ProcessAllSections(ProcessAllSections) {}
|
|
202
|
|
203 ObjectPtr Obj;
|
|
204 SymbolResolverPtrT Resolver;
|
|
205 FinalizerFtor Finalizer;
|
|
206 bool ProcessAllSections;
|
|
207 ObjHandleT Handle;
|
|
208 RuntimeDyld *RTDyld;
|
|
209 };
|
|
210
|
|
211 MemoryManagerPtrT MemMgr;
|
|
212 std::unique_ptr<PreFinalizeContents> PFC;
|
|
213 };
|
|
214
|
|
215 template <typename MemoryManagerPtrT, typename SymbolResolverPtrT,
|
|
216 typename FinalizerFtor>
|
|
217 std::unique_ptr<
|
|
218 ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT, FinalizerFtor>>
|
|
219 createLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr,
|
|
220 SymbolResolverPtrT Resolver,
|
|
221 FinalizerFtor Finalizer,
|
|
222 bool ProcessAllSections) {
|
|
223 using LOS = ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT,
|
|
224 FinalizerFtor>;
|
|
225 return llvm::make_unique<LOS>(std::move(Obj), std::move(MemMgr),
|
|
226 std::move(Resolver), std::move(Finalizer),
|
|
227 ProcessAllSections);
|
|
228 }
|
|
229
|
|
230 public:
|
|
231
|
|
232 /// @brief Functor for creating memory managers.
|
|
233 using MemoryManagerGetter =
|
|
234 std::function<std::shared_ptr<RuntimeDyld::MemoryManager>()>;
|
|
235
|
|
236 /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
|
|
237 /// and NotifyFinalized functors.
|
|
238 RTDyldObjectLinkingLayer(
|
|
239 MemoryManagerGetter GetMemMgr,
|
|
240 NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
|
|
241 NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
|
|
242 : GetMemMgr(GetMemMgr),
|
|
243 NotifyLoaded(std::move(NotifyLoaded)),
|
|
244 NotifyFinalized(std::move(NotifyFinalized)),
|
|
245 ProcessAllSections(false) {}
|
|
246
|
|
247 /// @brief Set the 'ProcessAllSections' flag.
|
|
248 ///
|
|
249 /// If set to true, all sections in each object file will be allocated using
|
|
250 /// the memory manager, rather than just the sections required for execution.
|
|
251 ///
|
|
252 /// This is kludgy, and may be removed in the future.
|
|
253 void setProcessAllSections(bool ProcessAllSections) {
|
|
254 this->ProcessAllSections = ProcessAllSections;
|
|
255 }
|
|
256
|
|
257 /// @brief Add an object to the JIT.
|
|
258 ///
|
|
259 /// @return A handle that can be used to refer to the loaded object (for
|
|
260 /// symbol searching, finalization, freeing memory, etc.).
|
|
261 Expected<ObjHandleT> addObject(ObjectPtr Obj,
|
|
262 std::shared_ptr<JITSymbolResolver> Resolver) {
|
|
263 auto Finalizer = [&](ObjHandleT H, RuntimeDyld &RTDyld,
|
|
264 const ObjectPtr &ObjToLoad,
|
|
265 std::function<void()> LOSHandleLoad) {
|
|
266 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
|
|
267 RTDyld.loadObject(*ObjToLoad->getBinary());
|
|
268
|
|
269 LOSHandleLoad();
|
|
270
|
|
271 if (this->NotifyLoaded)
|
|
272 this->NotifyLoaded(H, ObjToLoad, *Info);
|
|
273
|
|
274 RTDyld.finalizeWithMemoryManagerLocking();
|
|
275
|
|
276 if (this->NotifyFinalized)
|
|
277 this->NotifyFinalized(H);
|
|
278 };
|
|
279
|
|
280 auto LO =
|
|
281 createLinkedObject(std::move(Obj), GetMemMgr(),
|
|
282 std::move(Resolver), std::move(Finalizer),
|
|
283 ProcessAllSections);
|
|
284 // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle
|
|
285 // below.
|
|
286 auto *LOPtr = LO.get();
|
|
287
|
|
288 ObjHandleT Handle = LinkedObjList.insert(LinkedObjList.end(), std::move(LO));
|
|
289 LOPtr->setHandle(Handle);
|
|
290
|
|
291 return Handle;
|
|
292 }
|
|
293
|
|
294 /// @brief Remove the object associated with handle H.
|
|
295 ///
|
|
296 /// All memory allocated for the object will be freed, and the sections and
|
|
297 /// symbols it provided will no longer be available. No attempt is made to
|
|
298 /// re-emit the missing symbols, and any use of these symbols (directly or
|
|
299 /// indirectly) will result in undefined behavior. If dependence tracking is
|
|
300 /// required to detect or resolve such issues it should be added at a higher
|
|
301 /// layer.
|
|
302 Error removeObject(ObjHandleT H) {
|
|
303 // How do we invalidate the symbols in H?
|
|
304 LinkedObjList.erase(H);
|
|
305 return Error::success();
|
|
306 }
|
|
307
|
|
308 /// @brief Search for the given named symbol.
|
|
309 /// @param Name The name of the symbol to search for.
|
|
310 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
|
311 /// @return A handle for the given named symbol, if it exists.
|
|
312 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
|
|
313 for (auto I = LinkedObjList.begin(), E = LinkedObjList.end(); I != E;
|
|
314 ++I)
|
|
315 if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
|
|
316 return Symbol;
|
|
317
|
|
318 return nullptr;
|
|
319 }
|
|
320
|
|
321 /// @brief Search for the given named symbol in the context of the loaded
|
|
322 /// object represented by the handle H.
|
|
323 /// @param H The handle for the object to search in.
|
|
324 /// @param Name The name of the symbol to search for.
|
|
325 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
|
326 /// @return A handle for the given named symbol, if it is found in the
|
|
327 /// given object.
|
|
328 JITSymbol findSymbolIn(ObjHandleT H, StringRef Name,
|
|
329 bool ExportedSymbolsOnly) {
|
|
330 return (*H)->getSymbol(Name, ExportedSymbolsOnly);
|
|
331 }
|
|
332
|
|
333 /// @brief Map section addresses for the object associated with the handle H.
|
|
334 void mapSectionAddress(ObjHandleT H, const void *LocalAddress,
|
|
335 JITTargetAddress TargetAddr) {
|
|
336 (*H)->mapSectionAddress(LocalAddress, TargetAddr);
|
|
337 }
|
|
338
|
|
339 /// @brief Immediately emit and finalize the object represented by the given
|
|
340 /// handle.
|
|
341 /// @param H Handle for object to emit/finalize.
|
|
342 Error emitAndFinalize(ObjHandleT H) {
|
|
343 (*H)->finalize();
|
|
344 return Error::success();
|
|
345 }
|
|
346
|
|
347 private:
|
|
348
|
|
349 LinkedObjectListT LinkedObjList;
|
|
350 MemoryManagerGetter GetMemMgr;
|
|
351 NotifyLoadedFtor NotifyLoaded;
|
|
352 NotifyFinalizedFtor NotifyFinalized;
|
|
353 bool ProcessAllSections = false;
|
|
354 };
|
|
355
|
|
356 } // end namespace orc
|
|
357 } // end namespace llvm
|
|
358
|
|
359 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
|