1865 lines · cpp
1//===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"10 11#include "llvm/BinaryFormat/MachO.h"12#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"13#include "llvm/ExecutionEngine/JITLink/MachO.h"14#include "llvm/ExecutionEngine/JITLink/aarch64.h"15#include "llvm/ExecutionEngine/JITLink/x86_64.h"16#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"17#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"18#include "llvm/ExecutionEngine/Orc/MachOBuilder.h"19#include "llvm/Support/Debug.h"20#include <optional>21 22#define DEBUG_TYPE "orc"23 24using namespace llvm;25using namespace llvm::orc;26using namespace llvm::orc::shared;27 28namespace llvm {29namespace orc {30namespace shared {31 32using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;33using SPSMachOJITDylibDepInfoMap =34 SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;35 36class SPSMachOExecutorSymbolFlags;37 38template <>39class SPSSerializationTraits<SPSMachOJITDylibDepInfo,40 MachOPlatform::MachOJITDylibDepInfo> {41public:42 static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {43 return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);44 }45 46 static bool serialize(SPSOutputBuffer &OB,47 const MachOPlatform::MachOJITDylibDepInfo &DDI) {48 return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,49 DDI.DepHeaders);50 }51 52 static bool deserialize(SPSInputBuffer &IB,53 MachOPlatform::MachOJITDylibDepInfo &DDI) {54 return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,55 DDI.DepHeaders);56 }57};58 59template <>60class SPSSerializationTraits<SPSMachOExecutorSymbolFlags,61 MachOPlatform::MachOExecutorSymbolFlags> {62private:63 using UT = std::underlying_type_t<MachOPlatform::MachOExecutorSymbolFlags>;64 65public:66 static size_t size(const MachOPlatform::MachOExecutorSymbolFlags &SF) {67 return sizeof(UT);68 }69 70 static bool serialize(SPSOutputBuffer &OB,71 const MachOPlatform::MachOExecutorSymbolFlags &SF) {72 return SPSArgList<UT>::serialize(OB, static_cast<UT>(SF));73 }74 75 static bool deserialize(SPSInputBuffer &IB,76 MachOPlatform::MachOExecutorSymbolFlags &SF) {77 UT Tmp;78 if (!SPSArgList<UT>::deserialize(IB, Tmp))79 return false;80 SF = static_cast<MachOPlatform::MachOExecutorSymbolFlags>(Tmp);81 return true;82 }83};84 85} // namespace shared86} // namespace orc87} // namespace llvm88 89namespace {90 91using SPSRegisterSymbolsArgs =92 SPSArgList<SPSExecutorAddr,93 SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,94 SPSMachOExecutorSymbolFlags>>>;95 96std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,97 std::string Name) {98 auto &ES = MOP.getExecutionSession();99 return std::make_unique<jitlink::LinkGraph>(100 std::move(Name), ES.getSymbolStringPool(), ES.getTargetTriple(),101 SubtargetFeatures(), jitlink::getGenericEdgeKindName);102}103 104// Creates a Bootstrap-Complete LinkGraph to run deferred actions.105class MachOPlatformCompleteBootstrapMaterializationUnit106 : public MaterializationUnit {107public:108 using SymbolTableVector =109 SmallVector<std::tuple<ExecutorAddr, ExecutorAddr,110 MachOPlatform::MachOExecutorSymbolFlags>>;111 112 MachOPlatformCompleteBootstrapMaterializationUnit(113 MachOPlatform &MOP, StringRef PlatformJDName,114 SymbolStringPtr CompleteBootstrapSymbol, SymbolTableVector SymTab,115 shared::AllocActions DeferredAAs, ExecutorAddr MachOHeaderAddr,116 ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown,117 ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib,118 ExecutorAddr RegisterObjectSymbolTable,119 ExecutorAddr DeregisterObjectSymbolTable)120 : MaterializationUnit(121 {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),122 MOP(MOP), PlatformJDName(PlatformJDName),123 CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),124 SymTab(std::move(SymTab)), DeferredAAs(std::move(DeferredAAs)),125 MachOHeaderAddr(MachOHeaderAddr), PlatformBootstrap(PlatformBootstrap),126 PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),127 DeregisterJITDylib(DeregisterJITDylib),128 RegisterObjectSymbolTable(RegisterObjectSymbolTable),129 DeregisterObjectSymbolTable(DeregisterObjectSymbolTable) {}130 131 StringRef getName() const override {132 return "MachOPlatformCompleteBootstrap";133 }134 135 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {136 using namespace jitlink;137 auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>");138 auto &PlaceholderSection =139 G->createSection("__orc_rt_cplt_bs", MemProt::Read);140 auto &PlaceholderBlock =141 G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0);142 G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1,143 Linkage::Strong, Scope::Hidden, false, true);144 145 // Reserve space for the stolen actions, plus two extras.146 G->allocActions().reserve(DeferredAAs.size() + 3);147 148 // 1. Bootstrap the platform support code.149 G->allocActions().push_back(150 {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)),151 cantFail(152 WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});153 154 // 2. Register the platform JITDylib.155 G->allocActions().push_back(156 {cantFail(WrapperFunctionCall::Create<157 SPSArgList<SPSString, SPSExecutorAddr>>(158 RegisterJITDylib, PlatformJDName, MachOHeaderAddr)),159 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(160 DeregisterJITDylib, MachOHeaderAddr))});161 162 // 3. Register deferred symbols.163 G->allocActions().push_back(164 {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(165 RegisterObjectSymbolTable, MachOHeaderAddr, SymTab)),166 cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(167 DeregisterObjectSymbolTable, MachOHeaderAddr, SymTab))});168 169 // 4. Add the deferred actions to the graph.170 std::move(DeferredAAs.begin(), DeferredAAs.end(),171 std::back_inserter(G->allocActions()));172 173 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));174 }175 176 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}177 178private:179 MachOPlatform &MOP;180 StringRef PlatformJDName;181 SymbolStringPtr CompleteBootstrapSymbol;182 SymbolTableVector SymTab;183 shared::AllocActions DeferredAAs;184 ExecutorAddr MachOHeaderAddr;185 ExecutorAddr PlatformBootstrap;186 ExecutorAddr PlatformShutdown;187 ExecutorAddr RegisterJITDylib;188 ExecutorAddr DeregisterJITDylib;189 ExecutorAddr RegisterObjectSymbolTable;190 ExecutorAddr DeregisterObjectSymbolTable;191};192 193static StringRef ObjCRuntimeObjectSectionsData[] = {194 MachOObjCCatListSectionName, MachOObjCCatList2SectionName,195 MachOObjCClassListSectionName, MachOObjCClassRefsSectionName,196 MachOObjCConstSectionName, MachOObjCDataSectionName,197 MachOObjCProtoListSectionName, MachOObjCProtoRefsSectionName,198 MachOObjCNLCatListSectionName, MachOObjCNLClassListSectionName,199 MachOObjCSelRefsSectionName};200 201static StringRef ObjCRuntimeObjectSectionsText[] = {202 MachOObjCClassNameSectionName, MachOObjCMethNameSectionName,203 MachOObjCMethTypeSectionName, MachOSwift5TypesSectionName,204 MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,205 MachOSwift5EntrySectionName, MachOSwift5ProtoSectionName,206 MachOSwift5ProtosSectionName};207 208static StringRef ObjCRuntimeObjectSectionName =209 "__llvm_jitlink_ObjCRuntimeRegistrationObject";210 211static StringRef ObjCImageInfoSymbolName =212 "__llvm_jitlink_macho_objc_imageinfo";213 214struct ObjCImageInfoFlags {215 uint16_t SwiftABIVersion;216 uint16_t SwiftVersion;217 bool HasCategoryClassProperties;218 bool HasSignedObjCClassROs;219 220 static constexpr uint32_t SIGNED_CLASS_RO = (1 << 4);221 static constexpr uint32_t HAS_CATEGORY_CLASS_PROPERTIES = (1 << 6);222 223 explicit ObjCImageInfoFlags(uint32_t RawFlags) {224 HasSignedObjCClassROs = RawFlags & SIGNED_CLASS_RO;225 HasCategoryClassProperties = RawFlags & HAS_CATEGORY_CLASS_PROPERTIES;226 SwiftABIVersion = (RawFlags >> 8) & 0xFF;227 SwiftVersion = (RawFlags >> 16) & 0xFFFF;228 }229 230 uint32_t rawFlags() const {231 uint32_t Result = 0;232 if (HasCategoryClassProperties)233 Result |= HAS_CATEGORY_CLASS_PROPERTIES;234 if (HasSignedObjCClassROs)235 Result |= SIGNED_CLASS_RO;236 Result |= (SwiftABIVersion << 8);237 Result |= (SwiftVersion << 16);238 return Result;239 }240};241} // end anonymous namespace242 243namespace llvm {244namespace orc {245 246std::optional<MachOPlatform::HeaderOptions::BuildVersionOpts>247MachOPlatform::HeaderOptions::BuildVersionOpts::fromTriple(const Triple &TT,248 uint32_t MinOS,249 uint32_t SDK) {250 251 uint32_t Platform;252 switch (TT.getOS()) {253 case Triple::IOS:254 Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_IOSSIMULATOR255 : MachO::PLATFORM_IOS;256 break;257 case Triple::MacOSX:258 Platform = MachO::PLATFORM_MACOS;259 break;260 case Triple::TvOS:261 Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_TVOSSIMULATOR262 : MachO::PLATFORM_TVOS;263 break;264 case Triple::WatchOS:265 Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_WATCHOSSIMULATOR266 : MachO::PLATFORM_WATCHOS;267 break;268 case Triple::XROS:269 Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_XROS_SIMULATOR270 : MachO::PLATFORM_XROS;271 break;272 default:273 return std::nullopt;274 }275 276 return MachOPlatform::HeaderOptions::BuildVersionOpts{Platform, MinOS, SDK};277}278 279Expected<std::unique_ptr<MachOPlatform>>280MachOPlatform::Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,281 std::unique_ptr<DefinitionGenerator> OrcRuntime,282 HeaderOptions PlatformJDOpts,283 MachOHeaderMUBuilder BuildMachOHeaderMU,284 std::optional<SymbolAliasMap> RuntimeAliases) {285 286 auto &ES = ObjLinkingLayer.getExecutionSession();287 288 // If the target is not supported then bail out immediately.289 if (!supportedTarget(ES.getTargetTriple()))290 return make_error<StringError>("Unsupported MachOPlatform triple: " +291 ES.getTargetTriple().str(),292 inconvertibleErrorCode());293 294 auto &EPC = ES.getExecutorProcessControl();295 296 // Create default aliases if the caller didn't supply any.297 if (!RuntimeAliases)298 RuntimeAliases = standardPlatformAliases(ES);299 300 // Define the aliases.301 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))302 return std::move(Err);303 304 // Add JIT-dispatch function support symbols.305 if (auto Err = PlatformJD.define(306 absoluteSymbols({{ES.intern("___orc_rt_jit_dispatch"),307 {EPC.getJITDispatchInfo().JITDispatchFunction,308 JITSymbolFlags::Exported}},309 {ES.intern("___orc_rt_jit_dispatch_ctx"),310 {EPC.getJITDispatchInfo().JITDispatchContext,311 JITSymbolFlags::Exported}}})))312 return std::move(Err);313 314 // Create the instance.315 Error Err = Error::success();316 auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform(317 ObjLinkingLayer, PlatformJD, std::move(OrcRuntime),318 std::move(PlatformJDOpts), std::move(BuildMachOHeaderMU), Err));319 if (Err)320 return std::move(Err);321 return std::move(P);322}323 324Expected<std::unique_ptr<MachOPlatform>>325MachOPlatform::Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,326 const char *OrcRuntimePath, HeaderOptions PlatformJDOpts,327 MachOHeaderMUBuilder BuildMachOHeaderMU,328 std::optional<SymbolAliasMap> RuntimeAliases) {329 330 // Create a generator for the ORC runtime archive.331 auto OrcRuntimeArchiveGenerator =332 StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);333 if (!OrcRuntimeArchiveGenerator)334 return OrcRuntimeArchiveGenerator.takeError();335 336 return Create(ObjLinkingLayer, PlatformJD,337 std::move(*OrcRuntimeArchiveGenerator),338 std::move(PlatformJDOpts), std::move(BuildMachOHeaderMU),339 std::move(RuntimeAliases));340}341 342Error MachOPlatform::setupJITDylib(JITDylib &JD) {343 return setupJITDylib(JD, /*Opts=*/{});344}345 346Error MachOPlatform::setupJITDylib(JITDylib &JD, HeaderOptions Opts) {347 if (auto Err = JD.define(BuildMachOHeaderMU(*this, std::move(Opts))))348 return Err;349 350 return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();351}352 353Error MachOPlatform::teardownJITDylib(JITDylib &JD) {354 std::lock_guard<std::mutex> Lock(PlatformMutex);355 auto I = JITDylibToHeaderAddr.find(&JD);356 if (I != JITDylibToHeaderAddr.end()) {357 assert(HeaderAddrToJITDylib.count(I->second) &&358 "HeaderAddrToJITDylib missing entry");359 HeaderAddrToJITDylib.erase(I->second);360 JITDylibToHeaderAddr.erase(I);361 }362 JITDylibToPThreadKey.erase(&JD);363 return Error::success();364}365 366Error MachOPlatform::notifyAdding(ResourceTracker &RT,367 const MaterializationUnit &MU) {368 auto &JD = RT.getJITDylib();369 const auto &InitSym = MU.getInitializerSymbol();370 if (!InitSym)371 return Error::success();372 373 RegisteredInitSymbols[&JD].add(InitSym,374 SymbolLookupFlags::WeaklyReferencedSymbol);375 LLVM_DEBUG({376 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "377 << MU.getName() << "\n";378 });379 return Error::success();380}381 382Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {383 llvm_unreachable("Not supported yet");384}385 386static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,387 ArrayRef<std::pair<const char *, const char *>> AL) {388 for (auto &KV : AL) {389 auto AliasName = ES.intern(KV.first);390 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");391 Aliases[std::move(AliasName)] = {ES.intern(KV.second),392 JITSymbolFlags::Exported};393 }394}395 396SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {397 SymbolAliasMap Aliases;398 addAliases(ES, Aliases, requiredCXXAliases());399 addAliases(ES, Aliases, standardRuntimeUtilityAliases());400 addAliases(ES, Aliases, standardLazyCompilationAliases());401 return Aliases;402}403 404ArrayRef<std::pair<const char *, const char *>>405MachOPlatform::requiredCXXAliases() {406 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {407 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};408 409 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);410}411 412ArrayRef<std::pair<const char *, const char *>>413MachOPlatform::standardRuntimeUtilityAliases() {414 static const std::pair<const char *, const char *>415 StandardRuntimeUtilityAliases[] = {416 {"___orc_rt_run_program", "___orc_rt_macho_run_program"},417 {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},418 {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},419 {"___orc_rt_jit_dlupdate", "___orc_rt_macho_jit_dlupdate"},420 {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},421 {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},422 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};423 424 return ArrayRef<std::pair<const char *, const char *>>(425 StandardRuntimeUtilityAliases);426}427 428ArrayRef<std::pair<const char *, const char *>>429MachOPlatform::standardLazyCompilationAliases() {430 static const std::pair<const char *, const char *>431 StandardLazyCompilationAliases[] = {432 {"__orc_rt_reenter", "__orc_rt_sysv_reenter"},433 {"__orc_rt_resolve_tag", "___orc_rt_resolve_tag"}};434 435 return ArrayRef<std::pair<const char *, const char *>>(436 StandardLazyCompilationAliases);437}438 439bool MachOPlatform::supportedTarget(const Triple &TT) {440 switch (TT.getArch()) {441 case Triple::aarch64:442 case Triple::x86_64:443 return true;444 default:445 return false;446 }447}448 449jitlink::Edge::Kind MachOPlatform::getPointerEdgeKind(jitlink::LinkGraph &G) {450 switch (G.getTargetTriple().getArch()) {451 case Triple::aarch64:452 return jitlink::aarch64::Pointer64;453 case Triple::x86_64:454 return jitlink::x86_64::Pointer64;455 default:456 llvm_unreachable("Unsupported architecture");457 }458}459 460MachOPlatform::MachOExecutorSymbolFlags461MachOPlatform::flagsForSymbol(jitlink::Symbol &Sym) {462 MachOPlatform::MachOExecutorSymbolFlags Flags{};463 if (Sym.getLinkage() == jitlink::Linkage::Weak)464 Flags |= MachOExecutorSymbolFlags::Weak;465 466 if (Sym.isCallable())467 Flags |= MachOExecutorSymbolFlags::Callable;468 469 return Flags;470}471 472MachOPlatform::MachOPlatform(473 ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,474 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,475 HeaderOptions PlatformJDOpts, MachOHeaderMUBuilder BuildMachOHeaderMU,476 Error &Err)477 : ES(ObjLinkingLayer.getExecutionSession()), PlatformJD(PlatformJD),478 ObjLinkingLayer(ObjLinkingLayer),479 BuildMachOHeaderMU(std::move(BuildMachOHeaderMU)) {480 ErrorAsOutParameter _(Err);481 ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));482 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));483 484 {485 // Check for force-eh-frame486 std::optional<bool> ForceEHFrames;487 if ((Err = ES.getBootstrapMapValue<bool, bool>("darwin-use-ehframes-only",488 ForceEHFrames)))489 return;490 this->ForceEHFrames = ForceEHFrames.value_or(false);491 }492 493 BootstrapInfo BI;494 Bootstrap = &BI;495 496 // Bootstrap process -- here be phase-ordering dragons.497 //498 // The MachOPlatform class uses allocation actions to register metadata499 // sections with the ORC runtime, however the runtime contains metadata500 // registration functions that have their own metadata that they need to501 // register (e.g. the frame-info registration functions have frame-info).502 // We can't use an ordinary lookup to find these registration functions503 // because their address is needed during the link of the containing graph504 // itself (to build the allocation actions that will call the registration505 // functions). Further complicating the situation (a) the graph containing506 // the registration functions is allowed to depend on other graphs (e.g. the507 // graph containing the ORC runtime RTTI support) so we need to handle an508 // unknown set of dependencies during bootstrap, and (b) these graphs may509 // be linked concurrently if the user has installed a concurrent dispatcher.510 //511 // We satisfy these constraints by implementing a bootstrap phase during which512 // allocation actions generated by MachOPlatform are appended to a list of513 // deferred allocation actions, rather than to the graphs themselves. At the514 // end of the bootstrap process the deferred actions are attached to a final515 // "complete-bootstrap" graph that causes them to be run.516 //517 // The bootstrap steps are as follows:518 //519 // 1. Request the graph containing the mach header. This graph is guaranteed520 // not to have any metadata so the fact that the registration functions521 // are not available yet is not a problem.522 //523 // 2. Look up the registration functions and discard the results. This will524 // trigger linking of the graph containing these functions, and525 // consequently any graphs that it depends on. We do not use the lookup526 // result to find the addresses of the functions requested (as described527 // above the lookup will return too late for that), instead we capture the528 // addresses in a post-allocation pass injected by the platform runtime529 // during bootstrap only.530 //531 // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of532 // graphs being linked (potentially concurrently), and we block until all533 // of these graphs have completed linking. This is to avoid a race on the534 // deferred-actions vector: the lookup for the runtime registration535 // functions may return while some functions (those that are being536 // incidentally linked in, but aren't reachable via the runtime functions)537 // are still being linked, and we need to capture any allocation actions538 // for this incidental code before we proceed.539 //540 // 4. Once all active links are complete we transfer the deferred actions to541 // a newly added CompleteBootstrap graph and then request a symbol from542 // the CompleteBootstrap graph to trigger materialization. This will cause543 // all deferred actions to be run, and once this lookup returns we can544 // proceed.545 //546 // 5. Finally, we associate runtime support methods in MachOPlatform with547 // the corresponding jit-dispatch tag variables in the ORC runtime to make548 // the support methods callable. The bootstrap is now complete.549 550 // Step (1) Add header materialization unit and request.551 if ((Err = PlatformJD.define(552 this->BuildMachOHeaderMU(*this, std::move(PlatformJDOpts)))))553 return;554 if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))555 return;556 557 // Step (2) Request runtime registration functions to trigger558 // materialization..559 if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),560 SymbolLookupSet(561 {PlatformBootstrap.Name, PlatformShutdown.Name,562 RegisterJITDylib.Name, DeregisterJITDylib.Name,563 RegisterObjectSymbolTable.Name,564 DeregisterObjectSymbolTable.Name,565 RegisterObjectPlatformSections.Name,566 DeregisterObjectPlatformSections.Name,567 CreatePThreadKey.Name}))568 .takeError()))569 return;570 571 // Step (3) Wait for any incidental linker work to complete.572 {573 std::unique_lock<std::mutex> Lock(PlatformMutex);574 BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });575 Bootstrap = nullptr;576 }577 578 // Step (4) Add complete-bootstrap materialization unit and request.579 auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap");580 if ((Err = PlatformJD.define(581 std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>(582 *this, PlatformJD.getName(), BootstrapCompleteSymbol,583 std::move(BI.SymTab), std::move(BI.DeferredAAs),584 BI.MachOHeaderAddr, PlatformBootstrap.Addr,585 PlatformShutdown.Addr, RegisterJITDylib.Addr,586 DeregisterJITDylib.Addr, RegisterObjectSymbolTable.Addr,587 DeregisterObjectSymbolTable.Addr))))588 return;589 if ((Err = ES.lookup(makeJITDylibSearchOrder(590 &PlatformJD, JITDylibLookupFlags::MatchAllSymbols),591 std::move(BootstrapCompleteSymbol))592 .takeError()))593 return;594 595 // (5) Associate runtime support functions.596 // TODO: Consider moving this above (4) to make runtime support functions597 // available to the bootstrap completion graph. We'd just need to be598 // sure that the runtime support functions are fully usable before any599 // bootstrap completion actions use them (e.g. the ORC runtime600 // macho_platform object would have to have been created and601 // initialized).602 if ((Err = associateRuntimeSupportFunctions()))603 return;604}605 606Error MachOPlatform::associateRuntimeSupportFunctions() {607 ExecutionSession::JITDispatchHandlerAssociationMap WFs;608 609 using PushInitializersSPSSig =610 SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr);611 WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =612 ES.wrapAsyncWithSPS<PushInitializersSPSSig>(613 this, &MachOPlatform::rt_pushInitializers);614 615 using PushSymbolsSPSSig =616 SPSError(SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool>>);617 WFs[ES.intern("___orc_rt_macho_push_symbols_tag")] =618 ES.wrapAsyncWithSPS<PushSymbolsSPSSig>(this,619 &MachOPlatform::rt_pushSymbols);620 621 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));622}623 624void MachOPlatform::pushInitializersLoop(625 PushInitializersSendResultFn SendResult, JITDylibSP JD) {626 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;627 DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;628 SmallVector<JITDylib *, 16> Worklist({JD.get()});629 630 ES.runSessionLocked([&]() {631 while (!Worklist.empty()) {632 // FIXME: Check for defunct dylibs.633 634 auto DepJD = Worklist.back();635 Worklist.pop_back();636 637 // If we've already visited this JITDylib on this iteration then continue.638 auto [It, Inserted] = JDDepMap.try_emplace(DepJD);639 if (!Inserted)640 continue;641 642 // Add dep info.643 auto &DM = It->second;644 DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {645 for (auto &KV : O) {646 if (KV.first == DepJD)647 continue;648 DM.push_back(KV.first);649 Worklist.push_back(KV.first);650 }651 });652 653 // Add any registered init symbols.654 auto RISItr = RegisteredInitSymbols.find(DepJD);655 if (RISItr != RegisteredInitSymbols.end()) {656 NewInitSymbols[DepJD] = std::move(RISItr->second);657 RegisteredInitSymbols.erase(RISItr);658 }659 }660 });661 662 // If there are no further init symbols to look up then send the link order663 // (as a list of header addresses) to the caller.664 if (NewInitSymbols.empty()) {665 666 // To make the list intelligible to the runtime we need to convert all667 // JITDylib pointers to their header addresses. Only include JITDylibs668 // that appear in the JITDylibToHeaderAddr map (i.e. those that have been669 // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.670 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;671 HeaderAddrs.reserve(JDDepMap.size());672 {673 std::lock_guard<std::mutex> Lock(PlatformMutex);674 for (auto &KV : JDDepMap) {675 auto I = JITDylibToHeaderAddr.find(KV.first);676 if (I != JITDylibToHeaderAddr.end())677 HeaderAddrs[KV.first] = I->second;678 }679 }680 681 // Build the dep info map to return.682 MachOJITDylibDepInfoMap DIM;683 DIM.reserve(JDDepMap.size());684 for (auto &KV : JDDepMap) {685 auto HI = HeaderAddrs.find(KV.first);686 // Skip unmanaged JITDylibs.687 if (HI == HeaderAddrs.end())688 continue;689 auto H = HI->second;690 MachOJITDylibDepInfo DepInfo;691 for (auto &Dep : KV.second) {692 auto HJ = HeaderAddrs.find(Dep);693 if (HJ != HeaderAddrs.end())694 DepInfo.DepHeaders.push_back(HJ->second);695 }696 DIM.push_back(std::make_pair(H, std::move(DepInfo)));697 }698 SendResult(DIM);699 return;700 }701 702 // Otherwise issue a lookup and re-run this phase when it completes.703 lookupInitSymbolsAsync(704 [this, SendResult = std::move(SendResult), JD](Error Err) mutable {705 if (Err)706 SendResult(std::move(Err));707 else708 pushInitializersLoop(std::move(SendResult), JD);709 },710 ES, std::move(NewInitSymbols));711}712 713void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,714 ExecutorAddr JDHeaderAddr) {715 JITDylibSP JD;716 {717 std::lock_guard<std::mutex> Lock(PlatformMutex);718 auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);719 if (I != HeaderAddrToJITDylib.end())720 JD = I->second;721 }722 723 LLVM_DEBUG({724 dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";725 if (JD)726 dbgs() << "pushing initializers for " << JD->getName() << "\n";727 else728 dbgs() << "No JITDylib for header address.\n";729 });730 731 if (!JD) {732 SendResult(make_error<StringError>("No JITDylib with header addr " +733 formatv("{0:x}", JDHeaderAddr),734 inconvertibleErrorCode()));735 return;736 }737 738 pushInitializersLoop(std::move(SendResult), JD);739}740 741void MachOPlatform::rt_pushSymbols(742 PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle,743 const std::vector<std::pair<StringRef, bool>> &SymbolNames) {744 745 JITDylib *JD = nullptr;746 747 {748 std::lock_guard<std::mutex> Lock(PlatformMutex);749 auto I = HeaderAddrToJITDylib.find(Handle);750 if (I != HeaderAddrToJITDylib.end())751 JD = I->second;752 }753 LLVM_DEBUG({754 dbgs() << "MachOPlatform::rt_pushSymbols(";755 if (JD)756 dbgs() << "\"" << JD->getName() << "\", [ ";757 else758 dbgs() << "<invalid handle " << Handle << ">, [ ";759 for (auto &Name : SymbolNames)760 dbgs() << "\"" << Name.first << "\" ";761 dbgs() << "])\n";762 });763 764 if (!JD) {765 SendResult(make_error<StringError>("No JITDylib associated with handle " +766 formatv("{0:x}", Handle),767 inconvertibleErrorCode()));768 return;769 }770 771 SymbolLookupSet LS;772 for (auto &[Name, Required] : SymbolNames)773 LS.add(ES.intern(Name), Required774 ? SymbolLookupFlags::RequiredSymbol775 : SymbolLookupFlags::WeaklyReferencedSymbol);776 777 ES.lookup(778 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},779 std::move(LS), SymbolState::Ready,780 [SendResult = std::move(SendResult)](Expected<SymbolMap> Result) mutable {781 SendResult(Result.takeError());782 },783 NoDependenciesToRegister);784}785 786Expected<uint64_t> MachOPlatform::createPThreadKey() {787 if (!CreatePThreadKey.Addr)788 return make_error<StringError>(789 "Attempting to create pthread key in target, but runtime support has "790 "not been loaded yet",791 inconvertibleErrorCode());792 793 Expected<uint64_t> Result(0);794 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(795 CreatePThreadKey.Addr, Result))796 return std::move(Err);797 return Result;798}799 800void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(801 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,802 jitlink::PassConfiguration &Config) {803 804 using namespace jitlink;805 806 bool InBootstrapPhase = false;807 808 ExecutorAddr HeaderAddr;809 {810 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);811 if (LLVM_UNLIKELY(&MR.getTargetJITDylib() == &MP.PlatformJD)) {812 if (MP.Bootstrap) {813 InBootstrapPhase = true;814 ++MP.Bootstrap->ActiveGraphs;815 }816 }817 818 // Get the dso-base address if available.819 auto I = MP.JITDylibToHeaderAddr.find(&MR.getTargetJITDylib());820 if (I != MP.JITDylibToHeaderAddr.end())821 HeaderAddr = I->second;822 }823 824 // If we're forcing eh-frame use then discard the compact-unwind section825 // immediately to prevent FDEs from being stripped.826 if (MP.ForceEHFrames)827 if (auto *CUSec = LG.findSectionByName(MachOCompactUnwindSectionName))828 LG.removeSection(*CUSec);829 830 // Point the libunwind dso-base absolute symbol at the header for the831 // JITDylib. This will prevent us from synthesizing a new header for832 // every object.833 if (HeaderAddr)834 LG.addAbsoluteSymbol("__jitlink$libunwind_dso_base", HeaderAddr, 0,835 Linkage::Strong, Scope::Local, true);836 837 // If we're in the bootstrap phase then increment the active graphs.838 if (LLVM_UNLIKELY(InBootstrapPhase))839 Config.PostAllocationPasses.push_back([this](LinkGraph &G) {840 return bootstrapPipelineRecordRuntimeFunctions(G);841 });842 843 // --- Handle Initializers ---844 if (auto InitSymbol = MR.getInitializerSymbol()) {845 846 // If the initializer symbol is the MachOHeader start symbol then just847 // register it and then bail out -- the header materialization unit848 // definitely doesn't need any other passes.849 if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) {850 Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {851 return associateJITDylibHeaderSymbol(G, MR);852 });853 return;854 }855 856 // If the object contains an init symbol other than the header start symbol857 // then add passes to preserve, process and register the init858 // sections/symbols.859 Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {860 if (auto Err = preserveImportantSections(G, MR))861 return Err;862 return processObjCImageInfo(G, MR);863 });864 Config.PostPrunePasses.push_back(865 [this](LinkGraph &G) { return createObjCRuntimeObject(G); });866 Config.PostAllocationPasses.push_back(867 [this, &MR](LinkGraph &G) { return populateObjCRuntimeObject(G, MR); });868 }869 870 // Insert TLV lowering at the start of the PostPrunePasses, since we want871 // it to run before GOT/PLT lowering.872 Config.PostPrunePasses.insert(873 Config.PostPrunePasses.begin(),874 [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) {875 return fixTLVSectionsAndEdges(G, JD);876 });877 878 // Add symbol table prepare and register passes: These will add strings for879 // all symbols to the c-strings section, and build a symbol table registration880 // call.881 auto JITSymTabInfo = std::make_shared<JITSymTabVector>();882 Config.PostPrunePasses.push_back([this, JITSymTabInfo](LinkGraph &G) {883 return prepareSymbolTableRegistration(G, *JITSymTabInfo);884 });885 Config.PostFixupPasses.push_back([this, &MR, JITSymTabInfo,886 InBootstrapPhase](LinkGraph &G) {887 return addSymbolTableRegistration(G, MR, *JITSymTabInfo, InBootstrapPhase);888 });889 890 // Add a pass to register the final addresses of any special sections in the891 // object with the runtime.892 Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib(),893 HeaderAddr,894 InBootstrapPhase](LinkGraph &G) {895 return registerObjectPlatformSections(G, JD, HeaderAddr, InBootstrapPhase);896 });897 898 // If we're in the bootstrap phase then steal allocation actions and then899 // decrement the active graphs.900 if (InBootstrapPhase)901 Config.PostFixupPasses.push_back(902 [this](LinkGraph &G) { return bootstrapPipelineEnd(G); });903}904 905Error MachOPlatform::MachOPlatformPlugin::906 bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) {907 // Record bootstrap function names.908 std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = {909 {*MP.MachOHeaderStartSymbol, &MP.Bootstrap->MachOHeaderAddr},910 {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr},911 {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr},912 {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr},913 {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr},914 {*MP.RegisterObjectSymbolTable.Name, &MP.RegisterObjectSymbolTable.Addr},915 {*MP.DeregisterObjectSymbolTable.Name,916 &MP.DeregisterObjectSymbolTable.Addr},917 {*MP.RegisterObjectPlatformSections.Name,918 &MP.RegisterObjectPlatformSections.Addr},919 {*MP.DeregisterObjectPlatformSections.Name,920 &MP.DeregisterObjectPlatformSections.Addr},921 {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr},922 {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr},923 {*MP.DeregisterObjCRuntimeObject.Name,924 &MP.DeregisterObjCRuntimeObject.Addr}};925 926 bool RegisterMachOHeader = false;927 928 for (auto *Sym : G.defined_symbols()) {929 for (auto &RTSym : RuntimeSymbols) {930 if (Sym->hasName() && *Sym->getName() == RTSym.first) {931 if (*RTSym.second)932 return make_error<StringError>(933 "Duplicate " + RTSym.first +934 " detected during MachOPlatform bootstrap",935 inconvertibleErrorCode());936 937 if (Sym->getName() == MP.MachOHeaderStartSymbol)938 RegisterMachOHeader = true;939 940 *RTSym.second = Sym->getAddress();941 }942 }943 }944 945 if (RegisterMachOHeader) {946 // If this graph defines the macho header symbol then create the internal947 // mapping between it and PlatformJD.948 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);949 MP.JITDylibToHeaderAddr[&MP.PlatformJD] = MP.Bootstrap->MachOHeaderAddr;950 MP.HeaderAddrToJITDylib[MP.Bootstrap->MachOHeaderAddr] = &MP.PlatformJD;951 }952 953 return Error::success();954}955 956Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(957 jitlink::LinkGraph &G) {958 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);959 960 --MP.Bootstrap->ActiveGraphs;961 // Notify Bootstrap->CV while holding the mutex because the mutex is962 // also keeping Bootstrap->CV alive.963 if (MP.Bootstrap->ActiveGraphs == 0)964 MP.Bootstrap->CV.notify_all();965 return Error::success();966}967 968Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(969 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {970 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {971 return Sym->getName() == MP.MachOHeaderStartSymbol;972 });973 assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");974 975 auto &JD = MR.getTargetJITDylib();976 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);977 auto HeaderAddr = (*I)->getAddress();978 MP.JITDylibToHeaderAddr[&JD] = HeaderAddr;979 MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;980 // We can unconditionally add these actions to the Graph because this pass981 // isn't used during bootstrap.982 G.allocActions().push_back(983 {cantFail(984 WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>(985 MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)),986 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(987 MP.DeregisterJITDylib.Addr, HeaderAddr))});988 return Error::success();989}990 991Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections(992 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {993 // __objc_imageinfo is "important": we want to preserve it and record its994 // address in the first graph that it appears in, then verify and discard it995 // in all subsequent graphs. In this pass we preserve unconditionally -- we'll996 // manually throw it away in the processObjCImageInfo pass.997 if (auto *ObjCImageInfoSec =998 G.findSectionByName(MachOObjCImageInfoSectionName)) {999 if (ObjCImageInfoSec->blocks_size() != 1)1000 return make_error<StringError>(1001 "In " + G.getName() +1002 "__DATA,__objc_imageinfo contains multiple blocks",1003 inconvertibleErrorCode());1004 G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false,1005 true);1006 1007 for (auto *B : ObjCImageInfoSec->blocks())1008 if (!B->edges_empty())1009 return make_error<StringError>("In " + G.getName() + ", " +1010 MachOObjCImageInfoSectionName +1011 " contains references to symbols",1012 inconvertibleErrorCode());1013 }1014 1015 // Init sections are important: We need to preserve them and so that their1016 // addresses can be captured and reported to the ORC runtime in1017 // registerObjectPlatformSections.1018 if (const auto &InitSymName = MR.getInitializerSymbol()) {1019 1020 jitlink::Symbol *InitSym = nullptr;1021 for (auto &InitSectionName : MachOInitSectionNames) {1022 // Skip ObjCImageInfo -- this shouldn't have any dependencies, and we may1023 // remove it later.1024 if (InitSectionName == MachOObjCImageInfoSectionName)1025 continue;1026 1027 // Skip non-init sections.1028 auto *InitSection = G.findSectionByName(InitSectionName);1029 if (!InitSection || InitSection->empty())1030 continue;1031 1032 // Create the init symbol if it has not been created already and attach it1033 // to the first block.1034 if (!InitSym) {1035 auto &B = **InitSection->blocks().begin();1036 InitSym = &G.addDefinedSymbol(1037 B, 0, *InitSymName, B.getSize(), jitlink::Linkage::Strong,1038 jitlink::Scope::SideEffectsOnly, false, true);1039 }1040 1041 // Add keep-alive edges to anonymous symbols in all other init blocks.1042 for (auto *B : InitSection->blocks()) {1043 if (B == &InitSym->getBlock())1044 continue;1045 1046 auto &S = G.addAnonymousSymbol(*B, 0, B->getSize(), false, true);1047 InitSym->getBlock().addEdge(jitlink::Edge::KeepAlive, 0, S, 0);1048 }1049 }1050 }1051 1052 return Error::success();1053}1054 1055Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(1056 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {1057 1058 // If there's an ObjC imagine info then either1059 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In1060 // this case we name and record it.1061 // OR1062 // (2) We already have a recorded __objc_imageinfo for this JITDylib,1063 // in which case we just verify it.1064 auto *ObjCImageInfo = G.findSectionByName(MachOObjCImageInfoSectionName);1065 if (!ObjCImageInfo)1066 return Error::success();1067 1068 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();1069 1070 // Check that the section is not empty if present.1071 if (ObjCImageInfoBlocks.empty())1072 return make_error<StringError>("Empty " + MachOObjCImageInfoSectionName +1073 " section in " + G.getName(),1074 inconvertibleErrorCode());1075 1076 // Check that there's only one block in the section.1077 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())1078 return make_error<StringError>("Multiple blocks in " +1079 MachOObjCImageInfoSectionName +1080 " section in " + G.getName(),1081 inconvertibleErrorCode());1082 1083 // Check that the __objc_imageinfo section is unreferenced.1084 // FIXME: We could optimize this check if Symbols had a ref-count.1085 for (auto &Sec : G.sections()) {1086 if (&Sec != ObjCImageInfo)1087 for (auto *B : Sec.blocks())1088 for (auto &E : B->edges())1089 if (E.getTarget().isDefined() &&1090 &E.getTarget().getSection() == ObjCImageInfo)1091 return make_error<StringError>(MachOObjCImageInfoSectionName +1092 " is referenced within file " +1093 G.getName(),1094 inconvertibleErrorCode());1095 }1096 1097 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();1098 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();1099 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());1100 auto Flags =1101 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());1102 1103 // Lock the mutex while we verify / update the ObjCImageInfos map.1104 std::lock_guard<std::mutex> Lock(PluginMutex);1105 1106 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());1107 if (ObjCImageInfoItr != ObjCImageInfos.end()) {1108 // We've already registered an __objc_imageinfo section. Verify the1109 // content of this new section matches, then delete it.1110 if (ObjCImageInfoItr->second.Version != Version)1111 return make_error<StringError>(1112 "ObjC version in " + G.getName() +1113 " does not match first registered version",1114 inconvertibleErrorCode());1115 if (ObjCImageInfoItr->second.Flags != Flags)1116 if (Error E = mergeImageInfoFlags(G, MR, ObjCImageInfoItr->second, Flags))1117 return E;1118 1119 // __objc_imageinfo is valid. Delete the block.1120 for (auto *S : ObjCImageInfo->symbols())1121 G.removeDefinedSymbol(*S);1122 G.removeBlock(ObjCImageInfoBlock);1123 } else {1124 LLVM_DEBUG({1125 dbgs() << "MachOPlatform: Registered __objc_imageinfo for "1126 << MR.getTargetJITDylib().getName() << " in " << G.getName()1127 << "; flags = " << formatv("{0:x4}", Flags) << "\n";1128 });1129 // We haven't registered an __objc_imageinfo section yet. Register and1130 // move on. The section should already be marked no-dead-strip.1131 G.addDefinedSymbol(ObjCImageInfoBlock, 0, ObjCImageInfoSymbolName,1132 ObjCImageInfoBlock.getSize(), jitlink::Linkage::Strong,1133 jitlink::Scope::Hidden, false, true);1134 if (auto Err = MR.defineMaterializing(1135 {{MR.getExecutionSession().intern(ObjCImageInfoSymbolName),1136 JITSymbolFlags()}}))1137 return Err;1138 ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags, false};1139 }1140 1141 return Error::success();1142}1143 1144Error MachOPlatform::MachOPlatformPlugin::mergeImageInfoFlags(1145 jitlink::LinkGraph &G, MaterializationResponsibility &MR,1146 ObjCImageInfo &Info, uint32_t NewFlags) {1147 if (Info.Flags == NewFlags)1148 return Error::success();1149 1150 ObjCImageInfoFlags Old(Info.Flags);1151 ObjCImageInfoFlags New(NewFlags);1152 1153 // Check for incompatible flags.1154 if (Old.SwiftABIVersion && New.SwiftABIVersion &&1155 Old.SwiftABIVersion != New.SwiftABIVersion)1156 return make_error<StringError>("Swift ABI version in " + G.getName() +1157 " does not match first registered flags",1158 inconvertibleErrorCode());1159 1160 // HasCategoryClassProperties and HasSignedObjCClassROs can be disabled before1161 // they are registered, if necessary, but once they are in use must be1162 // supported by subsequent objects.1163 if (Info.Finalized && Old.HasCategoryClassProperties &&1164 !New.HasCategoryClassProperties)1165 return make_error<StringError>("ObjC category class property support in " +1166 G.getName() +1167 " does not match first registered flags",1168 inconvertibleErrorCode());1169 if (Info.Finalized && Old.HasSignedObjCClassROs && !New.HasSignedObjCClassROs)1170 return make_error<StringError>("ObjC class_ro_t pointer signing in " +1171 G.getName() +1172 " does not match first registered flags",1173 inconvertibleErrorCode());1174 1175 // If we cannot change the flags, ignore any remaining differences. Adding1176 // Swift or changing its version are unlikely to cause problems in practice.1177 if (Info.Finalized)1178 return Error::success();1179 1180 // Use the minimum Swift version.1181 if (Old.SwiftVersion && New.SwiftVersion)1182 New.SwiftVersion = std::min(Old.SwiftVersion, New.SwiftVersion);1183 else if (Old.SwiftVersion)1184 New.SwiftVersion = Old.SwiftVersion;1185 // Add a Swift ABI version if it was pure objc before.1186 if (!New.SwiftABIVersion)1187 New.SwiftABIVersion = Old.SwiftABIVersion;1188 // Disable class properties if any object does not support it.1189 if (Old.HasCategoryClassProperties != New.HasCategoryClassProperties)1190 New.HasCategoryClassProperties = false;1191 // Disable signed class ro data if any object does not support it.1192 if (Old.HasSignedObjCClassROs != New.HasSignedObjCClassROs)1193 New.HasSignedObjCClassROs = false;1194 1195 LLVM_DEBUG({1196 dbgs() << "MachOPlatform: Merging __objc_imageinfo flags for "1197 << MR.getTargetJITDylib().getName() << " (was "1198 << formatv("{0:x4}", Old.rawFlags()) << ")"1199 << " with " << G.getName() << " (" << formatv("{0:x4}", NewFlags)1200 << ")"1201 << " -> " << formatv("{0:x4}", New.rawFlags()) << "\n";1202 });1203 1204 Info.Flags = New.rawFlags();1205 return Error::success();1206}1207 1208Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(1209 jitlink::LinkGraph &G, JITDylib &JD) {1210 auto TLVBootStrapSymbolName = G.intern("__tlv_bootstrap");1211 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.1212 for (auto *Sym : G.external_symbols())1213 if (Sym->getName() == TLVBootStrapSymbolName) {1214 auto TLSGetADDR =1215 MP.getExecutionSession().intern("___orc_rt_macho_tlv_get_addr");1216 Sym->setName(std::move(TLSGetADDR));1217 break;1218 }1219 1220 // Store key in __thread_vars struct fields.1221 if (auto *ThreadDataSec = G.findSectionByName(MachOThreadVarsSectionName)) {1222 std::optional<uint64_t> Key;1223 {1224 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);1225 auto I = MP.JITDylibToPThreadKey.find(&JD);1226 if (I != MP.JITDylibToPThreadKey.end())1227 Key = I->second;1228 }1229 1230 if (!Key) {1231 if (auto KeyOrErr = MP.createPThreadKey())1232 Key = *KeyOrErr;1233 else1234 return KeyOrErr.takeError();1235 }1236 1237 uint64_t PlatformKeyBits =1238 support::endian::byte_swap(*Key, G.getEndianness());1239 1240 for (auto *B : ThreadDataSec->blocks()) {1241 if (B->getSize() != 3 * G.getPointerSize())1242 return make_error<StringError>("__thread_vars block at " +1243 formatv("{0:x}", B->getAddress()) +1244 " has unexpected size",1245 inconvertibleErrorCode());1246 1247 auto NewBlockContent = G.allocateBuffer(B->getSize());1248 llvm::copy(B->getContent(), NewBlockContent.data());1249 memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,1250 G.getPointerSize());1251 B->setContent(NewBlockContent);1252 }1253 }1254 1255 // Transform any TLV edges into GOT edges.1256 for (auto *B : G.blocks())1257 for (auto &E : B->edges())1258 if (E.getKind() ==1259 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)1260 E.setKind(jitlink::x86_64::1261 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);1262 1263 return Error::success();1264}1265 1266std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>1267MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(1268 jitlink::LinkGraph &G) {1269 using namespace jitlink;1270 1271 UnwindSections US;1272 1273 // ScanSection records a section range and adds any executable blocks that1274 // that section points to to the CodeBlocks vector.1275 SmallVector<Block *> CodeBlocks;1276 auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange,1277 auto AddCodeBlocks) {1278 if (Sec.blocks().empty())1279 return;1280 SecRange = (*Sec.blocks().begin())->getRange();1281 for (auto *B : Sec.blocks()) {1282 auto R = B->getRange();1283 SecRange.Start = std::min(SecRange.Start, R.Start);1284 SecRange.End = std::max(SecRange.End, R.End);1285 AddCodeBlocks(*B);1286 }1287 };1288 1289 if (Section *EHFrameSec = G.findSectionByName(MachOEHFrameSectionName)) {1290 ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection, [&](Block &B) {1291 if (auto *Fn = jitlink::EHFrameCFIBlockInspector::FromEdgeScan(B)1292 .getPCBeginEdge())1293 if (Fn->getTarget().isDefined())1294 CodeBlocks.push_back(&Fn->getTarget().getBlock());1295 });1296 }1297 1298 if (Section *CUInfoSec = G.findSectionByName(MachOUnwindInfoSectionName)) {1299 ScanUnwindInfoSection(1300 *CUInfoSec, US.CompactUnwindSection, [&](Block &B) {1301 for (auto &E : B.edges()) {1302 assert(E.getTarget().isDefined() &&1303 "unwind-info record edge has external target");1304 assert(E.getKind() == Edge::KeepAlive &&1305 "unwind-info record has unexpected edge kind");1306 CodeBlocks.push_back(&E.getTarget().getBlock());1307 }1308 });1309 }1310 1311 // If we didn't find any pointed-to code-blocks then there's no need to1312 // register any info.1313 if (CodeBlocks.empty())1314 return std::nullopt;1315 1316 // We have info to register. Sort the code blocks into address order and1317 // build a list of contiguous address ranges covering them all.1318 llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) {1319 return LHS->getAddress() < RHS->getAddress();1320 });1321 for (auto *B : CodeBlocks) {1322 if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress())1323 US.CodeRanges.push_back(B->getRange());1324 else1325 US.CodeRanges.back().End = B->getRange().End;1326 }1327 1328 LLVM_DEBUG({1329 dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n"1330 << " DWARF: ";1331 if (US.DwarfSection.Start)1332 dbgs() << US.DwarfSection << "\n";1333 else1334 dbgs() << "none\n";1335 dbgs() << " Compact-unwind: ";1336 if (US.CompactUnwindSection.Start)1337 dbgs() << US.CompactUnwindSection << "\n";1338 else1339 dbgs() << "none\n"1340 << "for code ranges:\n";1341 for (auto &CR : US.CodeRanges)1342 dbgs() << " " << CR << "\n";1343 if (US.CodeRanges.size() >= G.sections_size())1344 dbgs() << "WARNING: High number of discontiguous code ranges! "1345 "Padding may be interfering with coalescing.\n";1346 });1347 1348 return US;1349}1350 1351Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(1352 jitlink::LinkGraph &G, JITDylib &JD, ExecutorAddr HeaderAddr,1353 bool InBootstrapPhase) {1354 1355 // Get a pointer to the thread data section if there is one. It will be used1356 // below.1357 jitlink::Section *ThreadDataSection =1358 G.findSectionByName(MachOThreadDataSectionName);1359 1360 // Handle thread BSS section if there is one.1361 if (auto *ThreadBSSSection = G.findSectionByName(MachOThreadBSSSectionName)) {1362 // If there's already a thread data section in this graph then merge the1363 // thread BSS section content into it, otherwise just treat the thread1364 // BSS section as the thread data section.1365 if (ThreadDataSection)1366 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);1367 else1368 ThreadDataSection = ThreadBSSSection;1369 }1370 1371 SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;1372 1373 // Collect data sections to register.1374 StringRef DataSections[] = {MachODataDataSectionName,1375 MachODataCommonSectionName,1376 MachOEHFrameSectionName};1377 for (auto &SecName : DataSections) {1378 if (auto *Sec = G.findSectionByName(SecName)) {1379 jitlink::SectionRange R(*Sec);1380 if (!R.empty())1381 MachOPlatformSecs.push_back({SecName, R.getRange()});1382 }1383 }1384 1385 // Having merged thread BSS (if present) and thread data (if present),1386 // record the resulting section range.1387 if (ThreadDataSection) {1388 jitlink::SectionRange R(*ThreadDataSection);1389 if (!R.empty())1390 MachOPlatformSecs.push_back({MachOThreadDataSectionName, R.getRange()});1391 }1392 1393 // If any platform sections were found then add an allocation action to call1394 // the registration function.1395 StringRef PlatformSections[] = {MachOModInitFuncSectionName,1396 ObjCRuntimeObjectSectionName};1397 1398 for (auto &SecName : PlatformSections) {1399 auto *Sec = G.findSectionByName(SecName);1400 if (!Sec)1401 continue;1402 jitlink::SectionRange R(*Sec);1403 if (R.empty())1404 continue;1405 1406 MachOPlatformSecs.push_back({SecName, R.getRange()});1407 }1408 1409 std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,1410 ExecutorAddrRange>>1411 UnwindInfo;1412 if (auto UI = findUnwindSectionInfo(G))1413 UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,1414 UI->CompactUnwindSection);1415 1416 if (!MachOPlatformSecs.empty() || UnwindInfo) {1417 // Dump the scraped inits.1418 LLVM_DEBUG({1419 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";1420 for (auto &KV : MachOPlatformSecs)1421 dbgs() << " " << KV.first << ": " << KV.second << "\n";1422 });1423 1424 assert(HeaderAddr && "Null header registered for JD");1425 using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<1426 SPSExecutorAddr,1427 SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>,1428 SPSExecutorAddrRange, SPSExecutorAddrRange>>,1429 SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;1430 1431 AllocActionCallPair AllocActions = {1432 cantFail(1433 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(1434 MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo,1435 MachOPlatformSecs)),1436 cantFail(1437 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(1438 MP.DeregisterObjectPlatformSections.Addr, HeaderAddr,1439 UnwindInfo, MachOPlatformSecs))};1440 1441 if (LLVM_LIKELY(!InBootstrapPhase))1442 G.allocActions().push_back(std::move(AllocActions));1443 else {1444 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);1445 MP.Bootstrap->DeferredAAs.push_back(std::move(AllocActions));1446 }1447 }1448 1449 return Error::success();1450}1451 1452Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(1453 jitlink::LinkGraph &G) {1454 1455 bool NeedTextSegment = false;1456 size_t NumRuntimeSections = 0;1457 1458 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)1459 if (G.findSectionByName(ObjCRuntimeSectionName))1460 ++NumRuntimeSections;1461 1462 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {1463 if (G.findSectionByName(ObjCRuntimeSectionName)) {1464 ++NumRuntimeSections;1465 NeedTextSegment = true;1466 }1467 }1468 1469 // Early out for no runtime sections.1470 if (NumRuntimeSections == 0)1471 return Error::success();1472 1473 // If there were any runtime sections then we need to add an __objc_imageinfo1474 // section.1475 ++NumRuntimeSections;1476 1477 size_t MachOSize = sizeof(MachO::mach_header_64) +1478 (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +1479 NumRuntimeSections * sizeof(MachO::section_64);1480 1481 auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,1482 MemProt::Read | MemProt::Write);1483 G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);1484 1485 return Error::success();1486}1487 1488Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(1489 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {1490 1491 auto *ObjCRuntimeObjectSec =1492 G.findSectionByName(ObjCRuntimeObjectSectionName);1493 1494 if (!ObjCRuntimeObjectSec)1495 return Error::success();1496 1497 switch (G.getTargetTriple().getArch()) {1498 case Triple::aarch64:1499 case Triple::x86_64:1500 // Supported.1501 break;1502 default:1503 return make_error<StringError>("Unrecognized MachO arch in triple " +1504 G.getTargetTriple().str(),1505 inconvertibleErrorCode());1506 }1507 1508 auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();1509 1510 struct SecDesc {1511 MachO::section_64 Sec;1512 unique_function<void(size_t RecordOffset)> AddFixups;1513 };1514 1515 std::vector<SecDesc> TextSections, DataSections;1516 auto AddSection = [&](SecDesc &SD, jitlink::Section &GraphSec) {1517 jitlink::SectionRange SR(GraphSec);1518 StringRef FQName = GraphSec.getName();1519 memset(&SD.Sec, 0, sizeof(MachO::section_64));1520 memcpy(SD.Sec.sectname, FQName.drop_front(7).data(), FQName.size() - 7);1521 memcpy(SD.Sec.segname, FQName.data(), 6);1522 SD.Sec.addr = SR.getStart() - SecBlock.getAddress();1523 SD.Sec.size = SR.getSize();1524 SD.Sec.flags = MachO::S_REGULAR;1525 };1526 1527 // Add the __objc_imageinfo section.1528 {1529 DataSections.push_back({});1530 auto &SD = DataSections.back();1531 memset(&SD.Sec, 0, sizeof(SD.Sec));1532 memcpy(SD.Sec.sectname, "__objc_imageinfo", 16);1533 strcpy(SD.Sec.segname, "__DATA");1534 SD.Sec.size = 8;1535 jitlink::Symbol *ObjCImageInfoSym = nullptr;1536 SD.AddFixups = [&, ObjCImageInfoSym](size_t RecordOffset) mutable {1537 auto PointerEdge = getPointerEdgeKind(G);1538 1539 // Look for an existing __objc_imageinfo symbol.1540 if (!ObjCImageInfoSym) {1541 auto Name = G.intern(ObjCImageInfoSymbolName);1542 ObjCImageInfoSym = G.findExternalSymbolByName(Name);1543 if (!ObjCImageInfoSym)1544 ObjCImageInfoSym = G.findAbsoluteSymbolByName(Name);1545 if (!ObjCImageInfoSym) {1546 ObjCImageInfoSym = G.findDefinedSymbolByName(Name);1547 if (ObjCImageInfoSym) {1548 std::optional<uint32_t> Flags;1549 {1550 std::lock_guard<std::mutex> Lock(PluginMutex);1551 auto It = ObjCImageInfos.find(&MR.getTargetJITDylib());1552 if (It != ObjCImageInfos.end()) {1553 It->second.Finalized = true;1554 Flags = It->second.Flags;1555 }1556 }1557 1558 if (Flags) {1559 // We own the definition of __objc_image_info; write the final1560 // merged flags value.1561 auto Content = ObjCImageInfoSym->getBlock().getMutableContent(G);1562 assert(1563 Content.size() == 8 &&1564 "__objc_image_info size should have been verified already");1565 support::endian::write32(&Content[4], *Flags, G.getEndianness());1566 }1567 }1568 }1569 if (!ObjCImageInfoSym)1570 ObjCImageInfoSym = &G.addExternalSymbol(std::move(Name), 8, false);1571 }1572 1573 SecBlock.addEdge(PointerEdge,1574 RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec),1575 *ObjCImageInfoSym, -SecBlock.getAddress().getValue());1576 };1577 }1578 1579 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {1580 if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {1581 DataSections.push_back({});1582 AddSection(DataSections.back(), *GraphSec);1583 }1584 }1585 1586 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {1587 if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {1588 TextSections.push_back({});1589 AddSection(TextSections.back(), *GraphSec);1590 }1591 }1592 1593 assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&1594 "Unexpected number of blocks in runtime sections object");1595 1596 // Build the header struct up-front. This also gives us a chance to check1597 // that the triple is supported, which we'll assume below.1598 MachO::mach_header_64 Hdr;1599 Hdr.magic = MachO::MH_MAGIC_64;1600 switch (G.getTargetTriple().getArch()) {1601 case Triple::aarch64:1602 Hdr.cputype = MachO::CPU_TYPE_ARM64;1603 Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;1604 break;1605 case Triple::x86_64:1606 Hdr.cputype = MachO::CPU_TYPE_X86_64;1607 Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;1608 break;1609 default:1610 llvm_unreachable("Unsupported architecture");1611 }1612 1613 Hdr.filetype = MachO::MH_DYLIB;1614 Hdr.ncmds = 1 + !TextSections.empty();1615 Hdr.sizeofcmds =1616 Hdr.ncmds * sizeof(MachO::segment_command_64) +1617 (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64);1618 Hdr.flags = 0;1619 Hdr.reserved = 0;1620 1621 auto SecContent = SecBlock.getAlreadyMutableContent();1622 char *P = SecContent.data();1623 auto WriteMachOStruct = [&](auto S) {1624 if (G.getEndianness() != llvm::endianness::native)1625 MachO::swapStruct(S);1626 memcpy(P, &S, sizeof(S));1627 P += sizeof(S);1628 };1629 1630 auto WriteSegment = [&](StringRef Name, std::vector<SecDesc> &Secs) {1631 MachO::segment_command_64 SegLC;1632 memset(&SegLC, 0, sizeof(SegLC));1633 memcpy(SegLC.segname, Name.data(), Name.size());1634 SegLC.cmd = MachO::LC_SEGMENT_64;1635 SegLC.cmdsize = sizeof(MachO::segment_command_64) +1636 Secs.size() * sizeof(MachO::section_64);1637 SegLC.nsects = Secs.size();1638 WriteMachOStruct(SegLC);1639 for (auto &SD : Secs) {1640 if (SD.AddFixups)1641 SD.AddFixups(P - SecContent.data());1642 WriteMachOStruct(SD.Sec);1643 }1644 };1645 1646 WriteMachOStruct(Hdr);1647 if (!TextSections.empty())1648 WriteSegment("__TEXT", TextSections);1649 if (!DataSections.empty())1650 WriteSegment("__DATA", DataSections);1651 1652 assert(P == SecContent.end() && "Underflow writing ObjC runtime object");1653 return Error::success();1654}1655 1656Error MachOPlatform::MachOPlatformPlugin::prepareSymbolTableRegistration(1657 jitlink::LinkGraph &G, JITSymTabVector &JITSymTabInfo) {1658 1659 auto *CStringSec = G.findSectionByName(MachOCStringSectionName);1660 if (!CStringSec)1661 CStringSec = &G.createSection(MachOCStringSectionName,1662 MemProt::Read | MemProt::Exec);1663 1664 // Make a map of existing strings so that we can re-use them:1665 DenseMap<StringRef, jitlink::Symbol *> ExistingStrings;1666 for (auto *Sym : CStringSec->symbols()) {1667 1668 // The LinkGraph builder should have created single strings blocks, and all1669 // plugins should have maintained this invariant.1670 auto Content = Sym->getBlock().getContent();1671 ExistingStrings.insert(1672 std::make_pair(StringRef(Content.data(), Content.size()), Sym));1673 }1674 1675 // Add all symbol names to the string section, and record the symbols for1676 // those names.1677 {1678 SmallVector<jitlink::Symbol *> SymsToProcess;1679 llvm::append_range(SymsToProcess, G.defined_symbols());1680 llvm::append_range(SymsToProcess, G.absolute_symbols());1681 1682 for (auto *Sym : SymsToProcess) {1683 if (!Sym->hasName())1684 continue;1685 1686 auto I = ExistingStrings.find(*Sym->getName());1687 if (I == ExistingStrings.end()) {1688 auto &NameBlock = G.createMutableContentBlock(1689 *CStringSec, G.allocateCString(*Sym->getName()),1690 orc::ExecutorAddr(), 1, 0);1691 auto &SymbolNameSym = G.addAnonymousSymbol(1692 NameBlock, 0, NameBlock.getSize(), false, true);1693 JITSymTabInfo.push_back({Sym, &SymbolNameSym});1694 } else1695 JITSymTabInfo.push_back({Sym, I->second});1696 }1697 }1698 1699 return Error::success();1700}1701 1702Error MachOPlatform::MachOPlatformPlugin::addSymbolTableRegistration(1703 jitlink::LinkGraph &G, MaterializationResponsibility &MR,1704 JITSymTabVector &JITSymTabInfo, bool InBootstrapPhase) {1705 1706 ExecutorAddr HeaderAddr;1707 {1708 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);1709 auto I = MP.JITDylibToHeaderAddr.find(&MR.getTargetJITDylib());1710 assert(I != MP.JITDylibToHeaderAddr.end() && "No header registered for JD");1711 assert(I->second && "Null header registered for JD");1712 HeaderAddr = I->second;1713 }1714 1715 if (LLVM_UNLIKELY(InBootstrapPhase)) {1716 // If we're in the bootstrap phase then just record these symbols in the1717 // bootstrap object and then bail out -- registration will be attached to1718 // the bootstrap graph.1719 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);1720 auto &SymTab = MP.Bootstrap->SymTab;1721 for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo)1722 SymTab.push_back({NameSym->getAddress(), OriginalSymbol->getAddress(),1723 flagsForSymbol(*OriginalSymbol)});1724 return Error::success();1725 }1726 1727 SymbolTableVector SymTab;1728 for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo)1729 SymTab.push_back({NameSym->getAddress(), OriginalSymbol->getAddress(),1730 flagsForSymbol(*OriginalSymbol)});1731 1732 G.allocActions().push_back(1733 {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(1734 MP.RegisterObjectSymbolTable.Addr, HeaderAddr, SymTab)),1735 cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(1736 MP.DeregisterObjectSymbolTable.Addr, HeaderAddr, SymTab))});1737 1738 return Error::success();1739}1740 1741template <typename MachOTraits>1742jitlink::Block &createHeaderBlock(MachOPlatform &MOP,1743 const MachOPlatform::HeaderOptions &Opts,1744 JITDylib &JD, jitlink::LinkGraph &G,1745 jitlink::Section &HeaderSection) {1746 auto HdrInfo =1747 getMachOHeaderInfoFromTriple(MOP.getExecutionSession().getTargetTriple());1748 MachOBuilder<MachOTraits> B(HdrInfo.PageSize);1749 1750 B.Header.filetype = MachO::MH_DYLIB;1751 B.Header.cputype = HdrInfo.CPUType;1752 B.Header.cpusubtype = HdrInfo.CPUSubType;1753 1754 if (Opts.IDDylib)1755 B.template addLoadCommand<MachO::LC_ID_DYLIB>(1756 Opts.IDDylib->Name, Opts.IDDylib->Timestamp,1757 Opts.IDDylib->CurrentVersion, Opts.IDDylib->CompatibilityVersion);1758 else1759 B.template addLoadCommand<MachO::LC_ID_DYLIB>(JD.getName(), 0, 0, 0);1760 1761 for (auto &BV : Opts.BuildVersions)1762 B.template addLoadCommand<MachO::LC_BUILD_VERSION>(1763 BV.Platform, BV.MinOS, BV.SDK, static_cast<uint32_t>(0));1764 1765 using LoadKind = MachOPlatform::HeaderOptions::LoadDylibCmd::LoadKind;1766 for (auto &LD : Opts.LoadDylibs) {1767 switch (LD.K) {1768 case LoadKind::Default:1769 B.template addLoadCommand<MachO::LC_LOAD_DYLIB>(1770 LD.D.Name, LD.D.Timestamp, LD.D.CurrentVersion,1771 LD.D.CompatibilityVersion);1772 break;1773 case LoadKind::Weak:1774 B.template addLoadCommand<MachO::LC_LOAD_WEAK_DYLIB>(1775 LD.D.Name, LD.D.Timestamp, LD.D.CurrentVersion,1776 LD.D.CompatibilityVersion);1777 break;1778 }1779 }1780 for (auto &P : Opts.RPaths)1781 B.template addLoadCommand<MachO::LC_RPATH>(P);1782 1783 auto HeaderContent = G.allocateBuffer(B.layout());1784 B.write(HeaderContent);1785 1786 return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,1787 0);1788}1789 1790SimpleMachOHeaderMU::SimpleMachOHeaderMU(MachOPlatform &MOP,1791 SymbolStringPtr HeaderStartSymbol,1792 MachOPlatform::HeaderOptions Opts)1793 : MaterializationUnit(1794 createHeaderInterface(MOP, std::move(HeaderStartSymbol))),1795 MOP(MOP), Opts(std::move(Opts)) {}1796 1797void SimpleMachOHeaderMU::materialize(1798 std::unique_ptr<MaterializationResponsibility> R) {1799 auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");1800 addMachOHeader(R->getTargetJITDylib(), *G, R->getInitializerSymbol());1801 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));1802}1803 1804void SimpleMachOHeaderMU::discard(const JITDylib &JD,1805 const SymbolStringPtr &Sym) {}1806 1807void SimpleMachOHeaderMU::addMachOHeader(1808 JITDylib &JD, jitlink::LinkGraph &G,1809 const SymbolStringPtr &InitializerSymbol) {1810 auto &HeaderSection = G.createSection("__header", MemProt::Read);1811 auto &HeaderBlock = createHeaderBlock(JD, G, HeaderSection);1812 1813 // Init symbol is header-start symbol.1814 G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, HeaderBlock.getSize(),1815 jitlink::Linkage::Strong, jitlink::Scope::Default, false,1816 true);1817 for (auto &HS : AdditionalHeaderSymbols)1818 G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),1819 jitlink::Linkage::Strong, jitlink::Scope::Default, false,1820 true);1821}1822 1823jitlink::Block &1824SimpleMachOHeaderMU::createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,1825 jitlink::Section &HeaderSection) {1826 switch (MOP.getExecutionSession().getTargetTriple().getArch()) {1827 case Triple::aarch64:1828 case Triple::x86_64:1829 return ::createHeaderBlock<MachO64LE>(MOP, Opts, JD, G, HeaderSection);1830 default:1831 llvm_unreachable("Unsupported architecture");1832 }1833}1834 1835MaterializationUnit::Interface SimpleMachOHeaderMU::createHeaderInterface(1836 MachOPlatform &MOP, const SymbolStringPtr &HeaderStartSymbol) {1837 SymbolFlagsMap HeaderSymbolFlags;1838 1839 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;1840 for (auto &HS : AdditionalHeaderSymbols)1841 HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =1842 JITSymbolFlags::Exported;1843 1844 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),1845 HeaderStartSymbol);1846}1847 1848MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT) {1849 switch (TT.getArch()) {1850 case Triple::aarch64:1851 return {/* PageSize = */ 16 * 1024,1852 /* CPUType = */ MachO::CPU_TYPE_ARM64,1853 /* CPUSubType = */ MachO::CPU_SUBTYPE_ARM64_ALL};1854 case Triple::x86_64:1855 return {/* PageSize = */ 4 * 1024,1856 /* CPUType = */ MachO::CPU_TYPE_X86_64,1857 /* CPUSubType = */ MachO::CPU_SUBTYPE_X86_64_ALL};1858 default:1859 llvm_unreachable("Unrecognized architecture");1860 }1861}1862 1863} // End namespace orc.1864} // End namespace llvm.1865