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 | |
36 | namespace llvm { |
37 | namespace orc { |
38 | |
39 | class RTDyldObjectLinkingLayer : public ObjectLayer { |
40 | public: |
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 | |
105 | private: |
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 | |
124 | class LegacyRTDyldObjectLinkingLayerBase { |
125 | public: |
126 | using ObjectPtr = std::unique_ptr<MemoryBuffer>; |
127 | |
128 | protected: |
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. |
176 | class LegacyRTDyldObjectLinkingLayer : public LegacyRTDyldObjectLinkingLayerBase { |
177 | public: |
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 | |
194 | private: |
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 | |
334 | public: |
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 | |
443 | private: |
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 | |