1 //===-- ObjectLinkingLayer.h - JITLink-based jit linking layer --*- 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 the definition for an JITLink-based, in-process object linking 10 // layer. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H 15 #define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H 16 17 #include "llvm/ADT/STLExtras.h" 18 #include "llvm/ADT/StringMap.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 21 #include "llvm/ExecutionEngine/JITSymbol.h" 22 #include "llvm/ExecutionEngine/Orc/Core.h" 23 #include "llvm/ExecutionEngine/Orc/Layer.h" 24 #include "llvm/Support/Error.h" 25 #include <algorithm> 26 #include <cassert> 27 #include <functional> 28 #include <list> 29 #include <memory> 30 #include <string> 31 #include <utility> 32 #include <vector> 33 34 namespace llvm { 35 36 namespace jitlink { 37 class EHFrameRegistrar; 38 class Symbol; 39 } // namespace jitlink 40 41 namespace object { 42 class ObjectFile; 43 } // namespace object 44 45 namespace orc { 46 47 class ObjectLinkingLayerJITLinkContext; 48 49 /// An ObjectLayer implementation built on JITLink. 50 /// 51 /// Clients can use this class to add relocatable object files to an 52 /// ExecutionSession, and it typically serves as the base layer (underneath 53 /// a compiling layer like IRCompileLayer) for the rest of the JIT. 54 class ObjectLinkingLayer : public ObjectLayer, private ResourceManager { 55 friend class ObjectLinkingLayerJITLinkContext; 56 57 public: 58 /// Plugin instances can be added to the ObjectLinkingLayer to receive 59 /// callbacks when code is loaded or emitted, and when JITLink is being 60 /// configured. 61 class Plugin { 62 public: 63 using JITLinkSymbolVector = std::vector<const jitlink::Symbol *>; 64 using LocalDependenciesMap = DenseMap<SymbolStringPtr, JITLinkSymbolVector>; 65 66 virtual ~Plugin(); modifyPassConfig(MaterializationResponsibility & MR,const Triple & TT,jitlink::PassConfiguration & Config)67 virtual void modifyPassConfig(MaterializationResponsibility &MR, 68 const Triple &TT, 69 jitlink::PassConfiguration &Config) {} 70 notifyLoaded(MaterializationResponsibility & MR)71 virtual void notifyLoaded(MaterializationResponsibility &MR) {} notifyEmitted(MaterializationResponsibility & MR)72 virtual Error notifyEmitted(MaterializationResponsibility &MR) { 73 return Error::success(); 74 } 75 virtual Error notifyFailed(MaterializationResponsibility &MR) = 0; 76 virtual Error notifyRemovingResources(ResourceKey K) = 0; 77 virtual void notifyTransferringResources(ResourceKey DstKey, 78 ResourceKey SrcKey) = 0; 79 80 /// Return any dependencies that synthetic symbols (e.g. init symbols) 81 /// have on locally scoped jitlink::Symbols. This is used by the 82 /// ObjectLinkingLayer to update the dependencies for the synthetic 83 /// symbols. 84 virtual LocalDependenciesMap getSyntheticSymbolLocalDependencies(MaterializationResponsibility & MR)85 getSyntheticSymbolLocalDependencies(MaterializationResponsibility &MR) { 86 return LocalDependenciesMap(); 87 } 88 }; 89 90 using ReturnObjectBufferFunction = 91 std::function<void(std::unique_ptr<MemoryBuffer>)>; 92 93 /// Construct an ObjectLinkingLayer. 94 ObjectLinkingLayer(ExecutionSession &ES, 95 jitlink::JITLinkMemoryManager &MemMgr); 96 97 /// Construct an ObjectLinkingLayer. Takes ownership of the given 98 /// JITLinkMemoryManager. This method is a temporary hack to simplify 99 /// co-existence with RTDyldObjectLinkingLayer (which also owns its 100 /// allocators). 101 ObjectLinkingLayer(ExecutionSession &ES, 102 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr); 103 104 /// Destruct an ObjectLinkingLayer. 105 ~ObjectLinkingLayer(); 106 107 /// Set an object buffer return function. By default object buffers are 108 /// deleted once the JIT has linked them. If a return function is set then 109 /// it will be called to transfer ownership of the buffer instead. setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer)110 void setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer) { 111 this->ReturnObjectBuffer = std::move(ReturnObjectBuffer); 112 } 113 114 /// Add a pass-config modifier. addPlugin(std::unique_ptr<Plugin> P)115 ObjectLinkingLayer &addPlugin(std::unique_ptr<Plugin> P) { 116 std::lock_guard<std::mutex> Lock(LayerMutex); 117 Plugins.push_back(std::move(P)); 118 return *this; 119 } 120 121 /// Emit the object. 122 void emit(std::unique_ptr<MaterializationResponsibility> R, 123 std::unique_ptr<MemoryBuffer> O) override; 124 125 /// Instructs this ObjectLinkingLayer instance to override the symbol flags 126 /// found in the AtomGraph with the flags supplied by the 127 /// MaterializationResponsibility instance. This is a workaround to support 128 /// symbol visibility in COFF, which does not use the libObject's 129 /// SF_Exported flag. Use only when generating / adding COFF object files. 130 /// 131 /// FIXME: We should be able to remove this if/when COFF properly tracks 132 /// exported symbols. 133 ObjectLinkingLayer & setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags)134 setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) { 135 this->OverrideObjectFlags = OverrideObjectFlags; 136 return *this; 137 } 138 139 /// If set, this ObjectLinkingLayer instance will claim responsibility 140 /// for any symbols provided by a given object file that were not already in 141 /// the MaterializationResponsibility instance. Setting this flag allows 142 /// higher-level program representations (e.g. LLVM IR) to be added based on 143 /// only a subset of the symbols they provide, without having to write 144 /// intervening layers to scan and add the additional symbols. This trades 145 /// diagnostic quality for convenience however: If all symbols are enumerated 146 /// up-front then clashes can be detected and reported early (and usually 147 /// deterministically). If this option is set, clashes for the additional 148 /// symbols may not be detected until late, and detection may depend on 149 /// the flow of control through JIT'd code. Use with care. 150 ObjectLinkingLayer & setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols)151 setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) { 152 this->AutoClaimObjectSymbols = AutoClaimObjectSymbols; 153 return *this; 154 } 155 156 private: 157 using AllocPtr = std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>; 158 159 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, 160 jitlink::PassConfiguration &PassConfig); 161 void notifyLoaded(MaterializationResponsibility &MR); 162 Error notifyEmitted(MaterializationResponsibility &MR, AllocPtr Alloc); 163 164 Error handleRemoveResources(ResourceKey K) override; 165 void handleTransferResources(ResourceKey DstKey, ResourceKey SrcKey) override; 166 167 mutable std::mutex LayerMutex; 168 jitlink::JITLinkMemoryManager &MemMgr; 169 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgrOwnership; 170 bool OverrideObjectFlags = false; 171 bool AutoClaimObjectSymbols = false; 172 ReturnObjectBufferFunction ReturnObjectBuffer; 173 DenseMap<ResourceKey, std::vector<AllocPtr>> Allocs; 174 std::vector<std::unique_ptr<Plugin>> Plugins; 175 }; 176 177 class EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin { 178 public: 179 EHFrameRegistrationPlugin( 180 ExecutionSession &ES, 181 std::unique_ptr<jitlink::EHFrameRegistrar> Registrar); 182 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, 183 jitlink::PassConfiguration &PassConfig) override; 184 Error notifyEmitted(MaterializationResponsibility &MR) override; 185 Error notifyFailed(MaterializationResponsibility &MR) override; 186 Error notifyRemovingResources(ResourceKey K) override; 187 void notifyTransferringResources(ResourceKey DstKey, 188 ResourceKey SrcKey) override; 189 190 private: 191 192 struct EHFrameRange { 193 JITTargetAddress Addr = 0; 194 size_t Size; 195 }; 196 197 std::mutex EHFramePluginMutex; 198 ExecutionSession &ES; 199 std::unique_ptr<jitlink::EHFrameRegistrar> Registrar; 200 DenseMap<MaterializationResponsibility *, EHFrameRange> InProcessLinks; 201 DenseMap<ResourceKey, std::vector<EHFrameRange>> EHFrameRanges; 202 }; 203 204 } // end namespace orc 205 } // end namespace llvm 206 207 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H 208