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