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, const char *OrcRuntimePath, 83 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); 84 getExecutionSession()85 ExecutionSession &getExecutionSession() const { return ES; } getObjectLinkingLayer()86 ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } 87 88 Error setupJITDylib(JITDylib &JD) override; 89 Error teardownJITDylib(JITDylib &JD) override; 90 Error notifyAdding(ResourceTracker &RT, 91 const MaterializationUnit &MU) override; 92 Error notifyRemoving(ResourceTracker &RT) override; 93 94 /// Returns an AliasMap containing the default aliases for the MachOPlatform. 95 /// This can be modified by clients when constructing the platform to add 96 /// or remove aliases. 97 static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES); 98 99 /// Returns the array of required CXX aliases. 100 static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases(); 101 102 /// Returns the array of standard runtime utility aliases for MachO. 103 static ArrayRef<std::pair<const char *, const char *>> 104 standardRuntimeUtilityAliases(); 105 106 /// Returns true if the given section name is an initializer section. 107 static bool isInitializerSection(StringRef SegName, StringRef SectName); 108 109 private: 110 // Data needed for bootstrap only. 111 struct BootstrapInfo { 112 std::mutex Mutex; 113 std::condition_variable CV; 114 size_t ActiveGraphs = 0; 115 shared::AllocActions DeferredAAs; 116 ExecutorAddr MachOHeaderAddr; 117 }; 118 119 // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO 120 // platform features including initializers, exceptions, TLV, and language 121 // runtime registration. 122 class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin { 123 public: MachOPlatformPlugin(MachOPlatform & MP)124 MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {} 125 126 void modifyPassConfig(MaterializationResponsibility &MR, 127 jitlink::LinkGraph &G, 128 jitlink::PassConfiguration &Config) override; 129 130 SyntheticSymbolDependenciesMap 131 getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override; 132 133 // FIXME: We should be tentatively tracking scraped sections and discarding 134 // if the MR fails. notifyFailed(MaterializationResponsibility & MR)135 Error notifyFailed(MaterializationResponsibility &MR) override { 136 return Error::success(); 137 } 138 notifyRemovingResources(JITDylib & JD,ResourceKey K)139 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { 140 return Error::success(); 141 } 142 notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)143 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 144 ResourceKey SrcKey) override {} 145 146 private: 147 using InitSymbolDepMap = 148 DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>; 149 150 struct UnwindSections { 151 SmallVector<ExecutorAddrRange> CodeRanges; 152 ExecutorAddrRange DwarfSection; 153 ExecutorAddrRange CompactUnwindSection; 154 }; 155 156 Error bootstrapPipelineStart(jitlink::LinkGraph &G); 157 Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G); 158 Error bootstrapPipelineEnd(jitlink::LinkGraph &G); 159 160 Error recordRuntimeRegistrationFunctions(jitlink::LinkGraph &G); 161 162 Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G, 163 MaterializationResponsibility &MR); 164 165 Error preserveInitSections(jitlink::LinkGraph &G, 166 MaterializationResponsibility &MR); 167 168 Error processObjCImageInfo(jitlink::LinkGraph &G, 169 MaterializationResponsibility &MR); 170 171 Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD); 172 173 std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G); 174 175 Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD, 176 bool InBootstrapPhase); 177 178 std::mutex PluginMutex; 179 MachOPlatform &MP; 180 181 // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when 182 // JITDylibs are removed. 183 DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos; 184 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs; 185 InitSymbolDepMap InitSymbolDeps; 186 }; 187 188 using GetJITDylibHeaderSendResultFn = 189 unique_function<void(Expected<ExecutorAddr>)>; 190 using GetJITDylibNameSendResultFn = 191 unique_function<void(Expected<StringRef>)>; 192 using PushInitializersSendResultFn = 193 unique_function<void(Expected<MachOJITDylibDepInfoMap>)>; 194 using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>; 195 196 static bool supportedTarget(const Triple &TT); 197 198 MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 199 JITDylib &PlatformJD, 200 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, 201 Error &Err); 202 203 // Associate MachOPlatform JIT-side runtime support functions with handlers. 204 Error associateRuntimeSupportFunctions(); 205 206 // Implements rt_pushInitializers by making repeat async lookups for 207 // initializer symbols (each lookup may spawn more initializer symbols if 208 // it pulls in new materializers, e.g. from objects in a static library). 209 void pushInitializersLoop(PushInitializersSendResultFn SendResult, 210 JITDylibSP JD); 211 212 // Handle requests from the ORC runtime to push MachO initializer info. 213 void rt_pushInitializers(PushInitializersSendResultFn SendResult, 214 ExecutorAddr JDHeaderAddr); 215 216 // Handle requests for symbol addresses from the ORC runtime. 217 void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle, 218 StringRef SymbolName); 219 220 // Call the ORC runtime to create a pthread key. 221 Expected<uint64_t> createPThreadKey(); 222 223 ExecutionSession &ES; 224 JITDylib &PlatformJD; 225 ObjectLinkingLayer &ObjLinkingLayer; 226 227 SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle"); 228 229 struct RuntimeFunction { RuntimeFunctionRuntimeFunction230 RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {} 231 SymbolStringPtr Name; 232 ExecutorAddr Addr; 233 }; 234 235 RuntimeFunction PlatformBootstrap{ 236 ES.intern("___orc_rt_macho_platform_bootstrap")}; 237 RuntimeFunction PlatformShutdown{ 238 ES.intern("___orc_rt_macho_platform_shutdown")}; 239 RuntimeFunction RegisterEHFrameSection{ 240 ES.intern("___orc_rt_macho_register_ehframe_section")}; 241 RuntimeFunction DeregisterEHFrameSection{ 242 ES.intern("___orc_rt_macho_deregister_ehframe_section")}; 243 RuntimeFunction RegisterJITDylib{ 244 ES.intern("___orc_rt_macho_register_jitdylib")}; 245 RuntimeFunction DeregisterJITDylib{ 246 ES.intern("___orc_rt_macho_deregister_jitdylib")}; 247 RuntimeFunction RegisterObjectPlatformSections{ 248 ES.intern("___orc_rt_macho_register_object_platform_sections")}; 249 RuntimeFunction DeregisterObjectPlatformSections{ 250 ES.intern("___orc_rt_macho_deregister_object_platform_sections")}; 251 RuntimeFunction CreatePThreadKey{ 252 ES.intern("___orc_rt_macho_create_pthread_key")}; 253 254 DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols; 255 256 std::mutex PlatformMutex; 257 DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr; 258 DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib; 259 DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey; 260 261 std::atomic<BootstrapInfo *> Bootstrap; 262 }; 263 264 namespace shared { 265 266 using SPSNamedExecutorAddrRangeSequence = 267 SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>; 268 269 } // end namespace shared 270 } // end namespace orc 271 } // end namespace llvm 272 273 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H 274