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/LLVMSPSSerializers.h" 20 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 21 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" 22 23 #include <future> 24 #include <thread> 25 #include <vector> 26 27 namespace llvm { 28 namespace orc { 29 30 struct MachOPerObjectSectionsToRegister { 31 ExecutorAddressRange EHFrameSection; 32 ExecutorAddressRange ThreadDataSection; 33 }; 34 35 struct MachOJITDylibInitializers { 36 using SectionList = std::vector<ExecutorAddressRange>; 37 MachOJITDylibInitializersMachOJITDylibInitializers38 MachOJITDylibInitializers(std::string Name, 39 ExecutorAddress MachOHeaderAddress) 40 : Name(std::move(Name)), 41 MachOHeaderAddress(std::move(MachOHeaderAddress)) {} 42 43 std::string Name; 44 ExecutorAddress MachOHeaderAddress; 45 ExecutorAddress ObjCImageInfoAddress; 46 47 StringMap<SectionList> InitSections; 48 }; 49 50 class MachOJITDylibDeinitializers {}; 51 52 using MachOJITDylibInitializerSequence = std::vector<MachOJITDylibInitializers>; 53 54 using MachOJITDylibDeinitializerSequence = 55 std::vector<MachOJITDylibDeinitializers>; 56 57 /// Mediates between MachO initialization and ExecutionSession state. 58 class MachOPlatform : public Platform { 59 public: 60 /// Try to create a MachOPlatform instance, adding the ORC runtime to the 61 /// given JITDylib. 62 /// 63 /// The ORC runtime requires access to a number of symbols in libc++, and 64 /// requires access to symbols in libobjc, and libswiftCore to support 65 /// Objective-C and Swift code. It is up to the caller to ensure that the 66 /// requried symbols can be referenced by code added to PlatformJD. The 67 /// standard way to achieve this is to first attach dynamic library search 68 /// generators for either the given process, or for the specific required 69 /// libraries, to PlatformJD, then to create the platform instance: 70 /// 71 /// \code{.cpp} 72 /// auto &PlatformJD = ES.createBareJITDylib("stdlib"); 73 /// PlatformJD.addGenerator( 74 /// ExitOnErr(EPCDynamicLibrarySearchGenerator 75 /// ::GetForTargetProcess(EPC))); 76 /// ES.setPlatform( 77 /// ExitOnErr(MachOPlatform::Create(ES, ObjLayer, EPC, PlatformJD, 78 /// "/path/to/orc/runtime"))); 79 /// \endcode 80 /// 81 /// Alternatively, these symbols could be added to another JITDylib that 82 /// PlatformJD links against. 83 /// 84 /// Clients are also responsible for ensuring that any JIT'd code that 85 /// depends on runtime functions (including any code using TLV or static 86 /// destructors) can reference the runtime symbols. This is usually achieved 87 /// by linking any JITDylibs containing regular code against 88 /// PlatformJD. 89 /// 90 /// By default, MachOPlatform will add the set of aliases returned by the 91 /// standardPlatformAliases function. This includes both required aliases 92 /// (e.g. __cxa_atexit -> __orc_rt_macho_cxa_atexit for static destructor 93 /// support), and optional aliases that provide JIT versions of common 94 /// functions (e.g. dlopen -> __orc_rt_macho_jit_dlopen). Clients can 95 /// override these defaults by passing a non-None value for the 96 /// RuntimeAliases function, in which case the client is responsible for 97 /// setting up all aliases (including the required ones). 98 static Expected<std::unique_ptr<MachOPlatform>> 99 Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 100 JITDylib &PlatformJD, const char *OrcRuntimePath, 101 Optional<SymbolAliasMap> RuntimeAliases = None); 102 getExecutionSession()103 ExecutionSession &getExecutionSession() const { return ES; } getObjectLinkingLayer()104 ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } 105 106 Error setupJITDylib(JITDylib &JD) override; 107 Error notifyAdding(ResourceTracker &RT, 108 const MaterializationUnit &MU) override; 109 Error notifyRemoving(ResourceTracker &RT) override; 110 111 /// Returns an AliasMap containing the default aliases for the MachOPlatform. 112 /// This can be modified by clients when constructing the platform to add 113 /// or remove aliases. 114 static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES); 115 116 /// Returns the array of required CXX aliases. 117 static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases(); 118 119 /// Returns the array of standard runtime utility aliases for MachO. 120 static ArrayRef<std::pair<const char *, const char *>> 121 standardRuntimeUtilityAliases(); 122 123 /// Returns true if the given section name is an initializer section. 124 static bool isInitializerSection(StringRef SegName, StringRef SectName); 125 126 private: 127 // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO 128 // platform features including initializers, exceptions, TLV, and language 129 // runtime registration. 130 class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin { 131 public: MachOPlatformPlugin(MachOPlatform & MP)132 MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {} 133 134 void modifyPassConfig(MaterializationResponsibility &MR, 135 jitlink::LinkGraph &G, 136 jitlink::PassConfiguration &Config) override; 137 138 SyntheticSymbolDependenciesMap 139 getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override; 140 141 // FIXME: We should be tentatively tracking scraped sections and discarding 142 // if the MR fails. notifyFailed(MaterializationResponsibility & MR)143 Error notifyFailed(MaterializationResponsibility &MR) override { 144 return Error::success(); 145 } 146 notifyRemovingResources(ResourceKey K)147 Error notifyRemovingResources(ResourceKey K) override { 148 return Error::success(); 149 } 150 notifyTransferringResources(ResourceKey DstKey,ResourceKey SrcKey)151 void notifyTransferringResources(ResourceKey DstKey, 152 ResourceKey SrcKey) override {} 153 154 private: 155 using InitSymbolDepMap = 156 DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>; 157 158 void addInitializerSupportPasses(MaterializationResponsibility &MR, 159 jitlink::PassConfiguration &Config); 160 161 void addMachOHeaderSupportPasses(MaterializationResponsibility &MR, 162 jitlink::PassConfiguration &Config); 163 164 void addEHAndTLVSupportPasses(MaterializationResponsibility &MR, 165 jitlink::PassConfiguration &Config); 166 167 Error preserveInitSections(jitlink::LinkGraph &G, 168 MaterializationResponsibility &MR); 169 170 Error processObjCImageInfo(jitlink::LinkGraph &G, 171 MaterializationResponsibility &MR); 172 173 Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD); 174 175 Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD); 176 177 std::mutex PluginMutex; 178 MachOPlatform &MP; 179 DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos; 180 InitSymbolDepMap InitSymbolDeps; 181 }; 182 183 using SendInitializerSequenceFn = 184 unique_function<void(Expected<MachOJITDylibInitializerSequence>)>; 185 186 using SendDeinitializerSequenceFn = 187 unique_function<void(Expected<MachOJITDylibDeinitializerSequence>)>; 188 189 using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddress>)>; 190 191 static bool supportedTarget(const Triple &TT); 192 193 MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 194 JITDylib &PlatformJD, 195 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, 196 Error &Err); 197 198 // Associate MachOPlatform JIT-side runtime support functions with handlers. 199 Error associateRuntimeSupportFunctions(JITDylib &PlatformJD); 200 201 void getInitializersBuildSequencePhase(SendInitializerSequenceFn SendResult, 202 JITDylib &JD, 203 std::vector<JITDylibSP> DFSLinkOrder); 204 205 void getInitializersLookupPhase(SendInitializerSequenceFn SendResult, 206 JITDylib &JD); 207 208 void rt_getInitializers(SendInitializerSequenceFn SendResult, 209 StringRef JDName); 210 211 void rt_getDeinitializers(SendDeinitializerSequenceFn SendResult, 212 ExecutorAddress Handle); 213 214 void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddress Handle, 215 StringRef SymbolName); 216 217 // Records the addresses of runtime symbols used by the platform. 218 Error bootstrapMachORuntime(JITDylib &PlatformJD); 219 220 Error registerInitInfo(JITDylib &JD, ExecutorAddress ObjCImageInfoAddr, 221 ArrayRef<jitlink::Section *> InitSections); 222 223 Error registerPerObjectSections(const MachOPerObjectSectionsToRegister &POSR); 224 225 Expected<uint64_t> createPThreadKey(); 226 227 ExecutionSession &ES; 228 ObjectLinkingLayer &ObjLinkingLayer; 229 230 SymbolStringPtr MachOHeaderStartSymbol; 231 std::atomic<bool> RuntimeBootstrapped{false}; 232 233 ExecutorAddress orc_rt_macho_platform_bootstrap; 234 ExecutorAddress orc_rt_macho_platform_shutdown; 235 ExecutorAddress orc_rt_macho_register_object_sections; 236 ExecutorAddress orc_rt_macho_create_pthread_key; 237 238 DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols; 239 240 // InitSeqs gets its own mutex to avoid locking the whole session when 241 // aggregating data from the jitlink. 242 std::mutex PlatformMutex; 243 DenseMap<JITDylib *, MachOJITDylibInitializers> InitSeqs; 244 std::vector<MachOPerObjectSectionsToRegister> BootstrapPOSRs; 245 246 DenseMap<JITTargetAddress, JITDylib *> HeaderAddrToJITDylib; 247 DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey; 248 }; 249 250 namespace shared { 251 252 using SPSMachOPerObjectSectionsToRegister = 253 SPSTuple<SPSExecutorAddressRange, SPSExecutorAddressRange>; 254 255 template <> 256 class SPSSerializationTraits<SPSMachOPerObjectSectionsToRegister, 257 MachOPerObjectSectionsToRegister> { 258 259 public: size(const MachOPerObjectSectionsToRegister & MOPOSR)260 static size_t size(const MachOPerObjectSectionsToRegister &MOPOSR) { 261 return SPSMachOPerObjectSectionsToRegister::AsArgList::size( 262 MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection); 263 } 264 serialize(SPSOutputBuffer & OB,const MachOPerObjectSectionsToRegister & MOPOSR)265 static bool serialize(SPSOutputBuffer &OB, 266 const MachOPerObjectSectionsToRegister &MOPOSR) { 267 return SPSMachOPerObjectSectionsToRegister::AsArgList::serialize( 268 OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection); 269 } 270 deserialize(SPSInputBuffer & IB,MachOPerObjectSectionsToRegister & MOPOSR)271 static bool deserialize(SPSInputBuffer &IB, 272 MachOPerObjectSectionsToRegister &MOPOSR) { 273 return SPSMachOPerObjectSectionsToRegister::AsArgList::deserialize( 274 IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection); 275 } 276 }; 277 278 using SPSNamedExecutorAddressRangeSequenceMap = 279 SPSSequence<SPSTuple<SPSString, SPSExecutorAddressRangeSequence>>; 280 281 using SPSMachOJITDylibInitializers = 282 SPSTuple<SPSString, SPSExecutorAddress, SPSExecutorAddress, 283 SPSNamedExecutorAddressRangeSequenceMap>; 284 285 using SPSMachOJITDylibInitializerSequence = 286 SPSSequence<SPSMachOJITDylibInitializers>; 287 288 /// Serialization traits for MachOJITDylibInitializers. 289 template <> 290 class SPSSerializationTraits<SPSMachOJITDylibInitializers, 291 MachOJITDylibInitializers> { 292 public: size(const MachOJITDylibInitializers & MOJDIs)293 static size_t size(const MachOJITDylibInitializers &MOJDIs) { 294 return SPSMachOJITDylibInitializers::AsArgList::size( 295 MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress, 296 MOJDIs.InitSections); 297 } 298 serialize(SPSOutputBuffer & OB,const MachOJITDylibInitializers & MOJDIs)299 static bool serialize(SPSOutputBuffer &OB, 300 const MachOJITDylibInitializers &MOJDIs) { 301 return SPSMachOJITDylibInitializers::AsArgList::serialize( 302 OB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress, 303 MOJDIs.InitSections); 304 } 305 deserialize(SPSInputBuffer & IB,MachOJITDylibInitializers & MOJDIs)306 static bool deserialize(SPSInputBuffer &IB, 307 MachOJITDylibInitializers &MOJDIs) { 308 return SPSMachOJITDylibInitializers::AsArgList::deserialize( 309 IB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress, 310 MOJDIs.InitSections); 311 } 312 }; 313 314 using SPSMachOJITDylibDeinitializers = SPSEmpty; 315 316 using SPSMachOJITDylibDeinitializerSequence = 317 SPSSequence<SPSMachOJITDylibDeinitializers>; 318 319 template <> 320 class SPSSerializationTraits<SPSMachOJITDylibDeinitializers, 321 MachOJITDylibDeinitializers> { 322 public: size(const MachOJITDylibDeinitializers & MOJDDs)323 static size_t size(const MachOJITDylibDeinitializers &MOJDDs) { return 0; } 324 serialize(SPSOutputBuffer & OB,const MachOJITDylibDeinitializers & MOJDDs)325 static bool serialize(SPSOutputBuffer &OB, 326 const MachOJITDylibDeinitializers &MOJDDs) { 327 return true; 328 } 329 deserialize(SPSInputBuffer & IB,MachOJITDylibDeinitializers & MOJDDs)330 static bool deserialize(SPSInputBuffer &IB, 331 MachOJITDylibDeinitializers &MOJDDs) { 332 MOJDDs = MachOJITDylibDeinitializers(); 333 return true; 334 } 335 }; 336 337 } // end namespace shared 338 } // end namespace orc 339 } // end namespace llvm 340 341 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H 342