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/RuntimeDyld.h" 21 #include "llvm/ExecutionEngine/Orc/OrcError.h" 22 #include <algorithm> 23 #include <cstdint> 24 #include <string> 25 #include <vector> 26 #include <utility> 27 28 namespace llvm { 29 30 class ConstantArray; 31 class GlobalVariable; 32 class Function; 33 class Module; 34 class Value; 35 36 namespace orc { 37 38 /// @brief This iterator provides a convenient way to iterate over the elements 39 /// of an llvm.global_ctors/llvm.global_dtors instance. 40 /// 41 /// The easiest way to get hold of instances of this class is to use the 42 /// getConstructors/getDestructors functions. 43 class CtorDtorIterator { 44 public: 45 /// @brief Accessor for an element of the global_ctors/global_dtors array. 46 /// 47 /// This class provides a read-only view of the element with any casts on 48 /// the function stripped away. 49 struct Element { 50 Element(unsigned Priority, Function *Func, Value *Data) 51 : Priority(Priority), Func(Func), Data(Data) {} 52 53 unsigned Priority; 54 Function *Func; 55 Value *Data; 56 }; 57 58 /// @brief Construct an iterator instance. If End is true then this iterator 59 /// acts as the end of the range, otherwise it is the beginning. 60 CtorDtorIterator(const GlobalVariable *GV, bool End); 61 62 /// @brief Test iterators for equality. 63 bool operator==(const CtorDtorIterator &Other) const; 64 65 /// @brief Test iterators for inequality. 66 bool operator!=(const CtorDtorIterator &Other) const; 67 68 /// @brief Pre-increment iterator. 69 CtorDtorIterator& operator++(); 70 71 /// @brief Post-increment iterator. 72 CtorDtorIterator operator++(int); 73 74 /// @brief Dereference iterator. The resulting value provides a read-only view 75 /// of this element of the global_ctors/global_dtors list. 76 Element operator*() const; 77 78 private: 79 const ConstantArray *InitList; 80 unsigned I; 81 }; 82 83 /// @brief Create an iterator range over the entries of the llvm.global_ctors 84 /// array. 85 iterator_range<CtorDtorIterator> getConstructors(const Module &M); 86 87 /// @brief Create an iterator range over the entries of the llvm.global_ctors 88 /// array. 89 iterator_range<CtorDtorIterator> getDestructors(const Module &M); 90 91 /// @brief Convenience class for recording constructor/destructor names for 92 /// later execution. 93 template <typename JITLayerT> 94 class CtorDtorRunner { 95 public: 96 /// @brief Construct a CtorDtorRunner for the given range using the given 97 /// name mangling function. 98 CtorDtorRunner(std::vector<std::string> CtorDtorNames, 99 typename JITLayerT::ModuleHandleT H) 100 : CtorDtorNames(std::move(CtorDtorNames)), H(H) {} 101 102 /// @brief Run the recorded constructors/destructors through the given JIT 103 /// layer. 104 Error runViaLayer(JITLayerT &JITLayer) const { 105 using CtorDtorTy = void (*)(); 106 107 for (const auto &CtorDtorName : CtorDtorNames) 108 if (auto CtorDtorSym = JITLayer.findSymbolIn(H, CtorDtorName, false)) { 109 if (auto AddrOrErr = CtorDtorSym.getAddress()) { 110 CtorDtorTy CtorDtor = 111 reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr)); 112 CtorDtor(); 113 } else 114 return AddrOrErr.takeError(); 115 } else { 116 if (auto Err = CtorDtorSym.takeError()) 117 return Err; 118 else 119 return make_error<JITSymbolNotFound>(CtorDtorName); 120 } 121 return Error::success(); 122 } 123 124 private: 125 std::vector<std::string> CtorDtorNames; 126 typename JITLayerT::ModuleHandleT H; 127 }; 128 129 /// @brief Support class for static dtor execution. For hosted (in-process) JITs 130 /// only! 131 /// 132 /// If a __cxa_atexit function isn't found C++ programs that use static 133 /// destructors will fail to link. However, we don't want to use the host 134 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run 135 /// after the JIT has been torn down, which is no good. This class makes it easy 136 /// to override __cxa_atexit (and the related __dso_handle). 137 /// 138 /// To use, clients should manually call searchOverrides from their symbol 139 /// resolver. This should generally be done after attempting symbol resolution 140 /// inside the JIT, but before searching the host process's symbol table. When 141 /// the client determines that destructors should be run (generally at JIT 142 /// teardown or after a return from main), the runDestructors method should be 143 /// called. 144 class LocalCXXRuntimeOverrides { 145 public: 146 /// Create a runtime-overrides class. 147 template <typename MangleFtorT> 148 LocalCXXRuntimeOverrides(const MangleFtorT &Mangle) { 149 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); 150 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); 151 } 152 153 /// Search overrided symbols. 154 JITEvaluatedSymbol searchOverrides(const std::string &Name) { 155 auto I = CXXRuntimeOverrides.find(Name); 156 if (I != CXXRuntimeOverrides.end()) 157 return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported); 158 return nullptr; 159 } 160 161 /// Run any destructors recorded by the overriden __cxa_atexit function 162 /// (CXAAtExitOverride). 163 void runDestructors(); 164 165 private: 166 template <typename PtrTy> 167 JITTargetAddress toTargetAddress(PtrTy* P) { 168 return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P)); 169 } 170 171 void addOverride(const std::string &Name, JITTargetAddress Addr) { 172 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr)); 173 } 174 175 StringMap<JITTargetAddress> CXXRuntimeOverrides; 176 177 using DestructorPtr = void (*)(void *); 178 using CXXDestructorDataPair = std::pair<DestructorPtr, void *>; 179 using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>; 180 CXXDestructorDataPairList DSOHandleOverride; 181 static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, 182 void *DSOHandle); 183 }; 184 185 } // end namespace orc 186 187 } // end namespace llvm 188 189 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H 190