15ffd83dbSDimitry Andric //===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" 105ffd83dbSDimitry Andric 115ffd83dbSDimitry Andric #include "llvm/BinaryFormat/MachO.h" 12*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/MachO.h" 13*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch64.h" 14fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/x86_64.h" 155ffd83dbSDimitry Andric #include "llvm/ExecutionEngine/Orc/DebugUtils.h" 16fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 17349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" 18*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" 195ffd83dbSDimitry Andric #include "llvm/Support/BinaryByteStream.h" 205ffd83dbSDimitry Andric #include "llvm/Support/Debug.h" 21bdd1243dSDimitry Andric #include <optional> 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric #define DEBUG_TYPE "orc" 245ffd83dbSDimitry Andric 25fe6060f1SDimitry Andric using namespace llvm; 26fe6060f1SDimitry Andric using namespace llvm::orc; 27fe6060f1SDimitry Andric using namespace llvm::orc::shared; 28fe6060f1SDimitry Andric 2981ad6265SDimitry Andric namespace llvm { 3081ad6265SDimitry Andric namespace orc { 3181ad6265SDimitry Andric namespace shared { 3281ad6265SDimitry Andric 3381ad6265SDimitry Andric using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>; 3481ad6265SDimitry Andric using SPSMachOJITDylibDepInfoMap = 3581ad6265SDimitry Andric SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>; 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric template <> 3881ad6265SDimitry Andric class SPSSerializationTraits<SPSMachOJITDylibDepInfo, 3981ad6265SDimitry Andric MachOPlatform::MachOJITDylibDepInfo> { 4081ad6265SDimitry Andric public: 4181ad6265SDimitry Andric static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) { 4281ad6265SDimitry Andric return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders); 4381ad6265SDimitry Andric } 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric static bool serialize(SPSOutputBuffer &OB, 4681ad6265SDimitry Andric const MachOPlatform::MachOJITDylibDepInfo &DDI) { 4781ad6265SDimitry Andric return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed, 4881ad6265SDimitry Andric DDI.DepHeaders); 4981ad6265SDimitry Andric } 5081ad6265SDimitry Andric 5181ad6265SDimitry Andric static bool deserialize(SPSInputBuffer &IB, 5281ad6265SDimitry Andric MachOPlatform::MachOJITDylibDepInfo &DDI) { 5381ad6265SDimitry Andric return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed, 5481ad6265SDimitry Andric DDI.DepHeaders); 5581ad6265SDimitry Andric } 5681ad6265SDimitry Andric }; 5781ad6265SDimitry Andric 5881ad6265SDimitry Andric } // namespace shared 5981ad6265SDimitry Andric } // namespace orc 6081ad6265SDimitry Andric } // namespace llvm 6181ad6265SDimitry Andric 625ffd83dbSDimitry Andric namespace { 635ffd83dbSDimitry Andric 64bdd1243dSDimitry Andric std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP, 65bdd1243dSDimitry Andric std::string Name) { 66fe6060f1SDimitry Andric unsigned PointerSize; 67fe6060f1SDimitry Andric support::endianness Endianness; 68*06c3fb27SDimitry Andric const auto &TT = MOP.getExecutionSession().getTargetTriple(); 695ffd83dbSDimitry Andric 70fe6060f1SDimitry Andric switch (TT.getArch()) { 71fe6060f1SDimitry Andric case Triple::aarch64: 72fe6060f1SDimitry Andric case Triple::x86_64: 73fe6060f1SDimitry Andric PointerSize = 8; 74fe6060f1SDimitry Andric Endianness = support::endianness::little; 75fe6060f1SDimitry Andric break; 76fe6060f1SDimitry Andric default: 77fe6060f1SDimitry Andric llvm_unreachable("Unrecognized architecture"); 78fe6060f1SDimitry Andric } 795ffd83dbSDimitry Andric 80bdd1243dSDimitry Andric return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize, 81bdd1243dSDimitry Andric Endianness, 82fe6060f1SDimitry Andric jitlink::getGenericEdgeKindName); 83bdd1243dSDimitry Andric } 84fe6060f1SDimitry Andric 85bdd1243dSDimitry Andric // Generates a MachO header. 86bdd1243dSDimitry Andric class MachOHeaderMaterializationUnit : public MaterializationUnit { 87bdd1243dSDimitry Andric public: 88bdd1243dSDimitry Andric MachOHeaderMaterializationUnit(MachOPlatform &MOP, 89bdd1243dSDimitry Andric const SymbolStringPtr &HeaderStartSymbol) 90bdd1243dSDimitry Andric : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)), 91bdd1243dSDimitry Andric MOP(MOP) {} 92fe6060f1SDimitry Andric 93bdd1243dSDimitry Andric StringRef getName() const override { return "MachOHeaderMU"; } 94bdd1243dSDimitry Andric 95bdd1243dSDimitry Andric void materialize(std::unique_ptr<MaterializationResponsibility> R) override { 96bdd1243dSDimitry Andric auto G = createPlatformGraph(MOP, "<MachOHeaderMU>"); 97bdd1243dSDimitry Andric addMachOHeader(*G, MOP, R->getInitializerSymbol()); 98fe6060f1SDimitry Andric MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); 99fe6060f1SDimitry Andric } 100fe6060f1SDimitry Andric 101fe6060f1SDimitry Andric void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} 102fe6060f1SDimitry Andric 103bdd1243dSDimitry Andric static void addMachOHeader(jitlink::LinkGraph &G, MachOPlatform &MOP, 104bdd1243dSDimitry Andric const SymbolStringPtr &InitializerSymbol) { 105bdd1243dSDimitry Andric auto &HeaderSection = G.createSection("__header", MemProt::Read); 106bdd1243dSDimitry Andric auto &HeaderBlock = createHeaderBlock(G, HeaderSection); 107bdd1243dSDimitry Andric 108bdd1243dSDimitry Andric // Init symbol is header-start symbol. 109bdd1243dSDimitry Andric G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, 110bdd1243dSDimitry Andric HeaderBlock.getSize(), jitlink::Linkage::Strong, 111bdd1243dSDimitry Andric jitlink::Scope::Default, false, true); 112bdd1243dSDimitry Andric for (auto &HS : AdditionalHeaderSymbols) 113bdd1243dSDimitry Andric G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(), 114bdd1243dSDimitry Andric jitlink::Linkage::Strong, jitlink::Scope::Default, 115bdd1243dSDimitry Andric false, true); 116bdd1243dSDimitry Andric } 117bdd1243dSDimitry Andric 118fe6060f1SDimitry Andric private: 119fe6060f1SDimitry Andric struct HeaderSymbol { 120fe6060f1SDimitry Andric const char *Name; 121fe6060f1SDimitry Andric uint64_t Offset; 122fe6060f1SDimitry Andric }; 123fe6060f1SDimitry Andric 124fe6060f1SDimitry Andric static constexpr HeaderSymbol AdditionalHeaderSymbols[] = { 125fe6060f1SDimitry Andric {"___mh_executable_header", 0}}; 126fe6060f1SDimitry Andric 127fe6060f1SDimitry Andric static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G, 128fe6060f1SDimitry Andric jitlink::Section &HeaderSection) { 129fe6060f1SDimitry Andric MachO::mach_header_64 Hdr; 130fe6060f1SDimitry Andric Hdr.magic = MachO::MH_MAGIC_64; 131fe6060f1SDimitry Andric switch (G.getTargetTriple().getArch()) { 132fe6060f1SDimitry Andric case Triple::aarch64: 133fe6060f1SDimitry Andric Hdr.cputype = MachO::CPU_TYPE_ARM64; 134fe6060f1SDimitry Andric Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL; 135fe6060f1SDimitry Andric break; 136fe6060f1SDimitry Andric case Triple::x86_64: 137fe6060f1SDimitry Andric Hdr.cputype = MachO::CPU_TYPE_X86_64; 138fe6060f1SDimitry Andric Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL; 139fe6060f1SDimitry Andric break; 140fe6060f1SDimitry Andric default: 141fe6060f1SDimitry Andric llvm_unreachable("Unrecognized architecture"); 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric Hdr.filetype = MachO::MH_DYLIB; // Custom file type? 144fe6060f1SDimitry Andric Hdr.ncmds = 0; 145fe6060f1SDimitry Andric Hdr.sizeofcmds = 0; 146fe6060f1SDimitry Andric Hdr.flags = 0; 147fe6060f1SDimitry Andric Hdr.reserved = 0; 148fe6060f1SDimitry Andric 149fe6060f1SDimitry Andric if (G.getEndianness() != support::endian::system_endianness()) 150fe6060f1SDimitry Andric MachO::swapStruct(Hdr); 151fe6060f1SDimitry Andric 152*06c3fb27SDimitry Andric auto HeaderContent = G.allocateContent( 153*06c3fb27SDimitry Andric ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr))); 154fe6060f1SDimitry Andric 15504eeddc0SDimitry Andric return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8, 15604eeddc0SDimitry Andric 0); 157fe6060f1SDimitry Andric } 158fe6060f1SDimitry Andric 1590eae32dcSDimitry Andric static MaterializationUnit::Interface 1600eae32dcSDimitry Andric createHeaderInterface(MachOPlatform &MOP, 161fe6060f1SDimitry Andric const SymbolStringPtr &HeaderStartSymbol) { 162fe6060f1SDimitry Andric SymbolFlagsMap HeaderSymbolFlags; 163fe6060f1SDimitry Andric 164fe6060f1SDimitry Andric HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported; 165fe6060f1SDimitry Andric for (auto &HS : AdditionalHeaderSymbols) 166fe6060f1SDimitry Andric HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] = 167fe6060f1SDimitry Andric JITSymbolFlags::Exported; 168fe6060f1SDimitry Andric 1690eae32dcSDimitry Andric return MaterializationUnit::Interface(std::move(HeaderSymbolFlags), 1700eae32dcSDimitry Andric HeaderStartSymbol); 171fe6060f1SDimitry Andric } 172fe6060f1SDimitry Andric 173fe6060f1SDimitry Andric MachOPlatform &MOP; 174fe6060f1SDimitry Andric }; 175fe6060f1SDimitry Andric 176fe6060f1SDimitry Andric constexpr MachOHeaderMaterializationUnit::HeaderSymbol 177fe6060f1SDimitry Andric MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[]; 178fe6060f1SDimitry Andric 179bdd1243dSDimitry Andric // Creates a Bootstrap-Complete LinkGraph to run deferred actions. 180bdd1243dSDimitry Andric class MachOPlatformCompleteBootstrapMaterializationUnit 181bdd1243dSDimitry Andric : public MaterializationUnit { 182bdd1243dSDimitry Andric public: 183bdd1243dSDimitry Andric MachOPlatformCompleteBootstrapMaterializationUnit( 184bdd1243dSDimitry Andric MachOPlatform &MOP, StringRef PlatformJDName, 185bdd1243dSDimitry Andric SymbolStringPtr CompleteBootstrapSymbol, shared::AllocActions DeferredAAs, 186bdd1243dSDimitry Andric ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown, 187bdd1243dSDimitry Andric ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib, 188bdd1243dSDimitry Andric ExecutorAddr MachOHeaderAddr) 189bdd1243dSDimitry Andric : MaterializationUnit( 190bdd1243dSDimitry Andric {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}), 191bdd1243dSDimitry Andric MOP(MOP), PlatformJDName(PlatformJDName), 192bdd1243dSDimitry Andric CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)), 193bdd1243dSDimitry Andric DeferredAAs(std::move(DeferredAAs)), 194bdd1243dSDimitry Andric PlatformBootstrap(PlatformBootstrap), 195bdd1243dSDimitry Andric PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib), 196bdd1243dSDimitry Andric DeregisterJITDylib(DeregisterJITDylib), 197bdd1243dSDimitry Andric MachOHeaderAddr(MachOHeaderAddr) {} 198bdd1243dSDimitry Andric 199bdd1243dSDimitry Andric StringRef getName() const override { 200bdd1243dSDimitry Andric return "MachOPlatformCompleteBootstrap"; 201bdd1243dSDimitry Andric } 202bdd1243dSDimitry Andric 203bdd1243dSDimitry Andric void materialize(std::unique_ptr<MaterializationResponsibility> R) override { 204bdd1243dSDimitry Andric using namespace jitlink; 205bdd1243dSDimitry Andric auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>"); 206bdd1243dSDimitry Andric auto &PlaceholderSection = 207bdd1243dSDimitry Andric G->createSection("__orc_rt_cplt_bs", MemProt::Read); 208bdd1243dSDimitry Andric auto &PlaceholderBlock = 209bdd1243dSDimitry Andric G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0); 210bdd1243dSDimitry Andric G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1, 211bdd1243dSDimitry Andric Linkage::Strong, Scope::Hidden, false, true); 212bdd1243dSDimitry Andric 213bdd1243dSDimitry Andric // Reserve space for the stolen actions, plus two extras. 214bdd1243dSDimitry Andric G->allocActions().reserve(DeferredAAs.size() + 2); 215bdd1243dSDimitry Andric 216bdd1243dSDimitry Andric // 1. Bootstrap the platform support code. 217bdd1243dSDimitry Andric G->allocActions().push_back( 218bdd1243dSDimitry Andric {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)), 219bdd1243dSDimitry Andric cantFail( 220bdd1243dSDimitry Andric WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))}); 221bdd1243dSDimitry Andric 222bdd1243dSDimitry Andric // 2. Register the platform JITDylib. 223bdd1243dSDimitry Andric G->allocActions().push_back( 224bdd1243dSDimitry Andric {cantFail(WrapperFunctionCall::Create< 225bdd1243dSDimitry Andric SPSArgList<SPSString, SPSExecutorAddr>>( 226bdd1243dSDimitry Andric RegisterJITDylib, PlatformJDName, MachOHeaderAddr)), 227bdd1243dSDimitry Andric cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 228bdd1243dSDimitry Andric DeregisterJITDylib, MachOHeaderAddr))}); 229bdd1243dSDimitry Andric 230bdd1243dSDimitry Andric // 3. Add the deferred actions to the graph. 231bdd1243dSDimitry Andric std::move(DeferredAAs.begin(), DeferredAAs.end(), 232bdd1243dSDimitry Andric std::back_inserter(G->allocActions())); 233bdd1243dSDimitry Andric 234bdd1243dSDimitry Andric MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); 235bdd1243dSDimitry Andric } 236bdd1243dSDimitry Andric 237bdd1243dSDimitry Andric void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} 238bdd1243dSDimitry Andric 239bdd1243dSDimitry Andric private: 240bdd1243dSDimitry Andric MachOPlatform &MOP; 241bdd1243dSDimitry Andric StringRef PlatformJDName; 242bdd1243dSDimitry Andric SymbolStringPtr CompleteBootstrapSymbol; 243bdd1243dSDimitry Andric shared::AllocActions DeferredAAs; 244bdd1243dSDimitry Andric ExecutorAddr PlatformBootstrap; 245bdd1243dSDimitry Andric ExecutorAddr PlatformShutdown; 246bdd1243dSDimitry Andric ExecutorAddr RegisterJITDylib; 247bdd1243dSDimitry Andric ExecutorAddr DeregisterJITDylib; 248bdd1243dSDimitry Andric ExecutorAddr MachOHeaderAddr; 249bdd1243dSDimitry Andric }; 250bdd1243dSDimitry Andric 251*06c3fb27SDimitry Andric static StringRef ObjCRuntimeObjectSectionsData[] = { 252*06c3fb27SDimitry Andric MachOObjCCatListSectionName, MachOObjCClassListSectionName, 253*06c3fb27SDimitry Andric MachOObjCClassRefsSectionName, MachOObjCConstSectionName, 254*06c3fb27SDimitry Andric MachOObjCDataSectionName, MachOObjCSelRefsSectionName}; 255fe6060f1SDimitry Andric 256*06c3fb27SDimitry Andric static StringRef ObjCRuntimeObjectSectionsText[] = { 257*06c3fb27SDimitry Andric MachOObjCClassNameSectionName, MachOObjCMethNameSectionName, 258*06c3fb27SDimitry Andric MachOObjCMethTypeSectionName, MachOSwift5TypesSectionName, 259*06c3fb27SDimitry Andric MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName, 260*06c3fb27SDimitry Andric MachOSwift5EntrySectionName, MachOSwift5ProtoSectionName, 261*06c3fb27SDimitry Andric MachOSwift5ProtosSectionName}; 262*06c3fb27SDimitry Andric 263*06c3fb27SDimitry Andric static StringRef ObjCRuntimeObjectSectionName = 264*06c3fb27SDimitry Andric "__llvm_jitlink_ObjCRuntimeRegistrationObject"; 265*06c3fb27SDimitry Andric 266*06c3fb27SDimitry Andric static StringRef ObjCImageInfoSymbolName = 267*06c3fb27SDimitry Andric "__llvm_jitlink_macho_objc_imageinfo"; 2685ffd83dbSDimitry Andric 2695ffd83dbSDimitry Andric } // end anonymous namespace 2705ffd83dbSDimitry Andric 2715ffd83dbSDimitry Andric namespace llvm { 2725ffd83dbSDimitry Andric namespace orc { 2735ffd83dbSDimitry Andric 274fe6060f1SDimitry Andric Expected<std::unique_ptr<MachOPlatform>> 275fe6060f1SDimitry Andric MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 276*06c3fb27SDimitry Andric JITDylib &PlatformJD, 277*06c3fb27SDimitry Andric std::unique_ptr<DefinitionGenerator> OrcRuntime, 278bdd1243dSDimitry Andric std::optional<SymbolAliasMap> RuntimeAliases) { 279fe6060f1SDimitry Andric 280fe6060f1SDimitry Andric // If the target is not supported then bail out immediately. 281*06c3fb27SDimitry Andric if (!supportedTarget(ES.getTargetTriple())) 282fe6060f1SDimitry Andric return make_error<StringError>("Unsupported MachOPlatform triple: " + 283*06c3fb27SDimitry Andric ES.getTargetTriple().str(), 2845ffd83dbSDimitry Andric inconvertibleErrorCode()); 2855ffd83dbSDimitry Andric 286*06c3fb27SDimitry Andric auto &EPC = ES.getExecutorProcessControl(); 287*06c3fb27SDimitry Andric 288fe6060f1SDimitry Andric // Create default aliases if the caller didn't supply any. 289fe6060f1SDimitry Andric if (!RuntimeAliases) 290fe6060f1SDimitry Andric RuntimeAliases = standardPlatformAliases(ES); 2915ffd83dbSDimitry Andric 292fe6060f1SDimitry Andric // Define the aliases. 293fe6060f1SDimitry Andric if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases)))) 294fe6060f1SDimitry Andric return std::move(Err); 2955ffd83dbSDimitry Andric 296fe6060f1SDimitry Andric // Add JIT-dispatch function support symbols. 297*06c3fb27SDimitry Andric if (auto Err = PlatformJD.define( 298*06c3fb27SDimitry Andric absoluteSymbols({{ES.intern("___orc_rt_jit_dispatch"), 299*06c3fb27SDimitry Andric {EPC.getJITDispatchInfo().JITDispatchFunction, 300fe6060f1SDimitry Andric JITSymbolFlags::Exported}}, 301fe6060f1SDimitry Andric {ES.intern("___orc_rt_jit_dispatch_ctx"), 302*06c3fb27SDimitry Andric {EPC.getJITDispatchInfo().JITDispatchContext, 303fe6060f1SDimitry Andric JITSymbolFlags::Exported}}}))) 304fe6060f1SDimitry Andric return std::move(Err); 3055ffd83dbSDimitry Andric 306fe6060f1SDimitry Andric // Create the instance. 307fe6060f1SDimitry Andric Error Err = Error::success(); 308*06c3fb27SDimitry Andric auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform( 309*06c3fb27SDimitry Andric ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err)); 310fe6060f1SDimitry Andric if (Err) 311fe6060f1SDimitry Andric return std::move(Err); 312fe6060f1SDimitry Andric return std::move(P); 3135ffd83dbSDimitry Andric } 3145ffd83dbSDimitry Andric 315*06c3fb27SDimitry Andric Expected<std::unique_ptr<MachOPlatform>> 316*06c3fb27SDimitry Andric MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 317*06c3fb27SDimitry Andric JITDylib &PlatformJD, const char *OrcRuntimePath, 318*06c3fb27SDimitry Andric std::optional<SymbolAliasMap> RuntimeAliases) { 319*06c3fb27SDimitry Andric 320*06c3fb27SDimitry Andric // Create a generator for the ORC runtime archive. 321*06c3fb27SDimitry Andric auto OrcRuntimeArchiveGenerator = 322*06c3fb27SDimitry Andric StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath); 323*06c3fb27SDimitry Andric if (!OrcRuntimeArchiveGenerator) 324*06c3fb27SDimitry Andric return OrcRuntimeArchiveGenerator.takeError(); 325*06c3fb27SDimitry Andric 326*06c3fb27SDimitry Andric return Create(ES, ObjLinkingLayer, PlatformJD, 327*06c3fb27SDimitry Andric std::move(*OrcRuntimeArchiveGenerator), 328*06c3fb27SDimitry Andric std::move(RuntimeAliases)); 329*06c3fb27SDimitry Andric } 330*06c3fb27SDimitry Andric 3315ffd83dbSDimitry Andric Error MachOPlatform::setupJITDylib(JITDylib &JD) { 33281ad6265SDimitry Andric if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>( 33381ad6265SDimitry Andric *this, MachOHeaderStartSymbol))) 33481ad6265SDimitry Andric return Err; 33581ad6265SDimitry Andric 33681ad6265SDimitry Andric return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError(); 3375ffd83dbSDimitry Andric } 3385ffd83dbSDimitry Andric 33981ad6265SDimitry Andric Error MachOPlatform::teardownJITDylib(JITDylib &JD) { 34081ad6265SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex); 34181ad6265SDimitry Andric auto I = JITDylibToHeaderAddr.find(&JD); 34281ad6265SDimitry Andric if (I != JITDylibToHeaderAddr.end()) { 34381ad6265SDimitry Andric assert(HeaderAddrToJITDylib.count(I->second) && 34481ad6265SDimitry Andric "HeaderAddrToJITDylib missing entry"); 34581ad6265SDimitry Andric HeaderAddrToJITDylib.erase(I->second); 34681ad6265SDimitry Andric JITDylibToHeaderAddr.erase(I); 34781ad6265SDimitry Andric } 34881ad6265SDimitry Andric JITDylibToPThreadKey.erase(&JD); 34981ad6265SDimitry Andric return Error::success(); 35081ad6265SDimitry Andric } 35104eeddc0SDimitry Andric 352e8d8bef9SDimitry Andric Error MachOPlatform::notifyAdding(ResourceTracker &RT, 353e8d8bef9SDimitry Andric const MaterializationUnit &MU) { 354e8d8bef9SDimitry Andric auto &JD = RT.getJITDylib(); 3555ffd83dbSDimitry Andric const auto &InitSym = MU.getInitializerSymbol(); 3565ffd83dbSDimitry Andric if (!InitSym) 3575ffd83dbSDimitry Andric return Error::success(); 3585ffd83dbSDimitry Andric 3595ffd83dbSDimitry Andric RegisteredInitSymbols[&JD].add(InitSym, 3605ffd83dbSDimitry Andric SymbolLookupFlags::WeaklyReferencedSymbol); 3615ffd83dbSDimitry Andric LLVM_DEBUG({ 3625ffd83dbSDimitry Andric dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU " 3635ffd83dbSDimitry Andric << MU.getName() << "\n"; 3645ffd83dbSDimitry Andric }); 3655ffd83dbSDimitry Andric return Error::success(); 3665ffd83dbSDimitry Andric } 3675ffd83dbSDimitry Andric 368e8d8bef9SDimitry Andric Error MachOPlatform::notifyRemoving(ResourceTracker &RT) { 3695ffd83dbSDimitry Andric llvm_unreachable("Not supported yet"); 3705ffd83dbSDimitry Andric } 3715ffd83dbSDimitry Andric 372fe6060f1SDimitry Andric static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, 373fe6060f1SDimitry Andric ArrayRef<std::pair<const char *, const char *>> AL) { 374fe6060f1SDimitry Andric for (auto &KV : AL) { 375fe6060f1SDimitry Andric auto AliasName = ES.intern(KV.first); 376fe6060f1SDimitry Andric assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map"); 377fe6060f1SDimitry Andric Aliases[std::move(AliasName)] = {ES.intern(KV.second), 378fe6060f1SDimitry Andric JITSymbolFlags::Exported}; 379fe6060f1SDimitry Andric } 380fe6060f1SDimitry Andric } 3815ffd83dbSDimitry Andric 382fe6060f1SDimitry Andric SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) { 383fe6060f1SDimitry Andric SymbolAliasMap Aliases; 384fe6060f1SDimitry Andric addAliases(ES, Aliases, requiredCXXAliases()); 385fe6060f1SDimitry Andric addAliases(ES, Aliases, standardRuntimeUtilityAliases()); 386fe6060f1SDimitry Andric return Aliases; 387fe6060f1SDimitry Andric } 388fe6060f1SDimitry Andric 389fe6060f1SDimitry Andric ArrayRef<std::pair<const char *, const char *>> 390fe6060f1SDimitry Andric MachOPlatform::requiredCXXAliases() { 391fe6060f1SDimitry Andric static const std::pair<const char *, const char *> RequiredCXXAliases[] = { 392fe6060f1SDimitry Andric {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}}; 393fe6060f1SDimitry Andric 394fe6060f1SDimitry Andric return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases); 395fe6060f1SDimitry Andric } 396fe6060f1SDimitry Andric 397fe6060f1SDimitry Andric ArrayRef<std::pair<const char *, const char *>> 398fe6060f1SDimitry Andric MachOPlatform::standardRuntimeUtilityAliases() { 399fe6060f1SDimitry Andric static const std::pair<const char *, const char *> 400fe6060f1SDimitry Andric StandardRuntimeUtilityAliases[] = { 401fe6060f1SDimitry Andric {"___orc_rt_run_program", "___orc_rt_macho_run_program"}, 40281ad6265SDimitry Andric {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"}, 40381ad6265SDimitry Andric {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"}, 40481ad6265SDimitry Andric {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"}, 40581ad6265SDimitry Andric {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"}, 406fe6060f1SDimitry Andric {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}}; 407fe6060f1SDimitry Andric 408fe6060f1SDimitry Andric return ArrayRef<std::pair<const char *, const char *>>( 409fe6060f1SDimitry Andric StandardRuntimeUtilityAliases); 410fe6060f1SDimitry Andric } 411fe6060f1SDimitry Andric 412fe6060f1SDimitry Andric bool MachOPlatform::supportedTarget(const Triple &TT) { 413fe6060f1SDimitry Andric switch (TT.getArch()) { 414349cc55cSDimitry Andric case Triple::aarch64: 415fe6060f1SDimitry Andric case Triple::x86_64: 416fe6060f1SDimitry Andric return true; 417fe6060f1SDimitry Andric default: 418fe6060f1SDimitry Andric return false; 419fe6060f1SDimitry Andric } 420fe6060f1SDimitry Andric } 421fe6060f1SDimitry Andric 422fe6060f1SDimitry Andric MachOPlatform::MachOPlatform( 423fe6060f1SDimitry Andric ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 424fe6060f1SDimitry Andric JITDylib &PlatformJD, 425fe6060f1SDimitry Andric std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err) 426bdd1243dSDimitry Andric : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) { 427fe6060f1SDimitry Andric ErrorAsOutParameter _(&Err); 428fe6060f1SDimitry Andric ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this)); 429fe6060f1SDimitry Andric PlatformJD.addGenerator(std::move(OrcRuntimeGenerator)); 430fe6060f1SDimitry Andric 431bdd1243dSDimitry Andric BootstrapInfo BI; 432bdd1243dSDimitry Andric Bootstrap = &BI; 433bdd1243dSDimitry Andric 434bdd1243dSDimitry Andric // Bootstrap process -- here be phase-ordering dragons. 435bdd1243dSDimitry Andric // 436bdd1243dSDimitry Andric // The MachOPlatform class uses allocation actions to register metadata 437bdd1243dSDimitry Andric // sections with the ORC runtime, however the runtime contains metadata 438bdd1243dSDimitry Andric // registration functions that have their own metadata that they need to 439bdd1243dSDimitry Andric // register (e.g. the frame-info registration functions have frame-info). 440bdd1243dSDimitry Andric // We can't use an ordinary lookup to find these registration functions 441bdd1243dSDimitry Andric // because their address is needed during the link of the containing graph 442bdd1243dSDimitry Andric // itself (to build the allocation actions that will call the registration 443bdd1243dSDimitry Andric // functions). Further complicating the situation (a) the graph containing 444bdd1243dSDimitry Andric // the registration functions is allowed to depend on other graphs (e.g. the 445bdd1243dSDimitry Andric // graph containing the ORC runtime RTTI support) so we need to handle with 446bdd1243dSDimitry Andric // an unknown set of dependencies during bootstrap, and (b) these graphs may 447bdd1243dSDimitry Andric // be linked concurrently if the user has installed a concurrent dispatcher. 448bdd1243dSDimitry Andric // 449bdd1243dSDimitry Andric // We satisfy these constraint by implementing a bootstrap phase during which 450bdd1243dSDimitry Andric // allocation actions generated by MachOPlatform are appended to a list of 451bdd1243dSDimitry Andric // deferred allocation actions, rather than to the graphs themselves. At the 452bdd1243dSDimitry Andric // end of the bootstrap process the deferred actions are attached to a final 453bdd1243dSDimitry Andric // "complete-bootstrap" graph that causes them to be run. 454bdd1243dSDimitry Andric // 455bdd1243dSDimitry Andric // The bootstrap steps are as follows: 456bdd1243dSDimitry Andric // 457bdd1243dSDimitry Andric // 1. Request the graph containing the mach header. This graph is guaranteed 458bdd1243dSDimitry Andric // not to have any metadata so the fact that the registration functions 459bdd1243dSDimitry Andric // are not available yet is not a problem. 460bdd1243dSDimitry Andric // 461bdd1243dSDimitry Andric // 2. Look up the registration functions and discard the results. This will 462bdd1243dSDimitry Andric // trigger linking of the graph containing these functions, and 463bdd1243dSDimitry Andric // consequently any graphs that it depends on. We do not use the lookup 464bdd1243dSDimitry Andric // result to find the addresses of the functions requested (as described 465bdd1243dSDimitry Andric // above the lookup will return too late for that), instead we capture the 466bdd1243dSDimitry Andric // addresses in a post-allocation pass injected by the platform runtime 467bdd1243dSDimitry Andric // during bootstrap only. 468bdd1243dSDimitry Andric // 469bdd1243dSDimitry Andric // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of 470bdd1243dSDimitry Andric // graphs being linked (potentially concurrently), and we block until all 471bdd1243dSDimitry Andric // of these graphs have completed linking. This is to avoid a race on the 472bdd1243dSDimitry Andric // deferred-actions vector: the lookup for the runtime registration 473bdd1243dSDimitry Andric // functions may return while some functions (those that are being 474bdd1243dSDimitry Andric // incidentally linked in, but aren't reachable via the runtime functions) 475bdd1243dSDimitry Andric // are still being linked, and we need to capture any allocation actions 476bdd1243dSDimitry Andric // for this incidental code before we proceed. 477bdd1243dSDimitry Andric // 478bdd1243dSDimitry Andric // 4. Once all active links are complete we transfer the deferred actions to 479bdd1243dSDimitry Andric // a newly added CompleteBootstrap graph and then request a symbol from 480bdd1243dSDimitry Andric // the CompleteBootstrap graph to trigger materialization. This will cause 481bdd1243dSDimitry Andric // all deferred actions to be run, and once this lookup returns we can 482bdd1243dSDimitry Andric // proceed. 483bdd1243dSDimitry Andric // 484bdd1243dSDimitry Andric // 5. Finally, we associate runtime support methods in MachOPlatform with 485bdd1243dSDimitry Andric // the corresponding jit-dispatch tag variables in the ORC runtime to make 486bdd1243dSDimitry Andric // the support methods callable. The bootstrap is now complete. 487bdd1243dSDimitry Andric 488bdd1243dSDimitry Andric // Step (1) Add header materialization unit and request. 489bdd1243dSDimitry Andric if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>( 490bdd1243dSDimitry Andric *this, MachOHeaderStartSymbol)))) 491bdd1243dSDimitry Andric return; 492bdd1243dSDimitry Andric if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError())) 493bdd1243dSDimitry Andric return; 494bdd1243dSDimitry Andric 495bdd1243dSDimitry Andric // Step (2) Request runtime registration functions to trigger 496bdd1243dSDimitry Andric // materialization.. 497bdd1243dSDimitry Andric if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD), 498bdd1243dSDimitry Andric SymbolLookupSet( 499bdd1243dSDimitry Andric {PlatformBootstrap.Name, PlatformShutdown.Name, 500bdd1243dSDimitry Andric RegisterJITDylib.Name, DeregisterJITDylib.Name, 501bdd1243dSDimitry Andric RegisterObjectPlatformSections.Name, 502bdd1243dSDimitry Andric DeregisterObjectPlatformSections.Name, 503bdd1243dSDimitry Andric CreatePThreadKey.Name})) 504bdd1243dSDimitry Andric .takeError())) 505bdd1243dSDimitry Andric return; 506bdd1243dSDimitry Andric 507bdd1243dSDimitry Andric // Step (3) Wait for any incidental linker work to complete. 508bdd1243dSDimitry Andric { 509bdd1243dSDimitry Andric std::unique_lock<std::mutex> Lock(BI.Mutex); 510bdd1243dSDimitry Andric BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; }); 511bdd1243dSDimitry Andric Bootstrap = nullptr; 512bdd1243dSDimitry Andric } 513bdd1243dSDimitry Andric 514bdd1243dSDimitry Andric // Step (4) Add complete-bootstrap materialization unit and request. 515bdd1243dSDimitry Andric auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap"); 516bdd1243dSDimitry Andric if ((Err = PlatformJD.define( 517bdd1243dSDimitry Andric std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>( 518bdd1243dSDimitry Andric *this, PlatformJD.getName(), BootstrapCompleteSymbol, 519bdd1243dSDimitry Andric std::move(BI.DeferredAAs), PlatformBootstrap.Addr, 520bdd1243dSDimitry Andric PlatformShutdown.Addr, RegisterJITDylib.Addr, 521bdd1243dSDimitry Andric DeregisterJITDylib.Addr, BI.MachOHeaderAddr)))) 522bdd1243dSDimitry Andric return; 523bdd1243dSDimitry Andric if ((Err = ES.lookup(makeJITDylibSearchOrder( 524bdd1243dSDimitry Andric &PlatformJD, JITDylibLookupFlags::MatchAllSymbols), 525bdd1243dSDimitry Andric std::move(BootstrapCompleteSymbol)) 526bdd1243dSDimitry Andric .takeError())) 527bdd1243dSDimitry Andric return; 528bdd1243dSDimitry Andric 529bdd1243dSDimitry Andric // (5) Associate runtime support functions. 530bdd1243dSDimitry Andric if ((Err = associateRuntimeSupportFunctions())) 531349cc55cSDimitry Andric return; 532349cc55cSDimitry Andric } 533349cc55cSDimitry Andric 534bdd1243dSDimitry Andric Error MachOPlatform::associateRuntimeSupportFunctions() { 535fe6060f1SDimitry Andric ExecutionSession::JITDispatchHandlerAssociationMap WFs; 536fe6060f1SDimitry Andric 53781ad6265SDimitry Andric using PushInitializersSPSSig = 53881ad6265SDimitry Andric SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr); 53981ad6265SDimitry Andric WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] = 54081ad6265SDimitry Andric ES.wrapAsyncWithSPS<PushInitializersSPSSig>( 54181ad6265SDimitry Andric this, &MachOPlatform::rt_pushInitializers); 542fe6060f1SDimitry Andric 543fe6060f1SDimitry Andric using LookupSymbolSPSSig = 544349cc55cSDimitry Andric SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString); 545fe6060f1SDimitry Andric WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] = 546fe6060f1SDimitry Andric ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this, 547fe6060f1SDimitry Andric &MachOPlatform::rt_lookupSymbol); 548fe6060f1SDimitry Andric 549fe6060f1SDimitry Andric return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); 550fe6060f1SDimitry Andric } 551fe6060f1SDimitry Andric 55281ad6265SDimitry Andric void MachOPlatform::pushInitializersLoop( 55381ad6265SDimitry Andric PushInitializersSendResultFn SendResult, JITDylibSP JD) { 5545ffd83dbSDimitry Andric DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; 55581ad6265SDimitry Andric DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap; 55681ad6265SDimitry Andric SmallVector<JITDylib *, 16> Worklist({JD.get()}); 55781ad6265SDimitry Andric 5585ffd83dbSDimitry Andric ES.runSessionLocked([&]() { 55981ad6265SDimitry Andric while (!Worklist.empty()) { 56081ad6265SDimitry Andric // FIXME: Check for defunct dylibs. 56181ad6265SDimitry Andric 56281ad6265SDimitry Andric auto DepJD = Worklist.back(); 56381ad6265SDimitry Andric Worklist.pop_back(); 56481ad6265SDimitry Andric 56581ad6265SDimitry Andric // If we've already visited this JITDylib on this iteration then continue. 56681ad6265SDimitry Andric if (JDDepMap.count(DepJD)) 56781ad6265SDimitry Andric continue; 56881ad6265SDimitry Andric 56981ad6265SDimitry Andric // Add dep info. 57081ad6265SDimitry Andric auto &DM = JDDepMap[DepJD]; 57181ad6265SDimitry Andric DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) { 57281ad6265SDimitry Andric for (auto &KV : O) { 57381ad6265SDimitry Andric if (KV.first == DepJD) 57481ad6265SDimitry Andric continue; 57581ad6265SDimitry Andric DM.push_back(KV.first); 57681ad6265SDimitry Andric Worklist.push_back(KV.first); 57781ad6265SDimitry Andric } 57881ad6265SDimitry Andric }); 57981ad6265SDimitry Andric 58081ad6265SDimitry Andric // Add any registered init symbols. 58181ad6265SDimitry Andric auto RISItr = RegisteredInitSymbols.find(DepJD); 5825ffd83dbSDimitry Andric if (RISItr != RegisteredInitSymbols.end()) { 58381ad6265SDimitry Andric NewInitSymbols[DepJD] = std::move(RISItr->second); 5845ffd83dbSDimitry Andric RegisteredInitSymbols.erase(RISItr); 5855ffd83dbSDimitry Andric } 5865ffd83dbSDimitry Andric } 5875ffd83dbSDimitry Andric }); 5885ffd83dbSDimitry Andric 58981ad6265SDimitry Andric // If there are no further init symbols to look up then send the link order 59081ad6265SDimitry Andric // (as a list of header addresses) to the caller. 591fe6060f1SDimitry Andric if (NewInitSymbols.empty()) { 59281ad6265SDimitry Andric 59381ad6265SDimitry Andric // To make the list intelligible to the runtime we need to convert all 594bdd1243dSDimitry Andric // JITDylib pointers to their header addresses. Only include JITDylibs 595bdd1243dSDimitry Andric // that appear in the JITDylibToHeaderAddr map (i.e. those that have been 596bdd1243dSDimitry Andric // through setupJITDylib) -- bare JITDylibs aren't managed by the platform. 59781ad6265SDimitry Andric DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs; 59881ad6265SDimitry Andric HeaderAddrs.reserve(JDDepMap.size()); 59981ad6265SDimitry Andric { 60081ad6265SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex); 60181ad6265SDimitry Andric for (auto &KV : JDDepMap) { 60281ad6265SDimitry Andric auto I = JITDylibToHeaderAddr.find(KV.first); 603bdd1243dSDimitry Andric if (I != JITDylibToHeaderAddr.end()) 60481ad6265SDimitry Andric HeaderAddrs[KV.first] = I->second; 60581ad6265SDimitry Andric } 60681ad6265SDimitry Andric } 60781ad6265SDimitry Andric 60881ad6265SDimitry Andric // Build the dep info map to return. 60981ad6265SDimitry Andric MachOJITDylibDepInfoMap DIM; 61081ad6265SDimitry Andric DIM.reserve(JDDepMap.size()); 61181ad6265SDimitry Andric for (auto &KV : JDDepMap) { 612bdd1243dSDimitry Andric auto HI = HeaderAddrs.find(KV.first); 613bdd1243dSDimitry Andric // Skip unmanaged JITDylibs. 614bdd1243dSDimitry Andric if (HI == HeaderAddrs.end()) 615bdd1243dSDimitry Andric continue; 616bdd1243dSDimitry Andric auto H = HI->second; 61781ad6265SDimitry Andric MachOJITDylibDepInfo DepInfo; 61881ad6265SDimitry Andric for (auto &Dep : KV.second) { 619bdd1243dSDimitry Andric auto HJ = HeaderAddrs.find(Dep); 620bdd1243dSDimitry Andric if (HJ != HeaderAddrs.end()) 621bdd1243dSDimitry Andric DepInfo.DepHeaders.push_back(HJ->second); 62281ad6265SDimitry Andric } 62381ad6265SDimitry Andric DIM.push_back(std::make_pair(H, std::move(DepInfo))); 62481ad6265SDimitry Andric } 62581ad6265SDimitry Andric SendResult(DIM); 626e8d8bef9SDimitry Andric return; 6275ffd83dbSDimitry Andric } 6285ffd83dbSDimitry Andric 629fe6060f1SDimitry Andric // Otherwise issue a lookup and re-run this phase when it completes. 630fe6060f1SDimitry Andric lookupInitSymbolsAsync( 631bdd1243dSDimitry Andric [this, SendResult = std::move(SendResult), JD](Error Err) mutable { 632fe6060f1SDimitry Andric if (Err) 633fe6060f1SDimitry Andric SendResult(std::move(Err)); 634fe6060f1SDimitry Andric else 63581ad6265SDimitry Andric pushInitializersLoop(std::move(SendResult), JD); 636fe6060f1SDimitry Andric }, 637fe6060f1SDimitry Andric ES, std::move(NewInitSymbols)); 638fe6060f1SDimitry Andric } 639fe6060f1SDimitry Andric 64081ad6265SDimitry Andric void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult, 64181ad6265SDimitry Andric ExecutorAddr JDHeaderAddr) { 64281ad6265SDimitry Andric JITDylibSP JD; 643fe6060f1SDimitry Andric { 644fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex); 64581ad6265SDimitry Andric auto I = HeaderAddrToJITDylib.find(JDHeaderAddr); 646fe6060f1SDimitry Andric if (I != HeaderAddrToJITDylib.end()) 647fe6060f1SDimitry Andric JD = I->second; 648fe6060f1SDimitry Andric } 649fe6060f1SDimitry Andric 650fe6060f1SDimitry Andric LLVM_DEBUG({ 65181ad6265SDimitry Andric dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") "; 65281ad6265SDimitry Andric if (JD) 65381ad6265SDimitry Andric dbgs() << "pushing initializers for " << JD->getName() << "\n"; 65481ad6265SDimitry Andric else 65581ad6265SDimitry Andric dbgs() << "No JITDylib for header address.\n"; 656fe6060f1SDimitry Andric }); 65781ad6265SDimitry Andric 65881ad6265SDimitry Andric if (!JD) { 659*06c3fb27SDimitry Andric SendResult(make_error<StringError>("No JITDylib with header addr " + 660*06c3fb27SDimitry Andric formatv("{0:x}", JDHeaderAddr), 661fe6060f1SDimitry Andric inconvertibleErrorCode())); 662fe6060f1SDimitry Andric return; 663fe6060f1SDimitry Andric } 664fe6060f1SDimitry Andric 66581ad6265SDimitry Andric pushInitializersLoop(std::move(SendResult), JD); 666fe6060f1SDimitry Andric } 667fe6060f1SDimitry Andric 668fe6060f1SDimitry Andric void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, 669349cc55cSDimitry Andric ExecutorAddr Handle, StringRef SymbolName) { 670fe6060f1SDimitry Andric LLVM_DEBUG({ 671*06c3fb27SDimitry Andric dbgs() << "MachOPlatform::rt_lookupSymbol(\"" << Handle << "\")\n"; 672fe6060f1SDimitry Andric }); 673fe6060f1SDimitry Andric 674fe6060f1SDimitry Andric JITDylib *JD = nullptr; 675fe6060f1SDimitry Andric 676fe6060f1SDimitry Andric { 677fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex); 67804eeddc0SDimitry Andric auto I = HeaderAddrToJITDylib.find(Handle); 679fe6060f1SDimitry Andric if (I != HeaderAddrToJITDylib.end()) 680fe6060f1SDimitry Andric JD = I->second; 681fe6060f1SDimitry Andric } 682fe6060f1SDimitry Andric 683fe6060f1SDimitry Andric if (!JD) { 684*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n"); 685fe6060f1SDimitry Andric SendResult(make_error<StringError>("No JITDylib associated with handle " + 686*06c3fb27SDimitry Andric formatv("{0:x}", Handle), 687fe6060f1SDimitry Andric inconvertibleErrorCode())); 688fe6060f1SDimitry Andric return; 689fe6060f1SDimitry Andric } 690fe6060f1SDimitry Andric 691fe6060f1SDimitry Andric // Use functor class to work around XL build compiler issue on AIX. 692fe6060f1SDimitry Andric class RtLookupNotifyComplete { 693fe6060f1SDimitry Andric public: 694fe6060f1SDimitry Andric RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult) 695fe6060f1SDimitry Andric : SendResult(std::move(SendResult)) {} 696fe6060f1SDimitry Andric void operator()(Expected<SymbolMap> Result) { 697fe6060f1SDimitry Andric if (Result) { 698fe6060f1SDimitry Andric assert(Result->size() == 1 && "Unexpected result map count"); 699*06c3fb27SDimitry Andric SendResult(Result->begin()->second.getAddress()); 700fe6060f1SDimitry Andric } else { 701fe6060f1SDimitry Andric SendResult(Result.takeError()); 702fe6060f1SDimitry Andric } 703fe6060f1SDimitry Andric } 704fe6060f1SDimitry Andric 705fe6060f1SDimitry Andric private: 706fe6060f1SDimitry Andric SendSymbolAddressFn SendResult; 707fe6060f1SDimitry Andric }; 708fe6060f1SDimitry Andric 709fe6060f1SDimitry Andric // FIXME: Proper mangling. 710fe6060f1SDimitry Andric auto MangledName = ("_" + SymbolName).str(); 711fe6060f1SDimitry Andric ES.lookup( 712fe6060f1SDimitry Andric LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, 713fe6060f1SDimitry Andric SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready, 714fe6060f1SDimitry Andric RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); 715fe6060f1SDimitry Andric } 716fe6060f1SDimitry Andric 717fe6060f1SDimitry Andric Expected<uint64_t> MachOPlatform::createPThreadKey() { 718bdd1243dSDimitry Andric if (!CreatePThreadKey.Addr) 719fe6060f1SDimitry Andric return make_error<StringError>( 720fe6060f1SDimitry Andric "Attempting to create pthread key in target, but runtime support has " 721fe6060f1SDimitry Andric "not been loaded yet", 722fe6060f1SDimitry Andric inconvertibleErrorCode()); 723fe6060f1SDimitry Andric 724fe6060f1SDimitry Andric Expected<uint64_t> Result(0); 725fe6060f1SDimitry Andric if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>( 726bdd1243dSDimitry Andric CreatePThreadKey.Addr, Result)) 727fe6060f1SDimitry Andric return std::move(Err); 728fe6060f1SDimitry Andric return Result; 729fe6060f1SDimitry Andric } 730fe6060f1SDimitry Andric 731fe6060f1SDimitry Andric void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( 732fe6060f1SDimitry Andric MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 733fe6060f1SDimitry Andric jitlink::PassConfiguration &Config) { 734fe6060f1SDimitry Andric 735bdd1243dSDimitry Andric using namespace jitlink; 736bdd1243dSDimitry Andric 737bdd1243dSDimitry Andric bool InBootstrapPhase = 738bdd1243dSDimitry Andric &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap; 739bdd1243dSDimitry Andric 740bdd1243dSDimitry Andric // If we're in the bootstrap phase then increment the active graphs. 741bdd1243dSDimitry Andric if (InBootstrapPhase) { 742bdd1243dSDimitry Andric Config.PrePrunePasses.push_back( 743bdd1243dSDimitry Andric [this](LinkGraph &G) { return bootstrapPipelineStart(G); }); 744bdd1243dSDimitry Andric Config.PostAllocationPasses.push_back([this](LinkGraph &G) { 745bdd1243dSDimitry Andric return bootstrapPipelineRecordRuntimeFunctions(G); 746bdd1243dSDimitry Andric }); 747bdd1243dSDimitry Andric } 748349cc55cSDimitry Andric 749349cc55cSDimitry Andric // --- Handle Initializers --- 750349cc55cSDimitry Andric if (auto InitSymbol = MR.getInitializerSymbol()) { 751349cc55cSDimitry Andric 752349cc55cSDimitry Andric // If the initializer symbol is the MachOHeader start symbol then just 753349cc55cSDimitry Andric // register it and then bail out -- the header materialization unit 754349cc55cSDimitry Andric // definitely doesn't need any other passes. 755bdd1243dSDimitry Andric if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) { 756bdd1243dSDimitry Andric Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) { 757349cc55cSDimitry Andric return associateJITDylibHeaderSymbol(G, MR); 758349cc55cSDimitry Andric }); 759fe6060f1SDimitry Andric return; 760fe6060f1SDimitry Andric } 761fe6060f1SDimitry Andric 762349cc55cSDimitry Andric // If the object contains an init symbol other than the header start symbol 763349cc55cSDimitry Andric // then add passes to preserve, process and register the init 764349cc55cSDimitry Andric // sections/symbols. 765bdd1243dSDimitry Andric Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) { 766*06c3fb27SDimitry Andric if (auto Err = preserveImportantSections(G, MR)) 767349cc55cSDimitry Andric return Err; 768349cc55cSDimitry Andric return processObjCImageInfo(G, MR); 769349cc55cSDimitry Andric }); 770*06c3fb27SDimitry Andric Config.PostPrunePasses.push_back( 771*06c3fb27SDimitry Andric [this](LinkGraph &G) { return createObjCRuntimeObject(G); }); 772*06c3fb27SDimitry Andric Config.PostAllocationPasses.push_back( 773*06c3fb27SDimitry Andric [this, &MR](LinkGraph &G) { return populateObjCRuntimeObject(G, MR); }); 774349cc55cSDimitry Andric } 775349cc55cSDimitry Andric 776349cc55cSDimitry Andric // Insert TLV lowering at the start of the PostPrunePasses, since we want 777349cc55cSDimitry Andric // it to run before GOT/PLT lowering. 778349cc55cSDimitry Andric Config.PostPrunePasses.insert( 779349cc55cSDimitry Andric Config.PostPrunePasses.begin(), 780bdd1243dSDimitry Andric [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) { 781349cc55cSDimitry Andric return fixTLVSectionsAndEdges(G, JD); 782349cc55cSDimitry Andric }); 783349cc55cSDimitry Andric 78481ad6265SDimitry Andric // Add a pass to register the final addresses of any special sections in the 78581ad6265SDimitry Andric // object with the runtime. 78681ad6265SDimitry Andric Config.PostAllocationPasses.push_back( 787bdd1243dSDimitry Andric [this, &JD = MR.getTargetJITDylib(), InBootstrapPhase](LinkGraph &G) { 788bdd1243dSDimitry Andric return registerObjectPlatformSections(G, JD, InBootstrapPhase); 78981ad6265SDimitry Andric }); 790bdd1243dSDimitry Andric 791bdd1243dSDimitry Andric // If we're in the bootstrap phase then steal allocation actions and then 792bdd1243dSDimitry Andric // decrement the active graphs. 793bdd1243dSDimitry Andric if (InBootstrapPhase) 794bdd1243dSDimitry Andric Config.PostFixupPasses.push_back( 795bdd1243dSDimitry Andric [this](LinkGraph &G) { return bootstrapPipelineEnd(G); }); 796fe6060f1SDimitry Andric } 797fe6060f1SDimitry Andric 798fe6060f1SDimitry Andric ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap 799fe6060f1SDimitry Andric MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies( 8005ffd83dbSDimitry Andric MaterializationResponsibility &MR) { 801fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex); 8025ffd83dbSDimitry Andric auto I = InitSymbolDeps.find(&MR); 8035ffd83dbSDimitry Andric if (I != InitSymbolDeps.end()) { 804fe6060f1SDimitry Andric SyntheticSymbolDependenciesMap Result; 8055ffd83dbSDimitry Andric Result[MR.getInitializerSymbol()] = std::move(I->second); 8065ffd83dbSDimitry Andric InitSymbolDeps.erase(&MR); 8075ffd83dbSDimitry Andric return Result; 8085ffd83dbSDimitry Andric } 809fe6060f1SDimitry Andric return SyntheticSymbolDependenciesMap(); 8105ffd83dbSDimitry Andric } 8115ffd83dbSDimitry Andric 812bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart( 813bdd1243dSDimitry Andric jitlink::LinkGraph &G) { 814bdd1243dSDimitry Andric // Increment the active graphs count in BootstrapInfo. 815bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex); 816bdd1243dSDimitry Andric ++MP.Bootstrap.load()->ActiveGraphs; 817bdd1243dSDimitry Andric return Error::success(); 818bdd1243dSDimitry Andric } 819bdd1243dSDimitry Andric 820bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin:: 821bdd1243dSDimitry Andric bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) { 822bdd1243dSDimitry Andric // Record bootstrap function names. 823bdd1243dSDimitry Andric std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = { 824bdd1243dSDimitry Andric {*MP.MachOHeaderStartSymbol, &MP.Bootstrap.load()->MachOHeaderAddr}, 825bdd1243dSDimitry Andric {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr}, 826bdd1243dSDimitry Andric {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr}, 827bdd1243dSDimitry Andric {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr}, 828bdd1243dSDimitry Andric {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr}, 829bdd1243dSDimitry Andric {*MP.RegisterObjectPlatformSections.Name, 830bdd1243dSDimitry Andric &MP.RegisterObjectPlatformSections.Addr}, 831bdd1243dSDimitry Andric {*MP.DeregisterObjectPlatformSections.Name, 832bdd1243dSDimitry Andric &MP.DeregisterObjectPlatformSections.Addr}, 833*06c3fb27SDimitry Andric {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}, 834*06c3fb27SDimitry Andric {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr}, 835*06c3fb27SDimitry Andric {*MP.DeregisterObjCRuntimeObject.Name, 836*06c3fb27SDimitry Andric &MP.DeregisterObjCRuntimeObject.Addr}}; 837bdd1243dSDimitry Andric 838bdd1243dSDimitry Andric bool RegisterMachOHeader = false; 839bdd1243dSDimitry Andric 840bdd1243dSDimitry Andric for (auto *Sym : G.defined_symbols()) { 841bdd1243dSDimitry Andric for (auto &RTSym : RuntimeSymbols) { 842bdd1243dSDimitry Andric if (Sym->hasName() && Sym->getName() == RTSym.first) { 843bdd1243dSDimitry Andric if (*RTSym.second) 844bdd1243dSDimitry Andric return make_error<StringError>( 845bdd1243dSDimitry Andric "Duplicate " + RTSym.first + 846bdd1243dSDimitry Andric " detected during MachOPlatform bootstrap", 847bdd1243dSDimitry Andric inconvertibleErrorCode()); 848bdd1243dSDimitry Andric 849bdd1243dSDimitry Andric if (Sym->getName() == *MP.MachOHeaderStartSymbol) 850bdd1243dSDimitry Andric RegisterMachOHeader = true; 851bdd1243dSDimitry Andric 852bdd1243dSDimitry Andric *RTSym.second = Sym->getAddress(); 853bdd1243dSDimitry Andric } 854bdd1243dSDimitry Andric } 855bdd1243dSDimitry Andric } 856bdd1243dSDimitry Andric 857bdd1243dSDimitry Andric if (RegisterMachOHeader) { 858bdd1243dSDimitry Andric // If this graph defines the macho header symbol then create the internal 859bdd1243dSDimitry Andric // mapping between it and PlatformJD. 860bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 861bdd1243dSDimitry Andric MP.JITDylibToHeaderAddr[&MP.PlatformJD] = 862bdd1243dSDimitry Andric MP.Bootstrap.load()->MachOHeaderAddr; 863bdd1243dSDimitry Andric MP.HeaderAddrToJITDylib[MP.Bootstrap.load()->MachOHeaderAddr] = 864bdd1243dSDimitry Andric &MP.PlatformJD; 865bdd1243dSDimitry Andric } 866bdd1243dSDimitry Andric 867bdd1243dSDimitry Andric return Error::success(); 868bdd1243dSDimitry Andric } 869bdd1243dSDimitry Andric 870bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd( 871bdd1243dSDimitry Andric jitlink::LinkGraph &G) { 872bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex); 873bdd1243dSDimitry Andric assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed"); 874bdd1243dSDimitry Andric --MP.Bootstrap.load()->ActiveGraphs; 875bdd1243dSDimitry Andric // Notify Bootstrap->CV while holding the mutex because the mutex is 876bdd1243dSDimitry Andric // also keeping Bootstrap->CV alive. 877bdd1243dSDimitry Andric if (MP.Bootstrap.load()->ActiveGraphs == 0) 878bdd1243dSDimitry Andric MP.Bootstrap.load()->CV.notify_all(); 879bdd1243dSDimitry Andric return Error::success(); 880bdd1243dSDimitry Andric } 881bdd1243dSDimitry Andric 882349cc55cSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol( 883349cc55cSDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 884fe6060f1SDimitry Andric auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { 885fe6060f1SDimitry Andric return Sym->getName() == *MP.MachOHeaderStartSymbol; 886fe6060f1SDimitry Andric }); 887349cc55cSDimitry Andric assert(I != G.defined_symbols().end() && "Missing MachO header start symbol"); 888349cc55cSDimitry Andric 889349cc55cSDimitry Andric auto &JD = MR.getTargetJITDylib(); 890fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 89104eeddc0SDimitry Andric auto HeaderAddr = (*I)->getAddress(); 89281ad6265SDimitry Andric MP.JITDylibToHeaderAddr[&JD] = HeaderAddr; 893fe6060f1SDimitry Andric MP.HeaderAddrToJITDylib[HeaderAddr] = &JD; 894bdd1243dSDimitry Andric // We can unconditionally add these actions to the Graph because this pass 895bdd1243dSDimitry Andric // isn't used during bootstrap. 89681ad6265SDimitry Andric G.allocActions().push_back( 89781ad6265SDimitry Andric {cantFail( 89881ad6265SDimitry Andric WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>( 899bdd1243dSDimitry Andric MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)), 90081ad6265SDimitry Andric cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 901bdd1243dSDimitry Andric MP.DeregisterJITDylib.Addr, HeaderAddr))}); 902fe6060f1SDimitry Andric return Error::success(); 903fe6060f1SDimitry Andric } 904fe6060f1SDimitry Andric 905*06c3fb27SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections( 906fe6060f1SDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 907*06c3fb27SDimitry Andric // __objc_imageinfo is "important": we want to preserve it and record its 908*06c3fb27SDimitry Andric // address in the first graph that it appears in, then verify and discard it 909*06c3fb27SDimitry Andric // in all subsequent graphs. In this pass we preserve unconditionally -- we'll 910*06c3fb27SDimitry Andric // manually throw it away in the processObjCImageInfo pass. 911*06c3fb27SDimitry Andric if (auto *ObjCImageInfoSec = 912*06c3fb27SDimitry Andric G.findSectionByName(MachOObjCImageInfoSectionName)) { 913*06c3fb27SDimitry Andric if (ObjCImageInfoSec->blocks_size() != 1) 914*06c3fb27SDimitry Andric return make_error<StringError>( 915*06c3fb27SDimitry Andric "In " + G.getName() + 916*06c3fb27SDimitry Andric "__DATA,__objc_imageinfo contains multiple blocks", 917*06c3fb27SDimitry Andric inconvertibleErrorCode()); 918*06c3fb27SDimitry Andric G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false, 919*06c3fb27SDimitry Andric true); 920fe6060f1SDimitry Andric 921*06c3fb27SDimitry Andric for (auto *B : ObjCImageInfoSec->blocks()) 922*06c3fb27SDimitry Andric if (!B->edges_empty()) 923*06c3fb27SDimitry Andric return make_error<StringError>("In " + G.getName() + ", " + 924*06c3fb27SDimitry Andric MachOObjCImageInfoSectionName + 925*06c3fb27SDimitry Andric " contains references to symbols", 926*06c3fb27SDimitry Andric inconvertibleErrorCode()); 927*06c3fb27SDimitry Andric } 928*06c3fb27SDimitry Andric 929*06c3fb27SDimitry Andric // Init sections are important: We need to preserve them and so that their 930*06c3fb27SDimitry Andric // addresses can be captured and reported to the ORC runtime in 931*06c3fb27SDimitry Andric // registerObjectPlatformSections. 932fe6060f1SDimitry Andric JITLinkSymbolSet InitSectionSymbols; 933*06c3fb27SDimitry Andric for (auto &InitSectionName : MachOInitSectionNames) { 934*06c3fb27SDimitry Andric // Skip ObjCImageInfo -- this shouldn't have any dependencies, and we may 935*06c3fb27SDimitry Andric // remove it later. 936*06c3fb27SDimitry Andric if (InitSectionName == MachOObjCImageInfoSectionName) 937*06c3fb27SDimitry Andric continue; 938*06c3fb27SDimitry Andric 939fe6060f1SDimitry Andric // Skip non-init sections. 940fe6060f1SDimitry Andric auto *InitSection = G.findSectionByName(InitSectionName); 941fe6060f1SDimitry Andric if (!InitSection) 942fe6060f1SDimitry Andric continue; 943fe6060f1SDimitry Andric 944fe6060f1SDimitry Andric // Make a pass over live symbols in the section: those blocks are already 945fe6060f1SDimitry Andric // preserved. 946fe6060f1SDimitry Andric DenseSet<jitlink::Block *> AlreadyLiveBlocks; 947fe6060f1SDimitry Andric for (auto &Sym : InitSection->symbols()) { 948fe6060f1SDimitry Andric auto &B = Sym->getBlock(); 949fe6060f1SDimitry Andric if (Sym->isLive() && Sym->getOffset() == 0 && 950fe6060f1SDimitry Andric Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) { 951fe6060f1SDimitry Andric InitSectionSymbols.insert(Sym); 952fe6060f1SDimitry Andric AlreadyLiveBlocks.insert(&B); 9535ffd83dbSDimitry Andric } 9545ffd83dbSDimitry Andric } 9555ffd83dbSDimitry Andric 956fe6060f1SDimitry Andric // Add anonymous symbols to preserve any not-already-preserved blocks. 957fe6060f1SDimitry Andric for (auto *B : InitSection->blocks()) 958fe6060f1SDimitry Andric if (!AlreadyLiveBlocks.count(B)) 959fe6060f1SDimitry Andric InitSectionSymbols.insert( 960fe6060f1SDimitry Andric &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true)); 961fe6060f1SDimitry Andric } 962fe6060f1SDimitry Andric 963fe6060f1SDimitry Andric if (!InitSectionSymbols.empty()) { 964fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex); 965fe6060f1SDimitry Andric InitSymbolDeps[&MR] = std::move(InitSectionSymbols); 966fe6060f1SDimitry Andric } 967fe6060f1SDimitry Andric 968fe6060f1SDimitry Andric return Error::success(); 969fe6060f1SDimitry Andric } 970fe6060f1SDimitry Andric 971fe6060f1SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( 9725ffd83dbSDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 9735ffd83dbSDimitry Andric 9745ffd83dbSDimitry Andric // If there's an ObjC imagine info then either 9755ffd83dbSDimitry Andric // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In 9765ffd83dbSDimitry Andric // this case we name and record it. 9775ffd83dbSDimitry Andric // OR 9785ffd83dbSDimitry Andric // (2) We already have a recorded __objc_imageinfo for this JITDylib, 9795ffd83dbSDimitry Andric // in which case we just verify it. 980*06c3fb27SDimitry Andric auto *ObjCImageInfo = G.findSectionByName(MachOObjCImageInfoSectionName); 9815ffd83dbSDimitry Andric if (!ObjCImageInfo) 9825ffd83dbSDimitry Andric return Error::success(); 9835ffd83dbSDimitry Andric 9845ffd83dbSDimitry Andric auto ObjCImageInfoBlocks = ObjCImageInfo->blocks(); 9855ffd83dbSDimitry Andric 9865ffd83dbSDimitry Andric // Check that the section is not empty if present. 987bdd1243dSDimitry Andric if (ObjCImageInfoBlocks.empty()) 988*06c3fb27SDimitry Andric return make_error<StringError>("Empty " + MachOObjCImageInfoSectionName + 989fe6060f1SDimitry Andric " section in " + G.getName(), 9905ffd83dbSDimitry Andric inconvertibleErrorCode()); 9915ffd83dbSDimitry Andric 9925ffd83dbSDimitry Andric // Check that there's only one block in the section. 9935ffd83dbSDimitry Andric if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end()) 994fe6060f1SDimitry Andric return make_error<StringError>("Multiple blocks in " + 995*06c3fb27SDimitry Andric MachOObjCImageInfoSectionName + 996fe6060f1SDimitry Andric " section in " + G.getName(), 9975ffd83dbSDimitry Andric inconvertibleErrorCode()); 9985ffd83dbSDimitry Andric 9995ffd83dbSDimitry Andric // Check that the __objc_imageinfo section is unreferenced. 10005ffd83dbSDimitry Andric // FIXME: We could optimize this check if Symbols had a ref-count. 10015ffd83dbSDimitry Andric for (auto &Sec : G.sections()) { 10025ffd83dbSDimitry Andric if (&Sec != ObjCImageInfo) 10035ffd83dbSDimitry Andric for (auto *B : Sec.blocks()) 10045ffd83dbSDimitry Andric for (auto &E : B->edges()) 10055ffd83dbSDimitry Andric if (E.getTarget().isDefined() && 10065ffd83dbSDimitry Andric &E.getTarget().getBlock().getSection() == ObjCImageInfo) 1007*06c3fb27SDimitry Andric return make_error<StringError>(MachOObjCImageInfoSectionName + 1008fe6060f1SDimitry Andric " is referenced within file " + 10095ffd83dbSDimitry Andric G.getName(), 10105ffd83dbSDimitry Andric inconvertibleErrorCode()); 10115ffd83dbSDimitry Andric } 10125ffd83dbSDimitry Andric 10135ffd83dbSDimitry Andric auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin(); 10145ffd83dbSDimitry Andric auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data(); 10155ffd83dbSDimitry Andric auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness()); 10165ffd83dbSDimitry Andric auto Flags = 10175ffd83dbSDimitry Andric support::endian::read32(ObjCImageInfoData + 4, G.getEndianness()); 10185ffd83dbSDimitry Andric 10195ffd83dbSDimitry Andric // Lock the mutex while we verify / update the ObjCImageInfos map. 1020fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex); 10215ffd83dbSDimitry Andric 10225ffd83dbSDimitry Andric auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib()); 10235ffd83dbSDimitry Andric if (ObjCImageInfoItr != ObjCImageInfos.end()) { 10245ffd83dbSDimitry Andric // We've already registered an __objc_imageinfo section. Verify the 10255ffd83dbSDimitry Andric // content of this new section matches, then delete it. 1026*06c3fb27SDimitry Andric if (ObjCImageInfoItr->second.Version != Version) 10275ffd83dbSDimitry Andric return make_error<StringError>( 10285ffd83dbSDimitry Andric "ObjC version in " + G.getName() + 10295ffd83dbSDimitry Andric " does not match first registered version", 10305ffd83dbSDimitry Andric inconvertibleErrorCode()); 1031*06c3fb27SDimitry Andric if (ObjCImageInfoItr->second.Flags != Flags) 10325ffd83dbSDimitry Andric return make_error<StringError>("ObjC flags in " + G.getName() + 10335ffd83dbSDimitry Andric " do not match first registered flags", 10345ffd83dbSDimitry Andric inconvertibleErrorCode()); 10355ffd83dbSDimitry Andric 10365ffd83dbSDimitry Andric // __objc_imageinfo is valid. Delete the block. 10375ffd83dbSDimitry Andric for (auto *S : ObjCImageInfo->symbols()) 10385ffd83dbSDimitry Andric G.removeDefinedSymbol(*S); 10395ffd83dbSDimitry Andric G.removeBlock(ObjCImageInfoBlock); 10405ffd83dbSDimitry Andric } else { 10415ffd83dbSDimitry Andric // We haven't registered an __objc_imageinfo section yet. Register and 10425ffd83dbSDimitry Andric // move on. The section should already be marked no-dead-strip. 1043*06c3fb27SDimitry Andric G.addDefinedSymbol(ObjCImageInfoBlock, 0, ObjCImageInfoSymbolName, 1044*06c3fb27SDimitry Andric ObjCImageInfoBlock.getSize(), jitlink::Linkage::Strong, 1045*06c3fb27SDimitry Andric jitlink::Scope::Hidden, false, true); 1046*06c3fb27SDimitry Andric if (auto Err = MR.defineMaterializing( 1047*06c3fb27SDimitry Andric {{MR.getExecutionSession().intern(ObjCImageInfoSymbolName), 1048*06c3fb27SDimitry Andric JITSymbolFlags()}})) 1049*06c3fb27SDimitry Andric return Err; 1050*06c3fb27SDimitry Andric ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags}; 10515ffd83dbSDimitry Andric } 10525ffd83dbSDimitry Andric 10535ffd83dbSDimitry Andric return Error::success(); 10545ffd83dbSDimitry Andric } 10555ffd83dbSDimitry Andric 1056fe6060f1SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( 1057fe6060f1SDimitry Andric jitlink::LinkGraph &G, JITDylib &JD) { 1058fe6060f1SDimitry Andric 1059fe6060f1SDimitry Andric // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr. 1060fe6060f1SDimitry Andric for (auto *Sym : G.external_symbols()) 1061fe6060f1SDimitry Andric if (Sym->getName() == "__tlv_bootstrap") { 1062fe6060f1SDimitry Andric Sym->setName("___orc_rt_macho_tlv_get_addr"); 1063fe6060f1SDimitry Andric break; 1064fe6060f1SDimitry Andric } 1065fe6060f1SDimitry Andric 1066fe6060f1SDimitry Andric // Store key in __thread_vars struct fields. 1067*06c3fb27SDimitry Andric if (auto *ThreadDataSec = G.findSectionByName(MachOThreadVarsSectionName)) { 1068bdd1243dSDimitry Andric std::optional<uint64_t> Key; 1069fe6060f1SDimitry Andric { 1070fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 1071fe6060f1SDimitry Andric auto I = MP.JITDylibToPThreadKey.find(&JD); 1072fe6060f1SDimitry Andric if (I != MP.JITDylibToPThreadKey.end()) 1073fe6060f1SDimitry Andric Key = I->second; 1074fe6060f1SDimitry Andric } 1075fe6060f1SDimitry Andric 1076fe6060f1SDimitry Andric if (!Key) { 1077fe6060f1SDimitry Andric if (auto KeyOrErr = MP.createPThreadKey()) 1078fe6060f1SDimitry Andric Key = *KeyOrErr; 1079fe6060f1SDimitry Andric else 1080fe6060f1SDimitry Andric return KeyOrErr.takeError(); 1081fe6060f1SDimitry Andric } 1082fe6060f1SDimitry Andric 1083fe6060f1SDimitry Andric uint64_t PlatformKeyBits = 1084fe6060f1SDimitry Andric support::endian::byte_swap(*Key, G.getEndianness()); 1085fe6060f1SDimitry Andric 1086fe6060f1SDimitry Andric for (auto *B : ThreadDataSec->blocks()) { 1087fe6060f1SDimitry Andric if (B->getSize() != 3 * G.getPointerSize()) 1088fe6060f1SDimitry Andric return make_error<StringError>("__thread_vars block at " + 1089fe6060f1SDimitry Andric formatv("{0:x}", B->getAddress()) + 1090fe6060f1SDimitry Andric " has unexpected size", 1091fe6060f1SDimitry Andric inconvertibleErrorCode()); 1092fe6060f1SDimitry Andric 1093fe6060f1SDimitry Andric auto NewBlockContent = G.allocateBuffer(B->getSize()); 1094fe6060f1SDimitry Andric llvm::copy(B->getContent(), NewBlockContent.data()); 1095fe6060f1SDimitry Andric memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits, 1096fe6060f1SDimitry Andric G.getPointerSize()); 1097fe6060f1SDimitry Andric B->setContent(NewBlockContent); 1098fe6060f1SDimitry Andric } 1099fe6060f1SDimitry Andric } 1100fe6060f1SDimitry Andric 1101fe6060f1SDimitry Andric // Transform any TLV edges into GOT edges. 1102fe6060f1SDimitry Andric for (auto *B : G.blocks()) 1103fe6060f1SDimitry Andric for (auto &E : B->edges()) 1104fe6060f1SDimitry Andric if (E.getKind() == 1105349cc55cSDimitry Andric jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable) 1106349cc55cSDimitry Andric E.setKind(jitlink::x86_64:: 1107349cc55cSDimitry Andric RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable); 1108349cc55cSDimitry Andric 1109349cc55cSDimitry Andric return Error::success(); 1110349cc55cSDimitry Andric } 1111349cc55cSDimitry Andric 1112bdd1243dSDimitry Andric std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections> 1113bdd1243dSDimitry Andric MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo( 1114bdd1243dSDimitry Andric jitlink::LinkGraph &G) { 1115bdd1243dSDimitry Andric using namespace jitlink; 1116349cc55cSDimitry Andric 1117bdd1243dSDimitry Andric UnwindSections US; 1118bdd1243dSDimitry Andric 1119bdd1243dSDimitry Andric // ScanSection records a section range and adds any executable blocks that 1120bdd1243dSDimitry Andric // that section points to to the CodeBlocks vector. 1121bdd1243dSDimitry Andric SmallVector<Block *> CodeBlocks; 1122bdd1243dSDimitry Andric auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) { 1123bdd1243dSDimitry Andric if (Sec.blocks().empty()) 1124bdd1243dSDimitry Andric return; 1125bdd1243dSDimitry Andric SecRange = (*Sec.blocks().begin())->getRange(); 1126bdd1243dSDimitry Andric for (auto *B : Sec.blocks()) { 1127bdd1243dSDimitry Andric auto R = B->getRange(); 1128bdd1243dSDimitry Andric SecRange.Start = std::min(SecRange.Start, R.Start); 1129bdd1243dSDimitry Andric SecRange.End = std::max(SecRange.End, R.End); 1130bdd1243dSDimitry Andric for (auto &E : B->edges()) { 1131bdd1243dSDimitry Andric if (!E.getTarget().isDefined()) 1132bdd1243dSDimitry Andric continue; 1133bdd1243dSDimitry Andric auto &TargetBlock = E.getTarget().getBlock(); 1134bdd1243dSDimitry Andric auto &TargetSection = TargetBlock.getSection(); 1135bdd1243dSDimitry Andric if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec) 1136bdd1243dSDimitry Andric CodeBlocks.push_back(&TargetBlock); 1137349cc55cSDimitry Andric } 1138bdd1243dSDimitry Andric } 1139bdd1243dSDimitry Andric }; 1140bdd1243dSDimitry Andric 1141*06c3fb27SDimitry Andric if (Section *EHFrameSec = G.findSectionByName(MachOEHFrameSectionName)) 1142bdd1243dSDimitry Andric ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection); 1143bdd1243dSDimitry Andric 1144*06c3fb27SDimitry Andric if (Section *CUInfoSec = 1145*06c3fb27SDimitry Andric G.findSectionByName(MachOCompactUnwindInfoSectionName)) 1146bdd1243dSDimitry Andric ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection); 1147bdd1243dSDimitry Andric 1148bdd1243dSDimitry Andric // If we didn't find any pointed-to code-blocks then there's no need to 1149bdd1243dSDimitry Andric // register any info. 1150bdd1243dSDimitry Andric if (CodeBlocks.empty()) 1151bdd1243dSDimitry Andric return std::nullopt; 1152bdd1243dSDimitry Andric 1153bdd1243dSDimitry Andric // We have info to register. Sort the code blocks into address order and 1154bdd1243dSDimitry Andric // build a list of contiguous address ranges covering them all. 1155bdd1243dSDimitry Andric llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) { 1156bdd1243dSDimitry Andric return LHS->getAddress() < RHS->getAddress(); 1157bdd1243dSDimitry Andric }); 1158bdd1243dSDimitry Andric for (auto *B : CodeBlocks) { 1159bdd1243dSDimitry Andric if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress()) 1160bdd1243dSDimitry Andric US.CodeRanges.push_back(B->getRange()); 1161bdd1243dSDimitry Andric else 1162bdd1243dSDimitry Andric US.CodeRanges.back().End = B->getRange().End; 1163bdd1243dSDimitry Andric } 1164bdd1243dSDimitry Andric 1165bdd1243dSDimitry Andric LLVM_DEBUG({ 1166bdd1243dSDimitry Andric dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n" 1167bdd1243dSDimitry Andric << " DWARF: "; 1168bdd1243dSDimitry Andric if (US.DwarfSection.Start) 1169bdd1243dSDimitry Andric dbgs() << US.DwarfSection << "\n"; 1170bdd1243dSDimitry Andric else 1171bdd1243dSDimitry Andric dbgs() << "none\n"; 1172bdd1243dSDimitry Andric dbgs() << " Compact-unwind: "; 1173bdd1243dSDimitry Andric if (US.CompactUnwindSection.Start) 1174bdd1243dSDimitry Andric dbgs() << US.CompactUnwindSection << "\n"; 1175bdd1243dSDimitry Andric else 1176bdd1243dSDimitry Andric dbgs() << "none\n" 1177bdd1243dSDimitry Andric << "for code ranges:\n"; 1178bdd1243dSDimitry Andric for (auto &CR : US.CodeRanges) 1179bdd1243dSDimitry Andric dbgs() << " " << CR << "\n"; 1180bdd1243dSDimitry Andric if (US.CodeRanges.size() >= G.sections_size()) 1181bdd1243dSDimitry Andric dbgs() << "WARNING: High number of discontiguous code ranges! " 1182bdd1243dSDimitry Andric "Padding may be interfering with coalescing.\n"; 1183bdd1243dSDimitry Andric }); 1184bdd1243dSDimitry Andric 1185bdd1243dSDimitry Andric return US; 1186bdd1243dSDimitry Andric } 1187bdd1243dSDimitry Andric 1188bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( 1189bdd1243dSDimitry Andric jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) { 1190349cc55cSDimitry Andric 1191349cc55cSDimitry Andric // Get a pointer to the thread data section if there is one. It will be used 1192349cc55cSDimitry Andric // below. 1193349cc55cSDimitry Andric jitlink::Section *ThreadDataSection = 1194*06c3fb27SDimitry Andric G.findSectionByName(MachOThreadDataSectionName); 1195349cc55cSDimitry Andric 1196349cc55cSDimitry Andric // Handle thread BSS section if there is one. 1197*06c3fb27SDimitry Andric if (auto *ThreadBSSSection = G.findSectionByName(MachOThreadBSSSectionName)) { 1198349cc55cSDimitry Andric // If there's already a thread data section in this graph then merge the 1199349cc55cSDimitry Andric // thread BSS section content into it, otherwise just treat the thread 1200349cc55cSDimitry Andric // BSS section as the thread data section. 1201349cc55cSDimitry Andric if (ThreadDataSection) 1202349cc55cSDimitry Andric G.mergeSections(*ThreadDataSection, *ThreadBSSSection); 1203349cc55cSDimitry Andric else 1204349cc55cSDimitry Andric ThreadDataSection = ThreadBSSSection; 1205349cc55cSDimitry Andric } 1206349cc55cSDimitry Andric 120781ad6265SDimitry Andric SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs; 120881ad6265SDimitry Andric 1209bdd1243dSDimitry Andric // Collect data sections to register. 1210*06c3fb27SDimitry Andric StringRef DataSections[] = {MachODataDataSectionName, 1211*06c3fb27SDimitry Andric MachODataCommonSectionName, 1212*06c3fb27SDimitry Andric MachOEHFrameSectionName}; 1213bdd1243dSDimitry Andric for (auto &SecName : DataSections) { 1214bdd1243dSDimitry Andric if (auto *Sec = G.findSectionByName(SecName)) { 1215bdd1243dSDimitry Andric jitlink::SectionRange R(*Sec); 1216bdd1243dSDimitry Andric if (!R.empty()) 1217bdd1243dSDimitry Andric MachOPlatformSecs.push_back({SecName, R.getRange()}); 1218bdd1243dSDimitry Andric } 1219bdd1243dSDimitry Andric } 1220bdd1243dSDimitry Andric 1221349cc55cSDimitry Andric // Having merged thread BSS (if present) and thread data (if present), 1222349cc55cSDimitry Andric // record the resulting section range. 1223349cc55cSDimitry Andric if (ThreadDataSection) { 1224349cc55cSDimitry Andric jitlink::SectionRange R(*ThreadDataSection); 1225bdd1243dSDimitry Andric if (!R.empty()) 1226*06c3fb27SDimitry Andric MachOPlatformSecs.push_back({MachOThreadDataSectionName, R.getRange()}); 122781ad6265SDimitry Andric } 122881ad6265SDimitry Andric 122981ad6265SDimitry Andric // If any platform sections were found then add an allocation action to call 123081ad6265SDimitry Andric // the registration function. 1231*06c3fb27SDimitry Andric StringRef PlatformSections[] = {MachOModInitFuncSectionName, 1232*06c3fb27SDimitry Andric ObjCRuntimeObjectSectionName}; 123381ad6265SDimitry Andric 123481ad6265SDimitry Andric for (auto &SecName : PlatformSections) { 123581ad6265SDimitry Andric auto *Sec = G.findSectionByName(SecName); 123681ad6265SDimitry Andric if (!Sec) 123781ad6265SDimitry Andric continue; 123881ad6265SDimitry Andric jitlink::SectionRange R(*Sec); 123981ad6265SDimitry Andric if (R.empty()) 124081ad6265SDimitry Andric continue; 124181ad6265SDimitry Andric 124281ad6265SDimitry Andric MachOPlatformSecs.push_back({SecName, R.getRange()}); 124381ad6265SDimitry Andric } 124481ad6265SDimitry Andric 1245bdd1243dSDimitry Andric std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange, 1246bdd1243dSDimitry Andric ExecutorAddrRange>> 1247bdd1243dSDimitry Andric UnwindInfo; 1248bdd1243dSDimitry Andric if (auto UI = findUnwindSectionInfo(G)) 1249bdd1243dSDimitry Andric UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection, 1250bdd1243dSDimitry Andric UI->CompactUnwindSection); 1251bdd1243dSDimitry Andric 1252bdd1243dSDimitry Andric if (!MachOPlatformSecs.empty() || UnwindInfo) { 1253bdd1243dSDimitry Andric ExecutorAddr HeaderAddr; 125481ad6265SDimitry Andric { 125581ad6265SDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 125681ad6265SDimitry Andric auto I = MP.JITDylibToHeaderAddr.find(&JD); 1257bdd1243dSDimitry Andric assert(I != MP.JITDylibToHeaderAddr.end() && 1258bdd1243dSDimitry Andric "Missing header for JITDylib"); 125981ad6265SDimitry Andric HeaderAddr = I->second; 126081ad6265SDimitry Andric } 126181ad6265SDimitry Andric 126281ad6265SDimitry Andric // Dump the scraped inits. 126381ad6265SDimitry Andric LLVM_DEBUG({ 126481ad6265SDimitry Andric dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; 126581ad6265SDimitry Andric for (auto &KV : MachOPlatformSecs) 126681ad6265SDimitry Andric dbgs() << " " << KV.first << ": " << KV.second << "\n"; 126781ad6265SDimitry Andric }); 126881ad6265SDimitry Andric 1269bdd1243dSDimitry Andric using SPSRegisterObjectPlatformSectionsArgs = SPSArgList< 1270bdd1243dSDimitry Andric SPSExecutorAddr, 1271bdd1243dSDimitry Andric SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>, 1272bdd1243dSDimitry Andric SPSExecutorAddrRange, SPSExecutorAddrRange>>, 127381ad6265SDimitry Andric SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>; 1274bdd1243dSDimitry Andric 1275bdd1243dSDimitry Andric shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase) 1276bdd1243dSDimitry Andric ? G.allocActions() 1277bdd1243dSDimitry Andric : MP.Bootstrap.load()->DeferredAAs; 1278bdd1243dSDimitry Andric 1279bdd1243dSDimitry Andric allocActions.push_back( 128004eeddc0SDimitry Andric {cantFail( 128181ad6265SDimitry Andric WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( 1282bdd1243dSDimitry Andric MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo, 128381ad6265SDimitry Andric MachOPlatformSecs)), 128404eeddc0SDimitry Andric cantFail( 128581ad6265SDimitry Andric WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( 1286bdd1243dSDimitry Andric MP.DeregisterObjectPlatformSections.Addr, HeaderAddr, 1287bdd1243dSDimitry Andric UnwindInfo, MachOPlatformSecs))}); 1288349cc55cSDimitry Andric } 128981ad6265SDimitry Andric 1290349cc55cSDimitry Andric return Error::success(); 1291349cc55cSDimitry Andric } 1292349cc55cSDimitry Andric 1293*06c3fb27SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject( 1294*06c3fb27SDimitry Andric jitlink::LinkGraph &G) { 1295*06c3fb27SDimitry Andric 1296*06c3fb27SDimitry Andric bool NeedTextSegment = false; 1297*06c3fb27SDimitry Andric size_t NumRuntimeSections = 0; 1298*06c3fb27SDimitry Andric 1299*06c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) 1300*06c3fb27SDimitry Andric if (G.findSectionByName(ObjCRuntimeSectionName)) 1301*06c3fb27SDimitry Andric ++NumRuntimeSections; 1302*06c3fb27SDimitry Andric 1303*06c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) { 1304*06c3fb27SDimitry Andric if (G.findSectionByName(ObjCRuntimeSectionName)) { 1305*06c3fb27SDimitry Andric ++NumRuntimeSections; 1306*06c3fb27SDimitry Andric NeedTextSegment = true; 1307*06c3fb27SDimitry Andric } 1308*06c3fb27SDimitry Andric } 1309*06c3fb27SDimitry Andric 1310*06c3fb27SDimitry Andric // Early out for no runtime sections. 1311*06c3fb27SDimitry Andric if (NumRuntimeSections == 0) 1312*06c3fb27SDimitry Andric return Error::success(); 1313*06c3fb27SDimitry Andric 1314*06c3fb27SDimitry Andric // If there were any runtime sections then we need to add an __objc_imageinfo 1315*06c3fb27SDimitry Andric // section. 1316*06c3fb27SDimitry Andric ++NumRuntimeSections; 1317*06c3fb27SDimitry Andric 1318*06c3fb27SDimitry Andric size_t MachOSize = sizeof(MachO::mach_header_64) + 1319*06c3fb27SDimitry Andric (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) + 1320*06c3fb27SDimitry Andric NumRuntimeSections * sizeof(MachO::section_64); 1321*06c3fb27SDimitry Andric 1322*06c3fb27SDimitry Andric auto &Sec = G.createSection(ObjCRuntimeObjectSectionName, 1323*06c3fb27SDimitry Andric MemProt::Read | MemProt::Write); 1324*06c3fb27SDimitry Andric G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true); 1325*06c3fb27SDimitry Andric 1326*06c3fb27SDimitry Andric return Error::success(); 1327*06c3fb27SDimitry Andric } 1328*06c3fb27SDimitry Andric 1329*06c3fb27SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject( 1330*06c3fb27SDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 1331*06c3fb27SDimitry Andric 1332*06c3fb27SDimitry Andric auto *ObjCRuntimeObjectSec = 1333*06c3fb27SDimitry Andric G.findSectionByName(ObjCRuntimeObjectSectionName); 1334*06c3fb27SDimitry Andric 1335*06c3fb27SDimitry Andric if (!ObjCRuntimeObjectSec) 1336*06c3fb27SDimitry Andric return Error::success(); 1337*06c3fb27SDimitry Andric 1338*06c3fb27SDimitry Andric switch (G.getTargetTriple().getArch()) { 1339*06c3fb27SDimitry Andric case Triple::aarch64: 1340*06c3fb27SDimitry Andric case Triple::x86_64: 1341*06c3fb27SDimitry Andric // Supported. 1342*06c3fb27SDimitry Andric break; 1343*06c3fb27SDimitry Andric default: 1344*06c3fb27SDimitry Andric return make_error<StringError>("Unrecognized MachO arch in triple " + 1345*06c3fb27SDimitry Andric G.getTargetTriple().str(), 1346*06c3fb27SDimitry Andric inconvertibleErrorCode()); 1347*06c3fb27SDimitry Andric } 1348*06c3fb27SDimitry Andric 1349*06c3fb27SDimitry Andric auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin(); 1350*06c3fb27SDimitry Andric 1351*06c3fb27SDimitry Andric struct SecDesc { 1352*06c3fb27SDimitry Andric MachO::section_64 Sec; 1353*06c3fb27SDimitry Andric unique_function<void(size_t RecordOffset)> AddFixups; 1354*06c3fb27SDimitry Andric }; 1355*06c3fb27SDimitry Andric 1356*06c3fb27SDimitry Andric std::vector<SecDesc> TextSections, DataSections; 1357*06c3fb27SDimitry Andric auto AddSection = [&](SecDesc &SD, jitlink::Section &GraphSec) { 1358*06c3fb27SDimitry Andric jitlink::SectionRange SR(GraphSec); 1359*06c3fb27SDimitry Andric StringRef FQName = GraphSec.getName(); 1360*06c3fb27SDimitry Andric memset(&SD.Sec, 0, sizeof(MachO::section_64)); 1361*06c3fb27SDimitry Andric memcpy(SD.Sec.sectname, FQName.drop_front(7).data(), FQName.size() - 7); 1362*06c3fb27SDimitry Andric memcpy(SD.Sec.segname, FQName.data(), 6); 1363*06c3fb27SDimitry Andric SD.Sec.addr = SR.getStart() - SecBlock.getAddress(); 1364*06c3fb27SDimitry Andric SD.Sec.size = SR.getSize(); 1365*06c3fb27SDimitry Andric SD.Sec.flags = MachO::S_REGULAR; 1366*06c3fb27SDimitry Andric }; 1367*06c3fb27SDimitry Andric 1368*06c3fb27SDimitry Andric // Add the __objc_imageinfo section. 1369*06c3fb27SDimitry Andric { 1370*06c3fb27SDimitry Andric DataSections.push_back({}); 1371*06c3fb27SDimitry Andric auto &SD = DataSections.back(); 1372*06c3fb27SDimitry Andric memset(&SD.Sec, 0, sizeof(SD.Sec)); 1373*06c3fb27SDimitry Andric memcpy(SD.Sec.sectname, "__objc_imageinfo", 16); 1374*06c3fb27SDimitry Andric strcpy(SD.Sec.segname, "__DATA"); 1375*06c3fb27SDimitry Andric SD.Sec.size = 8; 1376*06c3fb27SDimitry Andric SD.AddFixups = [&](size_t RecordOffset) { 1377*06c3fb27SDimitry Andric jitlink::Edge::Kind PointerEdge = jitlink::Edge::Invalid; 1378*06c3fb27SDimitry Andric switch (G.getTargetTriple().getArch()) { 1379*06c3fb27SDimitry Andric case Triple::aarch64: 1380*06c3fb27SDimitry Andric PointerEdge = jitlink::aarch64::Pointer64; 1381*06c3fb27SDimitry Andric break; 1382*06c3fb27SDimitry Andric case Triple::x86_64: 1383*06c3fb27SDimitry Andric PointerEdge = jitlink::x86_64::Pointer64; 1384*06c3fb27SDimitry Andric break; 1385*06c3fb27SDimitry Andric default: 1386*06c3fb27SDimitry Andric llvm_unreachable("Unsupported architecture"); 1387*06c3fb27SDimitry Andric } 1388*06c3fb27SDimitry Andric 1389*06c3fb27SDimitry Andric // Look for an existing __objc_imageinfo symbol. 1390*06c3fb27SDimitry Andric jitlink::Symbol *ObjCImageInfoSym = nullptr; 1391*06c3fb27SDimitry Andric for (auto *Sym : G.external_symbols()) 1392*06c3fb27SDimitry Andric if (Sym->getName() == ObjCImageInfoSymbolName) { 1393*06c3fb27SDimitry Andric ObjCImageInfoSym = Sym; 1394*06c3fb27SDimitry Andric break; 1395*06c3fb27SDimitry Andric } 1396*06c3fb27SDimitry Andric if (!ObjCImageInfoSym) 1397*06c3fb27SDimitry Andric for (auto *Sym : G.absolute_symbols()) 1398*06c3fb27SDimitry Andric if (Sym->getName() == ObjCImageInfoSymbolName) { 1399*06c3fb27SDimitry Andric ObjCImageInfoSym = Sym; 1400*06c3fb27SDimitry Andric break; 1401*06c3fb27SDimitry Andric } 1402*06c3fb27SDimitry Andric if (!ObjCImageInfoSym) 1403*06c3fb27SDimitry Andric for (auto *Sym : G.defined_symbols()) 1404*06c3fb27SDimitry Andric if (Sym->hasName() && Sym->getName() == ObjCImageInfoSymbolName) { 1405*06c3fb27SDimitry Andric ObjCImageInfoSym = Sym; 1406*06c3fb27SDimitry Andric break; 1407*06c3fb27SDimitry Andric } 1408*06c3fb27SDimitry Andric if (!ObjCImageInfoSym) 1409*06c3fb27SDimitry Andric ObjCImageInfoSym = 1410*06c3fb27SDimitry Andric &G.addExternalSymbol(ObjCImageInfoSymbolName, 8, false); 1411*06c3fb27SDimitry Andric 1412*06c3fb27SDimitry Andric SecBlock.addEdge(PointerEdge, 1413*06c3fb27SDimitry Andric RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec), 1414*06c3fb27SDimitry Andric *ObjCImageInfoSym, -SecBlock.getAddress().getValue()); 1415*06c3fb27SDimitry Andric }; 1416*06c3fb27SDimitry Andric } 1417*06c3fb27SDimitry Andric 1418*06c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) { 1419*06c3fb27SDimitry Andric if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) { 1420*06c3fb27SDimitry Andric DataSections.push_back({}); 1421*06c3fb27SDimitry Andric AddSection(DataSections.back(), *GraphSec); 1422*06c3fb27SDimitry Andric } 1423*06c3fb27SDimitry Andric } 1424*06c3fb27SDimitry Andric 1425*06c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) { 1426*06c3fb27SDimitry Andric if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) { 1427*06c3fb27SDimitry Andric TextSections.push_back({}); 1428*06c3fb27SDimitry Andric AddSection(TextSections.back(), *GraphSec); 1429*06c3fb27SDimitry Andric } 1430*06c3fb27SDimitry Andric } 1431*06c3fb27SDimitry Andric 1432*06c3fb27SDimitry Andric assert(ObjCRuntimeObjectSec->blocks_size() == 1 && 1433*06c3fb27SDimitry Andric "Unexpected number of blocks in runtime sections object"); 1434*06c3fb27SDimitry Andric 1435*06c3fb27SDimitry Andric // Build the header struct up-front. This also gives us a chance to check 1436*06c3fb27SDimitry Andric // that the triple is supported, which we'll assume below. 1437*06c3fb27SDimitry Andric MachO::mach_header_64 Hdr; 1438*06c3fb27SDimitry Andric Hdr.magic = MachO::MH_MAGIC_64; 1439*06c3fb27SDimitry Andric switch (G.getTargetTriple().getArch()) { 1440*06c3fb27SDimitry Andric case Triple::aarch64: 1441*06c3fb27SDimitry Andric Hdr.cputype = MachO::CPU_TYPE_ARM64; 1442*06c3fb27SDimitry Andric Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL; 1443*06c3fb27SDimitry Andric break; 1444*06c3fb27SDimitry Andric case Triple::x86_64: 1445*06c3fb27SDimitry Andric Hdr.cputype = MachO::CPU_TYPE_X86_64; 1446*06c3fb27SDimitry Andric Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL; 1447*06c3fb27SDimitry Andric break; 1448*06c3fb27SDimitry Andric default: 1449*06c3fb27SDimitry Andric llvm_unreachable("Unsupported architecture"); 1450*06c3fb27SDimitry Andric } 1451*06c3fb27SDimitry Andric 1452*06c3fb27SDimitry Andric Hdr.filetype = MachO::MH_DYLIB; 1453*06c3fb27SDimitry Andric Hdr.ncmds = 1 + !TextSections.empty(); 1454*06c3fb27SDimitry Andric Hdr.sizeofcmds = 1455*06c3fb27SDimitry Andric Hdr.ncmds * sizeof(MachO::segment_command_64) + 1456*06c3fb27SDimitry Andric (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64); 1457*06c3fb27SDimitry Andric Hdr.flags = 0; 1458*06c3fb27SDimitry Andric Hdr.reserved = 0; 1459*06c3fb27SDimitry Andric 1460*06c3fb27SDimitry Andric auto SecContent = SecBlock.getAlreadyMutableContent(); 1461*06c3fb27SDimitry Andric char *P = SecContent.data(); 1462*06c3fb27SDimitry Andric auto WriteMachOStruct = [&](auto S) { 1463*06c3fb27SDimitry Andric if (G.getEndianness() != support::endian::system_endianness()) 1464*06c3fb27SDimitry Andric MachO::swapStruct(S); 1465*06c3fb27SDimitry Andric memcpy(P, &S, sizeof(S)); 1466*06c3fb27SDimitry Andric P += sizeof(S); 1467*06c3fb27SDimitry Andric }; 1468*06c3fb27SDimitry Andric 1469*06c3fb27SDimitry Andric auto WriteSegment = [&](StringRef Name, std::vector<SecDesc> &Secs) { 1470*06c3fb27SDimitry Andric MachO::segment_command_64 SegLC; 1471*06c3fb27SDimitry Andric memset(&SegLC, 0, sizeof(SegLC)); 1472*06c3fb27SDimitry Andric memcpy(SegLC.segname, Name.data(), Name.size()); 1473*06c3fb27SDimitry Andric SegLC.cmd = MachO::LC_SEGMENT_64; 1474*06c3fb27SDimitry Andric SegLC.cmdsize = sizeof(MachO::segment_command_64) + 1475*06c3fb27SDimitry Andric Secs.size() * sizeof(MachO::section_64); 1476*06c3fb27SDimitry Andric SegLC.nsects = Secs.size(); 1477*06c3fb27SDimitry Andric WriteMachOStruct(SegLC); 1478*06c3fb27SDimitry Andric for (auto &SD : Secs) { 1479*06c3fb27SDimitry Andric if (SD.AddFixups) 1480*06c3fb27SDimitry Andric SD.AddFixups(P - SecContent.data()); 1481*06c3fb27SDimitry Andric WriteMachOStruct(SD.Sec); 1482*06c3fb27SDimitry Andric } 1483*06c3fb27SDimitry Andric }; 1484*06c3fb27SDimitry Andric 1485*06c3fb27SDimitry Andric WriteMachOStruct(Hdr); 1486*06c3fb27SDimitry Andric if (!TextSections.empty()) 1487*06c3fb27SDimitry Andric WriteSegment("__TEXT", TextSections); 1488*06c3fb27SDimitry Andric if (!DataSections.empty()) 1489*06c3fb27SDimitry Andric WriteSegment("__DATA", DataSections); 1490*06c3fb27SDimitry Andric 1491*06c3fb27SDimitry Andric assert(P == SecContent.end() && "Underflow writing ObjC runtime object"); 1492*06c3fb27SDimitry Andric return Error::success(); 1493*06c3fb27SDimitry Andric } 1494*06c3fb27SDimitry Andric 14955ffd83dbSDimitry Andric } // End namespace orc. 14965ffd83dbSDimitry Andric } // End namespace llvm. 1497