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/OrcError.h" 21 #include "llvm/ExecutionEngine/RuntimeDyld.h" 22 #include "llvm/Support/DynamicLibrary.h" 23 #include <algorithm> 24 #include <cstdint> 25 #include <string> 26 #include <utility> 27 #include <vector> 28 29 namespace llvm { 30 31 class ConstantArray; 32 class GlobalVariable; 33 class Function; 34 class Module; 35 class TargetMachine; 36 class Value; 37 38 namespace orc { 39 40 /// This iterator provides a convenient way to iterate over the elements 41 /// of an llvm.global_ctors/llvm.global_dtors instance. 42 /// 43 /// The easiest way to get hold of instances of this class is to use the 44 /// getConstructors/getDestructors functions. 45 class CtorDtorIterator { 46 public: 47 /// Accessor for an element of the global_ctors/global_dtors array. 48 /// 49 /// This class provides a read-only view of the element with any casts on 50 /// the function stripped away. 51 struct Element { 52 Element(unsigned Priority, Function *Func, Value *Data) 53 : Priority(Priority), Func(Func), Data(Data) {} 54 55 unsigned Priority; 56 Function *Func; 57 Value *Data; 58 }; 59 60 /// Construct an iterator instance. If End is true then this iterator 61 /// acts as the end of the range, otherwise it is the beginning. 62 CtorDtorIterator(const GlobalVariable *GV, bool End); 63 64 /// Test iterators for equality. 65 bool operator==(const CtorDtorIterator &Other) const; 66 67 /// Test iterators for inequality. 68 bool operator!=(const CtorDtorIterator &Other) const; 69 70 /// Pre-increment iterator. 71 CtorDtorIterator& operator++(); 72 73 /// Post-increment iterator. 74 CtorDtorIterator operator++(int); 75 76 /// Dereference iterator. The resulting value provides a read-only view 77 /// of this element of the global_ctors/global_dtors list. 78 Element operator*() const; 79 80 private: 81 const ConstantArray *InitList; 82 unsigned I; 83 }; 84 85 /// Create an iterator range over the entries of the llvm.global_ctors 86 /// array. 87 iterator_range<CtorDtorIterator> getConstructors(const Module &M); 88 89 /// Create an iterator range over the entries of the llvm.global_ctors 90 /// array. 91 iterator_range<CtorDtorIterator> getDestructors(const Module &M); 92 93 /// Convenience class for recording constructor/destructor names for 94 /// later execution. 95 template <typename JITLayerT> 96 class LegacyCtorDtorRunner { 97 public: 98 /// Construct a CtorDtorRunner for the given range using the given 99 /// name mangling function. 100 LLVM_ATTRIBUTE_DEPRECATED( 101 LegacyCtorDtorRunner(std::vector<std::string> CtorDtorNames, 102 VModuleKey K), 103 "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. " 104 "Please use the ORCv2 CtorDtorRunner utility instead"); 105 106 LegacyCtorDtorRunner(ORCv1DeprecationAcknowledgement, 107 std::vector<std::string> CtorDtorNames, VModuleKey K) 108 : CtorDtorNames(std::move(CtorDtorNames)), K(K) {} 109 110 /// Run the recorded constructors/destructors through the given JIT 111 /// layer. 112 Error runViaLayer(JITLayerT &JITLayer) const { 113 using CtorDtorTy = void (*)(); 114 115 for (const auto &CtorDtorName : CtorDtorNames) { 116 if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) { 117 if (auto AddrOrErr = CtorDtorSym.getAddress()) { 118 CtorDtorTy CtorDtor = 119 reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr)); 120 CtorDtor(); 121 } else 122 return AddrOrErr.takeError(); 123 } else { 124 if (auto Err = CtorDtorSym.takeError()) 125 return Err; 126 else 127 return make_error<JITSymbolNotFound>(CtorDtorName); 128 } 129 } 130 return Error::success(); 131 } 132 133 private: 134 std::vector<std::string> CtorDtorNames; 135 orc::VModuleKey K; 136 }; 137 138 template <typename JITLayerT> 139 LegacyCtorDtorRunner<JITLayerT>::LegacyCtorDtorRunner( 140 std::vector<std::string> CtorDtorNames, VModuleKey K) 141 : CtorDtorNames(std::move(CtorDtorNames)), K(K) {} 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 LegacyLocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { 192 public: 193 /// Create a runtime-overrides class. 194 template <typename MangleFtorT> 195 LLVM_ATTRIBUTE_DEPRECATED( 196 LegacyLocalCXXRuntimeOverrides(const MangleFtorT &Mangle), 197 "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. " 198 "Please use the ORCv2 LocalCXXRuntimeOverrides utility instead"); 199 200 template <typename MangleFtorT> 201 LegacyLocalCXXRuntimeOverrides(ORCv1DeprecationAcknowledgement, 202 const MangleFtorT &Mangle) { 203 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); 204 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); 205 } 206 207 /// Search overrided symbols. 208 JITEvaluatedSymbol searchOverrides(const std::string &Name) { 209 auto I = CXXRuntimeOverrides.find(Name); 210 if (I != CXXRuntimeOverrides.end()) 211 return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported); 212 return nullptr; 213 } 214 215 private: 216 void addOverride(const std::string &Name, JITTargetAddress Addr) { 217 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr)); 218 } 219 220 StringMap<JITTargetAddress> CXXRuntimeOverrides; 221 }; 222 223 template <typename MangleFtorT> 224 LegacyLocalCXXRuntimeOverrides::LegacyLocalCXXRuntimeOverrides( 225 const MangleFtorT &Mangle) { 226 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); 227 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); 228 } 229 230 class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { 231 public: 232 Error enable(JITDylib &JD, MangleAndInterner &Mangler); 233 }; 234 235 /// A utility class to expose symbols found via dlsym to the JIT. 236 /// 237 /// If an instance of this class is attached to a JITDylib as a fallback 238 /// definition generator, then any symbol found in the given DynamicLibrary that 239 /// passes the 'Allow' predicate will be added to the JITDylib. 240 class DynamicLibrarySearchGenerator { 241 public: 242 using SymbolPredicate = std::function<bool(SymbolStringPtr)>; 243 244 /// Create a DynamicLibrarySearchGenerator that searches for symbols in the 245 /// given sys::DynamicLibrary. 246 /// 247 /// If the Allow predicate is given then only symbols matching the predicate 248 /// will be searched for. If the predicate is not given then all symbols will 249 /// be searched for. 250 DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix, 251 SymbolPredicate Allow = SymbolPredicate()); 252 253 /// Permanently loads the library at the given path and, on success, returns 254 /// a DynamicLibrarySearchGenerator that will search it for symbol definitions 255 /// in the library. On failure returns the reason the library failed to load. 256 static Expected<DynamicLibrarySearchGenerator> 257 Load(const char *FileName, char GlobalPrefix, 258 SymbolPredicate Allow = SymbolPredicate()); 259 260 /// Creates a DynamicLibrarySearchGenerator that searches for symbols in 261 /// the current process. 262 static Expected<DynamicLibrarySearchGenerator> 263 GetForCurrentProcess(char GlobalPrefix, 264 SymbolPredicate Allow = SymbolPredicate()) { 265 return Load(nullptr, GlobalPrefix, std::move(Allow)); 266 } 267 268 Expected<SymbolNameSet> operator()(JITDylib &JD, const SymbolNameSet &Names); 269 270 private: 271 sys::DynamicLibrary Dylib; 272 SymbolPredicate Allow; 273 char GlobalPrefix; 274 }; 275 276 } // end namespace orc 277 } // end namespace llvm 278 279 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 280