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/StringMap.h" 17 #include "llvm/ADT/iterator_range.h" 18 #include "llvm/ExecutionEngine/JITSymbol.h" 19 #include "llvm/ExecutionEngine/Orc/Core.h" 20 #include "llvm/ExecutionEngine/Orc/Mangling.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 orc { 39 40 class ObjectLayer; 41 42 /// This iterator provides a convenient way to iterate over the elements 43 /// of an llvm.global_ctors/llvm.global_dtors instance. 44 /// 45 /// The easiest way to get hold of instances of this class is to use the 46 /// getConstructors/getDestructors functions. 47 class CtorDtorIterator { 48 public: 49 /// Accessor for an element of the global_ctors/global_dtors array. 50 /// 51 /// This class provides a read-only view of the element with any casts on 52 /// the function stripped away. 53 struct Element { 54 Element(unsigned Priority, Function *Func, Value *Data) 55 : Priority(Priority), Func(Func), Data(Data) {} 56 57 unsigned Priority; 58 Function *Func; 59 Value *Data; 60 }; 61 62 /// Construct an iterator instance. If End is true then this iterator 63 /// acts as the end of the range, otherwise it is the beginning. 64 CtorDtorIterator(const GlobalVariable *GV, bool End); 65 66 /// Test iterators for equality. 67 bool operator==(const CtorDtorIterator &Other) const; 68 69 /// Test iterators for inequality. 70 bool operator!=(const CtorDtorIterator &Other) const; 71 72 /// Pre-increment iterator. 73 CtorDtorIterator& operator++(); 74 75 /// Post-increment iterator. 76 CtorDtorIterator operator++(int); 77 78 /// Dereference iterator. The resulting value provides a read-only view 79 /// of this element of the global_ctors/global_dtors list. 80 Element operator*() const; 81 82 private: 83 const ConstantArray *InitList; 84 unsigned I; 85 }; 86 87 /// Create an iterator range over the entries of the llvm.global_ctors 88 /// array. 89 iterator_range<CtorDtorIterator> getConstructors(const Module &M); 90 91 /// Create an iterator range over the entries of the llvm.global_ctors 92 /// array. 93 iterator_range<CtorDtorIterator> getDestructors(const Module &M); 94 95 /// This iterator provides a convenient way to iterate over GlobalValues that 96 /// have initialization effects. 97 class StaticInitGVIterator { 98 public: 99 StaticInitGVIterator() = default; 100 101 StaticInitGVIterator(Module &M) 102 : I(M.global_values().begin()), E(M.global_values().end()), 103 ObjFmt(Triple(M.getTargetTriple()).getObjectFormat()) { 104 if (I != E) { 105 if (!isStaticInitGlobal(*I)) 106 moveToNextStaticInitGlobal(); 107 } else 108 I = E = Module::global_value_iterator(); 109 } 110 111 bool operator==(const StaticInitGVIterator &O) const { return I == O.I; } 112 bool operator!=(const StaticInitGVIterator &O) const { return I != O.I; } 113 114 StaticInitGVIterator &operator++() { 115 assert(I != E && "Increment past end of range"); 116 moveToNextStaticInitGlobal(); 117 return *this; 118 } 119 120 GlobalValue &operator*() { return *I; } 121 122 private: 123 bool isStaticInitGlobal(GlobalValue &GV); 124 void moveToNextStaticInitGlobal() { 125 ++I; 126 while (I != E && !isStaticInitGlobal(*I)) 127 ++I; 128 if (I == E) 129 I = E = Module::global_value_iterator(); 130 } 131 132 Module::global_value_iterator I, E; 133 Triple::ObjectFormatType ObjFmt; 134 }; 135 136 /// Create an iterator range over the GlobalValues that contribute to static 137 /// initialization. 138 inline iterator_range<StaticInitGVIterator> getStaticInitGVs(Module &M) { 139 return make_range(StaticInitGVIterator(M), StaticInitGVIterator()); 140 } 141 142 class CtorDtorRunner { 143 public: 144 CtorDtorRunner(JITDylib &JD) : JD(JD) {} 145 void add(iterator_range<CtorDtorIterator> CtorDtors); 146 Error run(); 147 148 private: 149 using CtorDtorList = std::vector<SymbolStringPtr>; 150 using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>; 151 152 JITDylib &JD; 153 CtorDtorPriorityMap CtorDtorsByPriority; 154 }; 155 156 /// Support class for static dtor execution. For hosted (in-process) JITs 157 /// only! 158 /// 159 /// If a __cxa_atexit function isn't found C++ programs that use static 160 /// destructors will fail to link. However, we don't want to use the host 161 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run 162 /// after the JIT has been torn down, which is no good. This class makes it easy 163 /// to override __cxa_atexit (and the related __dso_handle). 164 /// 165 /// To use, clients should manually call searchOverrides from their symbol 166 /// resolver. This should generally be done after attempting symbol resolution 167 /// inside the JIT, but before searching the host process's symbol table. When 168 /// the client determines that destructors should be run (generally at JIT 169 /// teardown or after a return from main), the runDestructors method should be 170 /// called. 171 class LocalCXXRuntimeOverridesBase { 172 public: 173 /// Run any destructors recorded by the overriden __cxa_atexit function 174 /// (CXAAtExitOverride). 175 void runDestructors(); 176 177 protected: 178 template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) { 179 return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P)); 180 } 181 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 220 /// Create a DynamicLibrarySearchGenerator that searches for symbols in the 221 /// given sys::DynamicLibrary. 222 /// 223 /// If the Allow predicate is given then only symbols matching the predicate 224 /// will be searched for. If the predicate is not given then all symbols will 225 /// be searched for. 226 DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix, 227 SymbolPredicate Allow = SymbolPredicate()); 228 229 /// Permanently loads the library at the given path and, on success, returns 230 /// a DynamicLibrarySearchGenerator that will search it for symbol definitions 231 /// in the library. On failure returns the reason the library failed to load. 232 static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> 233 Load(const char *FileName, char GlobalPrefix, 234 SymbolPredicate Allow = SymbolPredicate()); 235 236 /// Creates a DynamicLibrarySearchGenerator that searches for symbols in 237 /// the current process. 238 static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> 239 GetForCurrentProcess(char GlobalPrefix, 240 SymbolPredicate Allow = SymbolPredicate()) { 241 return Load(nullptr, GlobalPrefix, std::move(Allow)); 242 } 243 244 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 245 JITDylibLookupFlags JDLookupFlags, 246 const SymbolLookupSet &Symbols) override; 247 248 private: 249 sys::DynamicLibrary Dylib; 250 SymbolPredicate Allow; 251 char GlobalPrefix; 252 }; 253 254 /// A utility class to expose symbols from a static library. 255 /// 256 /// If an instance of this class is attached to a JITDylib as a fallback 257 /// definition generator, then any symbol found in the archive will result in 258 /// the containing object being added to the JITDylib. 259 class StaticLibraryDefinitionGenerator : public DefinitionGenerator { 260 public: 261 // Interface builder function for objects loaded from this archive. 262 using GetObjectFileInterface = 263 unique_function<Expected<MaterializationUnit::Interface>( 264 ExecutionSession &ES, MemoryBufferRef ObjBuffer)>; 265 266 /// Try to create a StaticLibraryDefinitionGenerator from the given path. 267 /// 268 /// This call will succeed if the file at the given path is a static library 269 /// is a valid archive, otherwise it will return an error. 270 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 271 Load(ObjectLayer &L, const char *FileName, 272 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 273 274 /// Try to create a StaticLibraryDefinitionGenerator from the given path. 275 /// 276 /// This call will succeed if the file at the given path is a static library 277 /// or a MachO universal binary containing a static library that is compatible 278 /// with the given triple. Otherwise it will return an error. 279 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 280 Load(ObjectLayer &L, const char *FileName, const Triple &TT, 281 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 282 283 /// Try to create a StaticLibrarySearchGenerator from the given memory buffer. 284 /// This call will succeed if the buffer contains a valid archive, otherwise 285 /// it will return an error. 286 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 287 Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, 288 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 289 290 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 291 JITDylibLookupFlags JDLookupFlags, 292 const SymbolLookupSet &Symbols) override; 293 294 private: 295 StaticLibraryDefinitionGenerator(ObjectLayer &L, 296 std::unique_ptr<MemoryBuffer> ArchiveBuffer, 297 GetObjectFileInterface GetObjFileInterface, 298 Error &Err); 299 300 ObjectLayer &L; 301 GetObjectFileInterface GetObjFileInterface; 302 std::unique_ptr<MemoryBuffer> ArchiveBuffer; 303 std::unique_ptr<object::Archive> Archive; 304 }; 305 306 } // end namespace orc 307 } // end namespace llvm 308 309 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 310