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(*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(*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(StaticInitGVIterator(M), 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 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 /// or a MachO universal binary containing a static library that is compatible 270 /// with the ExecutionSession's triple. Otherwise it will return an error. 271 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 272 Load(ObjectLayer &L, const char *FileName, 273 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 274 275 /// Try to create a StaticLibrarySearchGenerator from the given memory buffer 276 /// and Archive object. 277 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 278 Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, 279 std::unique_ptr<object::Archive> Archive, 280 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 281 282 /// Try to create a StaticLibrarySearchGenerator from the given memory buffer. 283 /// This call will succeed if the buffer contains a valid archive, otherwise 284 /// it will return an error. 285 /// 286 /// This call will succeed if the buffer contains a valid static library or a 287 /// MachO universal binary containing a static library that is compatible 288 /// with the ExecutionSession's triple. Otherwise it will return an error. 289 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 290 Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, 291 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 292 293 /// Returns a list of filenames of dynamic libraries that this archive has 294 /// imported. This class does not load these libraries by itself. User is 295 /// responsible for making sure these libraries are avaliable to the JITDylib. 296 const std::set<std::string> &getImportedDynamicLibraries() const { 297 return ImportedDynamicLibraries; 298 } 299 300 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 301 JITDylibLookupFlags JDLookupFlags, 302 const SymbolLookupSet &Symbols) override; 303 304 private: 305 StaticLibraryDefinitionGenerator(ObjectLayer &L, 306 std::unique_ptr<MemoryBuffer> ArchiveBuffer, 307 std::unique_ptr<object::Archive> Archive, 308 GetObjectFileInterface GetObjFileInterface, 309 Error &Err); 310 Error buildObjectFilesMap(); 311 312 static Expected<std::pair<size_t, size_t>> 313 getSliceRangeForArch(object::MachOUniversalBinary &UB, const Triple &TT); 314 315 ObjectLayer &L; 316 GetObjectFileInterface GetObjFileInterface; 317 std::set<std::string> ImportedDynamicLibraries; 318 std::unique_ptr<MemoryBuffer> ArchiveBuffer; 319 std::unique_ptr<object::Archive> Archive; 320 DenseMap<SymbolStringPtr, MemoryBufferRef> ObjectFilesMap; 321 }; 322 323 /// A utility class to create COFF dllimport GOT symbols (__imp_*) and PLT 324 /// stubs. 325 /// 326 /// If an instance of this class is attached to a JITDylib as a fallback 327 /// definition generator, PLT stubs and dllimport __imp_ symbols will be 328 /// generated for external symbols found outside the given jitdylib. Currently 329 /// only supports x86_64 architecture. 330 class DLLImportDefinitionGenerator : public DefinitionGenerator { 331 public: 332 /// Creates a DLLImportDefinitionGenerator instance. 333 static std::unique_ptr<DLLImportDefinitionGenerator> 334 Create(ExecutionSession &ES, ObjectLinkingLayer &L); 335 336 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 337 JITDylibLookupFlags JDLookupFlags, 338 const SymbolLookupSet &Symbols) override; 339 340 private: 341 DLLImportDefinitionGenerator(ExecutionSession &ES, ObjectLinkingLayer &L) 342 : ES(ES), L(L) {} 343 344 static Expected<unsigned> getTargetPointerSize(const Triple &TT); 345 static Expected<llvm::endianness> getTargetEndianness(const Triple &TT); 346 Expected<std::unique_ptr<jitlink::LinkGraph>> 347 createStubsGraph(const SymbolMap &Resolved); 348 349 static StringRef getImpPrefix() { return "__imp_"; } 350 351 static StringRef getSectionName() { return "$__DLLIMPORT_STUBS"; } 352 353 ExecutionSession &ES; 354 ObjectLinkingLayer &L; 355 }; 356 357 } // end namespace orc 358 } // end namespace llvm 359 360 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 361