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/StringRef.h" 19 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 20 #include "llvm/ExecutionEngine/JITSymbol.h" 21 #include "llvm/ExecutionEngine/Orc/Core.h" 22 #include "llvm/ExecutionEngine/Orc/Layer.h" 23 #include "llvm/Support/Error.h" 24 #include <algorithm> 25 #include <cassert> 26 #include <functional> 27 #include <list> 28 #include <memory> 29 #include <utility> 30 #include <vector> 31 32 namespace llvm { 33 34 namespace jitlink { 35 class EHFrameRegistrar; 36 class LinkGraph; 37 class Symbol; 38 } // namespace jitlink 39 40 namespace orc { 41 42 class ObjectLinkingLayerJITLinkContext; 43 44 /// An ObjectLayer implementation built on JITLink. 45 /// 46 /// Clients can use this class to add relocatable object files to an 47 /// ExecutionSession, and it typically serves as the base layer (underneath 48 /// a compiling layer like IRCompileLayer) for the rest of the JIT. 49 class ObjectLinkingLayer : public RTTIExtends<ObjectLinkingLayer, ObjectLayer>, 50 private ResourceManager { 51 friend class ObjectLinkingLayerJITLinkContext; 52 53 public: 54 static char ID; 55 56 /// Plugin instances can be added to the ObjectLinkingLayer to receive 57 /// callbacks when code is loaded or emitted, and when JITLink is being 58 /// configured. 59 class Plugin { 60 public: 61 using JITLinkSymbolSet = DenseSet<jitlink::Symbol *>; 62 using SyntheticSymbolDependenciesMap = 63 DenseMap<SymbolStringPtr, JITLinkSymbolSet>; 64 65 virtual ~Plugin(); modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & G,jitlink::PassConfiguration & Config)66 virtual void modifyPassConfig(MaterializationResponsibility &MR, 67 jitlink::LinkGraph &G, 68 jitlink::PassConfiguration &Config) {} 69 70 // Deprecated. Don't use this in new code. There will be a proper mechanism 71 // for capturing object buffers. notifyMaterializing(MaterializationResponsibility & MR,jitlink::LinkGraph & G,jitlink::JITLinkContext & Ctx,MemoryBufferRef InputObject)72 virtual void notifyMaterializing(MaterializationResponsibility &MR, 73 jitlink::LinkGraph &G, 74 jitlink::JITLinkContext &Ctx, 75 MemoryBufferRef InputObject) {} 76 notifyLoaded(MaterializationResponsibility & MR)77 virtual void notifyLoaded(MaterializationResponsibility &MR) {} notifyEmitted(MaterializationResponsibility & MR)78 virtual Error notifyEmitted(MaterializationResponsibility &MR) { 79 return Error::success(); 80 } 81 virtual Error notifyFailed(MaterializationResponsibility &MR) = 0; 82 virtual Error notifyRemovingResources(JITDylib &JD, ResourceKey K) = 0; 83 virtual void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 84 ResourceKey SrcKey) = 0; 85 86 /// Return any dependencies that synthetic symbols (e.g. init symbols) 87 /// have on symbols in the LinkGraph. 88 /// This is used by the ObjectLinkingLayer to update the dependencies for 89 /// the synthetic symbols. 90 virtual SyntheticSymbolDependenciesMap getSyntheticSymbolDependencies(MaterializationResponsibility & MR)91 getSyntheticSymbolDependencies(MaterializationResponsibility &MR) { 92 return SyntheticSymbolDependenciesMap(); 93 } 94 }; 95 96 using ReturnObjectBufferFunction = 97 std::function<void(std::unique_ptr<MemoryBuffer>)>; 98 99 /// Construct an ObjectLinkingLayer using the ExecutorProcessControl 100 /// instance's memory manager. 101 ObjectLinkingLayer(ExecutionSession &ES); 102 103 /// Construct an ObjectLinkingLayer using a custom memory manager. 104 ObjectLinkingLayer(ExecutionSession &ES, 105 jitlink::JITLinkMemoryManager &MemMgr); 106 107 /// Construct an ObjectLinkingLayer. Takes ownership of the given 108 /// JITLinkMemoryManager. This method is a temporary hack to simplify 109 /// co-existence with RTDyldObjectLinkingLayer (which also owns its 110 /// allocators). 111 ObjectLinkingLayer(ExecutionSession &ES, 112 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr); 113 114 /// Destruct an ObjectLinkingLayer. 115 ~ObjectLinkingLayer(); 116 117 /// Set an object buffer return function. By default object buffers are 118 /// deleted once the JIT has linked them. If a return function is set then 119 /// it will be called to transfer ownership of the buffer instead. setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer)120 void setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer) { 121 this->ReturnObjectBuffer = std::move(ReturnObjectBuffer); 122 } 123 124 /// Add a plugin. addPlugin(std::shared_ptr<Plugin> P)125 ObjectLinkingLayer &addPlugin(std::shared_ptr<Plugin> P) { 126 std::lock_guard<std::mutex> Lock(LayerMutex); 127 Plugins.push_back(std::move(P)); 128 return *this; 129 } 130 131 /// Remove a plugin. This remove applies only to subsequent links (links 132 /// already underway will continue to use the plugin), and does not of itself 133 /// destroy the plugin -- destruction will happen once all shared pointers 134 /// (including those held by in-progress links) are destroyed. removePlugin(Plugin & P)135 void removePlugin(Plugin &P) { 136 std::lock_guard<std::mutex> Lock(LayerMutex); 137 auto I = llvm::find_if(Plugins, [&](const std::shared_ptr<Plugin> &Elem) { 138 return Elem.get() == &P; 139 }); 140 assert(I != Plugins.end() && "Plugin not present"); 141 Plugins.erase(I); 142 } 143 144 /// Add a LinkGraph to the JITDylib targeted by the given tracker. 145 Error add(ResourceTrackerSP, std::unique_ptr<jitlink::LinkGraph> G); 146 147 /// Add a LinkGraph to the given JITDylib. add(JITDylib & JD,std::unique_ptr<jitlink::LinkGraph> G)148 Error add(JITDylib &JD, std::unique_ptr<jitlink::LinkGraph> G) { 149 return add(JD.getDefaultResourceTracker(), std::move(G)); 150 } 151 152 // Un-hide ObjectLayer add methods. 153 using ObjectLayer::add; 154 155 /// Emit an object file. 156 void emit(std::unique_ptr<MaterializationResponsibility> R, 157 std::unique_ptr<MemoryBuffer> O) override; 158 159 /// Emit a LinkGraph. 160 void emit(std::unique_ptr<MaterializationResponsibility> R, 161 std::unique_ptr<jitlink::LinkGraph> G); 162 163 /// Instructs this ObjectLinkingLayer instance to override the symbol flags 164 /// found in the AtomGraph with the flags supplied by the 165 /// MaterializationResponsibility instance. This is a workaround to support 166 /// symbol visibility in COFF, which does not use the libObject's 167 /// SF_Exported flag. Use only when generating / adding COFF object files. 168 /// 169 /// FIXME: We should be able to remove this if/when COFF properly tracks 170 /// exported symbols. 171 ObjectLinkingLayer & setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags)172 setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) { 173 this->OverrideObjectFlags = OverrideObjectFlags; 174 return *this; 175 } 176 177 /// If set, this ObjectLinkingLayer instance will claim responsibility 178 /// for any symbols provided by a given object file that were not already in 179 /// the MaterializationResponsibility instance. Setting this flag allows 180 /// higher-level program representations (e.g. LLVM IR) to be added based on 181 /// only a subset of the symbols they provide, without having to write 182 /// intervening layers to scan and add the additional symbols. This trades 183 /// diagnostic quality for convenience however: If all symbols are enumerated 184 /// up-front then clashes can be detected and reported early (and usually 185 /// deterministically). If this option is set, clashes for the additional 186 /// symbols may not be detected until late, and detection may depend on 187 /// the flow of control through JIT'd code. Use with care. 188 ObjectLinkingLayer & setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols)189 setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) { 190 this->AutoClaimObjectSymbols = AutoClaimObjectSymbols; 191 return *this; 192 } 193 194 private: 195 using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc; 196 197 Error recordFinalizedAlloc(MaterializationResponsibility &MR, 198 FinalizedAlloc FA); 199 200 Error handleRemoveResources(JITDylib &JD, ResourceKey K) override; 201 void handleTransferResources(JITDylib &JD, ResourceKey DstKey, 202 ResourceKey SrcKey) override; 203 204 mutable std::mutex LayerMutex; 205 jitlink::JITLinkMemoryManager &MemMgr; 206 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgrOwnership; 207 bool OverrideObjectFlags = false; 208 bool AutoClaimObjectSymbols = false; 209 ReturnObjectBufferFunction ReturnObjectBuffer; 210 DenseMap<ResourceKey, std::vector<FinalizedAlloc>> Allocs; 211 std::vector<std::shared_ptr<Plugin>> Plugins; 212 }; 213 214 class EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin { 215 public: 216 EHFrameRegistrationPlugin( 217 ExecutionSession &ES, 218 std::unique_ptr<jitlink::EHFrameRegistrar> Registrar); 219 void modifyPassConfig(MaterializationResponsibility &MR, 220 jitlink::LinkGraph &G, 221 jitlink::PassConfiguration &PassConfig) override; 222 Error notifyEmitted(MaterializationResponsibility &MR) override; 223 Error notifyFailed(MaterializationResponsibility &MR) override; 224 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override; 225 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 226 ResourceKey SrcKey) override; 227 228 private: 229 std::mutex EHFramePluginMutex; 230 ExecutionSession &ES; 231 std::unique_ptr<jitlink::EHFrameRegistrar> Registrar; 232 DenseMap<MaterializationResponsibility *, ExecutorAddrRange> InProcessLinks; 233 DenseMap<ResourceKey, std::vector<ExecutorAddrRange>> EHFrameRanges; 234 }; 235 236 } // end namespace orc 237 } // end namespace llvm 238 239 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H 240