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