blob: 8f0d9fa6eb641028f7d8d1ef7186df8f44c83eee [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- 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/Legacy.h"
23#include "llvm/ExecutionEngine/RuntimeDyld.h"
24#include "llvm/Object/ObjectFile.h"
25#include "llvm/Support/Error.h"
26#include <algorithm>
27#include <cassert>
28#include <functional>
29#include <list>
30#include <memory>
31#include <string>
32#include <utility>
33#include <vector>
34
35namespace llvm {
36namespace orc {
37
38class RTDyldObjectLinkingLayerBase {
39public:
40 using ObjectPtr = std::unique_ptr<MemoryBuffer>;
41
42protected:
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 Error 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
84/// @brief Bare bones object linking layer.
85///
86/// This class is intended to be used as the base layer for a JIT. It allows
87/// object files to be loaded into memory, linked, and the addresses of their
88/// symbols queried. All objects added to this layer can see each other's
89/// symbols.
90class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase {
91public:
92
93 using RTDyldObjectLinkingLayerBase::ObjectPtr;
94
95 /// @brief Functor for receiving object-loaded notifications.
96 using NotifyLoadedFtor =
97 std::function<void(VModuleKey, const object::ObjectFile &Obj,
98 const RuntimeDyld::LoadedObjectInfo &)>;
99
100 /// @brief Functor for receiving finalization notifications.
101 using NotifyFinalizedFtor = std::function<void(VModuleKey)>;
102
103private:
104 using OwnedObject = object::OwningBinary<object::ObjectFile>;
105
106 template <typename MemoryManagerPtrT>
107 class ConcreteLinkedObject : public LinkedObject {
108 public:
109 ConcreteLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
110 OwnedObject Obj, MemoryManagerPtrT MemMgr,
111 std::shared_ptr<SymbolResolver> Resolver,
112 bool ProcessAllSections)
113 : MemMgr(std::move(MemMgr)),
114 PFC(llvm::make_unique<PreFinalizeContents>(
115 Parent, std::move(K), std::move(Obj), std::move(Resolver),
116 ProcessAllSections)) {
117 buildInitialSymbolTable(PFC->Obj);
118 }
119
120 ~ConcreteLinkedObject() override {
121 MemMgr->deregisterEHFrames();
122 }
123
124 Error finalize() override {
125 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
126
127 JITSymbolResolverAdapter ResolverAdapter(PFC->Parent.ES, *PFC->Resolver);
128 PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
129 PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
130
131 Finalized = true;
132
133 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
134 PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
135
136 // Copy the symbol table out of the RuntimeDyld instance.
137 {
138 auto SymTab = PFC->RTDyld->getSymbolTable();
139 for (auto &KV : SymTab)
140 SymbolTable[KV.first] = KV.second;
141 }
142
143 if (PFC->Parent.NotifyLoaded)
144 PFC->Parent.NotifyLoaded(PFC->K, *PFC->Obj.getBinary(), *Info);
145
146 PFC->RTDyld->finalizeWithMemoryManagerLocking();
147
148 if (PFC->RTDyld->hasError())
149 return make_error<StringError>(PFC->RTDyld->getErrorString(),
150 inconvertibleErrorCode());
151
152 if (PFC->Parent.NotifyFinalized)
153 PFC->Parent.NotifyFinalized(PFC->K);
154
155 // Release resources.
156 PFC = nullptr;
157 return Error::success();
158 }
159
160 JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
161 return [this, Name]() -> Expected<JITTargetAddress> {
162 // The symbol may be materialized between the creation of this lambda
163 // and its execution, so we need to double check.
164 if (!this->Finalized)
165 if (auto Err = this->finalize())
166 return std::move(Err);
167 return this->getSymbol(Name, false).getAddress();
168 };
169 }
170
171 void mapSectionAddress(const void *LocalAddress,
172 JITTargetAddress TargetAddr) const override {
173 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
174 assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
175 PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
176 }
177
178 private:
179 void buildInitialSymbolTable(const OwnedObject &Obj) {
180 for (auto &Symbol : Obj.getBinary()->symbols()) {
181 if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
182 continue;
183 Expected<StringRef> SymbolName = Symbol.getName();
184 // FIXME: Raise an error for bad symbols.
185 if (!SymbolName) {
186 consumeError(SymbolName.takeError());
187 continue;
188 }
189 auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
190 SymbolTable.insert(
191 std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
192 }
193 }
194
195 // Contains the information needed prior to finalization: the object files,
196 // memory manager, resolver, and flags needed for RuntimeDyld.
197 struct PreFinalizeContents {
198 PreFinalizeContents(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
199 OwnedObject Obj,
200 std::shared_ptr<SymbolResolver> Resolver,
201 bool ProcessAllSections)
202 : Parent(Parent), K(std::move(K)), Obj(std::move(Obj)),
203 Resolver(std::move(Resolver)),
204 ProcessAllSections(ProcessAllSections) {}
205
206 RTDyldObjectLinkingLayer &Parent;
207 VModuleKey K;
208 OwnedObject Obj;
209 std::shared_ptr<SymbolResolver> Resolver;
210 bool ProcessAllSections;
211 std::unique_ptr<RuntimeDyld> RTDyld;
212 };
213
214 MemoryManagerPtrT MemMgr;
215 std::unique_ptr<PreFinalizeContents> PFC;
216 };
217
218 template <typename MemoryManagerPtrT>
219 std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
220 createLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
221 OwnedObject Obj, MemoryManagerPtrT MemMgr,
222 std::shared_ptr<SymbolResolver> Resolver,
223 bool ProcessAllSections) {
224 using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
225 return llvm::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
226 std::move(MemMgr), std::move(Resolver),
227 ProcessAllSections);
228 }
229
230public:
231 struct Resources {
232 std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
233 std::shared_ptr<SymbolResolver> Resolver;
234 };
235
236 using ResourcesGetter = std::function<Resources(VModuleKey)>;
237
238 /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
239 /// and NotifyFinalized functors.
240 RTDyldObjectLinkingLayer(
241 ExecutionSession &ES, ResourcesGetter GetResources,
242 NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
243 NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
244 : ES(ES), GetResources(std::move(GetResources)),
245 NotifyLoaded(std::move(NotifyLoaded)),
246 NotifyFinalized(std::move(NotifyFinalized)), ProcessAllSections(false) {
247 }
248
249 /// @brief Set the 'ProcessAllSections' flag.
250 ///
251 /// If set to true, all sections in each object file will be allocated using
252 /// the memory manager, rather than just the sections required for execution.
253 ///
254 /// This is kludgy, and may be removed in the future.
255 void setProcessAllSections(bool ProcessAllSections) {
256 this->ProcessAllSections = ProcessAllSections;
257 }
258
259 /// @brief Add an object to the JIT.
260 Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
261
262 auto Obj =
263 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
264 if (!Obj)
265 return Obj.takeError();
266
267 assert(!LinkedObjects.count(K) && "VModuleKey already in use");
268
269 auto R = GetResources(K);
270
271 LinkedObjects[K] = createLinkedObject(
272 *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
273 std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
274
275 return Error::success();
276 }
277
278 /// @brief Remove the object associated with VModuleKey K.
279 ///
280 /// All memory allocated for the object will be freed, and the sections and
281 /// symbols it provided will no longer be available. No attempt is made to
282 /// re-emit the missing symbols, and any use of these symbols (directly or
283 /// indirectly) will result in undefined behavior. If dependence tracking is
284 /// required to detect or resolve such issues it should be added at a higher
285 /// layer.
286 Error removeObject(VModuleKey K) {
287 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
288 // How do we invalidate the symbols in H?
289 LinkedObjects.erase(K);
290 return Error::success();
291 }
292
293 /// @brief Search for the given named symbol.
294 /// @param Name The name of the symbol to search for.
295 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
296 /// @return A handle for the given named symbol, if it exists.
297 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
298 for (auto &KV : LinkedObjects)
299 if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
300 return Sym;
301 else if (auto Err = Sym.takeError())
302 return std::move(Err);
303
304 return nullptr;
305 }
306
307 /// @brief Search for the given named symbol in the context of the loaded
308 /// object represented by the VModuleKey K.
309 /// @param K The VModuleKey for the object to search in.
310 /// @param Name The name of the symbol to search for.
311 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
312 /// @return A handle for the given named symbol, if it is found in the
313 /// given object.
314 JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
315 bool ExportedSymbolsOnly) {
316 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
317 return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
318 }
319
320 /// @brief Map section addresses for the object associated with the
321 /// VModuleKey K.
322 void mapSectionAddress(VModuleKey K, const void *LocalAddress,
323 JITTargetAddress TargetAddr) {
324 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
325 LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
326 }
327
328 /// @brief Immediately emit and finalize the object represented by the given
329 /// VModuleKey.
330 /// @param K VModuleKey for object to emit/finalize.
331 Error emitAndFinalize(VModuleKey K) {
332 assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
333 return LinkedObjects[K]->finalize();
334 }
335
336private:
337 ExecutionSession &ES;
338
339 std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
340 ResourcesGetter GetResources;
341 NotifyLoadedFtor NotifyLoaded;
342 NotifyFinalizedFtor NotifyFinalized;
343 bool ProcessAllSections = false;
344};
345
346} // end namespace orc
347} // end namespace llvm
348
349#endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H