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 // Used internally by MachOPlatform, but made public to enable serialization. 43 enum class MachOExecutorSymbolFlags : uint8_t { 44 None = 0, 45 Weak = 1U << 0, 46 Callable = 1U << 1, 47 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Callable) 48 }; 49 50 /// Configuration for the mach-o header of a JITDylib. Specify common load 51 /// commands that should be added to the header. 52 struct HeaderOptions { 53 /// A dylib for use with a dylib command (e.g. LC_ID_DYLIB, LC_LOAD_DYLIB). 54 struct Dylib { 55 std::string Name; 56 uint32_t Timestamp; 57 uint32_t CurrentVersion; 58 uint32_t CompatibilityVersion; 59 }; 60 61 struct BuildVersionOpts { 62 63 // Derive platform from triple if possible. 64 static std::optional<BuildVersionOpts> 65 fromTriple(const Triple &TT, uint32_t MinOS, uint32_t SDK); 66 67 uint32_t Platform; // Platform. 68 uint32_t MinOS; // X.Y.Z is encoded in nibbles xxxx.yy.zz 69 uint32_t SDK; // X.Y.Z is encoded in nibbles xxxx.yy.zz 70 }; 71 72 /// Override for LC_IC_DYLIB. If this is nullopt, {JD.getName(), 0, 0, 0} 73 /// will be used. 74 std::optional<Dylib> IDDylib; 75 76 /// List of LC_LOAD_DYLIBs. 77 std::vector<Dylib> LoadDylibs; 78 /// List of LC_RPATHs. 79 std::vector<std::string> RPaths; 80 /// List of LC_BUILD_VERSIONs. 81 std::vector<BuildVersionOpts> BuildVersions; 82 83 HeaderOptions() = default; 84 HeaderOptions(Dylib D) : IDDylib(std::move(D)) {} 85 }; 86 87 /// Used by setupJITDylib to create MachO header MaterializationUnits for 88 /// JITDylibs. 89 using MachOHeaderMUBuilder = 90 unique_function<std::unique_ptr<MaterializationUnit>(MachOPlatform &MOP, 91 HeaderOptions Opts)>; 92 93 /// Simple MachO header graph builder. 94 static inline std::unique_ptr<MaterializationUnit> 95 buildSimpleMachOHeaderMU(MachOPlatform &MOP, HeaderOptions Opts); 96 97 /// Try to create a MachOPlatform instance, adding the ORC runtime to the 98 /// given JITDylib. 99 /// 100 /// The ORC runtime requires access to a number of symbols in libc++, and 101 /// requires access to symbols in libobjc, and libswiftCore to support 102 /// Objective-C and Swift code. It is up to the caller to ensure that the 103 /// required symbols can be referenced by code added to PlatformJD. The 104 /// standard way to achieve this is to first attach dynamic library search 105 /// generators for either the given process, or for the specific required 106 /// libraries, to PlatformJD, then to create the platform instance: 107 /// 108 /// \code{.cpp} 109 /// auto &PlatformJD = ES.createBareJITDylib("stdlib"); 110 /// PlatformJD.addGenerator( 111 /// ExitOnErr(EPCDynamicLibrarySearchGenerator 112 /// ::GetForTargetProcess(EPC))); 113 /// ES.setPlatform( 114 /// ExitOnErr(MachOPlatform::Create(ES, ObjLayer, EPC, PlatformJD, 115 /// "/path/to/orc/runtime"))); 116 /// \endcode 117 /// 118 /// Alternatively, these symbols could be added to another JITDylib that 119 /// PlatformJD links against. 120 /// 121 /// Clients are also responsible for ensuring that any JIT'd code that 122 /// depends on runtime functions (including any code using TLV or static 123 /// destructors) can reference the runtime symbols. This is usually achieved 124 /// by linking any JITDylibs containing regular code against 125 /// PlatformJD. 126 /// 127 /// By default, MachOPlatform will add the set of aliases returned by the 128 /// standardPlatformAliases function. This includes both required aliases 129 /// (e.g. __cxa_atexit -> __orc_rt_macho_cxa_atexit for static destructor 130 /// support), and optional aliases that provide JIT versions of common 131 /// functions (e.g. dlopen -> __orc_rt_macho_jit_dlopen). Clients can 132 /// override these defaults by passing a non-None value for the 133 /// RuntimeAliases function, in which case the client is responsible for 134 /// setting up all aliases (including the required ones). 135 static Expected<std::unique_ptr<MachOPlatform>> 136 Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 137 JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime, 138 HeaderOptions PlatformJDOpts = {}, 139 MachOHeaderMUBuilder BuildMachOHeaderMU = buildSimpleMachOHeaderMU, 140 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); 141 142 /// Construct using a path to the ORC runtime. 143 static Expected<std::unique_ptr<MachOPlatform>> 144 Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 145 JITDylib &PlatformJD, const char *OrcRuntimePath, 146 HeaderOptions PlatformJDOpts = {}, 147 MachOHeaderMUBuilder BuildMachOHeaderMU = buildSimpleMachOHeaderMU, 148 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); 149 150 ExecutionSession &getExecutionSession() const { return ES; } 151 ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } 152 153 NonOwningSymbolStringPtr getMachOHeaderStartSymbol() const { 154 return NonOwningSymbolStringPtr(MachOHeaderStartSymbol); 155 } 156 157 Error setupJITDylib(JITDylib &JD) override; 158 159 /// Install any platform-specific symbols (e.g. `__dso_handle`) and create a 160 /// mach-o header based on the given options. 161 Error setupJITDylib(JITDylib &JD, HeaderOptions Opts); 162 163 Error teardownJITDylib(JITDylib &JD) override; 164 Error notifyAdding(ResourceTracker &RT, 165 const MaterializationUnit &MU) override; 166 Error notifyRemoving(ResourceTracker &RT) override; 167 168 /// Returns an AliasMap containing the default aliases for the MachOPlatform. 169 /// This can be modified by clients when constructing the platform to add 170 /// or remove aliases. 171 static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES); 172 173 /// Returns the array of required CXX aliases. 174 static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases(); 175 176 /// Returns the array of standard runtime utility aliases for MachO. 177 static ArrayRef<std::pair<const char *, const char *>> 178 standardRuntimeUtilityAliases(); 179 180 private: 181 using SymbolTableVector = SmallVector< 182 std::tuple<ExecutorAddr, ExecutorAddr, MachOExecutorSymbolFlags>>; 183 184 // Data needed for bootstrap only. 185 struct BootstrapInfo { 186 std::mutex Mutex; 187 std::condition_variable CV; 188 size_t ActiveGraphs = 0; 189 shared::AllocActions DeferredAAs; 190 ExecutorAddr MachOHeaderAddr; 191 SymbolTableVector SymTab; 192 }; 193 194 // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO 195 // platform features including initializers, exceptions, TLV, and language 196 // runtime registration. 197 class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin { 198 public: 199 MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {} 200 201 void modifyPassConfig(MaterializationResponsibility &MR, 202 jitlink::LinkGraph &G, 203 jitlink::PassConfiguration &Config) override; 204 205 SyntheticSymbolDependenciesMap 206 getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override; 207 208 // FIXME: We should be tentatively tracking scraped sections and discarding 209 // if the MR fails. 210 Error notifyFailed(MaterializationResponsibility &MR) override { 211 return Error::success(); 212 } 213 214 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { 215 return Error::success(); 216 } 217 218 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 219 ResourceKey SrcKey) override {} 220 221 private: 222 using InitSymbolDepMap = 223 DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>; 224 225 struct UnwindSections { 226 SmallVector<ExecutorAddrRange> CodeRanges; 227 ExecutorAddrRange DwarfSection; 228 ExecutorAddrRange CompactUnwindSection; 229 }; 230 231 struct ObjCImageInfo { 232 uint32_t Version = 0; 233 uint32_t Flags = 0; 234 /// Whether this image info can no longer be mutated, as it may have been 235 /// registered with the objc runtime. 236 bool Finalized = false; 237 }; 238 239 struct SymbolTablePair { 240 jitlink::Symbol *OriginalSym = nullptr; 241 jitlink::Symbol *NameSym = nullptr; 242 }; 243 using JITSymTabVector = SmallVector<SymbolTablePair>; 244 245 Error bootstrapPipelineStart(jitlink::LinkGraph &G); 246 Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G); 247 Error bootstrapPipelineEnd(jitlink::LinkGraph &G); 248 249 Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G, 250 MaterializationResponsibility &MR); 251 252 Error preserveImportantSections(jitlink::LinkGraph &G, 253 MaterializationResponsibility &MR); 254 255 Error processObjCImageInfo(jitlink::LinkGraph &G, 256 MaterializationResponsibility &MR); 257 Error mergeImageInfoFlags(jitlink::LinkGraph &G, 258 MaterializationResponsibility &MR, 259 ObjCImageInfo &Info, uint32_t NewFlags); 260 261 Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD); 262 263 std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G); 264 Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD, 265 bool InBootstrapPhase); 266 267 Error createObjCRuntimeObject(jitlink::LinkGraph &G); 268 Error populateObjCRuntimeObject(jitlink::LinkGraph &G, 269 MaterializationResponsibility &MR); 270 271 Error prepareSymbolTableRegistration(jitlink::LinkGraph &G, 272 JITSymTabVector &JITSymTabInfo); 273 Error addSymbolTableRegistration(jitlink::LinkGraph &G, 274 MaterializationResponsibility &MR, 275 JITSymTabVector &JITSymTabInfo, 276 bool InBootstrapPhase); 277 278 std::mutex PluginMutex; 279 MachOPlatform &MP; 280 281 // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when 282 // JITDylibs are removed. 283 DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos; 284 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs; 285 InitSymbolDepMap InitSymbolDeps; 286 }; 287 288 using GetJITDylibHeaderSendResultFn = 289 unique_function<void(Expected<ExecutorAddr>)>; 290 using GetJITDylibNameSendResultFn = 291 unique_function<void(Expected<StringRef>)>; 292 using PushInitializersSendResultFn = 293 unique_function<void(Expected<MachOJITDylibDepInfoMap>)>; 294 using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>; 295 using PushSymbolsInSendResultFn = unique_function<void(Error)>; 296 297 static bool supportedTarget(const Triple &TT); 298 299 static jitlink::Edge::Kind getPointerEdgeKind(jitlink::LinkGraph &G); 300 301 static MachOExecutorSymbolFlags flagsForSymbol(jitlink::Symbol &Sym); 302 303 MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 304 JITDylib &PlatformJD, 305 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, 306 HeaderOptions PlatformJDOpts, 307 MachOHeaderMUBuilder BuildMachOHeaderMU, Error &Err); 308 309 // Associate MachOPlatform JIT-side runtime support functions with handlers. 310 Error associateRuntimeSupportFunctions(); 311 312 // Implements rt_pushInitializers by making repeat async lookups for 313 // initializer symbols (each lookup may spawn more initializer symbols if 314 // it pulls in new materializers, e.g. from objects in a static library). 315 void pushInitializersLoop(PushInitializersSendResultFn SendResult, 316 JITDylibSP JD); 317 318 // Handle requests from the ORC runtime to push MachO initializer info. 319 void rt_pushInitializers(PushInitializersSendResultFn SendResult, 320 ExecutorAddr JDHeaderAddr); 321 322 // Request that that the given symbols be materialized. The bool element of 323 // each pair indicates whether the symbol must be initialized, or whether it 324 // is optional. If any required symbol is not found then the pushSymbols 325 // function will return an error. 326 void rt_pushSymbols(PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle, 327 const std::vector<std::pair<StringRef, bool>> &Symbols); 328 329 // Call the ORC runtime to create a pthread key. 330 Expected<uint64_t> createPThreadKey(); 331 332 ExecutionSession &ES; 333 JITDylib &PlatformJD; 334 ObjectLinkingLayer &ObjLinkingLayer; 335 MachOHeaderMUBuilder BuildMachOHeaderMU; 336 337 SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle"); 338 339 struct RuntimeFunction { 340 RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {} 341 SymbolStringPtr Name; 342 ExecutorAddr Addr; 343 }; 344 345 RuntimeFunction PlatformBootstrap{ 346 ES.intern("___orc_rt_macho_platform_bootstrap")}; 347 RuntimeFunction PlatformShutdown{ 348 ES.intern("___orc_rt_macho_platform_shutdown")}; 349 RuntimeFunction RegisterEHFrameSection{ 350 ES.intern("___orc_rt_macho_register_ehframe_section")}; 351 RuntimeFunction DeregisterEHFrameSection{ 352 ES.intern("___orc_rt_macho_deregister_ehframe_section")}; 353 RuntimeFunction RegisterJITDylib{ 354 ES.intern("___orc_rt_macho_register_jitdylib")}; 355 RuntimeFunction DeregisterJITDylib{ 356 ES.intern("___orc_rt_macho_deregister_jitdylib")}; 357 RuntimeFunction RegisterObjectSymbolTable{ 358 ES.intern("___orc_rt_macho_register_object_symbol_table")}; 359 RuntimeFunction DeregisterObjectSymbolTable{ 360 ES.intern("___orc_rt_macho_deregister_object_symbol_table")}; 361 RuntimeFunction RegisterObjectPlatformSections{ 362 ES.intern("___orc_rt_macho_register_object_platform_sections")}; 363 RuntimeFunction DeregisterObjectPlatformSections{ 364 ES.intern("___orc_rt_macho_deregister_object_platform_sections")}; 365 RuntimeFunction CreatePThreadKey{ 366 ES.intern("___orc_rt_macho_create_pthread_key")}; 367 RuntimeFunction RegisterObjCRuntimeObject{ 368 ES.intern("___orc_rt_macho_register_objc_runtime_object")}; 369 RuntimeFunction DeregisterObjCRuntimeObject{ 370 ES.intern("___orc_rt_macho_deregister_objc_runtime_object")}; 371 372 DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols; 373 374 std::mutex PlatformMutex; 375 DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr; 376 DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib; 377 DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey; 378 379 std::atomic<BootstrapInfo *> Bootstrap; 380 }; 381 382 // Generates a MachO header. 383 class SimpleMachOHeaderMU : public MaterializationUnit { 384 public: 385 SimpleMachOHeaderMU(MachOPlatform &MOP, SymbolStringPtr HeaderStartSymbol, 386 MachOPlatform::HeaderOptions Opts); 387 StringRef getName() const override { return "MachOHeaderMU"; } 388 void materialize(std::unique_ptr<MaterializationResponsibility> R) override; 389 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override; 390 391 protected: 392 virtual jitlink::Block &createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G, 393 jitlink::Section &HeaderSection); 394 395 MachOPlatform &MOP; 396 MachOPlatform::HeaderOptions Opts; 397 398 private: 399 struct HeaderSymbol { 400 const char *Name; 401 uint64_t Offset; 402 }; 403 404 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = { 405 {"___mh_executable_header", 0}}; 406 407 void addMachOHeader(JITDylib &JD, jitlink::LinkGraph &G, 408 const SymbolStringPtr &InitializerSymbol); 409 static MaterializationUnit::Interface 410 createHeaderInterface(MachOPlatform &MOP, 411 const SymbolStringPtr &HeaderStartSymbol); 412 }; 413 414 /// Simple MachO header graph builder. 415 inline std::unique_ptr<MaterializationUnit> 416 MachOPlatform::buildSimpleMachOHeaderMU(MachOPlatform &MOP, 417 HeaderOptions Opts) { 418 return std::make_unique<SimpleMachOHeaderMU>(MOP, MOP.MachOHeaderStartSymbol, 419 std::move(Opts)); 420 } 421 422 struct MachOHeaderInfo { 423 size_t PageSize = 0; 424 uint32_t CPUType = 0; 425 uint32_t CPUSubType = 0; 426 }; 427 MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT); 428 429 } // end namespace orc 430 } // end namespace llvm 431 432 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H 433