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/ObjectLinkingLayer.h" 22 #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h" 23 #include "llvm/ExecutionEngine/RuntimeDyld.h" 24 #include "llvm/Object/Archive.h" 25 #include "llvm/Support/DynamicLibrary.h" 26 #include <algorithm> 27 #include <cstdint> 28 #include <utility> 29 #include <vector> 30 31 namespace llvm { 32 33 class ConstantArray; 34 class GlobalVariable; 35 class Function; 36 class Module; 37 class Value; 38 39 namespace object { 40 class MachOUniversalBinary; 41 } 42 43 namespace orc { 44 45 class ObjectLayer; 46 47 /// This iterator provides a convenient way to iterate over the elements 48 /// of an llvm.global_ctors/llvm.global_dtors instance. 49 /// 50 /// The easiest way to get hold of instances of this class is to use the 51 /// getConstructors/getDestructors functions. 52 class CtorDtorIterator { 53 public: 54 /// Accessor for an element of the global_ctors/global_dtors array. 55 /// 56 /// This class provides a read-only view of the element with any casts on 57 /// the function stripped away. 58 struct Element { 59 Element(unsigned Priority, Function *Func, Value *Data) 60 : Priority(Priority), Func(Func), Data(Data) {} 61 62 unsigned Priority; 63 Function *Func; 64 Value *Data; 65 }; 66 67 /// Construct an iterator instance. If End is true then this iterator 68 /// acts as the end of the range, otherwise it is the beginning. 69 CtorDtorIterator(const GlobalVariable *GV, bool End); 70 71 /// Test iterators for equality. 72 bool operator==(const CtorDtorIterator &Other) const; 73 74 /// Test iterators for inequality. 75 bool operator!=(const CtorDtorIterator &Other) const; 76 77 /// Pre-increment iterator. 78 CtorDtorIterator& operator++(); 79 80 /// Post-increment iterator. 81 CtorDtorIterator operator++(int); 82 83 /// Dereference iterator. The resulting value provides a read-only view 84 /// of this element of the global_ctors/global_dtors list. 85 Element operator*() const; 86 87 private: 88 const ConstantArray *InitList; 89 unsigned I; 90 }; 91 92 /// Create an iterator range over the entries of the llvm.global_ctors 93 /// array. 94 iterator_range<CtorDtorIterator> getConstructors(const Module &M); 95 96 /// Create an iterator range over the entries of the llvm.global_ctors 97 /// array. 98 iterator_range<CtorDtorIterator> getDestructors(const Module &M); 99 100 /// This iterator provides a convenient way to iterate over GlobalValues that 101 /// have initialization effects. 102 class StaticInitGVIterator { 103 public: 104 StaticInitGVIterator() = default; 105 106 StaticInitGVIterator(Module &M) 107 : I(M.global_values().begin()), E(M.global_values().end()), 108 ObjFmt(Triple(M.getTargetTriple()).getObjectFormat()) { 109 if (I != E) { 110 if (!isStaticInitGlobal(*I)) 111 moveToNextStaticInitGlobal(); 112 } else 113 I = E = Module::global_value_iterator(); 114 } 115 116 bool operator==(const StaticInitGVIterator &O) const { return I == O.I; } 117 bool operator!=(const StaticInitGVIterator &O) const { return I != O.I; } 118 119 StaticInitGVIterator &operator++() { 120 assert(I != E && "Increment past end of range"); 121 moveToNextStaticInitGlobal(); 122 return *this; 123 } 124 125 GlobalValue &operator*() { return *I; } 126 127 private: 128 bool isStaticInitGlobal(GlobalValue &GV); 129 void moveToNextStaticInitGlobal() { 130 ++I; 131 while (I != E && !isStaticInitGlobal(*I)) 132 ++I; 133 if (I == E) 134 I = E = Module::global_value_iterator(); 135 } 136 137 Module::global_value_iterator I, E; 138 Triple::ObjectFormatType ObjFmt; 139 }; 140 141 /// Create an iterator range over the GlobalValues that contribute to static 142 /// initialization. 143 inline iterator_range<StaticInitGVIterator> getStaticInitGVs(Module &M) { 144 return make_range(StaticInitGVIterator(M), StaticInitGVIterator()); 145 } 146 147 class CtorDtorRunner { 148 public: 149 CtorDtorRunner(JITDylib &JD) : JD(JD) {} 150 void add(iterator_range<CtorDtorIterator> CtorDtors); 151 Error run(); 152 153 private: 154 using CtorDtorList = std::vector<SymbolStringPtr>; 155 using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>; 156 157 JITDylib &JD; 158 CtorDtorPriorityMap CtorDtorsByPriority; 159 }; 160 161 /// Support class for static dtor execution. For hosted (in-process) JITs 162 /// only! 163 /// 164 /// If a __cxa_atexit function isn't found C++ programs that use static 165 /// destructors will fail to link. However, we don't want to use the host 166 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run 167 /// after the JIT has been torn down, which is no good. This class makes it easy 168 /// to override __cxa_atexit (and the related __dso_handle). 169 /// 170 /// To use, clients should manually call searchOverrides from their symbol 171 /// resolver. This should generally be done after attempting symbol resolution 172 /// inside the JIT, but before searching the host process's symbol table. When 173 /// the client determines that destructors should be run (generally at JIT 174 /// teardown or after a return from main), the runDestructors method should be 175 /// called. 176 class LocalCXXRuntimeOverridesBase { 177 public: 178 /// Run any destructors recorded by the overriden __cxa_atexit function 179 /// (CXAAtExitOverride). 180 void runDestructors(); 181 182 protected: 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 // Interface builder function for objects loaded from this archive. 263 using GetObjectFileInterface = 264 unique_function<Expected<MaterializationUnit::Interface>( 265 ExecutionSession &ES, MemoryBufferRef ObjBuffer)>; 266 267 /// Try to create a StaticLibraryDefinitionGenerator from the given path. 268 /// 269 /// This call will succeed if the file at the given path is a static library 270 /// or a MachO universal binary containing a static library that is compatible 271 /// with the ExecutionSession's triple. Otherwise it will return an error. 272 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 273 Load(ObjectLayer &L, const char *FileName, 274 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 275 276 /// Try to create a StaticLibrarySearchGenerator from the given memory buffer 277 /// and Archive object. 278 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 279 Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, 280 std::unique_ptr<object::Archive> Archive, 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 /// 287 /// This call will succeed if the buffer contains a valid static library or a 288 /// MachO universal binary containing a static library that is compatible 289 /// with the ExecutionSession's triple. Otherwise it will return an error. 290 static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> 291 Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, 292 GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); 293 294 /// Returns a list of filenames of dynamic libraries that this archive has 295 /// imported. This class does not load these libraries by itself. User is 296 /// responsible for making sure these libraries are avaliable to the JITDylib. 297 const std::set<std::string> &getImportedDynamicLibraries() const { 298 return ImportedDynamicLibraries; 299 } 300 301 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 302 JITDylibLookupFlags JDLookupFlags, 303 const SymbolLookupSet &Symbols) override; 304 305 private: 306 StaticLibraryDefinitionGenerator(ObjectLayer &L, 307 std::unique_ptr<MemoryBuffer> ArchiveBuffer, 308 std::unique_ptr<object::Archive> Archive, 309 GetObjectFileInterface GetObjFileInterface, 310 Error &Err); 311 Error buildObjectFilesMap(); 312 313 static Expected<std::pair<size_t, size_t>> 314 getSliceRangeForArch(object::MachOUniversalBinary &UB, const Triple &TT); 315 316 ObjectLayer &L; 317 GetObjectFileInterface GetObjFileInterface; 318 std::set<std::string> ImportedDynamicLibraries; 319 std::unique_ptr<MemoryBuffer> ArchiveBuffer; 320 std::unique_ptr<object::Archive> Archive; 321 DenseMap<SymbolStringPtr, MemoryBufferRef> ObjectFilesMap; 322 }; 323 324 /// A utility class to create COFF dllimport GOT symbols (__imp_*) and PLT 325 /// stubs. 326 /// 327 /// If an instance of this class is attached to a JITDylib as a fallback 328 /// definition generator, PLT stubs and dllimport __imp_ symbols will be 329 /// generated for external symbols found outside the given jitdylib. Currently 330 /// only supports x86_64 architecture. 331 class DLLImportDefinitionGenerator : public DefinitionGenerator { 332 public: 333 /// Creates a DLLImportDefinitionGenerator instance. 334 static std::unique_ptr<DLLImportDefinitionGenerator> 335 Create(ExecutionSession &ES, ObjectLinkingLayer &L); 336 337 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 338 JITDylibLookupFlags JDLookupFlags, 339 const SymbolLookupSet &Symbols) override; 340 341 private: 342 DLLImportDefinitionGenerator(ExecutionSession &ES, ObjectLinkingLayer &L) 343 : ES(ES), L(L) {} 344 345 static Expected<unsigned> getTargetPointerSize(const Triple &TT); 346 static Expected<support::endianness> getTargetEndianness(const Triple &TT); 347 Expected<std::unique_ptr<jitlink::LinkGraph>> 348 createStubsGraph(const SymbolMap &Resolved); 349 350 static StringRef getImpPrefix() { return "__imp_"; } 351 352 static StringRef getSectionName() { return "$__DLLIMPORT_STUBS"; } 353 354 ExecutionSession &ES; 355 ObjectLinkingLayer &L; 356 }; 357 358 } // end namespace orc 359 } // end namespace llvm 360 361 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 362