Line data Source code
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 2 : 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 1 : 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 1 : 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 103 : LinkedObject() = default;
140 : LinkedObject(const LinkedObject&) = delete;
141 : void operator=(const LinkedObject&) = delete;
142 24 : 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 608 : JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
153 608 : auto SymEntry = SymbolTable.find(Name);
154 1216 : if (SymEntry == SymbolTable.end())
155 : return nullptr;
156 307 : if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
157 : return nullptr;
158 307 : if (!Finalized)
159 197 : return JITSymbol(getSymbolMaterializer(Name),
160 : SymEntry->second.getFlags());
161 209 : 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 103 : 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 206 : ProcessAllSections)) {
210 103 : buildInitialSymbolTable(PFC->Obj);
211 103 : }
212 :
213 48 : ~ConcreteLinkedObject() override {
214 24 : if (this->Parent.NotifyFreed && ObjForNotify.getBinary())
215 4 : this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
216 :
217 24 : MemMgr->deregisterEHFrames();
218 72 : }
219 24 :
220 : Error finalize() override {
221 : assert(PFC && "mapSectionAddress called on finalized LinkedObject");
222 :
223 : JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
224 24 : nullptr);
225 24 : PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
226 24 : PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
227 4 :
228 : Finalized = true;
229 24 :
230 48 : std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
231 : PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
232 102 :
233 : // Copy the symbol table out of the RuntimeDyld instance.
234 : {
235 102 : auto SymTab = PFC->RTDyld->getSymbolTable();
236 : for (auto &KV : SymTab)
237 102 : SymbolTable[KV.first] = KV.second;
238 102 : }
239 :
240 102 : if (Parent.NotifyLoaded)
241 : Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
242 102 :
243 : PFC->RTDyld->finalizeWithMemoryManagerLocking();
244 :
245 : if (PFC->RTDyld->hasError())
246 : return make_error<StringError>(PFC->RTDyld->getErrorString(),
247 102 : inconvertibleErrorCode());
248 303 :
249 201 : if (Parent.NotifyFinalized)
250 : Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
251 :
252 204 : // Release resources.
253 93 : if (this->Parent.NotifyFreed)
254 : ObjForNotify = std::move(PFC->Obj); // needed for callback
255 102 : PFC = nullptr;
256 : return Error::success();
257 102 : }
258 0 :
259 0 : JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
260 : return [this, Name]() -> Expected<JITTargetAddress> {
261 204 : // The symbol may be materialized between the creation of this lambda
262 97 : // and its execution, so we need to double check.
263 : if (!this->Finalized)
264 : if (auto Err = this->finalize())
265 204 : return std::move(Err);
266 4 : return this->getSymbol(Name, false).getAddress();
267 102 : };
268 : }
269 :
270 : void mapSectionAddress(const void *LocalAddress,
271 98 : 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 98 : for (auto &Symbol : Obj.getBinary()->symbols()) {
280 : if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
281 : continue;
282 0 : Expected<StringRef> SymbolName = Symbol.getName();
283 : // FIXME: Raise an error for bad symbols.
284 : if (!SymbolName) {
285 : consumeError(SymbolName.takeError());
286 0 : continue;
287 0 : }
288 : // FIXME: Raise an error for bad symbols.
289 : auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
290 103 : if (!Flags) {
291 683 : consumeError(Flags.takeError());
292 580 : continue;
293 167 : }
294 : SymbolTable.insert(
295 : std::make_pair(*SymbolName, JITEvaluatedSymbol(0, *Flags)));
296 413 : }
297 0 : }
298 0 :
299 : // Contains the information needed prior to finalization: the object files,
300 : // memory manager, resolver, and flags needed for RuntimeDyld.
301 413 : struct PreFinalizeContents {
302 413 : PreFinalizeContents(OwnedObject Obj,
303 0 : std::shared_ptr<SymbolResolver> Resolver,
304 : bool ProcessAllSections)
305 : : Obj(std::move(Obj)),
306 413 : Resolver(std::move(Resolver)),
307 : ProcessAllSections(ProcessAllSections) {}
308 :
309 103 : OwnedObject Obj;
310 : std::shared_ptr<SymbolResolver> Resolver;
311 : bool ProcessAllSections;
312 : std::unique_ptr<RuntimeDyld> RTDyld;
313 : };
314 0 :
315 : VModuleKey K;
316 : LegacyRTDyldObjectLinkingLayer &Parent;
317 : MemoryManagerPtrT MemMgr;
318 : OwnedObject ObjForNotify;
319 0 : 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 103 : /// 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 85 : /// 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 85 : /// This is kludgy, and may be removed in the future.
362 : void setProcessAllSections(bool ProcessAllSections) {
363 : this->ProcessAllSections = ProcessAllSections;
364 : }
365 170 :
366 85 : /// 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 1 :
376 : auto R = GetResources(K);
377 :
378 : LinkedObjects[K] = createLinkedObject(
379 103 : *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
380 : std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
381 :
382 309 : return Error::success();
383 103 : }
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 206 : /// 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 206 : /// indirectly) will result in undefined behavior. If dependence tracking is
391 103 : /// required to detect or resolve such issues it should be added at a higher
392 103 : /// 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 294 : /// @param K The VModuleKey for the object to search in.
417 472 : /// @param Name The name of the symbol to search for.
418 435 : /// @param ExportedSymbolsOnly If true, search only for exported symbols.
419 79 : /// @return A handle for the given named symbol, if it is found in the
420 178 : /// 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 253 : /// 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 0 : }
442 :
443 : private:
444 0 : ExecutionSession &ES;
445 0 :
446 : std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
447 : ResourcesGetter GetResources;
448 : NotifyLoadedFtor NotifyLoaded;
449 : NotifyFinalizedFtor NotifyFinalized;
450 4 : NotifyFreedFtor NotifyFreed;
451 : bool ProcessAllSections = false;
452 4 : };
453 :
454 : } // end namespace orc
455 : } // end namespace llvm
456 :
457 : #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
|