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