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