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