1 //===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking ---*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Contains the definition for an RTDyld-based, in-process object linking layer.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
15 #define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
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"
39 class RTDyldObjectLinkingLayer2 : public ObjectLayer {
41 /// Functor for receiving object-loaded notifications.
42 using NotifyLoadedFunction =
43 std::function<void(VModuleKey, const object::ObjectFile &Obj,
44 const RuntimeDyld::LoadedObjectInfo &)>;
46 /// Functor for receiving finalization notifications.
47 using NotifyFinalizedFunction = std::function<void(VModuleKey)>;
49 using GetMemoryManagerFunction =
50 std::function<std::shared_ptr<RuntimeDyld::MemoryManager>(VModuleKey)>;
52 /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
53 /// and NotifyFinalized functors.
54 RTDyldObjectLinkingLayer2(
55 ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager,
56 NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(),
57 NotifyFinalizedFunction NotifyFinalized = NotifyFinalizedFunction());
60 void emit(MaterializationResponsibility R, VModuleKey K,
61 std::unique_ptr<MemoryBuffer> O) override;
63 /// Map section addresses for the object associated with the
65 void mapSectionAddress(VModuleKey K, const void *LocalAddress,
66 JITTargetAddress TargetAddr) const;
68 /// Set the 'ProcessAllSections' flag.
70 /// If set to true, all sections in each object file will be allocated using
71 /// the memory manager, rather than just the sections required for execution.
73 /// This is kludgy, and may be removed in the future.
74 void setProcessAllSections(bool ProcessAllSections) {
75 this->ProcessAllSections = ProcessAllSections;
79 mutable std::mutex RTDyldLayerMutex;
80 GetMemoryManagerFunction GetMemoryManager;
81 NotifyLoadedFunction NotifyLoaded;
82 NotifyFinalizedFunction NotifyFinalized;
83 bool ProcessAllSections;
84 std::map<VModuleKey, RuntimeDyld *> ActiveRTDylds;
85 std::map<VModuleKey, std::shared_ptr<RuntimeDyld::MemoryManager>> MemMgrs;
88 class RTDyldObjectLinkingLayerBase {
90 using ObjectPtr = std::unique_ptr<MemoryBuffer>;
94 /// Holds an object to be allocated/linked as a unit in the JIT.
96 /// An instance of this class will be created for each object added
97 /// via JITObjectLayer::addObject. Deleting the instance (via
98 /// removeObject) frees its memory, removing all symbol definitions that
99 /// had been provided by this instance. Higher level layers are responsible
100 /// for taking any action required to handle the missing symbols.
103 LinkedObject() = default;
104 LinkedObject(const LinkedObject&) = delete;
105 void operator=(const LinkedObject&) = delete;
106 virtual ~LinkedObject() = default;
108 virtual Error finalize() = 0;
110 virtual JITSymbol::GetAddressFtor
111 getSymbolMaterializer(std::string Name) = 0;
113 virtual void mapSectionAddress(const void *LocalAddress,
114 JITTargetAddress TargetAddr) const = 0;
116 JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
117 auto SymEntry = SymbolTable.find(Name);
118 if (SymEntry == SymbolTable.end())
120 if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
123 return JITSymbol(getSymbolMaterializer(Name),
124 SymEntry->second.getFlags());
125 return JITSymbol(SymEntry->second);
129 StringMap<JITEvaluatedSymbol> SymbolTable;
130 bool Finalized = false;
134 /// Bare bones object linking layer.
136 /// This class is intended to be used as the base layer for a JIT. It allows
137 /// object files to be loaded into memory, linked, and the addresses of their
138 /// symbols queried. All objects added to this layer can see each other's
140 class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase {
143 using RTDyldObjectLinkingLayerBase::ObjectPtr;
145 /// Functor for receiving object-loaded notifications.
146 using NotifyLoadedFtor =
147 std::function<void(VModuleKey, const object::ObjectFile &Obj,
148 const RuntimeDyld::LoadedObjectInfo &)>;
150 /// Functor for receiving finalization notifications.
151 using NotifyFinalizedFtor =
152 std::function<void(VModuleKey, const object::ObjectFile &Obj,
153 const RuntimeDyld::LoadedObjectInfo &)>;
155 /// Functor for receiving deallocation notifications.
156 using NotifyFreedFtor = std::function<void(VModuleKey, const object::ObjectFile &Obj)>;
159 using OwnedObject = object::OwningBinary<object::ObjectFile>;
161 template <typename MemoryManagerPtrT>
162 class ConcreteLinkedObject : public LinkedObject {
164 ConcreteLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
165 OwnedObject Obj, MemoryManagerPtrT MemMgr,
166 std::shared_ptr<SymbolResolver> Resolver,
167 bool ProcessAllSections)
170 MemMgr(std::move(MemMgr)),
171 PFC(llvm::make_unique<PreFinalizeContents>(
172 std::move(Obj), std::move(Resolver),
173 ProcessAllSections)) {
174 buildInitialSymbolTable(PFC->Obj);
177 ~ConcreteLinkedObject() override {
178 if (this->Parent.NotifyFreed)
179 this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
181 MemMgr->deregisterEHFrames();
184 Error finalize() override {
185 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
187 JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
189 PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
190 PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
194 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
195 PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
197 // Copy the symbol table out of the RuntimeDyld instance.
199 auto SymTab = PFC->RTDyld->getSymbolTable();
200 for (auto &KV : SymTab)
201 SymbolTable[KV.first] = KV.second;
204 if (Parent.NotifyLoaded)
205 Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
207 PFC->RTDyld->finalizeWithMemoryManagerLocking();
209 if (PFC->RTDyld->hasError())
210 return make_error<StringError>(PFC->RTDyld->getErrorString(),
211 inconvertibleErrorCode());
213 if (Parent.NotifyFinalized)
214 Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
216 // Release resources.
217 if (this->Parent.NotifyFreed)
218 ObjForNotify = std::move(PFC->Obj); // needed for callback
220 return Error::success();
223 JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
224 return [this, Name]() -> Expected<JITTargetAddress> {
225 // The symbol may be materialized between the creation of this lambda
226 // and its execution, so we need to double check.
227 if (!this->Finalized)
228 if (auto Err = this->finalize())
229 return std::move(Err);
230 return this->getSymbol(Name, false).getAddress();
234 void mapSectionAddress(const void *LocalAddress,
235 JITTargetAddress TargetAddr) const override {
236 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
237 assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
238 PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
242 void buildInitialSymbolTable(const OwnedObject &Obj) {
243 for (auto &Symbol : Obj.getBinary()->symbols()) {
244 if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
246 Expected<StringRef> SymbolName = Symbol.getName();
247 // FIXME: Raise an error for bad symbols.
249 consumeError(SymbolName.takeError());
252 auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
254 std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
258 // Contains the information needed prior to finalization: the object files,
259 // memory manager, resolver, and flags needed for RuntimeDyld.
260 struct PreFinalizeContents {
261 PreFinalizeContents(OwnedObject Obj,
262 std::shared_ptr<SymbolResolver> Resolver,
263 bool ProcessAllSections)
264 : Obj(std::move(Obj)),
265 Resolver(std::move(Resolver)),
266 ProcessAllSections(ProcessAllSections) {}
269 std::shared_ptr<SymbolResolver> Resolver;
270 bool ProcessAllSections;
271 std::unique_ptr<RuntimeDyld> RTDyld;
275 RTDyldObjectLinkingLayer &Parent;
276 MemoryManagerPtrT MemMgr;
277 OwnedObject ObjForNotify;
278 std::unique_ptr<PreFinalizeContents> PFC;
281 template <typename MemoryManagerPtrT>
282 std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
283 createLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
284 OwnedObject Obj, MemoryManagerPtrT MemMgr,
285 std::shared_ptr<SymbolResolver> Resolver,
286 bool ProcessAllSections) {
287 using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
288 return llvm::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
289 std::move(MemMgr), std::move(Resolver),
295 std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
296 std::shared_ptr<SymbolResolver> Resolver;
299 using ResourcesGetter = std::function<Resources(VModuleKey)>;
301 /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
302 /// and NotifyFinalized functors.
303 RTDyldObjectLinkingLayer(
304 ExecutionSession &ES, ResourcesGetter GetResources,
305 NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
306 NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
307 NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
308 : ES(ES), GetResources(std::move(GetResources)),
309 NotifyLoaded(std::move(NotifyLoaded)),
310 NotifyFinalized(std::move(NotifyFinalized)),
311 NotifyFreed(std::move(NotifyFreed)),
312 ProcessAllSections(false) {
315 /// Set the 'ProcessAllSections' flag.
317 /// If set to true, all sections in each object file will be allocated using
318 /// the memory manager, rather than just the sections required for execution.
320 /// This is kludgy, and may be removed in the future.
321 void setProcessAllSections(bool ProcessAllSections) {
322 this->ProcessAllSections = ProcessAllSections;
325 /// Add an object to the JIT.
326 Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
329 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
331 return Obj.takeError();
333 assert(!LinkedObjects.count(K) && "VModuleKey already in use");
335 auto R = GetResources(K);
337 LinkedObjects[K] = createLinkedObject(
338 *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
339 std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
341 return Error::success();
344 /// Remove the object associated with VModuleKey K.
346 /// All memory allocated for the object will be freed, and the sections and
347 /// symbols it provided will no longer be available. No attempt is made to
348 /// re-emit the missing symbols, and any use of these symbols (directly or
349 /// indirectly) will result in undefined behavior. If dependence tracking is
350 /// required to detect or resolve such issues it should be added at a higher
352 Error removeObject(VModuleKey K) {
353 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
354 // How do we invalidate the symbols in H?
355 LinkedObjects.erase(K);
356 return Error::success();
359 /// Search for the given named symbol.
360 /// @param Name The name of the symbol to search for.
361 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
362 /// @return A handle for the given named symbol, if it exists.
363 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
364 for (auto &KV : LinkedObjects)
365 if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
367 else if (auto Err = Sym.takeError())
368 return std::move(Err);
373 /// Search for the given named symbol in the context of the loaded
374 /// object represented by the VModuleKey K.
375 /// @param K The VModuleKey for the object to search in.
376 /// @param Name The name of the symbol to search for.
377 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
378 /// @return A handle for the given named symbol, if it is found in the
380 JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
381 bool ExportedSymbolsOnly) {
382 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
383 return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
386 /// Map section addresses for the object associated with the
388 void mapSectionAddress(VModuleKey K, const void *LocalAddress,
389 JITTargetAddress TargetAddr) {
390 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
391 LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
394 /// Immediately emit and finalize the object represented by the given
396 /// @param K VModuleKey for object to emit/finalize.
397 Error emitAndFinalize(VModuleKey K) {
398 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
399 return LinkedObjects[K]->finalize();
403 ExecutionSession &ES;
405 std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
406 ResourcesGetter GetResources;
407 NotifyLoadedFtor NotifyLoaded;
408 NotifyFinalizedFtor NotifyFinalized;
409 NotifyFreedFtor NotifyFreed;
410 bool ProcessAllSections = false;
413 } // end namespace orc
414 } // end namespace llvm
416 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H