1 //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Contains utilities for executing code in Orc. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 15 #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 16 17 #include "llvm/ADT/StringMap.h" 18 #include "llvm/ADT/iterator_range.h" 19 #include "llvm/ExecutionEngine/JITSymbol.h" 20 #include "llvm/ExecutionEngine/Orc/Core.h" 21 #include "llvm/ExecutionEngine/Orc/OrcError.h" 22 #include "llvm/ExecutionEngine/RuntimeDyld.h" 23 #include "llvm/Support/DynamicLibrary.h" 24 #include <algorithm> 25 #include <cstdint> 26 #include <string> 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 /// This iterator provides a convenient way to iterate over the elements 42 /// of an llvm.global_ctors/llvm.global_dtors instance. 43 /// 44 /// The easiest way to get hold of instances of this class is to use the 45 /// getConstructors/getDestructors functions. 46 class CtorDtorIterator { 47 public: 48 /// Accessor for an element of the global_ctors/global_dtors array. 49 /// 50 /// This class provides a read-only view of the element with any casts on 51 /// the function stripped away. 52 struct Element { ElementElement53 Element(unsigned Priority, Function *Func, Value *Data) 54 : Priority(Priority), Func(Func), Data(Data) {} 55 56 unsigned Priority; 57 Function *Func; 58 Value *Data; 59 }; 60 61 /// Construct an iterator instance. If End is true then this iterator 62 /// acts as the end of the range, otherwise it is the beginning. 63 CtorDtorIterator(const GlobalVariable *GV, bool End); 64 65 /// Test iterators for equality. 66 bool operator==(const CtorDtorIterator &Other) const; 67 68 /// Test iterators for inequality. 69 bool operator!=(const CtorDtorIterator &Other) const; 70 71 /// Pre-increment iterator. 72 CtorDtorIterator& operator++(); 73 74 /// Post-increment iterator. 75 CtorDtorIterator operator++(int); 76 77 /// Dereference iterator. The resulting value provides a read-only view 78 /// of this element of the global_ctors/global_dtors list. 79 Element operator*() const; 80 81 private: 82 const ConstantArray *InitList; 83 unsigned I; 84 }; 85 86 /// Create an iterator range over the entries of the llvm.global_ctors 87 /// array. 88 iterator_range<CtorDtorIterator> getConstructors(const Module &M); 89 90 /// Create an iterator range over the entries of the llvm.global_ctors 91 /// array. 92 iterator_range<CtorDtorIterator> getDestructors(const Module &M); 93 94 /// Convenience class for recording constructor/destructor names for 95 /// later execution. 96 template <typename JITLayerT> 97 class LegacyCtorDtorRunner { 98 public: 99 /// Construct a CtorDtorRunner for the given range using the given 100 /// name mangling function. LegacyCtorDtorRunner(std::vector<std::string> CtorDtorNames,VModuleKey K)101 LegacyCtorDtorRunner(std::vector<std::string> CtorDtorNames, VModuleKey K) 102 : CtorDtorNames(std::move(CtorDtorNames)), K(K) {} 103 104 /// Run the recorded constructors/destructors through the given JIT 105 /// layer. runViaLayer(JITLayerT & JITLayer)106 Error runViaLayer(JITLayerT &JITLayer) const { 107 using CtorDtorTy = void (*)(); 108 109 for (const auto &CtorDtorName : CtorDtorNames) { 110 if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) { 111 if (auto AddrOrErr = CtorDtorSym.getAddress()) { 112 CtorDtorTy CtorDtor = 113 reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr)); 114 CtorDtor(); 115 } else 116 return AddrOrErr.takeError(); 117 } else { 118 if (auto Err = CtorDtorSym.takeError()) 119 return Err; 120 else 121 return make_error<JITSymbolNotFound>(CtorDtorName); 122 } 123 } 124 return Error::success(); 125 } 126 127 private: 128 std::vector<std::string> CtorDtorNames; 129 orc::VModuleKey K; 130 }; 131 132 class CtorDtorRunner { 133 public: CtorDtorRunner(JITDylib & JD)134 CtorDtorRunner(JITDylib &JD) : JD(JD) {} 135 void add(iterator_range<CtorDtorIterator> CtorDtors); 136 Error run(); 137 138 private: 139 using CtorDtorList = std::vector<SymbolStringPtr>; 140 using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>; 141 142 JITDylib &JD; 143 CtorDtorPriorityMap CtorDtorsByPriority; 144 }; 145 146 /// Support class for static dtor execution. For hosted (in-process) JITs 147 /// only! 148 /// 149 /// If a __cxa_atexit function isn't found C++ programs that use static 150 /// destructors will fail to link. However, we don't want to use the host 151 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run 152 /// after the JIT has been torn down, which is no good. This class makes it easy 153 /// to override __cxa_atexit (and the related __dso_handle). 154 /// 155 /// To use, clients should manually call searchOverrides from their symbol 156 /// resolver. This should generally be done after attempting symbol resolution 157 /// inside the JIT, but before searching the host process's symbol table. When 158 /// the client determines that destructors should be run (generally at JIT 159 /// teardown or after a return from main), the runDestructors method should be 160 /// called. 161 class LocalCXXRuntimeOverridesBase { 162 public: 163 /// Run any destructors recorded by the overriden __cxa_atexit function 164 /// (CXAAtExitOverride). 165 void runDestructors(); 166 167 protected: toTargetAddress(PtrTy * P)168 template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) { 169 return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P)); 170 } 171 172 using DestructorPtr = void (*)(void *); 173 using CXXDestructorDataPair = std::pair<DestructorPtr, void *>; 174 using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>; 175 CXXDestructorDataPairList DSOHandleOverride; 176 static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, 177 void *DSOHandle); 178 }; 179 180 class LegacyLocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { 181 public: 182 /// Create a runtime-overrides class. 183 template <typename MangleFtorT> LegacyLocalCXXRuntimeOverrides(const MangleFtorT & Mangle)184 LegacyLocalCXXRuntimeOverrides(const MangleFtorT &Mangle) { 185 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); 186 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); 187 } 188 189 /// Search overrided symbols. searchOverrides(const std::string & Name)190 JITEvaluatedSymbol searchOverrides(const std::string &Name) { 191 auto I = CXXRuntimeOverrides.find(Name); 192 if (I != CXXRuntimeOverrides.end()) 193 return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported); 194 return nullptr; 195 } 196 197 private: addOverride(const std::string & Name,JITTargetAddress Addr)198 void addOverride(const std::string &Name, JITTargetAddress Addr) { 199 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr)); 200 } 201 202 StringMap<JITTargetAddress> CXXRuntimeOverrides; 203 }; 204 205 class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { 206 public: 207 Error enable(JITDylib &JD, MangleAndInterner &Mangler); 208 }; 209 210 /// A utility class to expose symbols found via dlsym to the JIT. 211 /// 212 /// If an instance of this class is attached to a JITDylib as a fallback 213 /// definition generator, then any symbol found in the given DynamicLibrary that 214 /// passes the 'Allow' predicate will be added to the JITDylib. 215 class DynamicLibrarySearchGenerator { 216 public: 217 using SymbolPredicate = std::function<bool(SymbolStringPtr)>; 218 219 /// Create a DynamicLibrarySearchGenerator that searches for symbols in the 220 /// given sys::DynamicLibrary. 221 /// If the Allow predicate is given then only symbols matching the predicate 222 /// will be searched for in the DynamicLibrary. If the predicate is not given 223 /// then all symbols will be searched for. 224 DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, const DataLayout &DL, 225 SymbolPredicate Allow = SymbolPredicate()); 226 227 /// Permanently loads the library at the given path and, on success, returns 228 /// a DynamicLibrarySearchGenerator that will search it for symbol definitions 229 /// in the library. On failure returns the reason the library failed to load. 230 static Expected<DynamicLibrarySearchGenerator> 231 Load(const char *FileName, const DataLayout &DL, 232 SymbolPredicate Allow = SymbolPredicate()); 233 234 /// Creates a DynamicLibrarySearchGenerator that searches for symbols in 235 /// the current process. 236 static Expected<DynamicLibrarySearchGenerator> 237 GetForCurrentProcess(const DataLayout &DL, 238 SymbolPredicate Allow = SymbolPredicate()) { 239 return Load(nullptr, DL, std::move(Allow)); 240 } 241 242 SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names); 243 244 private: 245 sys::DynamicLibrary Dylib; 246 SymbolPredicate Allow; 247 char GlobalPrefix; 248 }; 249 250 } // end namespace orc 251 } // end namespace llvm 252 253 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 254