1 //===-- MachOPlatform.h - Utilities for executing MachO in Orc --*- 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 // Utilities for executing JIT'd MachO in Orc. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H 14 #define LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H 15 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/ExecutionEngine/Orc/Core.h" 18 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" 19 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 20 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" 21 22 #include <future> 23 #include <thread> 24 #include <vector> 25 26 namespace llvm { 27 namespace orc { 28 29 /// Mediates between MachO initialization and ExecutionSession state. 30 class MachOPlatform : public Platform { 31 public: 32 // Used internally by MachOPlatform, but made public to enable serialization. 33 struct MachOJITDylibDepInfo { 34 bool Sealed = false; 35 std::vector<ExecutorAddr> DepHeaders; 36 }; 37 38 // Used internally by MachOPlatform, but made public to enable serialization. 39 using MachOJITDylibDepInfoMap = 40 std::vector<std::pair<ExecutorAddr, MachOJITDylibDepInfo>>; 41 42 /// Try to create a MachOPlatform instance, adding the ORC runtime to the 43 /// given JITDylib. 44 /// 45 /// The ORC runtime requires access to a number of symbols in libc++, and 46 /// requires access to symbols in libobjc, and libswiftCore to support 47 /// Objective-C and Swift code. It is up to the caller to ensure that the 48 /// requried symbols can be referenced by code added to PlatformJD. The 49 /// standard way to achieve this is to first attach dynamic library search 50 /// generators for either the given process, or for the specific required 51 /// libraries, to PlatformJD, then to create the platform instance: 52 /// 53 /// \code{.cpp} 54 /// auto &PlatformJD = ES.createBareJITDylib("stdlib"); 55 /// PlatformJD.addGenerator( 56 /// ExitOnErr(EPCDynamicLibrarySearchGenerator 57 /// ::GetForTargetProcess(EPC))); 58 /// ES.setPlatform( 59 /// ExitOnErr(MachOPlatform::Create(ES, ObjLayer, EPC, PlatformJD, 60 /// "/path/to/orc/runtime"))); 61 /// \endcode 62 /// 63 /// Alternatively, these symbols could be added to another JITDylib that 64 /// PlatformJD links against. 65 /// 66 /// Clients are also responsible for ensuring that any JIT'd code that 67 /// depends on runtime functions (including any code using TLV or static 68 /// destructors) can reference the runtime symbols. This is usually achieved 69 /// by linking any JITDylibs containing regular code against 70 /// PlatformJD. 71 /// 72 /// By default, MachOPlatform will add the set of aliases returned by the 73 /// standardPlatformAliases function. This includes both required aliases 74 /// (e.g. __cxa_atexit -> __orc_rt_macho_cxa_atexit for static destructor 75 /// support), and optional aliases that provide JIT versions of common 76 /// functions (e.g. dlopen -> __orc_rt_macho_jit_dlopen). Clients can 77 /// override these defaults by passing a non-None value for the 78 /// RuntimeAliases function, in which case the client is responsible for 79 /// setting up all aliases (including the required ones). 80 static Expected<std::unique_ptr<MachOPlatform>> 81 Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 82 JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime, 83 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); 84 85 /// Construct using a path to the ORC runtime. 86 static Expected<std::unique_ptr<MachOPlatform>> 87 Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 88 JITDylib &PlatformJD, const char *OrcRuntimePath, 89 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); 90 91 ExecutionSession &getExecutionSession() const { return ES; } 92 ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } 93 94 Error setupJITDylib(JITDylib &JD) override; 95 Error teardownJITDylib(JITDylib &JD) override; 96 Error notifyAdding(ResourceTracker &RT, 97 const MaterializationUnit &MU) override; 98 Error notifyRemoving(ResourceTracker &RT) override; 99 100 /// Returns an AliasMap containing the default aliases for the MachOPlatform. 101 /// This can be modified by clients when constructing the platform to add 102 /// or remove aliases. 103 static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES); 104 105 /// Returns the array of required CXX aliases. 106 static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases(); 107 108 /// Returns the array of standard runtime utility aliases for MachO. 109 static ArrayRef<std::pair<const char *, const char *>> 110 standardRuntimeUtilityAliases(); 111 112 private: 113 // Data needed for bootstrap only. 114 struct BootstrapInfo { 115 std::mutex Mutex; 116 std::condition_variable CV; 117 size_t ActiveGraphs = 0; 118 shared::AllocActions DeferredAAs; 119 ExecutorAddr MachOHeaderAddr; 120 }; 121 122 // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO 123 // platform features including initializers, exceptions, TLV, and language 124 // runtime registration. 125 class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin { 126 public: 127 MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {} 128 129 void modifyPassConfig(MaterializationResponsibility &MR, 130 jitlink::LinkGraph &G, 131 jitlink::PassConfiguration &Config) override; 132 133 SyntheticSymbolDependenciesMap 134 getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override; 135 136 // FIXME: We should be tentatively tracking scraped sections and discarding 137 // if the MR fails. 138 Error notifyFailed(MaterializationResponsibility &MR) override { 139 return Error::success(); 140 } 141 142 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { 143 return Error::success(); 144 } 145 146 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 147 ResourceKey SrcKey) override {} 148 149 private: 150 using InitSymbolDepMap = 151 DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>; 152 153 struct UnwindSections { 154 SmallVector<ExecutorAddrRange> CodeRanges; 155 ExecutorAddrRange DwarfSection; 156 ExecutorAddrRange CompactUnwindSection; 157 }; 158 159 struct ObjCImageInfo { 160 uint32_t Version = 0; 161 uint32_t Flags = 0; 162 }; 163 164 Error bootstrapPipelineStart(jitlink::LinkGraph &G); 165 Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G); 166 Error bootstrapPipelineEnd(jitlink::LinkGraph &G); 167 168 Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G, 169 MaterializationResponsibility &MR); 170 171 Error preserveImportantSections(jitlink::LinkGraph &G, 172 MaterializationResponsibility &MR); 173 174 Error processObjCImageInfo(jitlink::LinkGraph &G, 175 MaterializationResponsibility &MR); 176 177 Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD); 178 179 std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G); 180 181 Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD, 182 bool InBootstrapPhase); 183 184 Error createObjCRuntimeObject(jitlink::LinkGraph &G); 185 Error populateObjCRuntimeObject(jitlink::LinkGraph &G, 186 MaterializationResponsibility &MR); 187 188 std::mutex PluginMutex; 189 MachOPlatform &MP; 190 191 // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when 192 // JITDylibs are removed. 193 DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos; 194 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs; 195 InitSymbolDepMap InitSymbolDeps; 196 }; 197 198 using GetJITDylibHeaderSendResultFn = 199 unique_function<void(Expected<ExecutorAddr>)>; 200 using GetJITDylibNameSendResultFn = 201 unique_function<void(Expected<StringRef>)>; 202 using PushInitializersSendResultFn = 203 unique_function<void(Expected<MachOJITDylibDepInfoMap>)>; 204 using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>; 205 206 static bool supportedTarget(const Triple &TT); 207 208 MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 209 JITDylib &PlatformJD, 210 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, 211 Error &Err); 212 213 // Associate MachOPlatform JIT-side runtime support functions with handlers. 214 Error associateRuntimeSupportFunctions(); 215 216 // Implements rt_pushInitializers by making repeat async lookups for 217 // initializer symbols (each lookup may spawn more initializer symbols if 218 // it pulls in new materializers, e.g. from objects in a static library). 219 void pushInitializersLoop(PushInitializersSendResultFn SendResult, 220 JITDylibSP JD); 221 222 // Handle requests from the ORC runtime to push MachO initializer info. 223 void rt_pushInitializers(PushInitializersSendResultFn SendResult, 224 ExecutorAddr JDHeaderAddr); 225 226 // Handle requests for symbol addresses from the ORC runtime. 227 void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle, 228 StringRef SymbolName); 229 230 // Call the ORC runtime to create a pthread key. 231 Expected<uint64_t> createPThreadKey(); 232 233 ExecutionSession &ES; 234 JITDylib &PlatformJD; 235 ObjectLinkingLayer &ObjLinkingLayer; 236 237 SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle"); 238 239 struct RuntimeFunction { 240 RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {} 241 SymbolStringPtr Name; 242 ExecutorAddr Addr; 243 }; 244 245 RuntimeFunction PlatformBootstrap{ 246 ES.intern("___orc_rt_macho_platform_bootstrap")}; 247 RuntimeFunction PlatformShutdown{ 248 ES.intern("___orc_rt_macho_platform_shutdown")}; 249 RuntimeFunction RegisterEHFrameSection{ 250 ES.intern("___orc_rt_macho_register_ehframe_section")}; 251 RuntimeFunction DeregisterEHFrameSection{ 252 ES.intern("___orc_rt_macho_deregister_ehframe_section")}; 253 RuntimeFunction RegisterJITDylib{ 254 ES.intern("___orc_rt_macho_register_jitdylib")}; 255 RuntimeFunction DeregisterJITDylib{ 256 ES.intern("___orc_rt_macho_deregister_jitdylib")}; 257 RuntimeFunction RegisterObjectPlatformSections{ 258 ES.intern("___orc_rt_macho_register_object_platform_sections")}; 259 RuntimeFunction DeregisterObjectPlatformSections{ 260 ES.intern("___orc_rt_macho_deregister_object_platform_sections")}; 261 RuntimeFunction CreatePThreadKey{ 262 ES.intern("___orc_rt_macho_create_pthread_key")}; 263 RuntimeFunction RegisterObjCRuntimeObject{ 264 ES.intern("___orc_rt_macho_register_objc_runtime_object")}; 265 RuntimeFunction DeregisterObjCRuntimeObject{ 266 ES.intern("___orc_rt_macho_deregister_objc_runtime_object")}; 267 268 DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols; 269 270 std::mutex PlatformMutex; 271 DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr; 272 DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib; 273 DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey; 274 275 std::atomic<BootstrapInfo *> Bootstrap; 276 }; 277 278 namespace shared { 279 280 using SPSNamedExecutorAddrRangeSequence = 281 SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>; 282 283 } // end namespace shared 284 } // end namespace orc 285 } // end namespace llvm 286 287 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H 288