1 | //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Contains utilities for executing code in Orc. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H |
14 | #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H |
15 | |
16 | #include "llvm/ADT/iterator_range.h" |
17 | #include "llvm/ExecutionEngine/JITSymbol.h" |
18 | #include "llvm/ExecutionEngine/Orc/Core.h" |
19 | #include "llvm/ExecutionEngine/Orc/Mangling.h" |
20 | #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" |
21 | #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h" |
22 | #include "llvm/ExecutionEngine/RuntimeDyld.h" |
23 | #include "llvm/Object/Archive.h" |
24 | #include "llvm/Support/DynamicLibrary.h" |
25 | #include <algorithm> |
26 | #include <cstdint> |
27 | #include <utility> |
28 | #include <vector> |
29 | |
30 | namespace llvm { |
31 | |
32 | class ConstantArray; |
33 | class GlobalVariable; |
34 | class Function; |
35 | class Module; |
36 | class Value; |
37 | |
38 | namespace object { |
39 | class MachOUniversalBinary; |
40 | } |
41 | |
42 | namespace orc { |
43 | |
44 | class ObjectLayer; |
45 | |
46 | /// This iterator provides a convenient way to iterate over the elements |
47 | /// of an llvm.global_ctors/llvm.global_dtors instance. |
48 | /// |
49 | /// The easiest way to get hold of instances of this class is to use the |
50 | /// getConstructors/getDestructors functions. |
51 | class CtorDtorIterator { |
52 | public: |
53 | /// Accessor for an element of the global_ctors/global_dtors array. |
54 | /// |
55 | /// This class provides a read-only view of the element with any casts on |
56 | /// the function stripped away. |
57 | struct Element { |
58 | Element(unsigned Priority, Function *Func, Value *Data) |
59 | : Priority(Priority), Func(Func), Data(Data) {} |
60 | |
61 | unsigned Priority; |
62 | Function *Func; |
63 | Value *Data; |
64 | }; |
65 | |
66 | /// Construct an iterator instance. If End is true then this iterator |
67 | /// acts as the end of the range, otherwise it is the beginning. |
68 | CtorDtorIterator(const GlobalVariable *GV, bool End); |
69 | |
70 | /// Test iterators for equality. |
71 | bool operator==(const CtorDtorIterator &Other) const; |
72 | |
73 | /// Test iterators for inequality. |
74 | bool operator!=(const CtorDtorIterator &Other) const; |
75 | |
76 | /// Pre-increment iterator. |
77 | CtorDtorIterator& operator++(); |
78 | |
79 | /// Post-increment iterator. |
80 | CtorDtorIterator operator++(int); |
81 | |
82 | /// Dereference iterator. The resulting value provides a read-only view |
83 | /// of this element of the global_ctors/global_dtors list. |
84 | Element operator*() const; |
85 | |
86 | private: |
87 | const ConstantArray *InitList; |
88 | unsigned I; |
89 | }; |
90 | |
91 | /// Create an iterator range over the entries of the llvm.global_ctors |
92 | /// array. |
93 | iterator_range<CtorDtorIterator> getConstructors(const Module &M); |
94 | |
95 | /// Create an iterator range over the entries of the llvm.global_ctors |
96 | /// array. |
97 | iterator_range<CtorDtorIterator> getDestructors(const Module &M); |
98 | |
99 | /// This iterator provides a convenient way to iterate over GlobalValues that |
100 | /// have initialization effects. |
101 | class StaticInitGVIterator { |
102 | public: |
103 | StaticInitGVIterator() = default; |
104 | |
105 | StaticInitGVIterator(Module &M) |
106 | : I(M.global_values().begin()), E(M.global_values().end()), |
107 | ObjFmt(Triple(M.getTargetTriple()).getObjectFormat()) { |
108 | if (I != E) { |
109 | if (!isStaticInitGlobal(GV&: *I)) |
110 | moveToNextStaticInitGlobal(); |
111 | } else |
112 | I = E = Module::global_value_iterator(); |
113 | } |
114 | |
115 | bool operator==(const StaticInitGVIterator &O) const { return I == O.I; } |
116 | bool operator!=(const StaticInitGVIterator &O) const { return I != O.I; } |
117 | |
118 | StaticInitGVIterator &operator++() { |
119 | assert(I != E && "Increment past end of range" ); |
120 | moveToNextStaticInitGlobal(); |
121 | return *this; |
122 | } |
123 | |
124 | GlobalValue &operator*() { return *I; } |
125 | |
126 | private: |
127 | bool isStaticInitGlobal(GlobalValue &GV); |
128 | void moveToNextStaticInitGlobal() { |
129 | ++I; |
130 | while (I != E && !isStaticInitGlobal(GV&: *I)) |
131 | ++I; |
132 | if (I == E) |
133 | I = E = Module::global_value_iterator(); |
134 | } |
135 | |
136 | Module::global_value_iterator I, E; |
137 | Triple::ObjectFormatType ObjFmt; |
138 | }; |
139 | |
140 | /// Create an iterator range over the GlobalValues that contribute to static |
141 | /// initialization. |
142 | inline iterator_range<StaticInitGVIterator> getStaticInitGVs(Module &M) { |
143 | return make_range(x: StaticInitGVIterator(M), y: StaticInitGVIterator()); |
144 | } |
145 | |
146 | class CtorDtorRunner { |
147 | public: |
148 | CtorDtorRunner(JITDylib &JD) : JD(JD) {} |
149 | void add(iterator_range<CtorDtorIterator> CtorDtors); |
150 | Error run(); |
151 | |
152 | private: |
153 | using CtorDtorList = std::vector<SymbolStringPtr>; |
154 | using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>; |
155 | |
156 | JITDylib &JD; |
157 | CtorDtorPriorityMap CtorDtorsByPriority; |
158 | }; |
159 | |
160 | /// Support class for static dtor execution. For hosted (in-process) JITs |
161 | /// only! |
162 | /// |
163 | /// If a __cxa_atexit function isn't found C++ programs that use static |
164 | /// destructors will fail to link. However, we don't want to use the host |
165 | /// process's __cxa_atexit, because it will schedule JIT'd destructors to run |
166 | /// after the JIT has been torn down, which is no good. This class makes it easy |
167 | /// to override __cxa_atexit (and the related __dso_handle). |
168 | /// |
169 | /// To use, clients should manually call searchOverrides from their symbol |
170 | /// resolver. This should generally be done after attempting symbol resolution |
171 | /// inside the JIT, but before searching the host process's symbol table. When |
172 | /// the client determines that destructors should be run (generally at JIT |
173 | /// teardown or after a return from main), the runDestructors method should be |
174 | /// called. |
175 | class LocalCXXRuntimeOverridesBase { |
176 | public: |
177 | /// Run any destructors recorded by the overriden __cxa_atexit function |
178 | /// (CXAAtExitOverride). |
179 | void runDestructors(); |
180 | |
181 | protected: |
182 | using DestructorPtr = void (*)(void *); |
183 | using CXXDestructorDataPair = std::pair<DestructorPtr, void *>; |
184 | using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>; |
185 | CXXDestructorDataPairList DSOHandleOverride; |
186 | static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, |
187 | void *DSOHandle); |
188 | }; |
189 | |
190 | class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { |
191 | public: |
192 | Error enable(JITDylib &JD, MangleAndInterner &Mangler); |
193 | }; |
194 | |
195 | /// An interface for Itanium __cxa_atexit interposer implementations. |
196 | class ItaniumCXAAtExitSupport { |
197 | public: |
198 | struct AtExitRecord { |
199 | void (*F)(void *); |
200 | void *Ctx; |
201 | }; |
202 | |
203 | void registerAtExit(void (*F)(void *), void *Ctx, void *DSOHandle); |
204 | void runAtExits(void *DSOHandle); |
205 | |
206 | private: |
207 | std::mutex AtExitsMutex; |
208 | DenseMap<void *, std::vector<AtExitRecord>> AtExitRecords; |
209 | }; |
210 | |
211 | /// A utility class to expose symbols found via dlsym to the JIT. |
212 | /// |
213 | /// If an instance of this class is attached to a JITDylib as a fallback |
214 | /// definition generator, then any symbol found in the given DynamicLibrary that |
215 | /// passes the 'Allow' predicate will be added to the JITDylib. |
216 | class DynamicLibrarySearchGenerator : public DefinitionGenerator { |
217 | public: |
218 | using SymbolPredicate = std::function<bool(const SymbolStringPtr &)>; |
219 | using AddAbsoluteSymbolsFn = unique_function<Error(JITDylib &, SymbolMap)>; |
220 | |
221 | /// Create a DynamicLibrarySearchGenerator that searches for symbols in the |
222 | /// given sys::DynamicLibrary. |
223 | /// |
224 | /// If the Allow predicate is given then only symbols matching the predicate |
225 | /// will be searched for. If the predicate is not given then all symbols will |
226 | /// be searched for. |
227 | /// |
228 | /// If \p AddAbsoluteSymbols is provided, it is used to add the symbols to the |
229 | /// \c JITDylib; otherwise it uses JD.define(absoluteSymbols(...)). |
230 | DynamicLibrarySearchGenerator( |
231 | sys::DynamicLibrary Dylib, char GlobalPrefix, |
232 | SymbolPredicate Allow = SymbolPredicate(), |
233 | AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr); |
234 | |
235 | /// Permanently loads the library at the given path and, on success, returns |
236 | /// a DynamicLibrarySearchGenerator that will search it for symbol definitions |
237 | /// in the library. On failure returns the reason the library failed to load. |
238 | static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> |
239 | Load(const char *FileName, char GlobalPrefix, |
240 | SymbolPredicate Allow = SymbolPredicate(), |
241 | AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr); |
242 | |
243 | /// Creates a DynamicLibrarySearchGenerator that searches for symbols in |
244 | /// the current process. |
245 | static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> |
246 | GetForCurrentProcess(char GlobalPrefix, |
247 | SymbolPredicate Allow = SymbolPredicate(), |
248 | AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr) { |
249 | return Load(FileName: nullptr, GlobalPrefix, Allow: std::move(Allow), |
250 | AddAbsoluteSymbols: std::move(AddAbsoluteSymbols)); |
251 | } |
252 | |
253 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
254 | JITDylibLookupFlags JDLookupFlags, |
255 | const SymbolLookupSet &Symbols) override; |
256 | |
257 | private: |
258 | sys::DynamicLibrary Dylib; |
259 | SymbolPredicate Allow; |
260 | AddAbsoluteSymbolsFn AddAbsoluteSymbols; |
261 | char GlobalPrefix; |
262 | }; |
263 | |
264 | /// A utility class to expose symbols from a static library. |
265 | /// |
266 | /// If an instance of this class is attached to a JITDylib as a fallback |
267 | /// definition generator, then any symbol found in the archive will result in |
268 | /// the containing object being added to the JITDylib. |
269 | class StaticLibraryDefinitionGenerator : public DefinitionGenerator { |
270 | public: |
271 | // Interface builder function for objects loaded from this archive. |
272 | using GetObjectFileInterface = |
273 | unique_function<Expected<MaterializationUnit::Interface>( |
274 | ExecutionSession &ES, MemoryBufferRef ObjBuffer)>; |
275 | |
276 | /// Try to create a StaticLibraryDefinitionGenerator from the given path. |
277 | /// |
278 | /// This call will succeed if the file at the given path is a static library |
279 | /// or a MachO universal binary containing a static library that is compatible |
280 | /// with the ExecutionSession's triple. Otherwise it will return an error. |
281 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
282 | Load(ObjectLayer &L, const char *FileName, |
283 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
284 | |
285 | /// Try to create a StaticLibrarySearchGenerator from the given memory buffer |
286 | /// and Archive object. |
287 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
288 | Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
289 | std::unique_ptr<object::Archive> Archive, |
290 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
291 | |
292 | /// Try to create a StaticLibrarySearchGenerator from the given memory buffer. |
293 | /// This call will succeed if the buffer contains a valid archive, otherwise |
294 | /// it will return an error. |
295 | /// |
296 | /// This call will succeed if the buffer contains a valid static library or a |
297 | /// MachO universal binary containing a static library that is compatible |
298 | /// with the ExecutionSession's triple. Otherwise it will return an error. |
299 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
300 | Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
301 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
302 | |
303 | /// Returns a list of filenames of dynamic libraries that this archive has |
304 | /// imported. This class does not load these libraries by itself. User is |
305 | /// responsible for making sure these libraries are avaliable to the JITDylib. |
306 | const std::set<std::string> &getImportedDynamicLibraries() const { |
307 | return ImportedDynamicLibraries; |
308 | } |
309 | |
310 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
311 | JITDylibLookupFlags JDLookupFlags, |
312 | const SymbolLookupSet &Symbols) override; |
313 | |
314 | private: |
315 | StaticLibraryDefinitionGenerator(ObjectLayer &L, |
316 | std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
317 | std::unique_ptr<object::Archive> Archive, |
318 | GetObjectFileInterface GetObjFileInterface, |
319 | Error &Err); |
320 | Error buildObjectFilesMap(); |
321 | |
322 | static Expected<std::pair<size_t, size_t>> |
323 | getSliceRangeForArch(object::MachOUniversalBinary &UB, const Triple &TT); |
324 | |
325 | ObjectLayer &L; |
326 | GetObjectFileInterface GetObjFileInterface; |
327 | std::set<std::string> ImportedDynamicLibraries; |
328 | std::unique_ptr<MemoryBuffer> ArchiveBuffer; |
329 | std::unique_ptr<object::Archive> Archive; |
330 | DenseMap<SymbolStringPtr, MemoryBufferRef> ObjectFilesMap; |
331 | }; |
332 | |
333 | /// A utility class to create COFF dllimport GOT symbols (__imp_*) and PLT |
334 | /// stubs. |
335 | /// |
336 | /// If an instance of this class is attached to a JITDylib as a fallback |
337 | /// definition generator, PLT stubs and dllimport __imp_ symbols will be |
338 | /// generated for external symbols found outside the given jitdylib. Currently |
339 | /// only supports x86_64 architecture. |
340 | class DLLImportDefinitionGenerator : public DefinitionGenerator { |
341 | public: |
342 | /// Creates a DLLImportDefinitionGenerator instance. |
343 | static std::unique_ptr<DLLImportDefinitionGenerator> |
344 | Create(ExecutionSession &ES, ObjectLinkingLayer &L); |
345 | |
346 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
347 | JITDylibLookupFlags JDLookupFlags, |
348 | const SymbolLookupSet &Symbols) override; |
349 | |
350 | private: |
351 | DLLImportDefinitionGenerator(ExecutionSession &ES, ObjectLinkingLayer &L) |
352 | : ES(ES), L(L) {} |
353 | |
354 | static Expected<unsigned> getTargetPointerSize(const Triple &TT); |
355 | static Expected<llvm::endianness> getTargetEndianness(const Triple &TT); |
356 | Expected<std::unique_ptr<jitlink::LinkGraph>> |
357 | createStubsGraph(const SymbolMap &Resolved); |
358 | |
359 | static StringRef getImpPrefix() { return "__imp_" ; } |
360 | |
361 | static StringRef getSectionName() { return "$__DLLIMPORT_STUBS" ; } |
362 | |
363 | ExecutionSession &ES; |
364 | ObjectLinkingLayer &L; |
365 | }; |
366 | |
367 | } // end namespace orc |
368 | } // end namespace llvm |
369 | |
370 | #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H |
371 | |