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/Orc/Core.h"
22#include "llvm/ExecutionEngine/Orc/Layer.h"
23#include "llvm/ExecutionEngine/Orc/Legacy.h"
24#include "llvm/ExecutionEngine/RuntimeDyld.h"
25#include "llvm/Object/ObjectFile.h"
26#include "llvm/Support/Error.h"
27#include <algorithm>
28#include <cassert>
29#include <functional>
30#include <list>
31#include <memory>
32#include <string>
33#include <utility>
34#include <vector>
35
36namespace llvm {
37namespace orc {
38
39class RTDyldObjectLinkingLayer : public ObjectLayer {
40public:
41 /// Functor for receiving object-loaded notifications.
42 using NotifyLoadedFunction =
43 std::function<void(VModuleKey, const object::ObjectFile &Obj,
44 const RuntimeDyld::LoadedObjectInfo &)>;
45
46 /// Functor for receiving finalization notifications.
47 using NotifyEmittedFunction = std::function<void(VModuleKey)>;
48
49 using GetMemoryManagerFunction =
50 std::function<std::unique_ptr<RuntimeDyld::MemoryManager>()>;
51
52 /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
53 /// and NotifyEmitted functors.
54 RTDyldObjectLinkingLayer(
55 ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager,
56 NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(),
57 NotifyEmittedFunction NotifyEmitted = NotifyEmittedFunction());
58
59 /// Emit the object.
60 void emit(MaterializationResponsibility R,
61 std::unique_ptr<MemoryBuffer> O) override;
62
63 /// Set the 'ProcessAllSections' flag.
64 ///
65 /// If set to true, all sections in each object file will be allocated using
66 /// the memory manager, rather than just the sections required for execution.
67 ///
68 /// This is kludgy, and may be removed in the future.
69 RTDyldObjectLinkingLayer &setProcessAllSections(bool ProcessAllSections) {
70 this->ProcessAllSections = ProcessAllSections;
71 return *this;
72 }
73
74 /// Instructs this RTDyldLinkingLayer2 instance to override the symbol flags
75 /// returned by RuntimeDyld for any given object file with the flags supplied
76 /// by the MaterializationResponsibility instance. This is a workaround to
77 /// support symbol visibility in COFF, which does not use the libObject's
78 /// SF_Exported flag. Use only when generating / adding COFF object files.
79 ///
80 /// FIXME: We should be able to remove this if/when COFF properly tracks
81 /// exported symbols.
82 RTDyldObjectLinkingLayer &
83 setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
84 this->OverrideObjectFlags = OverrideObjectFlags;
85 return *this;
86 }
87
88 /// If set, this RTDyldObjectLinkingLayer instance will claim responsibility
89 /// for any symbols provided by a given object file that were not already in
90 /// the MaterializationResponsibility instance. Setting this flag allows
91 /// higher-level program representations (e.g. LLVM IR) to be added based on
92 /// only a subset of the symbols they provide, without having to write
93 /// intervening layers to scan and add the additional symbols. This trades
94 /// diagnostic quality for convenience however: If all symbols are enumerated
95 /// up-front then clashes can be detected and reported early (and usually
96 /// deterministically). If this option is set, clashes for the additional
97 /// symbols may not be detected until late, and detection may depend on
98 /// the flow of control through JIT'd code. Use with care.
99 RTDyldObjectLinkingLayer &
100 setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
101 this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
102 return *this;
103 }
104
105private:
106 Error onObjLoad(VModuleKey K, MaterializationResponsibility &R,
107 object::ObjectFile &Obj,
108 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,
109 std::map<StringRef, JITEvaluatedSymbol> Resolved,
110 std::set<StringRef> &InternalSymbols);
111
112 void onObjEmit(VModuleKey K, MaterializationResponsibility &R, Error Err);
113
114 mutable std::mutex RTDyldLayerMutex;
115 GetMemoryManagerFunction GetMemoryManager;
116 NotifyLoadedFunction NotifyLoaded;
117 NotifyEmittedFunction NotifyEmitted;
118 bool ProcessAllSections = false;
119 bool OverrideObjectFlags = false;
120 bool AutoClaimObjectSymbols = false;
121 std::vector<std::unique_ptr<RuntimeDyld::MemoryManager>> MemMgrs;
122};
123
124class LegacyRTDyldObjectLinkingLayerBase {
125public:
126 using ObjectPtr = std::unique_ptr<MemoryBuffer>;
127
128protected:
129
130 /// Holds an object to be allocated/linked as a unit in the JIT.
131 ///
132 /// An instance of this class will be created for each object added
133 /// via JITObjectLayer::addObject. Deleting the instance (via
134 /// removeObject) frees its memory, removing all symbol definitions that
135 /// had been provided by this instance. Higher level layers are responsible
136 /// for taking any action required to handle the missing symbols.
137 class LinkedObject {
138 public:
139 LinkedObject() = default;
140 LinkedObject(const LinkedObject&) = delete;
141 void operator=(const LinkedObject&) = delete;
142 virtual ~LinkedObject() = default;
143
144 virtual Error finalize() = 0;
145
146 virtual JITSymbol::GetAddressFtor
147 getSymbolMaterializer(std::string Name) = 0;
148
149 virtual void mapSectionAddress(const void *LocalAddress,
150 JITTargetAddress TargetAddr) const = 0;
151
152 JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
153 auto SymEntry = SymbolTable.find(Name);
154 if (SymEntry == SymbolTable.end())
155 return nullptr;
156 if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
157 return nullptr;
158 if (!Finalized)
159 return JITSymbol(getSymbolMaterializer(Name),
160 SymEntry->second.getFlags());
161 return JITSymbol(SymEntry->second);
162 }
163
164 protected:
165 StringMap<JITEvaluatedSymbol> SymbolTable;
166 bool Finalized = false;
167 };
168};
169
170/// Bare bones object linking layer.
171///
172/// This class is intended to be used as the base layer for a JIT. It allows
173/// object files to be loaded into memory, linked, and the addresses of their
174/// symbols queried. All objects added to this layer can see each other's
175/// symbols.
176class LegacyRTDyldObjectLinkingLayer : public LegacyRTDyldObjectLinkingLayerBase {
177public:
178
179 using LegacyRTDyldObjectLinkingLayerBase::ObjectPtr;
180
181 /// Functor for receiving object-loaded notifications.
182 using NotifyLoadedFtor =
183 std::function<void(VModuleKey, const object::ObjectFile &Obj,
184 const RuntimeDyld::LoadedObjectInfo &)>;
185
186 /// Functor for receiving finalization notifications.
187 using NotifyFinalizedFtor =
188 std::function<void(VModuleKey, const object::ObjectFile &Obj,
189 const RuntimeDyld::LoadedObjectInfo &)>;
190
191 /// Functor for receiving deallocation notifications.
192 using NotifyFreedFtor = std::function<void(VModuleKey, const object::ObjectFile &Obj)>;
193
194private:
195 using OwnedObject = object::OwningBinary<object::ObjectFile>;
196
197 template <typename MemoryManagerPtrT>
198 class ConcreteLinkedObject : public LinkedObject {
199 public:
200 ConcreteLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K,
201 OwnedObject Obj, MemoryManagerPtrT MemMgr,
202 std::shared_ptr<SymbolResolver> Resolver,
203 bool ProcessAllSections)
204 : K(std::move(K)),
205 Parent(Parent),
206 MemMgr(std::move(MemMgr)),
207 PFC(llvm::make_unique<PreFinalizeContents>(
208 std::move(Obj), std::move(Resolver),
209 ProcessAllSections)) {
210 buildInitialSymbolTable(PFC->Obj);
211 }
212
213 ~ConcreteLinkedObject() override {
214 if (this->Parent.NotifyFreed && ObjForNotify.getBinary())
215 this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
216
217 MemMgr->deregisterEHFrames();
218 }
219
220 Error finalize() override {
221 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
222
223 JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
224 nullptr);
225 PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
226 PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
227
228 Finalized = true;
229
230 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
231 PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
232
233 // Copy the symbol table out of the RuntimeDyld instance.
234 {
235 auto SymTab = PFC->RTDyld->getSymbolTable();
236 for (auto &KV : SymTab)
237 SymbolTable[KV.first] = KV.second;
238 }
239
240 if (Parent.NotifyLoaded)
241 Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
242
243 PFC->RTDyld->finalizeWithMemoryManagerLocking();
244
245 if (PFC->RTDyld->hasError())
246 return make_error<StringError>(PFC->RTDyld->getErrorString(),
247 inconvertibleErrorCode());
248
249 if (Parent.NotifyFinalized)
250 Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
251
252 // Release resources.
253 if (this->Parent.NotifyFreed)
254 ObjForNotify = std::move(PFC->Obj); // needed for callback
255 PFC = nullptr;
256 return Error::success();
257 }
258
259 JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
260 return [this, Name]() -> Expected<JITTargetAddress> {
261 // The symbol may be materialized between the creation of this lambda
262 // and its execution, so we need to double check.
263 if (!this->Finalized)
264 if (auto Err = this->finalize())
265 return std::move(Err);
266 return this->getSymbol(Name, false).getAddress();
267 };
268 }
269
270 void mapSectionAddress(const void *LocalAddress,
271 JITTargetAddress TargetAddr) const override {
272 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
273 assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
274 PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
275 }
276
277 private:
278 void buildInitialSymbolTable(const OwnedObject &Obj) {
279 for (auto &Symbol : Obj.getBinary()->symbols()) {
280 if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
281 continue;
282 Expected<StringRef> SymbolName = Symbol.getName();
283 // FIXME: Raise an error for bad symbols.
284 if (!SymbolName) {
285 consumeError(SymbolName.takeError());
286 continue;
287 }
288 // FIXME: Raise an error for bad symbols.
289 auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
290 if (!Flags) {
291 consumeError(Flags.takeError());
292 continue;
293 }
294 SymbolTable.insert(
295 std::make_pair(*SymbolName, JITEvaluatedSymbol(0, *Flags)));
296 }
297 }
298
299 // Contains the information needed prior to finalization: the object files,
300 // memory manager, resolver, and flags needed for RuntimeDyld.
301 struct PreFinalizeContents {
302 PreFinalizeContents(OwnedObject Obj,
303 std::shared_ptr<SymbolResolver> Resolver,
304 bool ProcessAllSections)
305 : Obj(std::move(Obj)),
306 Resolver(std::move(Resolver)),
307 ProcessAllSections(ProcessAllSections) {}
308
309 OwnedObject Obj;
310 std::shared_ptr<SymbolResolver> Resolver;
311 bool ProcessAllSections;
312 std::unique_ptr<RuntimeDyld> RTDyld;
313 };
314
315 VModuleKey K;
316 LegacyRTDyldObjectLinkingLayer &Parent;
317 MemoryManagerPtrT MemMgr;
318 OwnedObject ObjForNotify;
319 std::unique_ptr<PreFinalizeContents> PFC;
320 };
321
322 template <typename MemoryManagerPtrT>
323 std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
324 createLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K,
325 OwnedObject Obj, MemoryManagerPtrT MemMgr,
326 std::shared_ptr<SymbolResolver> Resolver,
327 bool ProcessAllSections) {
328 using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
329 return llvm::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
330 std::move(MemMgr), std::move(Resolver),
331 ProcessAllSections);
332 }
333
334public:
335 struct Resources {
336 std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
337 std::shared_ptr<SymbolResolver> Resolver;
338 };
339
340 using ResourcesGetter = std::function<Resources(VModuleKey)>;
341
342 /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
343 /// and NotifyFinalized functors.
344 LegacyRTDyldObjectLinkingLayer(
345 ExecutionSession &ES, ResourcesGetter GetResources,
346 NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
347 NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
348 NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
349 : ES(ES), GetResources(std::move(GetResources)),
350 NotifyLoaded(std::move(NotifyLoaded)),
351 NotifyFinalized(std::move(NotifyFinalized)),
352 NotifyFreed(std::move(NotifyFreed)),
353 ProcessAllSections(false) {
354 }
355
356 /// Set the 'ProcessAllSections' flag.
357 ///
358 /// If set to true, all sections in each object file will be allocated using
359 /// the memory manager, rather than just the sections required for execution.
360 ///
361 /// This is kludgy, and may be removed in the future.
362 void setProcessAllSections(bool ProcessAllSections) {
363 this->ProcessAllSections = ProcessAllSections;
364 }
365
366 /// Add an object to the JIT.
367 Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
368
369 auto Obj =
370 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
371 if (!Obj)
372 return Obj.takeError();
373
374 assert(!LinkedObjects.count(K) && "VModuleKey already in use");
375
376 auto R = GetResources(K);
377
378 LinkedObjects[K] = createLinkedObject(
379 *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
380 std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
381
382 return Error::success();
383 }
384
385 /// Remove the object associated with VModuleKey K.
386 ///
387 /// All memory allocated for the object will be freed, and the sections and
388 /// symbols it provided will no longer be available. No attempt is made to
389 /// re-emit the missing symbols, and any use of these symbols (directly or
390 /// indirectly) will result in undefined behavior. If dependence tracking is
391 /// required to detect or resolve such issues it should be added at a higher
392 /// layer.
393 Error removeObject(VModuleKey K) {
394 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
395 // How do we invalidate the symbols in H?
396 LinkedObjects.erase(K);
397 return Error::success();
398 }
399
400 /// Search for the given named symbol.
401 /// @param Name The name of the symbol to search for.
402 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
403 /// @return A handle for the given named symbol, if it exists.
404 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
405 for (auto &KV : LinkedObjects)
406 if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
407 return Sym;
408 else if (auto Err = Sym.takeError())
409 return std::move(Err);
410
411 return nullptr;
412 }
413
414 /// Search for the given named symbol in the context of the loaded
415 /// object represented by the VModuleKey K.
416 /// @param K The VModuleKey for the object to search in.
417 /// @param Name The name of the symbol to search for.
418 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
419 /// @return A handle for the given named symbol, if it is found in the
420 /// given object.
421 JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
422 bool ExportedSymbolsOnly) {
423 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
424 return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
425 }
426
427 /// Map section addresses for the object associated with the
428 /// VModuleKey K.
429 void mapSectionAddress(VModuleKey K, const void *LocalAddress,
430 JITTargetAddress TargetAddr) {
431 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
432 LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
433 }
434
435 /// Immediately emit and finalize the object represented by the given
436 /// VModuleKey.
437 /// @param K VModuleKey for object to emit/finalize.
438 Error emitAndFinalize(VModuleKey K) {
439 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
440 return LinkedObjects[K]->finalize();
441 }
442
443private:
444 ExecutionSession &ES;
445
446 ResourcesGetter GetResources;
447 NotifyLoadedFtor NotifyLoaded;
448 NotifyFinalizedFtor NotifyFinalized;
449 NotifyFreedFtor NotifyFreed;
450
451 // NB! `LinkedObjects` needs to be destroyed before `NotifyFreed` because
452 // `~ConcreteLinkedObject` calls `NotifyFreed`
453 std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
454 bool ProcessAllSections = false;
455};
456
457} // end namespace orc
458} // end namespace llvm
459
460#endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
461