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(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, 137 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(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, 145 const char *OrcRuntimePath, HeaderOptions PlatformJDOpts = {}, 146 MachOHeaderMUBuilder BuildMachOHeaderMU = buildSimpleMachOHeaderMU, 147 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); 148 149 ExecutionSession &getExecutionSession() const { return ES; } 150 ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } 151 152 NonOwningSymbolStringPtr getMachOHeaderStartSymbol() const { 153 return NonOwningSymbolStringPtr(MachOHeaderStartSymbol); 154 } 155 156 Error setupJITDylib(JITDylib &JD) override; 157 158 /// Install any platform-specific symbols (e.g. `__dso_handle`) and create a 159 /// mach-o header based on the given options. 160 Error setupJITDylib(JITDylib &JD, HeaderOptions Opts); 161 162 Error teardownJITDylib(JITDylib &JD) override; 163 Error notifyAdding(ResourceTracker &RT, 164 const MaterializationUnit &MU) override; 165 Error notifyRemoving(ResourceTracker &RT) override; 166 167 /// Returns an AliasMap containing the default aliases for the MachOPlatform. 168 /// This can be modified by clients when constructing the platform to add 169 /// or remove aliases. 170 static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES); 171 172 /// Returns the array of required CXX aliases. 173 static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases(); 174 175 /// Returns the array of standard runtime utility aliases for MachO. 176 static ArrayRef<std::pair<const char *, const char *>> 177 standardRuntimeUtilityAliases(); 178 179 /// Returns a list of aliases required to enable lazy compilation via the 180 /// ORC runtime. 181 static ArrayRef<std::pair<const char *, const char *>> 182 standardLazyCompilationAliases(); 183 184 private: 185 using SymbolTableVector = SmallVector< 186 std::tuple<ExecutorAddr, ExecutorAddr, MachOExecutorSymbolFlags>>; 187 188 // Data needed for bootstrap only. 189 struct BootstrapInfo { 190 std::mutex Mutex; 191 std::condition_variable CV; 192 size_t ActiveGraphs = 0; 193 shared::AllocActions DeferredAAs; 194 ExecutorAddr MachOHeaderAddr; 195 SymbolTableVector SymTab; 196 }; 197 198 // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO 199 // platform features including initializers, exceptions, TLV, and language 200 // runtime registration. 201 class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin { 202 public: 203 MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {} 204 205 void modifyPassConfig(MaterializationResponsibility &MR, 206 jitlink::LinkGraph &G, 207 jitlink::PassConfiguration &Config) override; 208 209 // FIXME: We should be tentatively tracking scraped sections and discarding 210 // if the MR fails. 211 Error notifyFailed(MaterializationResponsibility &MR) override { 212 return Error::success(); 213 } 214 215 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { 216 return Error::success(); 217 } 218 219 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 220 ResourceKey SrcKey) override {} 221 222 private: 223 struct UnwindSections { 224 SmallVector<ExecutorAddrRange> CodeRanges; 225 ExecutorAddrRange DwarfSection; 226 ExecutorAddrRange CompactUnwindSection; 227 }; 228 229 struct ObjCImageInfo { 230 uint32_t Version = 0; 231 uint32_t Flags = 0; 232 /// Whether this image info can no longer be mutated, as it may have been 233 /// registered with the objc runtime. 234 bool Finalized = false; 235 }; 236 237 struct SymbolTablePair { 238 jitlink::Symbol *OriginalSym = nullptr; 239 jitlink::Symbol *NameSym = nullptr; 240 }; 241 using JITSymTabVector = SmallVector<SymbolTablePair>; 242 243 Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G); 244 Error bootstrapPipelineEnd(jitlink::LinkGraph &G); 245 246 Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G, 247 MaterializationResponsibility &MR); 248 249 Error preserveImportantSections(jitlink::LinkGraph &G, 250 MaterializationResponsibility &MR); 251 252 Error processObjCImageInfo(jitlink::LinkGraph &G, 253 MaterializationResponsibility &MR); 254 Error mergeImageInfoFlags(jitlink::LinkGraph &G, 255 MaterializationResponsibility &MR, 256 ObjCImageInfo &Info, uint32_t NewFlags); 257 258 Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD); 259 260 std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G); 261 Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD, 262 ExecutorAddr HeaderAddr, 263 bool InBootstrapPhase); 264 265 Error createObjCRuntimeObject(jitlink::LinkGraph &G); 266 Error populateObjCRuntimeObject(jitlink::LinkGraph &G, 267 MaterializationResponsibility &MR); 268 269 Error prepareSymbolTableRegistration(jitlink::LinkGraph &G, 270 JITSymTabVector &JITSymTabInfo); 271 Error addSymbolTableRegistration(jitlink::LinkGraph &G, 272 MaterializationResponsibility &MR, 273 JITSymTabVector &JITSymTabInfo, 274 bool InBootstrapPhase); 275 276 std::mutex PluginMutex; 277 MachOPlatform &MP; 278 279 // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when 280 // JITDylibs are removed. 281 DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos; 282 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs; 283 }; 284 285 using GetJITDylibHeaderSendResultFn = 286 unique_function<void(Expected<ExecutorAddr>)>; 287 using GetJITDylibNameSendResultFn = 288 unique_function<void(Expected<StringRef>)>; 289 using PushInitializersSendResultFn = 290 unique_function<void(Expected<MachOJITDylibDepInfoMap>)>; 291 using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>; 292 using PushSymbolsInSendResultFn = unique_function<void(Error)>; 293 294 static bool supportedTarget(const Triple &TT); 295 296 static jitlink::Edge::Kind getPointerEdgeKind(jitlink::LinkGraph &G); 297 298 static MachOExecutorSymbolFlags flagsForSymbol(jitlink::Symbol &Sym); 299 300 MachOPlatform(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, 301 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, 302 HeaderOptions PlatformJDOpts, 303 MachOHeaderMUBuilder BuildMachOHeaderMU, Error &Err); 304 305 // Associate MachOPlatform JIT-side runtime support functions with handlers. 306 Error associateRuntimeSupportFunctions(); 307 308 // Implements rt_pushInitializers by making repeat async lookups for 309 // initializer symbols (each lookup may spawn more initializer symbols if 310 // it pulls in new materializers, e.g. from objects in a static library). 311 void pushInitializersLoop(PushInitializersSendResultFn SendResult, 312 JITDylibSP JD); 313 314 // Handle requests from the ORC runtime to push MachO initializer info. 315 void rt_pushInitializers(PushInitializersSendResultFn SendResult, 316 ExecutorAddr JDHeaderAddr); 317 318 // Request that that the given symbols be materialized. The bool element of 319 // each pair indicates whether the symbol must be initialized, or whether it 320 // is optional. If any required symbol is not found then the pushSymbols 321 // function will return an error. 322 void rt_pushSymbols(PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle, 323 const std::vector<std::pair<StringRef, bool>> &Symbols); 324 325 // Call the ORC runtime to create a pthread key. 326 Expected<uint64_t> createPThreadKey(); 327 328 ExecutionSession &ES; 329 JITDylib &PlatformJD; 330 ObjectLinkingLayer &ObjLinkingLayer; 331 MachOHeaderMUBuilder BuildMachOHeaderMU; 332 333 SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle"); 334 335 struct RuntimeFunction { 336 RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {} 337 SymbolStringPtr Name; 338 ExecutorAddr Addr; 339 }; 340 341 RuntimeFunction PlatformBootstrap{ 342 ES.intern("___orc_rt_macho_platform_bootstrap")}; 343 RuntimeFunction PlatformShutdown{ 344 ES.intern("___orc_rt_macho_platform_shutdown")}; 345 RuntimeFunction RegisterEHFrameSection{ 346 ES.intern("___orc_rt_macho_register_ehframe_section")}; 347 RuntimeFunction DeregisterEHFrameSection{ 348 ES.intern("___orc_rt_macho_deregister_ehframe_section")}; 349 RuntimeFunction RegisterJITDylib{ 350 ES.intern("___orc_rt_macho_register_jitdylib")}; 351 RuntimeFunction DeregisterJITDylib{ 352 ES.intern("___orc_rt_macho_deregister_jitdylib")}; 353 RuntimeFunction RegisterObjectSymbolTable{ 354 ES.intern("___orc_rt_macho_register_object_symbol_table")}; 355 RuntimeFunction DeregisterObjectSymbolTable{ 356 ES.intern("___orc_rt_macho_deregister_object_symbol_table")}; 357 RuntimeFunction RegisterObjectPlatformSections{ 358 ES.intern("___orc_rt_macho_register_object_platform_sections")}; 359 RuntimeFunction DeregisterObjectPlatformSections{ 360 ES.intern("___orc_rt_macho_deregister_object_platform_sections")}; 361 RuntimeFunction CreatePThreadKey{ 362 ES.intern("___orc_rt_macho_create_pthread_key")}; 363 RuntimeFunction RegisterObjCRuntimeObject{ 364 ES.intern("___orc_rt_macho_register_objc_runtime_object")}; 365 RuntimeFunction DeregisterObjCRuntimeObject{ 366 ES.intern("___orc_rt_macho_deregister_objc_runtime_object")}; 367 368 DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols; 369 370 std::mutex PlatformMutex; 371 BootstrapInfo *Bootstrap = nullptr; 372 DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr; 373 DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib; 374 DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey; 375 }; 376 377 // Generates a MachO header. 378 class SimpleMachOHeaderMU : public MaterializationUnit { 379 public: 380 SimpleMachOHeaderMU(MachOPlatform &MOP, SymbolStringPtr HeaderStartSymbol, 381 MachOPlatform::HeaderOptions Opts); 382 StringRef getName() const override { return "MachOHeaderMU"; } 383 void materialize(std::unique_ptr<MaterializationResponsibility> R) override; 384 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override; 385 386 protected: 387 virtual jitlink::Block &createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G, 388 jitlink::Section &HeaderSection); 389 390 MachOPlatform &MOP; 391 MachOPlatform::HeaderOptions Opts; 392 393 private: 394 struct HeaderSymbol { 395 const char *Name; 396 uint64_t Offset; 397 }; 398 399 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = { 400 {"___mh_executable_header", 0}}; 401 402 void addMachOHeader(JITDylib &JD, jitlink::LinkGraph &G, 403 const SymbolStringPtr &InitializerSymbol); 404 static MaterializationUnit::Interface 405 createHeaderInterface(MachOPlatform &MOP, 406 const SymbolStringPtr &HeaderStartSymbol); 407 }; 408 409 /// Simple MachO header graph builder. 410 inline std::unique_ptr<MaterializationUnit> 411 MachOPlatform::buildSimpleMachOHeaderMU(MachOPlatform &MOP, 412 HeaderOptions Opts) { 413 return std::make_unique<SimpleMachOHeaderMU>(MOP, MOP.MachOHeaderStartSymbol, 414 std::move(Opts)); 415 } 416 417 struct MachOHeaderInfo { 418 size_t PageSize = 0; 419 uint32_t CPUType = 0; 420 uint32_t CPUSubType = 0; 421 }; 422 MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT); 423 424 } // end namespace orc 425 } // end namespace llvm 426 427 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H 428