1 //===- ObjectLinkingLayer.h - Add object files to a JIT process -*- 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 the object layer of the JIT.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
15 #define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
17 #include "JITSymbol.h"
18 #include "llvm/ExecutionEngine/ExecutionEngine.h"
19 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
26 class ObjectLinkingLayerBase {
29 /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT.
31 /// An instance of this class will be created for each set of objects added
32 /// via JITObjectLayer::addObjectSet. Deleting the instance (via
33 /// removeObjectSet) frees its memory, removing all symbol definitions that
34 /// had been provided by this instance. Higher level layers are responsible
35 /// for taking any action required to handle the missing symbols.
36 class LinkedObjectSet {
37 LinkedObjectSet(const LinkedObjectSet&) = delete;
38 void operator=(const LinkedObjectSet&) = delete;
40 LinkedObjectSet(RuntimeDyld::MemoryManager &MemMgr,
41 RuntimeDyld::SymbolResolver &Resolver)
42 : RTDyld(llvm::make_unique<RuntimeDyld>(MemMgr, Resolver)),
45 virtual ~LinkedObjectSet() {}
47 std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
48 addObject(const object::ObjectFile &Obj) {
49 return RTDyld->loadObject(Obj);
52 RuntimeDyld::SymbolInfo getSymbol(StringRef Name) const {
53 return RTDyld->getSymbol(Name);
56 bool NeedsFinalization() const { return (State == Raw); }
58 virtual void Finalize() = 0;
60 void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) {
61 assert((State != Finalized) &&
62 "Attempting to remap sections for finalized objects.");
63 RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
66 void takeOwnershipOfBuffer(std::unique_ptr<MemoryBuffer> B) {
67 OwnedBuffers.push_back(std::move(B));
71 std::unique_ptr<RuntimeDyld> RTDyld;
72 enum { Raw, Finalizing, Finalized } State;
74 // FIXME: This ownership hack only exists because RuntimeDyldELF still
75 // wants to be able to inspect the original object when resolving
76 // relocations. As soon as that can be fixed this should be removed.
77 std::vector<std::unique_ptr<MemoryBuffer>> OwnedBuffers;
80 typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT;
83 /// @brief Handle to a set of loaded objects.
84 typedef LinkedObjectSetListT::iterator ObjSetHandleT;
87 // FIXME: Remove this as soon as RuntimeDyldELF can apply relocations without
88 // referencing the original object.
89 template <typename OwningMBSet>
90 void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
92 (*H)->takeOwnershipOfBuffer(std::move(MB));
97 /// @brief Default (no-op) action to perform when loading objects.
98 class DoNothingOnNotifyLoaded {
100 template <typename ObjSetT, typename LoadResult>
101 void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
102 const LoadResult &) {}
105 /// @brief Bare bones object linking layer.
107 /// This class is intended to be used as the base layer for a JIT. It allows
108 /// object files to be loaded into memory, linked, and the addresses of their
109 /// symbols queried. All objects added to this layer can see each other's
111 template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded>
112 class ObjectLinkingLayer : public ObjectLinkingLayerBase {
115 template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
116 class ConcreteLinkedObjectSet : public LinkedObjectSet {
118 ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr,
119 SymbolResolverPtrT Resolver)
120 : LinkedObjectSet(*MemMgr, *Resolver), MemMgr(std::move(MemMgr)),
121 Resolver(std::move(Resolver)) { }
123 void Finalize() override {
125 RTDyld->resolveRelocations();
126 RTDyld->registerEHFrames();
127 MemMgr->finalizeMemory();
128 OwnedBuffers.clear();
133 MemoryManagerPtrT MemMgr;
134 SymbolResolverPtrT Resolver;
137 template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
138 std::unique_ptr<LinkedObjectSet>
139 createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) {
140 typedef ConcreteLinkedObjectSet<MemoryManagerPtrT, SymbolResolverPtrT> LOS;
141 return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver));
146 /// @brief LoadedObjectInfo list. Contains a list of owning pointers to
147 /// RuntimeDyld::LoadedObjectInfo instances.
148 typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>
151 /// @brief Functor for receiving finalization notifications.
152 typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor;
154 /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
155 /// and NotifyFinalized functors.
157 NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
158 NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
159 : NotifyLoaded(std::move(NotifyLoaded)),
160 NotifyFinalized(std::move(NotifyFinalized)) {}
162 /// @brief Add a set of objects (or archives) that will be treated as a unit
163 /// for the purposes of symbol lookup and memory management.
165 /// @return A pair containing (1) A handle that can be used to free the memory
166 /// allocated for the objects, and (2) a LoadedObjInfoList containing
167 /// one LoadedObjInfo instance for each object at the corresponding
168 /// index in the Objects list.
170 /// This version of this method allows the client to pass in an
171 /// RTDyldMemoryManager instance that will be used to allocate memory and look
172 /// up external symbol addresses for the given objects.
173 template <typename ObjSetT,
174 typename MemoryManagerPtrT,
175 typename SymbolResolverPtrT>
176 ObjSetHandleT addObjectSet(const ObjSetT &Objects,
177 MemoryManagerPtrT MemMgr,
178 SymbolResolverPtrT Resolver) {
179 ObjSetHandleT Handle =
180 LinkedObjSetList.insert(
181 LinkedObjSetList.end(),
182 createLinkedObjectSet(std::move(MemMgr), std::move(Resolver)));
184 LinkedObjectSet &LOS = **Handle;
185 LoadedObjInfoList LoadedObjInfos;
187 for (auto &Obj : Objects)
188 LoadedObjInfos.push_back(LOS.addObject(*Obj));
190 NotifyLoaded(Handle, Objects, LoadedObjInfos);
195 /// @brief Remove the set of objects associated with handle H.
197 /// All memory allocated for the objects will be freed, and the sections and
198 /// symbols they provided will no longer be available. No attempt is made to
199 /// re-emit the missing symbols, and any use of these symbols (directly or
200 /// indirectly) will result in undefined behavior. If dependence tracking is
201 /// required to detect or resolve such issues it should be added at a higher
203 void removeObjectSet(ObjSetHandleT H) {
204 // How do we invalidate the symbols in H?
205 LinkedObjSetList.erase(H);
208 /// @brief Search for the given named symbol.
209 /// @param Name The name of the symbol to search for.
210 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
211 /// @return A handle for the given named symbol, if it exists.
212 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
213 for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E;
215 if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
221 /// @brief Search for the given named symbol in the context of the set of
222 /// loaded objects represented by the handle H.
223 /// @param H The handle for the object set to search in.
224 /// @param Name The name of the symbol to search for.
225 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
226 /// @return A handle for the given named symbol, if it is found in the
227 /// given object set.
228 JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name,
229 bool ExportedSymbolsOnly) {
230 if (auto Sym = (*H)->getSymbol(Name)) {
231 if (Sym.isExported() || !ExportedSymbolsOnly) {
232 auto Addr = Sym.getAddress();
233 auto Flags = Sym.getFlags();
234 if (!(*H)->NeedsFinalization()) {
235 // If this instance has already been finalized then we can just return
237 return JITSymbol(Addr, Flags);
239 // If this instance needs finalization return a functor that will do
240 // it. The functor still needs to double-check whether finalization is
241 // required, in case someone else finalizes this set before the
242 // functor is called.
245 if ((*H)->NeedsFinalization()) {
252 return JITSymbol(std::move(GetAddress), Flags);
259 /// @brief Map section addresses for the objects associated with the handle H.
260 void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
261 TargetAddress TargetAddr) {
262 (*H)->mapSectionAddress(LocalAddress, TargetAddr);
265 /// @brief Immediately emit and finalize the object set represented by the
267 /// @param H Handle for object set to emit/finalize.
268 void emitAndFinalize(ObjSetHandleT H) {
275 LinkedObjectSetListT LinkedObjSetList;
276 NotifyLoadedFtor NotifyLoaded;
277 NotifyFinalizedFtor NotifyFinalized;
280 } // End namespace orc.
281 } // End namespace llvm
283 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H