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 "llvm/Target/TargetOptions.h" 25 #include <algorithm> 26 #include <cstdint> 27 #include <string> 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 TargetMachine; 38 class Value; 39 40 namespace orc { 41 42 /// A utility class for building TargetMachines for JITs. 43 class JITTargetMachineBuilder { 44 public: 45 JITTargetMachineBuilder(Triple TT); 46 static Expected<JITTargetMachineBuilder> detectHost(); 47 Expected<std::unique_ptr<TargetMachine>> createTargetMachine(); 48 setArch(std::string Arch)49 JITTargetMachineBuilder &setArch(std::string Arch) { 50 this->Arch = std::move(Arch); 51 return *this; 52 } setCPU(std::string CPU)53 JITTargetMachineBuilder &setCPU(std::string CPU) { 54 this->CPU = std::move(CPU); 55 return *this; 56 } setRelocationModel(Optional<Reloc::Model> RM)57 JITTargetMachineBuilder &setRelocationModel(Optional<Reloc::Model> RM) { 58 this->RM = std::move(RM); 59 return *this; 60 } setCodeModel(Optional<CodeModel::Model> CM)61 JITTargetMachineBuilder &setCodeModel(Optional<CodeModel::Model> CM) { 62 this->CM = std::move(CM); 63 return *this; 64 } 65 JITTargetMachineBuilder & 66 addFeatures(const std::vector<std::string> &FeatureVec); getFeatures()67 SubtargetFeatures &getFeatures() { return Features; } getOptions()68 TargetOptions &getOptions() { return Options; } 69 70 private: 71 Triple TT; 72 std::string Arch; 73 std::string CPU; 74 SubtargetFeatures Features; 75 TargetOptions Options; 76 Optional<Reloc::Model> RM; 77 Optional<CodeModel::Model> CM; 78 CodeGenOpt::Level OptLevel = CodeGenOpt::Default; 79 }; 80 81 /// This iterator provides a convenient way to iterate over the elements 82 /// of an llvm.global_ctors/llvm.global_dtors instance. 83 /// 84 /// The easiest way to get hold of instances of this class is to use the 85 /// getConstructors/getDestructors functions. 86 class CtorDtorIterator { 87 public: 88 /// Accessor for an element of the global_ctors/global_dtors array. 89 /// 90 /// This class provides a read-only view of the element with any casts on 91 /// the function stripped away. 92 struct Element { ElementElement93 Element(unsigned Priority, Function *Func, Value *Data) 94 : Priority(Priority), Func(Func), Data(Data) {} 95 96 unsigned Priority; 97 Function *Func; 98 Value *Data; 99 }; 100 101 /// Construct an iterator instance. If End is true then this iterator 102 /// acts as the end of the range, otherwise it is the beginning. 103 CtorDtorIterator(const GlobalVariable *GV, bool End); 104 105 /// Test iterators for equality. 106 bool operator==(const CtorDtorIterator &Other) const; 107 108 /// Test iterators for inequality. 109 bool operator!=(const CtorDtorIterator &Other) const; 110 111 /// Pre-increment iterator. 112 CtorDtorIterator& operator++(); 113 114 /// Post-increment iterator. 115 CtorDtorIterator operator++(int); 116 117 /// Dereference iterator. The resulting value provides a read-only view 118 /// of this element of the global_ctors/global_dtors list. 119 Element operator*() const; 120 121 private: 122 const ConstantArray *InitList; 123 unsigned I; 124 }; 125 126 /// Create an iterator range over the entries of the llvm.global_ctors 127 /// array. 128 iterator_range<CtorDtorIterator> getConstructors(const Module &M); 129 130 /// Create an iterator range over the entries of the llvm.global_ctors 131 /// array. 132 iterator_range<CtorDtorIterator> getDestructors(const Module &M); 133 134 /// Convenience class for recording constructor/destructor names for 135 /// later execution. 136 template <typename JITLayerT> 137 class CtorDtorRunner { 138 public: 139 /// Construct a CtorDtorRunner for the given range using the given 140 /// name mangling function. CtorDtorRunner(std::vector<std::string> CtorDtorNames,VModuleKey K)141 CtorDtorRunner(std::vector<std::string> CtorDtorNames, VModuleKey K) 142 : CtorDtorNames(std::move(CtorDtorNames)), K(K) {} 143 144 /// Run the recorded constructors/destructors through the given JIT 145 /// layer. runViaLayer(JITLayerT & JITLayer)146 Error runViaLayer(JITLayerT &JITLayer) const { 147 using CtorDtorTy = void (*)(); 148 149 for (const auto &CtorDtorName : CtorDtorNames) { 150 if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) { 151 if (auto AddrOrErr = CtorDtorSym.getAddress()) { 152 CtorDtorTy CtorDtor = 153 reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr)); 154 CtorDtor(); 155 } else 156 return AddrOrErr.takeError(); 157 } else { 158 if (auto Err = CtorDtorSym.takeError()) 159 return Err; 160 else 161 return make_error<JITSymbolNotFound>(CtorDtorName); 162 } 163 } 164 return Error::success(); 165 } 166 167 private: 168 std::vector<std::string> CtorDtorNames; 169 orc::VModuleKey K; 170 }; 171 172 class CtorDtorRunner2 { 173 public: CtorDtorRunner2(VSO & V)174 CtorDtorRunner2(VSO &V) : V(V) {} 175 void add(iterator_range<CtorDtorIterator> CtorDtors); 176 Error run(); 177 178 private: 179 using CtorDtorList = std::vector<SymbolStringPtr>; 180 using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>; 181 182 VSO &V; 183 CtorDtorPriorityMap CtorDtorsByPriority; 184 }; 185 186 /// Support class for static dtor execution. For hosted (in-process) JITs 187 /// only! 188 /// 189 /// If a __cxa_atexit function isn't found C++ programs that use static 190 /// destructors will fail to link. However, we don't want to use the host 191 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run 192 /// after the JIT has been torn down, which is no good. This class makes it easy 193 /// to override __cxa_atexit (and the related __dso_handle). 194 /// 195 /// To use, clients should manually call searchOverrides from their symbol 196 /// resolver. This should generally be done after attempting symbol resolution 197 /// inside the JIT, but before searching the host process's symbol table. When 198 /// the client determines that destructors should be run (generally at JIT 199 /// teardown or after a return from main), the runDestructors method should be 200 /// called. 201 class LocalCXXRuntimeOverridesBase { 202 public: 203 /// Run any destructors recorded by the overriden __cxa_atexit function 204 /// (CXAAtExitOverride). 205 void runDestructors(); 206 207 protected: toTargetAddress(PtrTy * P)208 template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) { 209 return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P)); 210 } 211 212 using DestructorPtr = void (*)(void *); 213 using CXXDestructorDataPair = std::pair<DestructorPtr, void *>; 214 using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>; 215 CXXDestructorDataPairList DSOHandleOverride; 216 static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, 217 void *DSOHandle); 218 }; 219 220 class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { 221 public: 222 /// Create a runtime-overrides class. 223 template <typename MangleFtorT> LocalCXXRuntimeOverrides(const MangleFtorT & Mangle)224 LocalCXXRuntimeOverrides(const MangleFtorT &Mangle) { 225 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); 226 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); 227 } 228 229 /// Search overrided symbols. searchOverrides(const std::string & Name)230 JITEvaluatedSymbol searchOverrides(const std::string &Name) { 231 auto I = CXXRuntimeOverrides.find(Name); 232 if (I != CXXRuntimeOverrides.end()) 233 return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported); 234 return nullptr; 235 } 236 237 private: addOverride(const std::string & Name,JITTargetAddress Addr)238 void addOverride(const std::string &Name, JITTargetAddress Addr) { 239 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr)); 240 } 241 242 StringMap<JITTargetAddress> CXXRuntimeOverrides; 243 }; 244 245 class LocalCXXRuntimeOverrides2 : public LocalCXXRuntimeOverridesBase { 246 public: 247 Error enable(VSO &V, MangleAndInterner &Mangler); 248 }; 249 250 /// A utility class to expose symbols found via dlsym to the JIT. 251 /// 252 /// If an instance of this class is attached to a VSO as a fallback definition 253 /// generator, then any symbol found in the given DynamicLibrary that passes 254 /// the 'Allow' predicate will be added to the VSO. 255 class DynamicLibraryFallbackGenerator { 256 public: 257 using SymbolPredicate = std::function<bool(SymbolStringPtr)>; 258 DynamicLibraryFallbackGenerator(sys::DynamicLibrary Dylib, 259 const DataLayout &DL, SymbolPredicate Allow); 260 SymbolNameSet operator()(VSO &V, const SymbolNameSet &Names); 261 262 private: 263 sys::DynamicLibrary Dylib; 264 SymbolPredicate Allow; 265 char GlobalPrefix; 266 }; 267 268 } // end namespace orc 269 } // end namespace llvm 270 271 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 272