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"
1206c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/MachO.h"
1306c3fb27SDimitry 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"
185f757f3fSDimitry Andric #include "llvm/ExecutionEngine/Orc/MachOBuilder.h"
1906c3fb27SDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
205ffd83dbSDimitry Andric #include "llvm/Support/BinaryByteStream.h"
215ffd83dbSDimitry Andric #include "llvm/Support/Debug.h"
22bdd1243dSDimitry Andric #include <optional>
235ffd83dbSDimitry Andric
245ffd83dbSDimitry Andric #define DEBUG_TYPE "orc"
255ffd83dbSDimitry Andric
26fe6060f1SDimitry Andric using namespace llvm;
27fe6060f1SDimitry Andric using namespace llvm::orc;
28fe6060f1SDimitry Andric using namespace llvm::orc::shared;
29fe6060f1SDimitry Andric
3081ad6265SDimitry Andric namespace llvm {
3181ad6265SDimitry Andric namespace orc {
3281ad6265SDimitry Andric namespace shared {
3381ad6265SDimitry Andric
3481ad6265SDimitry Andric using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
3581ad6265SDimitry Andric using SPSMachOJITDylibDepInfoMap =
3681ad6265SDimitry Andric SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
3781ad6265SDimitry Andric
385f757f3fSDimitry Andric class SPSMachOExecutorSymbolFlags;
395f757f3fSDimitry Andric
4081ad6265SDimitry Andric template <>
4181ad6265SDimitry Andric class SPSSerializationTraits<SPSMachOJITDylibDepInfo,
4281ad6265SDimitry Andric MachOPlatform::MachOJITDylibDepInfo> {
4381ad6265SDimitry Andric public:
size(const MachOPlatform::MachOJITDylibDepInfo & DDI)4481ad6265SDimitry Andric static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
4581ad6265SDimitry Andric return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
4681ad6265SDimitry Andric }
4781ad6265SDimitry Andric
serialize(SPSOutputBuffer & OB,const MachOPlatform::MachOJITDylibDepInfo & DDI)4881ad6265SDimitry Andric static bool serialize(SPSOutputBuffer &OB,
4981ad6265SDimitry Andric const MachOPlatform::MachOJITDylibDepInfo &DDI) {
5081ad6265SDimitry Andric return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
5181ad6265SDimitry Andric DDI.DepHeaders);
5281ad6265SDimitry Andric }
5381ad6265SDimitry Andric
deserialize(SPSInputBuffer & IB,MachOPlatform::MachOJITDylibDepInfo & DDI)5481ad6265SDimitry Andric static bool deserialize(SPSInputBuffer &IB,
5581ad6265SDimitry Andric MachOPlatform::MachOJITDylibDepInfo &DDI) {
5681ad6265SDimitry Andric return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
5781ad6265SDimitry Andric DDI.DepHeaders);
5881ad6265SDimitry Andric }
5981ad6265SDimitry Andric };
6081ad6265SDimitry Andric
615f757f3fSDimitry Andric template <>
625f757f3fSDimitry Andric class SPSSerializationTraits<SPSMachOExecutorSymbolFlags,
635f757f3fSDimitry Andric MachOPlatform::MachOExecutorSymbolFlags> {
645f757f3fSDimitry Andric private:
655f757f3fSDimitry Andric using UT = std::underlying_type_t<MachOPlatform::MachOExecutorSymbolFlags>;
665f757f3fSDimitry Andric
675f757f3fSDimitry Andric public:
size(const MachOPlatform::MachOExecutorSymbolFlags & SF)685f757f3fSDimitry Andric static size_t size(const MachOPlatform::MachOExecutorSymbolFlags &SF) {
695f757f3fSDimitry Andric return sizeof(UT);
705f757f3fSDimitry Andric }
715f757f3fSDimitry Andric
serialize(SPSOutputBuffer & OB,const MachOPlatform::MachOExecutorSymbolFlags & SF)725f757f3fSDimitry Andric static bool serialize(SPSOutputBuffer &OB,
735f757f3fSDimitry Andric const MachOPlatform::MachOExecutorSymbolFlags &SF) {
745f757f3fSDimitry Andric return SPSArgList<UT>::serialize(OB, static_cast<UT>(SF));
755f757f3fSDimitry Andric }
765f757f3fSDimitry Andric
deserialize(SPSInputBuffer & IB,MachOPlatform::MachOExecutorSymbolFlags & SF)775f757f3fSDimitry Andric static bool deserialize(SPSInputBuffer &IB,
785f757f3fSDimitry Andric MachOPlatform::MachOExecutorSymbolFlags &SF) {
795f757f3fSDimitry Andric UT Tmp;
805f757f3fSDimitry Andric if (!SPSArgList<UT>::deserialize(IB, Tmp))
815f757f3fSDimitry Andric return false;
825f757f3fSDimitry Andric SF = static_cast<MachOPlatform::MachOExecutorSymbolFlags>(Tmp);
835f757f3fSDimitry Andric return true;
845f757f3fSDimitry Andric }
855f757f3fSDimitry Andric };
865f757f3fSDimitry Andric
8781ad6265SDimitry Andric } // namespace shared
8881ad6265SDimitry Andric } // namespace orc
8981ad6265SDimitry Andric } // namespace llvm
9081ad6265SDimitry Andric
915ffd83dbSDimitry Andric namespace {
925ffd83dbSDimitry Andric
935f757f3fSDimitry Andric using SPSRegisterSymbolsArgs =
945f757f3fSDimitry Andric SPSArgList<SPSExecutorAddr,
955f757f3fSDimitry Andric SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
965f757f3fSDimitry Andric SPSMachOExecutorSymbolFlags>>>;
975f757f3fSDimitry Andric
createPlatformGraph(MachOPlatform & MOP,std::string Name)98bdd1243dSDimitry Andric std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
99bdd1243dSDimitry Andric std::string Name) {
100fe6060f1SDimitry Andric unsigned PointerSize;
1015f757f3fSDimitry Andric llvm::endianness Endianness;
10206c3fb27SDimitry Andric const auto &TT = MOP.getExecutionSession().getTargetTriple();
1035ffd83dbSDimitry Andric
104fe6060f1SDimitry Andric switch (TT.getArch()) {
105fe6060f1SDimitry Andric case Triple::aarch64:
106fe6060f1SDimitry Andric case Triple::x86_64:
107fe6060f1SDimitry Andric PointerSize = 8;
1085f757f3fSDimitry Andric Endianness = llvm::endianness::little;
109fe6060f1SDimitry Andric break;
110fe6060f1SDimitry Andric default:
111fe6060f1SDimitry Andric llvm_unreachable("Unrecognized architecture");
112fe6060f1SDimitry Andric }
1135ffd83dbSDimitry Andric
114bdd1243dSDimitry Andric return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize,
115bdd1243dSDimitry Andric Endianness,
116fe6060f1SDimitry Andric jitlink::getGenericEdgeKindName);
117bdd1243dSDimitry Andric }
118fe6060f1SDimitry Andric
119bdd1243dSDimitry Andric // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
120bdd1243dSDimitry Andric class MachOPlatformCompleteBootstrapMaterializationUnit
121bdd1243dSDimitry Andric : public MaterializationUnit {
122bdd1243dSDimitry Andric public:
1235f757f3fSDimitry Andric using SymbolTableVector =
1245f757f3fSDimitry Andric SmallVector<std::tuple<ExecutorAddr, ExecutorAddr,
1255f757f3fSDimitry Andric MachOPlatform::MachOExecutorSymbolFlags>>;
1265f757f3fSDimitry Andric
MachOPlatformCompleteBootstrapMaterializationUnit(MachOPlatform & MOP,StringRef PlatformJDName,SymbolStringPtr CompleteBootstrapSymbol,SymbolTableVector SymTab,shared::AllocActions DeferredAAs,ExecutorAddr MachOHeaderAddr,ExecutorAddr PlatformBootstrap,ExecutorAddr PlatformShutdown,ExecutorAddr RegisterJITDylib,ExecutorAddr DeregisterJITDylib,ExecutorAddr RegisterObjectSymbolTable,ExecutorAddr DeregisterObjectSymbolTable)127bdd1243dSDimitry Andric MachOPlatformCompleteBootstrapMaterializationUnit(
128bdd1243dSDimitry Andric MachOPlatform &MOP, StringRef PlatformJDName,
1295f757f3fSDimitry Andric SymbolStringPtr CompleteBootstrapSymbol, SymbolTableVector SymTab,
1305f757f3fSDimitry Andric shared::AllocActions DeferredAAs, ExecutorAddr MachOHeaderAddr,
131bdd1243dSDimitry Andric ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown,
132bdd1243dSDimitry Andric ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib,
1335f757f3fSDimitry Andric ExecutorAddr RegisterObjectSymbolTable,
1345f757f3fSDimitry Andric ExecutorAddr DeregisterObjectSymbolTable)
135bdd1243dSDimitry Andric : MaterializationUnit(
136bdd1243dSDimitry Andric {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),
137bdd1243dSDimitry Andric MOP(MOP), PlatformJDName(PlatformJDName),
138bdd1243dSDimitry Andric CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),
1395f757f3fSDimitry Andric SymTab(std::move(SymTab)), DeferredAAs(std::move(DeferredAAs)),
1405f757f3fSDimitry Andric MachOHeaderAddr(MachOHeaderAddr), PlatformBootstrap(PlatformBootstrap),
141bdd1243dSDimitry Andric PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),
142bdd1243dSDimitry Andric DeregisterJITDylib(DeregisterJITDylib),
1435f757f3fSDimitry Andric RegisterObjectSymbolTable(RegisterObjectSymbolTable),
1445f757f3fSDimitry Andric DeregisterObjectSymbolTable(DeregisterObjectSymbolTable) {}
145bdd1243dSDimitry Andric
getName() const146bdd1243dSDimitry Andric StringRef getName() const override {
147bdd1243dSDimitry Andric return "MachOPlatformCompleteBootstrap";
148bdd1243dSDimitry Andric }
149bdd1243dSDimitry Andric
materialize(std::unique_ptr<MaterializationResponsibility> R)150bdd1243dSDimitry Andric void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
151bdd1243dSDimitry Andric using namespace jitlink;
152bdd1243dSDimitry Andric auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>");
153bdd1243dSDimitry Andric auto &PlaceholderSection =
154bdd1243dSDimitry Andric G->createSection("__orc_rt_cplt_bs", MemProt::Read);
155bdd1243dSDimitry Andric auto &PlaceholderBlock =
156bdd1243dSDimitry Andric G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0);
157bdd1243dSDimitry Andric G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1,
158bdd1243dSDimitry Andric Linkage::Strong, Scope::Hidden, false, true);
159bdd1243dSDimitry Andric
160bdd1243dSDimitry Andric // Reserve space for the stolen actions, plus two extras.
1615f757f3fSDimitry Andric G->allocActions().reserve(DeferredAAs.size() + 3);
162bdd1243dSDimitry Andric
163bdd1243dSDimitry Andric // 1. Bootstrap the platform support code.
164bdd1243dSDimitry Andric G->allocActions().push_back(
165bdd1243dSDimitry Andric {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)),
166bdd1243dSDimitry Andric cantFail(
167bdd1243dSDimitry Andric WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
168bdd1243dSDimitry Andric
169bdd1243dSDimitry Andric // 2. Register the platform JITDylib.
170bdd1243dSDimitry Andric G->allocActions().push_back(
171bdd1243dSDimitry Andric {cantFail(WrapperFunctionCall::Create<
172bdd1243dSDimitry Andric SPSArgList<SPSString, SPSExecutorAddr>>(
173bdd1243dSDimitry Andric RegisterJITDylib, PlatformJDName, MachOHeaderAddr)),
174bdd1243dSDimitry Andric cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
175bdd1243dSDimitry Andric DeregisterJITDylib, MachOHeaderAddr))});
176bdd1243dSDimitry Andric
1775f757f3fSDimitry Andric // 3. Register deferred symbols.
1785f757f3fSDimitry Andric G->allocActions().push_back(
1795f757f3fSDimitry Andric {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
1805f757f3fSDimitry Andric RegisterObjectSymbolTable, MachOHeaderAddr, SymTab)),
1815f757f3fSDimitry Andric cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
1825f757f3fSDimitry Andric DeregisterObjectSymbolTable, MachOHeaderAddr, SymTab))});
1835f757f3fSDimitry Andric
1845f757f3fSDimitry Andric // 4. Add the deferred actions to the graph.
185bdd1243dSDimitry Andric std::move(DeferredAAs.begin(), DeferredAAs.end(),
186bdd1243dSDimitry Andric std::back_inserter(G->allocActions()));
187bdd1243dSDimitry Andric
188bdd1243dSDimitry Andric MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
189bdd1243dSDimitry Andric }
190bdd1243dSDimitry Andric
discard(const JITDylib & JD,const SymbolStringPtr & Sym)191bdd1243dSDimitry Andric void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
192bdd1243dSDimitry Andric
193bdd1243dSDimitry Andric private:
194bdd1243dSDimitry Andric MachOPlatform &MOP;
195bdd1243dSDimitry Andric StringRef PlatformJDName;
196bdd1243dSDimitry Andric SymbolStringPtr CompleteBootstrapSymbol;
1975f757f3fSDimitry Andric SymbolTableVector SymTab;
198bdd1243dSDimitry Andric shared::AllocActions DeferredAAs;
1995f757f3fSDimitry Andric ExecutorAddr MachOHeaderAddr;
200bdd1243dSDimitry Andric ExecutorAddr PlatformBootstrap;
201bdd1243dSDimitry Andric ExecutorAddr PlatformShutdown;
202bdd1243dSDimitry Andric ExecutorAddr RegisterJITDylib;
203bdd1243dSDimitry Andric ExecutorAddr DeregisterJITDylib;
2045f757f3fSDimitry Andric ExecutorAddr RegisterObjectSymbolTable;
2055f757f3fSDimitry Andric ExecutorAddr DeregisterObjectSymbolTable;
206bdd1243dSDimitry Andric };
207bdd1243dSDimitry Andric
20806c3fb27SDimitry Andric static StringRef ObjCRuntimeObjectSectionsData[] = {
209*0fca6ea1SDimitry Andric MachOObjCCatListSectionName, MachOObjCCatList2SectionName,
210*0fca6ea1SDimitry Andric MachOObjCClassListSectionName, MachOObjCClassRefsSectionName,
211*0fca6ea1SDimitry Andric MachOObjCConstSectionName, MachOObjCDataSectionName,
212*0fca6ea1SDimitry Andric MachOObjCProtoListSectionName, MachOObjCProtoRefsSectionName,
213*0fca6ea1SDimitry Andric MachOObjCNLCatListSectionName, MachOObjCNLClassListSectionName,
214*0fca6ea1SDimitry Andric MachOObjCSelRefsSectionName};
215fe6060f1SDimitry Andric
21606c3fb27SDimitry Andric static StringRef ObjCRuntimeObjectSectionsText[] = {
21706c3fb27SDimitry Andric MachOObjCClassNameSectionName, MachOObjCMethNameSectionName,
21806c3fb27SDimitry Andric MachOObjCMethTypeSectionName, MachOSwift5TypesSectionName,
21906c3fb27SDimitry Andric MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
22006c3fb27SDimitry Andric MachOSwift5EntrySectionName, MachOSwift5ProtoSectionName,
22106c3fb27SDimitry Andric MachOSwift5ProtosSectionName};
22206c3fb27SDimitry Andric
22306c3fb27SDimitry Andric static StringRef ObjCRuntimeObjectSectionName =
22406c3fb27SDimitry Andric "__llvm_jitlink_ObjCRuntimeRegistrationObject";
22506c3fb27SDimitry Andric
22606c3fb27SDimitry Andric static StringRef ObjCImageInfoSymbolName =
22706c3fb27SDimitry Andric "__llvm_jitlink_macho_objc_imageinfo";
2285ffd83dbSDimitry Andric
2295f757f3fSDimitry Andric struct ObjCImageInfoFlags {
2305f757f3fSDimitry Andric uint16_t SwiftABIVersion;
2315f757f3fSDimitry Andric uint16_t SwiftVersion;
2325f757f3fSDimitry Andric bool HasCategoryClassProperties;
2335f757f3fSDimitry Andric bool HasSignedObjCClassROs;
2345f757f3fSDimitry Andric
2355f757f3fSDimitry Andric static constexpr uint32_t SIGNED_CLASS_RO = (1 << 4);
2365f757f3fSDimitry Andric static constexpr uint32_t HAS_CATEGORY_CLASS_PROPERTIES = (1 << 6);
2375f757f3fSDimitry Andric
ObjCImageInfoFlags__anon04a50ca90111::ObjCImageInfoFlags2385f757f3fSDimitry Andric explicit ObjCImageInfoFlags(uint32_t RawFlags) {
2395f757f3fSDimitry Andric HasSignedObjCClassROs = RawFlags & SIGNED_CLASS_RO;
2405f757f3fSDimitry Andric HasCategoryClassProperties = RawFlags & HAS_CATEGORY_CLASS_PROPERTIES;
2415f757f3fSDimitry Andric SwiftABIVersion = (RawFlags >> 8) & 0xFF;
2425f757f3fSDimitry Andric SwiftVersion = (RawFlags >> 16) & 0xFFFF;
2435f757f3fSDimitry Andric }
2445f757f3fSDimitry Andric
rawFlags__anon04a50ca90111::ObjCImageInfoFlags2455f757f3fSDimitry Andric uint32_t rawFlags() const {
2465f757f3fSDimitry Andric uint32_t Result = 0;
2475f757f3fSDimitry Andric if (HasCategoryClassProperties)
2485f757f3fSDimitry Andric Result |= HAS_CATEGORY_CLASS_PROPERTIES;
2495f757f3fSDimitry Andric if (HasSignedObjCClassROs)
2505f757f3fSDimitry Andric Result |= SIGNED_CLASS_RO;
2515f757f3fSDimitry Andric Result |= (SwiftABIVersion << 8);
2525f757f3fSDimitry Andric Result |= (SwiftVersion << 16);
2535f757f3fSDimitry Andric return Result;
2545f757f3fSDimitry Andric }
2555f757f3fSDimitry Andric };
2565ffd83dbSDimitry Andric } // end anonymous namespace
2575ffd83dbSDimitry Andric
2585ffd83dbSDimitry Andric namespace llvm {
2595ffd83dbSDimitry Andric namespace orc {
2605ffd83dbSDimitry Andric
261*0fca6ea1SDimitry Andric std::optional<MachOPlatform::HeaderOptions::BuildVersionOpts>
fromTriple(const Triple & TT,uint32_t MinOS,uint32_t SDK)262*0fca6ea1SDimitry Andric MachOPlatform::HeaderOptions::BuildVersionOpts::fromTriple(const Triple &TT,
263*0fca6ea1SDimitry Andric uint32_t MinOS,
264*0fca6ea1SDimitry Andric uint32_t SDK) {
265*0fca6ea1SDimitry Andric
266*0fca6ea1SDimitry Andric uint32_t Platform;
267*0fca6ea1SDimitry Andric switch (TT.getOS()) {
268*0fca6ea1SDimitry Andric case Triple::IOS:
269*0fca6ea1SDimitry Andric Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_IOSSIMULATOR
270*0fca6ea1SDimitry Andric : MachO::PLATFORM_IOS;
271*0fca6ea1SDimitry Andric break;
272*0fca6ea1SDimitry Andric case Triple::MacOSX:
273*0fca6ea1SDimitry Andric Platform = MachO::PLATFORM_MACOS;
274*0fca6ea1SDimitry Andric break;
275*0fca6ea1SDimitry Andric case Triple::TvOS:
276*0fca6ea1SDimitry Andric Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_TVOSSIMULATOR
277*0fca6ea1SDimitry Andric : MachO::PLATFORM_TVOS;
278*0fca6ea1SDimitry Andric break;
279*0fca6ea1SDimitry Andric case Triple::WatchOS:
280*0fca6ea1SDimitry Andric Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_WATCHOSSIMULATOR
281*0fca6ea1SDimitry Andric : MachO::PLATFORM_WATCHOS;
282*0fca6ea1SDimitry Andric break;
283*0fca6ea1SDimitry Andric case Triple::XROS:
284*0fca6ea1SDimitry Andric Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_XROS_SIMULATOR
285*0fca6ea1SDimitry Andric : MachO::PLATFORM_XROS;
286*0fca6ea1SDimitry Andric break;
287*0fca6ea1SDimitry Andric default:
288*0fca6ea1SDimitry Andric return std::nullopt;
289*0fca6ea1SDimitry Andric }
290*0fca6ea1SDimitry Andric
291*0fca6ea1SDimitry Andric return MachOPlatform::HeaderOptions::BuildVersionOpts{Platform, MinOS, SDK};
292*0fca6ea1SDimitry Andric }
293*0fca6ea1SDimitry Andric
Create(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,std::unique_ptr<DefinitionGenerator> OrcRuntime,HeaderOptions PlatformJDOpts,MachOHeaderMUBuilder BuildMachOHeaderMU,std::optional<SymbolAliasMap> RuntimeAliases)2947a6dacacSDimitry Andric Expected<std::unique_ptr<MachOPlatform>> MachOPlatform::Create(
2957a6dacacSDimitry Andric ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
2967a6dacacSDimitry Andric JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,
2977a6dacacSDimitry Andric HeaderOptions PlatformJDOpts, MachOHeaderMUBuilder BuildMachOHeaderMU,
298bdd1243dSDimitry Andric std::optional<SymbolAliasMap> RuntimeAliases) {
299fe6060f1SDimitry Andric
300fe6060f1SDimitry Andric // If the target is not supported then bail out immediately.
30106c3fb27SDimitry Andric if (!supportedTarget(ES.getTargetTriple()))
302fe6060f1SDimitry Andric return make_error<StringError>("Unsupported MachOPlatform triple: " +
30306c3fb27SDimitry Andric ES.getTargetTriple().str(),
3045ffd83dbSDimitry Andric inconvertibleErrorCode());
3055ffd83dbSDimitry Andric
30606c3fb27SDimitry Andric auto &EPC = ES.getExecutorProcessControl();
30706c3fb27SDimitry Andric
308fe6060f1SDimitry Andric // Create default aliases if the caller didn't supply any.
309fe6060f1SDimitry Andric if (!RuntimeAliases)
310fe6060f1SDimitry Andric RuntimeAliases = standardPlatformAliases(ES);
3115ffd83dbSDimitry Andric
312fe6060f1SDimitry Andric // Define the aliases.
313fe6060f1SDimitry Andric if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
314fe6060f1SDimitry Andric return std::move(Err);
3155ffd83dbSDimitry Andric
316fe6060f1SDimitry Andric // Add JIT-dispatch function support symbols.
31706c3fb27SDimitry Andric if (auto Err = PlatformJD.define(
31806c3fb27SDimitry Andric absoluteSymbols({{ES.intern("___orc_rt_jit_dispatch"),
31906c3fb27SDimitry Andric {EPC.getJITDispatchInfo().JITDispatchFunction,
320fe6060f1SDimitry Andric JITSymbolFlags::Exported}},
321fe6060f1SDimitry Andric {ES.intern("___orc_rt_jit_dispatch_ctx"),
32206c3fb27SDimitry Andric {EPC.getJITDispatchInfo().JITDispatchContext,
323fe6060f1SDimitry Andric JITSymbolFlags::Exported}}})))
324fe6060f1SDimitry Andric return std::move(Err);
3255ffd83dbSDimitry Andric
326fe6060f1SDimitry Andric // Create the instance.
327fe6060f1SDimitry Andric Error Err = Error::success();
3287a6dacacSDimitry Andric auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform(
3297a6dacacSDimitry Andric ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime),
3307a6dacacSDimitry Andric std::move(PlatformJDOpts), std::move(BuildMachOHeaderMU), Err));
331fe6060f1SDimitry Andric if (Err)
332fe6060f1SDimitry Andric return std::move(Err);
333fe6060f1SDimitry Andric return std::move(P);
3345ffd83dbSDimitry Andric }
3355ffd83dbSDimitry Andric
33606c3fb27SDimitry Andric Expected<std::unique_ptr<MachOPlatform>>
Create(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,const char * OrcRuntimePath,HeaderOptions PlatformJDOpts,MachOHeaderMUBuilder BuildMachOHeaderMU,std::optional<SymbolAliasMap> RuntimeAliases)33706c3fb27SDimitry Andric MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
33806c3fb27SDimitry Andric JITDylib &PlatformJD, const char *OrcRuntimePath,
3397a6dacacSDimitry Andric HeaderOptions PlatformJDOpts,
3405f757f3fSDimitry Andric MachOHeaderMUBuilder BuildMachOHeaderMU,
34106c3fb27SDimitry Andric std::optional<SymbolAliasMap> RuntimeAliases) {
34206c3fb27SDimitry Andric
34306c3fb27SDimitry Andric // Create a generator for the ORC runtime archive.
34406c3fb27SDimitry Andric auto OrcRuntimeArchiveGenerator =
34506c3fb27SDimitry Andric StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
34606c3fb27SDimitry Andric if (!OrcRuntimeArchiveGenerator)
34706c3fb27SDimitry Andric return OrcRuntimeArchiveGenerator.takeError();
34806c3fb27SDimitry Andric
34906c3fb27SDimitry Andric return Create(ES, ObjLinkingLayer, PlatformJD,
35006c3fb27SDimitry Andric std::move(*OrcRuntimeArchiveGenerator),
3517a6dacacSDimitry Andric std::move(PlatformJDOpts), std::move(BuildMachOHeaderMU),
3527a6dacacSDimitry Andric std::move(RuntimeAliases));
35306c3fb27SDimitry Andric }
35406c3fb27SDimitry Andric
setupJITDylib(JITDylib & JD)3555ffd83dbSDimitry Andric Error MachOPlatform::setupJITDylib(JITDylib &JD) {
3567a6dacacSDimitry Andric return setupJITDylib(JD, /*Opts=*/{});
3577a6dacacSDimitry Andric }
3587a6dacacSDimitry Andric
setupJITDylib(JITDylib & JD,HeaderOptions Opts)3597a6dacacSDimitry Andric Error MachOPlatform::setupJITDylib(JITDylib &JD, HeaderOptions Opts) {
3607a6dacacSDimitry Andric if (auto Err = JD.define(BuildMachOHeaderMU(*this, std::move(Opts))))
36181ad6265SDimitry Andric return Err;
36281ad6265SDimitry Andric
36381ad6265SDimitry Andric return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
3645ffd83dbSDimitry Andric }
3655ffd83dbSDimitry Andric
teardownJITDylib(JITDylib & JD)36681ad6265SDimitry Andric Error MachOPlatform::teardownJITDylib(JITDylib &JD) {
36781ad6265SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex);
36881ad6265SDimitry Andric auto I = JITDylibToHeaderAddr.find(&JD);
36981ad6265SDimitry Andric if (I != JITDylibToHeaderAddr.end()) {
37081ad6265SDimitry Andric assert(HeaderAddrToJITDylib.count(I->second) &&
37181ad6265SDimitry Andric "HeaderAddrToJITDylib missing entry");
37281ad6265SDimitry Andric HeaderAddrToJITDylib.erase(I->second);
37381ad6265SDimitry Andric JITDylibToHeaderAddr.erase(I);
37481ad6265SDimitry Andric }
37581ad6265SDimitry Andric JITDylibToPThreadKey.erase(&JD);
37681ad6265SDimitry Andric return Error::success();
37781ad6265SDimitry Andric }
37804eeddc0SDimitry Andric
notifyAdding(ResourceTracker & RT,const MaterializationUnit & MU)379e8d8bef9SDimitry Andric Error MachOPlatform::notifyAdding(ResourceTracker &RT,
380e8d8bef9SDimitry Andric const MaterializationUnit &MU) {
381e8d8bef9SDimitry Andric auto &JD = RT.getJITDylib();
3825ffd83dbSDimitry Andric const auto &InitSym = MU.getInitializerSymbol();
3835ffd83dbSDimitry Andric if (!InitSym)
3845ffd83dbSDimitry Andric return Error::success();
3855ffd83dbSDimitry Andric
3865ffd83dbSDimitry Andric RegisteredInitSymbols[&JD].add(InitSym,
3875ffd83dbSDimitry Andric SymbolLookupFlags::WeaklyReferencedSymbol);
3885ffd83dbSDimitry Andric LLVM_DEBUG({
3895ffd83dbSDimitry Andric dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
3905ffd83dbSDimitry Andric << MU.getName() << "\n";
3915ffd83dbSDimitry Andric });
3925ffd83dbSDimitry Andric return Error::success();
3935ffd83dbSDimitry Andric }
3945ffd83dbSDimitry Andric
notifyRemoving(ResourceTracker & RT)395e8d8bef9SDimitry Andric Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
3965ffd83dbSDimitry Andric llvm_unreachable("Not supported yet");
3975ffd83dbSDimitry Andric }
3985ffd83dbSDimitry Andric
addAliases(ExecutionSession & ES,SymbolAliasMap & Aliases,ArrayRef<std::pair<const char *,const char * >> AL)399fe6060f1SDimitry Andric static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
400fe6060f1SDimitry Andric ArrayRef<std::pair<const char *, const char *>> AL) {
401fe6060f1SDimitry Andric for (auto &KV : AL) {
402fe6060f1SDimitry Andric auto AliasName = ES.intern(KV.first);
403fe6060f1SDimitry Andric assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
404fe6060f1SDimitry Andric Aliases[std::move(AliasName)] = {ES.intern(KV.second),
405fe6060f1SDimitry Andric JITSymbolFlags::Exported};
406fe6060f1SDimitry Andric }
407fe6060f1SDimitry Andric }
4085ffd83dbSDimitry Andric
standardPlatformAliases(ExecutionSession & ES)409fe6060f1SDimitry Andric SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
410fe6060f1SDimitry Andric SymbolAliasMap Aliases;
411fe6060f1SDimitry Andric addAliases(ES, Aliases, requiredCXXAliases());
412fe6060f1SDimitry Andric addAliases(ES, Aliases, standardRuntimeUtilityAliases());
413fe6060f1SDimitry Andric return Aliases;
414fe6060f1SDimitry Andric }
415fe6060f1SDimitry Andric
416fe6060f1SDimitry Andric ArrayRef<std::pair<const char *, const char *>>
requiredCXXAliases()417fe6060f1SDimitry Andric MachOPlatform::requiredCXXAliases() {
418fe6060f1SDimitry Andric static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
419fe6060f1SDimitry Andric {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
420fe6060f1SDimitry Andric
421fe6060f1SDimitry Andric return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
422fe6060f1SDimitry Andric }
423fe6060f1SDimitry Andric
424fe6060f1SDimitry Andric ArrayRef<std::pair<const char *, const char *>>
standardRuntimeUtilityAliases()425fe6060f1SDimitry Andric MachOPlatform::standardRuntimeUtilityAliases() {
426fe6060f1SDimitry Andric static const std::pair<const char *, const char *>
427fe6060f1SDimitry Andric StandardRuntimeUtilityAliases[] = {
428fe6060f1SDimitry Andric {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
42981ad6265SDimitry Andric {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
43081ad6265SDimitry Andric {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
43181ad6265SDimitry Andric {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
43281ad6265SDimitry Andric {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
433fe6060f1SDimitry Andric {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
434fe6060f1SDimitry Andric
435fe6060f1SDimitry Andric return ArrayRef<std::pair<const char *, const char *>>(
436fe6060f1SDimitry Andric StandardRuntimeUtilityAliases);
437fe6060f1SDimitry Andric }
438fe6060f1SDimitry Andric
supportedTarget(const Triple & TT)439fe6060f1SDimitry Andric bool MachOPlatform::supportedTarget(const Triple &TT) {
440fe6060f1SDimitry Andric switch (TT.getArch()) {
441349cc55cSDimitry Andric case Triple::aarch64:
442fe6060f1SDimitry Andric case Triple::x86_64:
443fe6060f1SDimitry Andric return true;
444fe6060f1SDimitry Andric default:
445fe6060f1SDimitry Andric return false;
446fe6060f1SDimitry Andric }
447fe6060f1SDimitry Andric }
448fe6060f1SDimitry Andric
getPointerEdgeKind(jitlink::LinkGraph & G)4495f757f3fSDimitry Andric jitlink::Edge::Kind MachOPlatform::getPointerEdgeKind(jitlink::LinkGraph &G) {
4505f757f3fSDimitry Andric switch (G.getTargetTriple().getArch()) {
4515f757f3fSDimitry Andric case Triple::aarch64:
4525f757f3fSDimitry Andric return jitlink::aarch64::Pointer64;
4535f757f3fSDimitry Andric case Triple::x86_64:
4545f757f3fSDimitry Andric return jitlink::x86_64::Pointer64;
4555f757f3fSDimitry Andric default:
4565f757f3fSDimitry Andric llvm_unreachable("Unsupported architecture");
4575f757f3fSDimitry Andric }
4585f757f3fSDimitry Andric }
4595f757f3fSDimitry Andric
4605f757f3fSDimitry Andric MachOPlatform::MachOExecutorSymbolFlags
flagsForSymbol(jitlink::Symbol & Sym)4615f757f3fSDimitry Andric MachOPlatform::flagsForSymbol(jitlink::Symbol &Sym) {
4625f757f3fSDimitry Andric MachOPlatform::MachOExecutorSymbolFlags Flags{};
4635f757f3fSDimitry Andric if (Sym.getLinkage() == jitlink::Linkage::Weak)
4645f757f3fSDimitry Andric Flags |= MachOExecutorSymbolFlags::Weak;
4655f757f3fSDimitry Andric
4665f757f3fSDimitry Andric if (Sym.isCallable())
4675f757f3fSDimitry Andric Flags |= MachOExecutorSymbolFlags::Callable;
4685f757f3fSDimitry Andric
4695f757f3fSDimitry Andric return Flags;
4705f757f3fSDimitry Andric }
4715f757f3fSDimitry Andric
MachOPlatform(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,HeaderOptions PlatformJDOpts,MachOHeaderMUBuilder BuildMachOHeaderMU,Error & Err)472fe6060f1SDimitry Andric MachOPlatform::MachOPlatform(
473fe6060f1SDimitry Andric ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
474fe6060f1SDimitry Andric JITDylib &PlatformJD,
4755f757f3fSDimitry Andric std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
4767a6dacacSDimitry Andric HeaderOptions PlatformJDOpts, MachOHeaderMUBuilder BuildMachOHeaderMU,
4777a6dacacSDimitry Andric Error &Err)
4785f757f3fSDimitry Andric : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer),
4795f757f3fSDimitry Andric BuildMachOHeaderMU(std::move(BuildMachOHeaderMU)) {
480fe6060f1SDimitry Andric ErrorAsOutParameter _(&Err);
481fe6060f1SDimitry Andric ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
482fe6060f1SDimitry Andric PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
483fe6060f1SDimitry Andric
484bdd1243dSDimitry Andric BootstrapInfo BI;
485bdd1243dSDimitry Andric Bootstrap = &BI;
486bdd1243dSDimitry Andric
487bdd1243dSDimitry Andric // Bootstrap process -- here be phase-ordering dragons.
488bdd1243dSDimitry Andric //
489bdd1243dSDimitry Andric // The MachOPlatform class uses allocation actions to register metadata
490bdd1243dSDimitry Andric // sections with the ORC runtime, however the runtime contains metadata
491bdd1243dSDimitry Andric // registration functions that have their own metadata that they need to
492bdd1243dSDimitry Andric // register (e.g. the frame-info registration functions have frame-info).
493bdd1243dSDimitry Andric // We can't use an ordinary lookup to find these registration functions
494bdd1243dSDimitry Andric // because their address is needed during the link of the containing graph
495bdd1243dSDimitry Andric // itself (to build the allocation actions that will call the registration
496bdd1243dSDimitry Andric // functions). Further complicating the situation (a) the graph containing
497bdd1243dSDimitry Andric // the registration functions is allowed to depend on other graphs (e.g. the
4985f757f3fSDimitry Andric // graph containing the ORC runtime RTTI support) so we need to handle an
4995f757f3fSDimitry Andric // unknown set of dependencies during bootstrap, and (b) these graphs may
500bdd1243dSDimitry Andric // be linked concurrently if the user has installed a concurrent dispatcher.
501bdd1243dSDimitry Andric //
5025f757f3fSDimitry Andric // We satisfy these constraints by implementing a bootstrap phase during which
503bdd1243dSDimitry Andric // allocation actions generated by MachOPlatform are appended to a list of
504bdd1243dSDimitry Andric // deferred allocation actions, rather than to the graphs themselves. At the
505bdd1243dSDimitry Andric // end of the bootstrap process the deferred actions are attached to a final
506bdd1243dSDimitry Andric // "complete-bootstrap" graph that causes them to be run.
507bdd1243dSDimitry Andric //
508bdd1243dSDimitry Andric // The bootstrap steps are as follows:
509bdd1243dSDimitry Andric //
510bdd1243dSDimitry Andric // 1. Request the graph containing the mach header. This graph is guaranteed
511bdd1243dSDimitry Andric // not to have any metadata so the fact that the registration functions
512bdd1243dSDimitry Andric // are not available yet is not a problem.
513bdd1243dSDimitry Andric //
514bdd1243dSDimitry Andric // 2. Look up the registration functions and discard the results. This will
515bdd1243dSDimitry Andric // trigger linking of the graph containing these functions, and
516bdd1243dSDimitry Andric // consequently any graphs that it depends on. We do not use the lookup
517bdd1243dSDimitry Andric // result to find the addresses of the functions requested (as described
518bdd1243dSDimitry Andric // above the lookup will return too late for that), instead we capture the
519bdd1243dSDimitry Andric // addresses in a post-allocation pass injected by the platform runtime
520bdd1243dSDimitry Andric // during bootstrap only.
521bdd1243dSDimitry Andric //
522bdd1243dSDimitry Andric // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of
523bdd1243dSDimitry Andric // graphs being linked (potentially concurrently), and we block until all
524bdd1243dSDimitry Andric // of these graphs have completed linking. This is to avoid a race on the
525bdd1243dSDimitry Andric // deferred-actions vector: the lookup for the runtime registration
526bdd1243dSDimitry Andric // functions may return while some functions (those that are being
527bdd1243dSDimitry Andric // incidentally linked in, but aren't reachable via the runtime functions)
528bdd1243dSDimitry Andric // are still being linked, and we need to capture any allocation actions
529bdd1243dSDimitry Andric // for this incidental code before we proceed.
530bdd1243dSDimitry Andric //
531bdd1243dSDimitry Andric // 4. Once all active links are complete we transfer the deferred actions to
532bdd1243dSDimitry Andric // a newly added CompleteBootstrap graph and then request a symbol from
533bdd1243dSDimitry Andric // the CompleteBootstrap graph to trigger materialization. This will cause
534bdd1243dSDimitry Andric // all deferred actions to be run, and once this lookup returns we can
535bdd1243dSDimitry Andric // proceed.
536bdd1243dSDimitry Andric //
537bdd1243dSDimitry Andric // 5. Finally, we associate runtime support methods in MachOPlatform with
538bdd1243dSDimitry Andric // the corresponding jit-dispatch tag variables in the ORC runtime to make
539bdd1243dSDimitry Andric // the support methods callable. The bootstrap is now complete.
540bdd1243dSDimitry Andric
541bdd1243dSDimitry Andric // Step (1) Add header materialization unit and request.
5427a6dacacSDimitry Andric if ((Err = PlatformJD.define(
5437a6dacacSDimitry Andric this->BuildMachOHeaderMU(*this, std::move(PlatformJDOpts)))))
544bdd1243dSDimitry Andric return;
545bdd1243dSDimitry Andric if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))
546bdd1243dSDimitry Andric return;
547bdd1243dSDimitry Andric
548bdd1243dSDimitry Andric // Step (2) Request runtime registration functions to trigger
549bdd1243dSDimitry Andric // materialization..
550bdd1243dSDimitry Andric if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
551bdd1243dSDimitry Andric SymbolLookupSet(
552bdd1243dSDimitry Andric {PlatformBootstrap.Name, PlatformShutdown.Name,
553bdd1243dSDimitry Andric RegisterJITDylib.Name, DeregisterJITDylib.Name,
5545f757f3fSDimitry Andric RegisterObjectSymbolTable.Name,
5555f757f3fSDimitry Andric DeregisterObjectSymbolTable.Name,
556bdd1243dSDimitry Andric RegisterObjectPlatformSections.Name,
557bdd1243dSDimitry Andric DeregisterObjectPlatformSections.Name,
558bdd1243dSDimitry Andric CreatePThreadKey.Name}))
559bdd1243dSDimitry Andric .takeError()))
560bdd1243dSDimitry Andric return;
561bdd1243dSDimitry Andric
562bdd1243dSDimitry Andric // Step (3) Wait for any incidental linker work to complete.
563bdd1243dSDimitry Andric {
564bdd1243dSDimitry Andric std::unique_lock<std::mutex> Lock(BI.Mutex);
565bdd1243dSDimitry Andric BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
566bdd1243dSDimitry Andric Bootstrap = nullptr;
567bdd1243dSDimitry Andric }
568bdd1243dSDimitry Andric
569bdd1243dSDimitry Andric // Step (4) Add complete-bootstrap materialization unit and request.
570bdd1243dSDimitry Andric auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap");
571bdd1243dSDimitry Andric if ((Err = PlatformJD.define(
572bdd1243dSDimitry Andric std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>(
573bdd1243dSDimitry Andric *this, PlatformJD.getName(), BootstrapCompleteSymbol,
5745f757f3fSDimitry Andric std::move(BI.SymTab), std::move(BI.DeferredAAs),
5755f757f3fSDimitry Andric BI.MachOHeaderAddr, PlatformBootstrap.Addr,
576bdd1243dSDimitry Andric PlatformShutdown.Addr, RegisterJITDylib.Addr,
5775f757f3fSDimitry Andric DeregisterJITDylib.Addr, RegisterObjectSymbolTable.Addr,
5785f757f3fSDimitry Andric DeregisterObjectSymbolTable.Addr))))
579bdd1243dSDimitry Andric return;
580bdd1243dSDimitry Andric if ((Err = ES.lookup(makeJITDylibSearchOrder(
581bdd1243dSDimitry Andric &PlatformJD, JITDylibLookupFlags::MatchAllSymbols),
582bdd1243dSDimitry Andric std::move(BootstrapCompleteSymbol))
583bdd1243dSDimitry Andric .takeError()))
584bdd1243dSDimitry Andric return;
585bdd1243dSDimitry Andric
586bdd1243dSDimitry Andric // (5) Associate runtime support functions.
587bdd1243dSDimitry Andric if ((Err = associateRuntimeSupportFunctions()))
588349cc55cSDimitry Andric return;
589349cc55cSDimitry Andric }
590349cc55cSDimitry Andric
associateRuntimeSupportFunctions()591bdd1243dSDimitry Andric Error MachOPlatform::associateRuntimeSupportFunctions() {
592fe6060f1SDimitry Andric ExecutionSession::JITDispatchHandlerAssociationMap WFs;
593fe6060f1SDimitry Andric
59481ad6265SDimitry Andric using PushInitializersSPSSig =
59581ad6265SDimitry Andric SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr);
59681ad6265SDimitry Andric WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =
59781ad6265SDimitry Andric ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
59881ad6265SDimitry Andric this, &MachOPlatform::rt_pushInitializers);
599fe6060f1SDimitry Andric
6005f757f3fSDimitry Andric using PushSymbolsSPSSig =
6015f757f3fSDimitry Andric SPSError(SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool>>);
6025f757f3fSDimitry Andric WFs[ES.intern("___orc_rt_macho_push_symbols_tag")] =
6035f757f3fSDimitry Andric ES.wrapAsyncWithSPS<PushSymbolsSPSSig>(this,
6045f757f3fSDimitry Andric &MachOPlatform::rt_pushSymbols);
605fe6060f1SDimitry Andric
606fe6060f1SDimitry Andric return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
607fe6060f1SDimitry Andric }
608fe6060f1SDimitry Andric
pushInitializersLoop(PushInitializersSendResultFn SendResult,JITDylibSP JD)60981ad6265SDimitry Andric void MachOPlatform::pushInitializersLoop(
61081ad6265SDimitry Andric PushInitializersSendResultFn SendResult, JITDylibSP JD) {
6115ffd83dbSDimitry Andric DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
61281ad6265SDimitry Andric DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;
61381ad6265SDimitry Andric SmallVector<JITDylib *, 16> Worklist({JD.get()});
61481ad6265SDimitry Andric
6155ffd83dbSDimitry Andric ES.runSessionLocked([&]() {
61681ad6265SDimitry Andric while (!Worklist.empty()) {
61781ad6265SDimitry Andric // FIXME: Check for defunct dylibs.
61881ad6265SDimitry Andric
61981ad6265SDimitry Andric auto DepJD = Worklist.back();
62081ad6265SDimitry Andric Worklist.pop_back();
62181ad6265SDimitry Andric
62281ad6265SDimitry Andric // If we've already visited this JITDylib on this iteration then continue.
62381ad6265SDimitry Andric if (JDDepMap.count(DepJD))
62481ad6265SDimitry Andric continue;
62581ad6265SDimitry Andric
62681ad6265SDimitry Andric // Add dep info.
62781ad6265SDimitry Andric auto &DM = JDDepMap[DepJD];
62881ad6265SDimitry Andric DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
62981ad6265SDimitry Andric for (auto &KV : O) {
63081ad6265SDimitry Andric if (KV.first == DepJD)
63181ad6265SDimitry Andric continue;
63281ad6265SDimitry Andric DM.push_back(KV.first);
63381ad6265SDimitry Andric Worklist.push_back(KV.first);
63481ad6265SDimitry Andric }
63581ad6265SDimitry Andric });
63681ad6265SDimitry Andric
63781ad6265SDimitry Andric // Add any registered init symbols.
63881ad6265SDimitry Andric auto RISItr = RegisteredInitSymbols.find(DepJD);
6395ffd83dbSDimitry Andric if (RISItr != RegisteredInitSymbols.end()) {
64081ad6265SDimitry Andric NewInitSymbols[DepJD] = std::move(RISItr->second);
6415ffd83dbSDimitry Andric RegisteredInitSymbols.erase(RISItr);
6425ffd83dbSDimitry Andric }
6435ffd83dbSDimitry Andric }
6445ffd83dbSDimitry Andric });
6455ffd83dbSDimitry Andric
64681ad6265SDimitry Andric // If there are no further init symbols to look up then send the link order
64781ad6265SDimitry Andric // (as a list of header addresses) to the caller.
648fe6060f1SDimitry Andric if (NewInitSymbols.empty()) {
64981ad6265SDimitry Andric
65081ad6265SDimitry Andric // To make the list intelligible to the runtime we need to convert all
651bdd1243dSDimitry Andric // JITDylib pointers to their header addresses. Only include JITDylibs
652bdd1243dSDimitry Andric // that appear in the JITDylibToHeaderAddr map (i.e. those that have been
653bdd1243dSDimitry Andric // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.
65481ad6265SDimitry Andric DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
65581ad6265SDimitry Andric HeaderAddrs.reserve(JDDepMap.size());
65681ad6265SDimitry Andric {
65781ad6265SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex);
65881ad6265SDimitry Andric for (auto &KV : JDDepMap) {
65981ad6265SDimitry Andric auto I = JITDylibToHeaderAddr.find(KV.first);
660bdd1243dSDimitry Andric if (I != JITDylibToHeaderAddr.end())
66181ad6265SDimitry Andric HeaderAddrs[KV.first] = I->second;
66281ad6265SDimitry Andric }
66381ad6265SDimitry Andric }
66481ad6265SDimitry Andric
66581ad6265SDimitry Andric // Build the dep info map to return.
66681ad6265SDimitry Andric MachOJITDylibDepInfoMap DIM;
66781ad6265SDimitry Andric DIM.reserve(JDDepMap.size());
66881ad6265SDimitry Andric for (auto &KV : JDDepMap) {
669bdd1243dSDimitry Andric auto HI = HeaderAddrs.find(KV.first);
670bdd1243dSDimitry Andric // Skip unmanaged JITDylibs.
671bdd1243dSDimitry Andric if (HI == HeaderAddrs.end())
672bdd1243dSDimitry Andric continue;
673bdd1243dSDimitry Andric auto H = HI->second;
67481ad6265SDimitry Andric MachOJITDylibDepInfo DepInfo;
67581ad6265SDimitry Andric for (auto &Dep : KV.second) {
676bdd1243dSDimitry Andric auto HJ = HeaderAddrs.find(Dep);
677bdd1243dSDimitry Andric if (HJ != HeaderAddrs.end())
678bdd1243dSDimitry Andric DepInfo.DepHeaders.push_back(HJ->second);
67981ad6265SDimitry Andric }
68081ad6265SDimitry Andric DIM.push_back(std::make_pair(H, std::move(DepInfo)));
68181ad6265SDimitry Andric }
68281ad6265SDimitry Andric SendResult(DIM);
683e8d8bef9SDimitry Andric return;
6845ffd83dbSDimitry Andric }
6855ffd83dbSDimitry Andric
686fe6060f1SDimitry Andric // Otherwise issue a lookup and re-run this phase when it completes.
687fe6060f1SDimitry Andric lookupInitSymbolsAsync(
688bdd1243dSDimitry Andric [this, SendResult = std::move(SendResult), JD](Error Err) mutable {
689fe6060f1SDimitry Andric if (Err)
690fe6060f1SDimitry Andric SendResult(std::move(Err));
691fe6060f1SDimitry Andric else
69281ad6265SDimitry Andric pushInitializersLoop(std::move(SendResult), JD);
693fe6060f1SDimitry Andric },
694fe6060f1SDimitry Andric ES, std::move(NewInitSymbols));
695fe6060f1SDimitry Andric }
696fe6060f1SDimitry Andric
rt_pushInitializers(PushInitializersSendResultFn SendResult,ExecutorAddr JDHeaderAddr)69781ad6265SDimitry Andric void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
69881ad6265SDimitry Andric ExecutorAddr JDHeaderAddr) {
69981ad6265SDimitry Andric JITDylibSP JD;
700fe6060f1SDimitry Andric {
701fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex);
70281ad6265SDimitry Andric auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
703fe6060f1SDimitry Andric if (I != HeaderAddrToJITDylib.end())
704fe6060f1SDimitry Andric JD = I->second;
705fe6060f1SDimitry Andric }
706fe6060f1SDimitry Andric
707fe6060f1SDimitry Andric LLVM_DEBUG({
70881ad6265SDimitry Andric dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
70981ad6265SDimitry Andric if (JD)
71081ad6265SDimitry Andric dbgs() << "pushing initializers for " << JD->getName() << "\n";
71181ad6265SDimitry Andric else
71281ad6265SDimitry Andric dbgs() << "No JITDylib for header address.\n";
713fe6060f1SDimitry Andric });
71481ad6265SDimitry Andric
71581ad6265SDimitry Andric if (!JD) {
71606c3fb27SDimitry Andric SendResult(make_error<StringError>("No JITDylib with header addr " +
71706c3fb27SDimitry Andric formatv("{0:x}", JDHeaderAddr),
718fe6060f1SDimitry Andric inconvertibleErrorCode()));
719fe6060f1SDimitry Andric return;
720fe6060f1SDimitry Andric }
721fe6060f1SDimitry Andric
72281ad6265SDimitry Andric pushInitializersLoop(std::move(SendResult), JD);
723fe6060f1SDimitry Andric }
724fe6060f1SDimitry Andric
rt_pushSymbols(PushSymbolsInSendResultFn SendResult,ExecutorAddr Handle,const std::vector<std::pair<StringRef,bool>> & SymbolNames)7255f757f3fSDimitry Andric void MachOPlatform::rt_pushSymbols(
7265f757f3fSDimitry Andric PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle,
7275f757f3fSDimitry Andric const std::vector<std::pair<StringRef, bool>> &SymbolNames) {
728fe6060f1SDimitry Andric
729fe6060f1SDimitry Andric JITDylib *JD = nullptr;
730fe6060f1SDimitry Andric
731fe6060f1SDimitry Andric {
732fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PlatformMutex);
73304eeddc0SDimitry Andric auto I = HeaderAddrToJITDylib.find(Handle);
734fe6060f1SDimitry Andric if (I != HeaderAddrToJITDylib.end())
735fe6060f1SDimitry Andric JD = I->second;
736fe6060f1SDimitry Andric }
7375f757f3fSDimitry Andric LLVM_DEBUG({
7385f757f3fSDimitry Andric dbgs() << "MachOPlatform::rt_pushSymbols(";
7395f757f3fSDimitry Andric if (JD)
7405f757f3fSDimitry Andric dbgs() << "\"" << JD->getName() << "\", [ ";
7415f757f3fSDimitry Andric else
7425f757f3fSDimitry Andric dbgs() << "<invalid handle " << Handle << ">, [ ";
7435f757f3fSDimitry Andric for (auto &Name : SymbolNames)
7445f757f3fSDimitry Andric dbgs() << "\"" << Name.first << "\" ";
7455f757f3fSDimitry Andric dbgs() << "])\n";
7465f757f3fSDimitry Andric });
747fe6060f1SDimitry Andric
748fe6060f1SDimitry Andric if (!JD) {
749fe6060f1SDimitry Andric SendResult(make_error<StringError>("No JITDylib associated with handle " +
75006c3fb27SDimitry Andric formatv("{0:x}", Handle),
751fe6060f1SDimitry Andric inconvertibleErrorCode()));
752fe6060f1SDimitry Andric return;
753fe6060f1SDimitry Andric }
754fe6060f1SDimitry Andric
7555f757f3fSDimitry Andric SymbolLookupSet LS;
7565f757f3fSDimitry Andric for (auto &[Name, Required] : SymbolNames)
7575f757f3fSDimitry Andric LS.add(ES.intern(Name), Required
7585f757f3fSDimitry Andric ? SymbolLookupFlags::RequiredSymbol
7595f757f3fSDimitry Andric : SymbolLookupFlags::WeaklyReferencedSymbol);
760fe6060f1SDimitry Andric
761fe6060f1SDimitry Andric ES.lookup(
762fe6060f1SDimitry Andric LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
7635f757f3fSDimitry Andric std::move(LS), SymbolState::Ready,
7645f757f3fSDimitry Andric [SendResult = std::move(SendResult)](Expected<SymbolMap> Result) mutable {
7655f757f3fSDimitry Andric SendResult(Result.takeError());
7665f757f3fSDimitry Andric },
7675f757f3fSDimitry Andric NoDependenciesToRegister);
768fe6060f1SDimitry Andric }
769fe6060f1SDimitry Andric
createPThreadKey()770fe6060f1SDimitry Andric Expected<uint64_t> MachOPlatform::createPThreadKey() {
771bdd1243dSDimitry Andric if (!CreatePThreadKey.Addr)
772fe6060f1SDimitry Andric return make_error<StringError>(
773fe6060f1SDimitry Andric "Attempting to create pthread key in target, but runtime support has "
774fe6060f1SDimitry Andric "not been loaded yet",
775fe6060f1SDimitry Andric inconvertibleErrorCode());
776fe6060f1SDimitry Andric
777fe6060f1SDimitry Andric Expected<uint64_t> Result(0);
778fe6060f1SDimitry Andric if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
779bdd1243dSDimitry Andric CreatePThreadKey.Addr, Result))
780fe6060f1SDimitry Andric return std::move(Err);
781fe6060f1SDimitry Andric return Result;
782fe6060f1SDimitry Andric }
783fe6060f1SDimitry Andric
modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & LG,jitlink::PassConfiguration & Config)784fe6060f1SDimitry Andric void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
785fe6060f1SDimitry Andric MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
786fe6060f1SDimitry Andric jitlink::PassConfiguration &Config) {
787fe6060f1SDimitry Andric
788bdd1243dSDimitry Andric using namespace jitlink;
789bdd1243dSDimitry Andric
790bdd1243dSDimitry Andric bool InBootstrapPhase =
791bdd1243dSDimitry Andric &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap;
792bdd1243dSDimitry Andric
793bdd1243dSDimitry Andric // If we're in the bootstrap phase then increment the active graphs.
794bdd1243dSDimitry Andric if (InBootstrapPhase) {
795bdd1243dSDimitry Andric Config.PrePrunePasses.push_back(
796bdd1243dSDimitry Andric [this](LinkGraph &G) { return bootstrapPipelineStart(G); });
797bdd1243dSDimitry Andric Config.PostAllocationPasses.push_back([this](LinkGraph &G) {
798bdd1243dSDimitry Andric return bootstrapPipelineRecordRuntimeFunctions(G);
799bdd1243dSDimitry Andric });
800bdd1243dSDimitry Andric }
801349cc55cSDimitry Andric
802349cc55cSDimitry Andric // --- Handle Initializers ---
803349cc55cSDimitry Andric if (auto InitSymbol = MR.getInitializerSymbol()) {
804349cc55cSDimitry Andric
805349cc55cSDimitry Andric // If the initializer symbol is the MachOHeader start symbol then just
806349cc55cSDimitry Andric // register it and then bail out -- the header materialization unit
807349cc55cSDimitry Andric // definitely doesn't need any other passes.
808bdd1243dSDimitry Andric if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) {
809bdd1243dSDimitry Andric Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {
810349cc55cSDimitry Andric return associateJITDylibHeaderSymbol(G, MR);
811349cc55cSDimitry Andric });
812fe6060f1SDimitry Andric return;
813fe6060f1SDimitry Andric }
814fe6060f1SDimitry Andric
815349cc55cSDimitry Andric // If the object contains an init symbol other than the header start symbol
816349cc55cSDimitry Andric // then add passes to preserve, process and register the init
817349cc55cSDimitry Andric // sections/symbols.
818bdd1243dSDimitry Andric Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
81906c3fb27SDimitry Andric if (auto Err = preserveImportantSections(G, MR))
820349cc55cSDimitry Andric return Err;
821349cc55cSDimitry Andric return processObjCImageInfo(G, MR);
822349cc55cSDimitry Andric });
82306c3fb27SDimitry Andric Config.PostPrunePasses.push_back(
82406c3fb27SDimitry Andric [this](LinkGraph &G) { return createObjCRuntimeObject(G); });
82506c3fb27SDimitry Andric Config.PostAllocationPasses.push_back(
82606c3fb27SDimitry Andric [this, &MR](LinkGraph &G) { return populateObjCRuntimeObject(G, MR); });
827349cc55cSDimitry Andric }
828349cc55cSDimitry Andric
829349cc55cSDimitry Andric // Insert TLV lowering at the start of the PostPrunePasses, since we want
830349cc55cSDimitry Andric // it to run before GOT/PLT lowering.
831349cc55cSDimitry Andric Config.PostPrunePasses.insert(
832349cc55cSDimitry Andric Config.PostPrunePasses.begin(),
833bdd1243dSDimitry Andric [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) {
834349cc55cSDimitry Andric return fixTLVSectionsAndEdges(G, JD);
835349cc55cSDimitry Andric });
836349cc55cSDimitry Andric
8375f757f3fSDimitry Andric // Add symbol table prepare and register passes: These will add strings for
8385f757f3fSDimitry Andric // all symbols to the c-strings section, and build a symbol table registration
8395f757f3fSDimitry Andric // call.
8405f757f3fSDimitry Andric auto JITSymTabInfo = std::make_shared<JITSymTabVector>();
8415f757f3fSDimitry Andric Config.PostPrunePasses.push_back([this, JITSymTabInfo](LinkGraph &G) {
8425f757f3fSDimitry Andric return prepareSymbolTableRegistration(G, *JITSymTabInfo);
8435f757f3fSDimitry Andric });
8445f757f3fSDimitry Andric Config.PostFixupPasses.push_back([this, &MR, JITSymTabInfo,
8455f757f3fSDimitry Andric InBootstrapPhase](LinkGraph &G) {
8465f757f3fSDimitry Andric return addSymbolTableRegistration(G, MR, *JITSymTabInfo, InBootstrapPhase);
8475f757f3fSDimitry Andric });
8485f757f3fSDimitry Andric
84981ad6265SDimitry Andric // Add a pass to register the final addresses of any special sections in the
85081ad6265SDimitry Andric // object with the runtime.
85181ad6265SDimitry Andric Config.PostAllocationPasses.push_back(
852bdd1243dSDimitry Andric [this, &JD = MR.getTargetJITDylib(), InBootstrapPhase](LinkGraph &G) {
853bdd1243dSDimitry Andric return registerObjectPlatformSections(G, JD, InBootstrapPhase);
85481ad6265SDimitry Andric });
855bdd1243dSDimitry Andric
856bdd1243dSDimitry Andric // If we're in the bootstrap phase then steal allocation actions and then
857bdd1243dSDimitry Andric // decrement the active graphs.
858bdd1243dSDimitry Andric if (InBootstrapPhase)
859bdd1243dSDimitry Andric Config.PostFixupPasses.push_back(
860bdd1243dSDimitry Andric [this](LinkGraph &G) { return bootstrapPipelineEnd(G); });
861fe6060f1SDimitry Andric }
862fe6060f1SDimitry Andric
863fe6060f1SDimitry Andric ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
getSyntheticSymbolDependencies(MaterializationResponsibility & MR)864fe6060f1SDimitry Andric MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
8655ffd83dbSDimitry Andric MaterializationResponsibility &MR) {
866fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
8675ffd83dbSDimitry Andric auto I = InitSymbolDeps.find(&MR);
8685ffd83dbSDimitry Andric if (I != InitSymbolDeps.end()) {
869fe6060f1SDimitry Andric SyntheticSymbolDependenciesMap Result;
8705ffd83dbSDimitry Andric Result[MR.getInitializerSymbol()] = std::move(I->second);
8715ffd83dbSDimitry Andric InitSymbolDeps.erase(&MR);
8725ffd83dbSDimitry Andric return Result;
8735ffd83dbSDimitry Andric }
874fe6060f1SDimitry Andric return SyntheticSymbolDependenciesMap();
8755ffd83dbSDimitry Andric }
8765ffd83dbSDimitry Andric
bootstrapPipelineStart(jitlink::LinkGraph & G)877bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart(
878bdd1243dSDimitry Andric jitlink::LinkGraph &G) {
879bdd1243dSDimitry Andric // Increment the active graphs count in BootstrapInfo.
880bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
881bdd1243dSDimitry Andric ++MP.Bootstrap.load()->ActiveGraphs;
882bdd1243dSDimitry Andric return Error::success();
883bdd1243dSDimitry Andric }
884bdd1243dSDimitry Andric
885bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::
bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph & G)886bdd1243dSDimitry Andric bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) {
887bdd1243dSDimitry Andric // Record bootstrap function names.
888bdd1243dSDimitry Andric std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = {
889bdd1243dSDimitry Andric {*MP.MachOHeaderStartSymbol, &MP.Bootstrap.load()->MachOHeaderAddr},
890bdd1243dSDimitry Andric {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr},
891bdd1243dSDimitry Andric {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr},
892bdd1243dSDimitry Andric {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr},
893bdd1243dSDimitry Andric {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr},
8945f757f3fSDimitry Andric {*MP.RegisterObjectSymbolTable.Name, &MP.RegisterObjectSymbolTable.Addr},
8955f757f3fSDimitry Andric {*MP.DeregisterObjectSymbolTable.Name,
8965f757f3fSDimitry Andric &MP.DeregisterObjectSymbolTable.Addr},
897bdd1243dSDimitry Andric {*MP.RegisterObjectPlatformSections.Name,
898bdd1243dSDimitry Andric &MP.RegisterObjectPlatformSections.Addr},
899bdd1243dSDimitry Andric {*MP.DeregisterObjectPlatformSections.Name,
900bdd1243dSDimitry Andric &MP.DeregisterObjectPlatformSections.Addr},
90106c3fb27SDimitry Andric {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr},
90206c3fb27SDimitry Andric {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr},
90306c3fb27SDimitry Andric {*MP.DeregisterObjCRuntimeObject.Name,
90406c3fb27SDimitry Andric &MP.DeregisterObjCRuntimeObject.Addr}};
905bdd1243dSDimitry Andric
906bdd1243dSDimitry Andric bool RegisterMachOHeader = false;
907bdd1243dSDimitry Andric
908bdd1243dSDimitry Andric for (auto *Sym : G.defined_symbols()) {
909bdd1243dSDimitry Andric for (auto &RTSym : RuntimeSymbols) {
910bdd1243dSDimitry Andric if (Sym->hasName() && Sym->getName() == RTSym.first) {
911bdd1243dSDimitry Andric if (*RTSym.second)
912bdd1243dSDimitry Andric return make_error<StringError>(
913bdd1243dSDimitry Andric "Duplicate " + RTSym.first +
914bdd1243dSDimitry Andric " detected during MachOPlatform bootstrap",
915bdd1243dSDimitry Andric inconvertibleErrorCode());
916bdd1243dSDimitry Andric
917bdd1243dSDimitry Andric if (Sym->getName() == *MP.MachOHeaderStartSymbol)
918bdd1243dSDimitry Andric RegisterMachOHeader = true;
919bdd1243dSDimitry Andric
920bdd1243dSDimitry Andric *RTSym.second = Sym->getAddress();
921bdd1243dSDimitry Andric }
922bdd1243dSDimitry Andric }
923bdd1243dSDimitry Andric }
924bdd1243dSDimitry Andric
925bdd1243dSDimitry Andric if (RegisterMachOHeader) {
926bdd1243dSDimitry Andric // If this graph defines the macho header symbol then create the internal
927bdd1243dSDimitry Andric // mapping between it and PlatformJD.
928bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
929bdd1243dSDimitry Andric MP.JITDylibToHeaderAddr[&MP.PlatformJD] =
930bdd1243dSDimitry Andric MP.Bootstrap.load()->MachOHeaderAddr;
931bdd1243dSDimitry Andric MP.HeaderAddrToJITDylib[MP.Bootstrap.load()->MachOHeaderAddr] =
932bdd1243dSDimitry Andric &MP.PlatformJD;
933bdd1243dSDimitry Andric }
934bdd1243dSDimitry Andric
935bdd1243dSDimitry Andric return Error::success();
936bdd1243dSDimitry Andric }
937bdd1243dSDimitry Andric
bootstrapPipelineEnd(jitlink::LinkGraph & G)938bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(
939bdd1243dSDimitry Andric jitlink::LinkGraph &G) {
940bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
941bdd1243dSDimitry Andric assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed");
942bdd1243dSDimitry Andric --MP.Bootstrap.load()->ActiveGraphs;
943bdd1243dSDimitry Andric // Notify Bootstrap->CV while holding the mutex because the mutex is
944bdd1243dSDimitry Andric // also keeping Bootstrap->CV alive.
945bdd1243dSDimitry Andric if (MP.Bootstrap.load()->ActiveGraphs == 0)
946bdd1243dSDimitry Andric MP.Bootstrap.load()->CV.notify_all();
947bdd1243dSDimitry Andric return Error::success();
948bdd1243dSDimitry Andric }
949bdd1243dSDimitry Andric
associateJITDylibHeaderSymbol(jitlink::LinkGraph & G,MaterializationResponsibility & MR)950349cc55cSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
951349cc55cSDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
952fe6060f1SDimitry Andric auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
953fe6060f1SDimitry Andric return Sym->getName() == *MP.MachOHeaderStartSymbol;
954fe6060f1SDimitry Andric });
955349cc55cSDimitry Andric assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
956349cc55cSDimitry Andric
957349cc55cSDimitry Andric auto &JD = MR.getTargetJITDylib();
958fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
95904eeddc0SDimitry Andric auto HeaderAddr = (*I)->getAddress();
96081ad6265SDimitry Andric MP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
961fe6060f1SDimitry Andric MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
962bdd1243dSDimitry Andric // We can unconditionally add these actions to the Graph because this pass
963bdd1243dSDimitry Andric // isn't used during bootstrap.
96481ad6265SDimitry Andric G.allocActions().push_back(
96581ad6265SDimitry Andric {cantFail(
96681ad6265SDimitry Andric WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>(
967bdd1243dSDimitry Andric MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)),
96881ad6265SDimitry Andric cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
969bdd1243dSDimitry Andric MP.DeregisterJITDylib.Addr, HeaderAddr))});
970fe6060f1SDimitry Andric return Error::success();
971fe6060f1SDimitry Andric }
972fe6060f1SDimitry Andric
preserveImportantSections(jitlink::LinkGraph & G,MaterializationResponsibility & MR)97306c3fb27SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections(
974fe6060f1SDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
97506c3fb27SDimitry Andric // __objc_imageinfo is "important": we want to preserve it and record its
97606c3fb27SDimitry Andric // address in the first graph that it appears in, then verify and discard it
97706c3fb27SDimitry Andric // in all subsequent graphs. In this pass we preserve unconditionally -- we'll
97806c3fb27SDimitry Andric // manually throw it away in the processObjCImageInfo pass.
97906c3fb27SDimitry Andric if (auto *ObjCImageInfoSec =
98006c3fb27SDimitry Andric G.findSectionByName(MachOObjCImageInfoSectionName)) {
98106c3fb27SDimitry Andric if (ObjCImageInfoSec->blocks_size() != 1)
98206c3fb27SDimitry Andric return make_error<StringError>(
98306c3fb27SDimitry Andric "In " + G.getName() +
98406c3fb27SDimitry Andric "__DATA,__objc_imageinfo contains multiple blocks",
98506c3fb27SDimitry Andric inconvertibleErrorCode());
98606c3fb27SDimitry Andric G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false,
98706c3fb27SDimitry Andric true);
988fe6060f1SDimitry Andric
98906c3fb27SDimitry Andric for (auto *B : ObjCImageInfoSec->blocks())
99006c3fb27SDimitry Andric if (!B->edges_empty())
99106c3fb27SDimitry Andric return make_error<StringError>("In " + G.getName() + ", " +
99206c3fb27SDimitry Andric MachOObjCImageInfoSectionName +
99306c3fb27SDimitry Andric " contains references to symbols",
99406c3fb27SDimitry Andric inconvertibleErrorCode());
99506c3fb27SDimitry Andric }
99606c3fb27SDimitry Andric
99706c3fb27SDimitry Andric // Init sections are important: We need to preserve them and so that their
99806c3fb27SDimitry Andric // addresses can be captured and reported to the ORC runtime in
99906c3fb27SDimitry Andric // registerObjectPlatformSections.
1000fe6060f1SDimitry Andric JITLinkSymbolSet InitSectionSymbols;
100106c3fb27SDimitry Andric for (auto &InitSectionName : MachOInitSectionNames) {
100206c3fb27SDimitry Andric // Skip ObjCImageInfo -- this shouldn't have any dependencies, and we may
100306c3fb27SDimitry Andric // remove it later.
100406c3fb27SDimitry Andric if (InitSectionName == MachOObjCImageInfoSectionName)
100506c3fb27SDimitry Andric continue;
100606c3fb27SDimitry Andric
1007fe6060f1SDimitry Andric // Skip non-init sections.
1008fe6060f1SDimitry Andric auto *InitSection = G.findSectionByName(InitSectionName);
1009fe6060f1SDimitry Andric if (!InitSection)
1010fe6060f1SDimitry Andric continue;
1011fe6060f1SDimitry Andric
1012fe6060f1SDimitry Andric // Make a pass over live symbols in the section: those blocks are already
1013fe6060f1SDimitry Andric // preserved.
1014fe6060f1SDimitry Andric DenseSet<jitlink::Block *> AlreadyLiveBlocks;
1015fe6060f1SDimitry Andric for (auto &Sym : InitSection->symbols()) {
1016fe6060f1SDimitry Andric auto &B = Sym->getBlock();
1017fe6060f1SDimitry Andric if (Sym->isLive() && Sym->getOffset() == 0 &&
1018fe6060f1SDimitry Andric Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
1019fe6060f1SDimitry Andric InitSectionSymbols.insert(Sym);
1020fe6060f1SDimitry Andric AlreadyLiveBlocks.insert(&B);
10215ffd83dbSDimitry Andric }
10225ffd83dbSDimitry Andric }
10235ffd83dbSDimitry Andric
1024fe6060f1SDimitry Andric // Add anonymous symbols to preserve any not-already-preserved blocks.
1025fe6060f1SDimitry Andric for (auto *B : InitSection->blocks())
1026fe6060f1SDimitry Andric if (!AlreadyLiveBlocks.count(B))
1027fe6060f1SDimitry Andric InitSectionSymbols.insert(
1028fe6060f1SDimitry Andric &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
1029fe6060f1SDimitry Andric }
1030fe6060f1SDimitry Andric
1031fe6060f1SDimitry Andric if (!InitSectionSymbols.empty()) {
1032fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
1033fe6060f1SDimitry Andric InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
1034fe6060f1SDimitry Andric }
1035fe6060f1SDimitry Andric
1036fe6060f1SDimitry Andric return Error::success();
1037fe6060f1SDimitry Andric }
1038fe6060f1SDimitry Andric
processObjCImageInfo(jitlink::LinkGraph & G,MaterializationResponsibility & MR)1039fe6060f1SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
10405ffd83dbSDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
10415ffd83dbSDimitry Andric
10425ffd83dbSDimitry Andric // If there's an ObjC imagine info then either
10435ffd83dbSDimitry Andric // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
10445ffd83dbSDimitry Andric // this case we name and record it.
10455ffd83dbSDimitry Andric // OR
10465ffd83dbSDimitry Andric // (2) We already have a recorded __objc_imageinfo for this JITDylib,
10475ffd83dbSDimitry Andric // in which case we just verify it.
104806c3fb27SDimitry Andric auto *ObjCImageInfo = G.findSectionByName(MachOObjCImageInfoSectionName);
10495ffd83dbSDimitry Andric if (!ObjCImageInfo)
10505ffd83dbSDimitry Andric return Error::success();
10515ffd83dbSDimitry Andric
10525ffd83dbSDimitry Andric auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
10535ffd83dbSDimitry Andric
10545ffd83dbSDimitry Andric // Check that the section is not empty if present.
1055bdd1243dSDimitry Andric if (ObjCImageInfoBlocks.empty())
105606c3fb27SDimitry Andric return make_error<StringError>("Empty " + MachOObjCImageInfoSectionName +
1057fe6060f1SDimitry Andric " section in " + G.getName(),
10585ffd83dbSDimitry Andric inconvertibleErrorCode());
10595ffd83dbSDimitry Andric
10605ffd83dbSDimitry Andric // Check that there's only one block in the section.
10615ffd83dbSDimitry Andric if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
1062fe6060f1SDimitry Andric return make_error<StringError>("Multiple blocks in " +
106306c3fb27SDimitry Andric MachOObjCImageInfoSectionName +
1064fe6060f1SDimitry Andric " section in " + G.getName(),
10655ffd83dbSDimitry Andric inconvertibleErrorCode());
10665ffd83dbSDimitry Andric
10675ffd83dbSDimitry Andric // Check that the __objc_imageinfo section is unreferenced.
10685ffd83dbSDimitry Andric // FIXME: We could optimize this check if Symbols had a ref-count.
10695ffd83dbSDimitry Andric for (auto &Sec : G.sections()) {
10705ffd83dbSDimitry Andric if (&Sec != ObjCImageInfo)
10715ffd83dbSDimitry Andric for (auto *B : Sec.blocks())
10725ffd83dbSDimitry Andric for (auto &E : B->edges())
10735ffd83dbSDimitry Andric if (E.getTarget().isDefined() &&
10745ffd83dbSDimitry Andric &E.getTarget().getBlock().getSection() == ObjCImageInfo)
107506c3fb27SDimitry Andric return make_error<StringError>(MachOObjCImageInfoSectionName +
1076fe6060f1SDimitry Andric " is referenced within file " +
10775ffd83dbSDimitry Andric G.getName(),
10785ffd83dbSDimitry Andric inconvertibleErrorCode());
10795ffd83dbSDimitry Andric }
10805ffd83dbSDimitry Andric
10815ffd83dbSDimitry Andric auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
10825ffd83dbSDimitry Andric auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
10835ffd83dbSDimitry Andric auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
10845ffd83dbSDimitry Andric auto Flags =
10855ffd83dbSDimitry Andric support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
10865ffd83dbSDimitry Andric
10875ffd83dbSDimitry Andric // Lock the mutex while we verify / update the ObjCImageInfos map.
1088fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
10895ffd83dbSDimitry Andric
10905ffd83dbSDimitry Andric auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
10915ffd83dbSDimitry Andric if (ObjCImageInfoItr != ObjCImageInfos.end()) {
10925ffd83dbSDimitry Andric // We've already registered an __objc_imageinfo section. Verify the
10935ffd83dbSDimitry Andric // content of this new section matches, then delete it.
109406c3fb27SDimitry Andric if (ObjCImageInfoItr->second.Version != Version)
10955ffd83dbSDimitry Andric return make_error<StringError>(
10965ffd83dbSDimitry Andric "ObjC version in " + G.getName() +
10975ffd83dbSDimitry Andric " does not match first registered version",
10985ffd83dbSDimitry Andric inconvertibleErrorCode());
109906c3fb27SDimitry Andric if (ObjCImageInfoItr->second.Flags != Flags)
11005f757f3fSDimitry Andric if (Error E = mergeImageInfoFlags(G, MR, ObjCImageInfoItr->second, Flags))
11015f757f3fSDimitry Andric return E;
11025ffd83dbSDimitry Andric
11035ffd83dbSDimitry Andric // __objc_imageinfo is valid. Delete the block.
11045ffd83dbSDimitry Andric for (auto *S : ObjCImageInfo->symbols())
11055ffd83dbSDimitry Andric G.removeDefinedSymbol(*S);
11065ffd83dbSDimitry Andric G.removeBlock(ObjCImageInfoBlock);
11075ffd83dbSDimitry Andric } else {
11085f757f3fSDimitry Andric LLVM_DEBUG({
11095f757f3fSDimitry Andric dbgs() << "MachOPlatform: Registered __objc_imageinfo for "
11105f757f3fSDimitry Andric << MR.getTargetJITDylib().getName() << " in " << G.getName()
11115f757f3fSDimitry Andric << "; flags = " << formatv("{0:x4}", Flags) << "\n";
11125f757f3fSDimitry Andric });
11135ffd83dbSDimitry Andric // We haven't registered an __objc_imageinfo section yet. Register and
11145ffd83dbSDimitry Andric // move on. The section should already be marked no-dead-strip.
111506c3fb27SDimitry Andric G.addDefinedSymbol(ObjCImageInfoBlock, 0, ObjCImageInfoSymbolName,
111606c3fb27SDimitry Andric ObjCImageInfoBlock.getSize(), jitlink::Linkage::Strong,
111706c3fb27SDimitry Andric jitlink::Scope::Hidden, false, true);
111806c3fb27SDimitry Andric if (auto Err = MR.defineMaterializing(
111906c3fb27SDimitry Andric {{MR.getExecutionSession().intern(ObjCImageInfoSymbolName),
112006c3fb27SDimitry Andric JITSymbolFlags()}}))
112106c3fb27SDimitry Andric return Err;
11225f757f3fSDimitry Andric ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags, false};
11235ffd83dbSDimitry Andric }
11245ffd83dbSDimitry Andric
11255ffd83dbSDimitry Andric return Error::success();
11265ffd83dbSDimitry Andric }
11275ffd83dbSDimitry Andric
mergeImageInfoFlags(jitlink::LinkGraph & G,MaterializationResponsibility & MR,ObjCImageInfo & Info,uint32_t NewFlags)11285f757f3fSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::mergeImageInfoFlags(
11295f757f3fSDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR,
11305f757f3fSDimitry Andric ObjCImageInfo &Info, uint32_t NewFlags) {
11315f757f3fSDimitry Andric if (Info.Flags == NewFlags)
11325f757f3fSDimitry Andric return Error::success();
11335f757f3fSDimitry Andric
11345f757f3fSDimitry Andric ObjCImageInfoFlags Old(Info.Flags);
11355f757f3fSDimitry Andric ObjCImageInfoFlags New(NewFlags);
11365f757f3fSDimitry Andric
11375f757f3fSDimitry Andric // Check for incompatible flags.
11385f757f3fSDimitry Andric if (Old.SwiftABIVersion && New.SwiftABIVersion &&
11395f757f3fSDimitry Andric Old.SwiftABIVersion != New.SwiftABIVersion)
11405f757f3fSDimitry Andric return make_error<StringError>("Swift ABI version in " + G.getName() +
11415f757f3fSDimitry Andric " does not match first registered flags",
11425f757f3fSDimitry Andric inconvertibleErrorCode());
11435f757f3fSDimitry Andric
1144*0fca6ea1SDimitry Andric // HasCategoryClassProperties and HasSignedObjCClassROs can be disabled before
1145*0fca6ea1SDimitry Andric // they are registered, if necessary, but once they are in use must be
1146*0fca6ea1SDimitry Andric // supported by subsequent objects.
1147*0fca6ea1SDimitry Andric if (Info.Finalized && Old.HasCategoryClassProperties &&
1148*0fca6ea1SDimitry Andric !New.HasCategoryClassProperties)
11495f757f3fSDimitry Andric return make_error<StringError>("ObjC category class property support in " +
11505f757f3fSDimitry Andric G.getName() +
11515f757f3fSDimitry Andric " does not match first registered flags",
11525f757f3fSDimitry Andric inconvertibleErrorCode());
1153*0fca6ea1SDimitry Andric if (Info.Finalized && Old.HasSignedObjCClassROs && !New.HasSignedObjCClassROs)
11545f757f3fSDimitry Andric return make_error<StringError>("ObjC class_ro_t pointer signing in " +
11555f757f3fSDimitry Andric G.getName() +
11565f757f3fSDimitry Andric " does not match first registered flags",
11575f757f3fSDimitry Andric inconvertibleErrorCode());
11585f757f3fSDimitry Andric
11595f757f3fSDimitry Andric // If we cannot change the flags, ignore any remaining differences. Adding
11605f757f3fSDimitry Andric // Swift or changing its version are unlikely to cause problems in practice.
11615f757f3fSDimitry Andric if (Info.Finalized)
11625f757f3fSDimitry Andric return Error::success();
11635f757f3fSDimitry Andric
11645f757f3fSDimitry Andric // Use the minimum Swift version.
11655f757f3fSDimitry Andric if (Old.SwiftVersion && New.SwiftVersion)
11665f757f3fSDimitry Andric New.SwiftVersion = std::min(Old.SwiftVersion, New.SwiftVersion);
11675f757f3fSDimitry Andric else if (Old.SwiftVersion)
11685f757f3fSDimitry Andric New.SwiftVersion = Old.SwiftVersion;
11695f757f3fSDimitry Andric // Add a Swift ABI version if it was pure objc before.
11705f757f3fSDimitry Andric if (!New.SwiftABIVersion)
11715f757f3fSDimitry Andric New.SwiftABIVersion = Old.SwiftABIVersion;
1172*0fca6ea1SDimitry Andric // Disable class properties if any object does not support it.
1173*0fca6ea1SDimitry Andric if (Old.HasCategoryClassProperties != New.HasCategoryClassProperties)
1174*0fca6ea1SDimitry Andric New.HasCategoryClassProperties = false;
1175*0fca6ea1SDimitry Andric // Disable signed class ro data if any object does not support it.
1176*0fca6ea1SDimitry Andric if (Old.HasSignedObjCClassROs != New.HasSignedObjCClassROs)
1177*0fca6ea1SDimitry Andric New.HasSignedObjCClassROs = false;
11785f757f3fSDimitry Andric
11795f757f3fSDimitry Andric LLVM_DEBUG({
11805f757f3fSDimitry Andric dbgs() << "MachOPlatform: Merging __objc_imageinfo flags for "
11815f757f3fSDimitry Andric << MR.getTargetJITDylib().getName() << " (was "
11825f757f3fSDimitry Andric << formatv("{0:x4}", Old.rawFlags()) << ")"
11835f757f3fSDimitry Andric << " with " << G.getName() << " (" << formatv("{0:x4}", NewFlags)
11845f757f3fSDimitry Andric << ")"
11855f757f3fSDimitry Andric << " -> " << formatv("{0:x4}", New.rawFlags()) << "\n";
11865f757f3fSDimitry Andric });
11875f757f3fSDimitry Andric
11885f757f3fSDimitry Andric Info.Flags = New.rawFlags();
11895f757f3fSDimitry Andric return Error::success();
11905f757f3fSDimitry Andric }
11915f757f3fSDimitry Andric
fixTLVSectionsAndEdges(jitlink::LinkGraph & G,JITDylib & JD)1192fe6060f1SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1193fe6060f1SDimitry Andric jitlink::LinkGraph &G, JITDylib &JD) {
1194fe6060f1SDimitry Andric
1195fe6060f1SDimitry Andric // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
1196fe6060f1SDimitry Andric for (auto *Sym : G.external_symbols())
1197fe6060f1SDimitry Andric if (Sym->getName() == "__tlv_bootstrap") {
1198fe6060f1SDimitry Andric Sym->setName("___orc_rt_macho_tlv_get_addr");
1199fe6060f1SDimitry Andric break;
1200fe6060f1SDimitry Andric }
1201fe6060f1SDimitry Andric
1202fe6060f1SDimitry Andric // Store key in __thread_vars struct fields.
120306c3fb27SDimitry Andric if (auto *ThreadDataSec = G.findSectionByName(MachOThreadVarsSectionName)) {
1204bdd1243dSDimitry Andric std::optional<uint64_t> Key;
1205fe6060f1SDimitry Andric {
1206fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1207fe6060f1SDimitry Andric auto I = MP.JITDylibToPThreadKey.find(&JD);
1208fe6060f1SDimitry Andric if (I != MP.JITDylibToPThreadKey.end())
1209fe6060f1SDimitry Andric Key = I->second;
1210fe6060f1SDimitry Andric }
1211fe6060f1SDimitry Andric
1212fe6060f1SDimitry Andric if (!Key) {
1213fe6060f1SDimitry Andric if (auto KeyOrErr = MP.createPThreadKey())
1214fe6060f1SDimitry Andric Key = *KeyOrErr;
1215fe6060f1SDimitry Andric else
1216fe6060f1SDimitry Andric return KeyOrErr.takeError();
1217fe6060f1SDimitry Andric }
1218fe6060f1SDimitry Andric
1219fe6060f1SDimitry Andric uint64_t PlatformKeyBits =
1220fe6060f1SDimitry Andric support::endian::byte_swap(*Key, G.getEndianness());
1221fe6060f1SDimitry Andric
1222fe6060f1SDimitry Andric for (auto *B : ThreadDataSec->blocks()) {
1223fe6060f1SDimitry Andric if (B->getSize() != 3 * G.getPointerSize())
1224fe6060f1SDimitry Andric return make_error<StringError>("__thread_vars block at " +
1225fe6060f1SDimitry Andric formatv("{0:x}", B->getAddress()) +
1226fe6060f1SDimitry Andric " has unexpected size",
1227fe6060f1SDimitry Andric inconvertibleErrorCode());
1228fe6060f1SDimitry Andric
1229fe6060f1SDimitry Andric auto NewBlockContent = G.allocateBuffer(B->getSize());
1230fe6060f1SDimitry Andric llvm::copy(B->getContent(), NewBlockContent.data());
1231fe6060f1SDimitry Andric memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
1232fe6060f1SDimitry Andric G.getPointerSize());
1233fe6060f1SDimitry Andric B->setContent(NewBlockContent);
1234fe6060f1SDimitry Andric }
1235fe6060f1SDimitry Andric }
1236fe6060f1SDimitry Andric
1237fe6060f1SDimitry Andric // Transform any TLV edges into GOT edges.
1238fe6060f1SDimitry Andric for (auto *B : G.blocks())
1239fe6060f1SDimitry Andric for (auto &E : B->edges())
1240fe6060f1SDimitry Andric if (E.getKind() ==
1241349cc55cSDimitry Andric jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
1242349cc55cSDimitry Andric E.setKind(jitlink::x86_64::
1243349cc55cSDimitry Andric RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
1244349cc55cSDimitry Andric
1245349cc55cSDimitry Andric return Error::success();
1246349cc55cSDimitry Andric }
1247349cc55cSDimitry Andric
1248bdd1243dSDimitry Andric std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>
findUnwindSectionInfo(jitlink::LinkGraph & G)1249bdd1243dSDimitry Andric MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1250bdd1243dSDimitry Andric jitlink::LinkGraph &G) {
1251bdd1243dSDimitry Andric using namespace jitlink;
1252349cc55cSDimitry Andric
1253bdd1243dSDimitry Andric UnwindSections US;
1254bdd1243dSDimitry Andric
1255bdd1243dSDimitry Andric // ScanSection records a section range and adds any executable blocks that
1256bdd1243dSDimitry Andric // that section points to to the CodeBlocks vector.
1257bdd1243dSDimitry Andric SmallVector<Block *> CodeBlocks;
1258bdd1243dSDimitry Andric auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) {
1259bdd1243dSDimitry Andric if (Sec.blocks().empty())
1260bdd1243dSDimitry Andric return;
1261bdd1243dSDimitry Andric SecRange = (*Sec.blocks().begin())->getRange();
1262bdd1243dSDimitry Andric for (auto *B : Sec.blocks()) {
1263bdd1243dSDimitry Andric auto R = B->getRange();
1264bdd1243dSDimitry Andric SecRange.Start = std::min(SecRange.Start, R.Start);
1265bdd1243dSDimitry Andric SecRange.End = std::max(SecRange.End, R.End);
1266bdd1243dSDimitry Andric for (auto &E : B->edges()) {
1267bdd1243dSDimitry Andric if (!E.getTarget().isDefined())
1268bdd1243dSDimitry Andric continue;
1269bdd1243dSDimitry Andric auto &TargetBlock = E.getTarget().getBlock();
1270bdd1243dSDimitry Andric auto &TargetSection = TargetBlock.getSection();
1271bdd1243dSDimitry Andric if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec)
1272bdd1243dSDimitry Andric CodeBlocks.push_back(&TargetBlock);
1273349cc55cSDimitry Andric }
1274bdd1243dSDimitry Andric }
1275bdd1243dSDimitry Andric };
1276bdd1243dSDimitry Andric
127706c3fb27SDimitry Andric if (Section *EHFrameSec = G.findSectionByName(MachOEHFrameSectionName))
1278bdd1243dSDimitry Andric ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection);
1279bdd1243dSDimitry Andric
128006c3fb27SDimitry Andric if (Section *CUInfoSec =
128106c3fb27SDimitry Andric G.findSectionByName(MachOCompactUnwindInfoSectionName))
1282bdd1243dSDimitry Andric ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection);
1283bdd1243dSDimitry Andric
1284bdd1243dSDimitry Andric // If we didn't find any pointed-to code-blocks then there's no need to
1285bdd1243dSDimitry Andric // register any info.
1286bdd1243dSDimitry Andric if (CodeBlocks.empty())
1287bdd1243dSDimitry Andric return std::nullopt;
1288bdd1243dSDimitry Andric
1289bdd1243dSDimitry Andric // We have info to register. Sort the code blocks into address order and
1290bdd1243dSDimitry Andric // build a list of contiguous address ranges covering them all.
1291bdd1243dSDimitry Andric llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) {
1292bdd1243dSDimitry Andric return LHS->getAddress() < RHS->getAddress();
1293bdd1243dSDimitry Andric });
1294bdd1243dSDimitry Andric for (auto *B : CodeBlocks) {
1295bdd1243dSDimitry Andric if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress())
1296bdd1243dSDimitry Andric US.CodeRanges.push_back(B->getRange());
1297bdd1243dSDimitry Andric else
1298bdd1243dSDimitry Andric US.CodeRanges.back().End = B->getRange().End;
1299bdd1243dSDimitry Andric }
1300bdd1243dSDimitry Andric
1301bdd1243dSDimitry Andric LLVM_DEBUG({
1302bdd1243dSDimitry Andric dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n"
1303bdd1243dSDimitry Andric << " DWARF: ";
1304bdd1243dSDimitry Andric if (US.DwarfSection.Start)
1305bdd1243dSDimitry Andric dbgs() << US.DwarfSection << "\n";
1306bdd1243dSDimitry Andric else
1307bdd1243dSDimitry Andric dbgs() << "none\n";
1308bdd1243dSDimitry Andric dbgs() << " Compact-unwind: ";
1309bdd1243dSDimitry Andric if (US.CompactUnwindSection.Start)
1310bdd1243dSDimitry Andric dbgs() << US.CompactUnwindSection << "\n";
1311bdd1243dSDimitry Andric else
1312bdd1243dSDimitry Andric dbgs() << "none\n"
1313bdd1243dSDimitry Andric << "for code ranges:\n";
1314bdd1243dSDimitry Andric for (auto &CR : US.CodeRanges)
1315bdd1243dSDimitry Andric dbgs() << " " << CR << "\n";
1316bdd1243dSDimitry Andric if (US.CodeRanges.size() >= G.sections_size())
1317bdd1243dSDimitry Andric dbgs() << "WARNING: High number of discontiguous code ranges! "
1318bdd1243dSDimitry Andric "Padding may be interfering with coalescing.\n";
1319bdd1243dSDimitry Andric });
1320bdd1243dSDimitry Andric
1321bdd1243dSDimitry Andric return US;
1322bdd1243dSDimitry Andric }
1323bdd1243dSDimitry Andric
registerObjectPlatformSections(jitlink::LinkGraph & G,JITDylib & JD,bool InBootstrapPhase)1324bdd1243dSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1325bdd1243dSDimitry Andric jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) {
1326349cc55cSDimitry Andric
1327349cc55cSDimitry Andric // Get a pointer to the thread data section if there is one. It will be used
1328349cc55cSDimitry Andric // below.
1329349cc55cSDimitry Andric jitlink::Section *ThreadDataSection =
133006c3fb27SDimitry Andric G.findSectionByName(MachOThreadDataSectionName);
1331349cc55cSDimitry Andric
1332349cc55cSDimitry Andric // Handle thread BSS section if there is one.
133306c3fb27SDimitry Andric if (auto *ThreadBSSSection = G.findSectionByName(MachOThreadBSSSectionName)) {
1334349cc55cSDimitry Andric // If there's already a thread data section in this graph then merge the
1335349cc55cSDimitry Andric // thread BSS section content into it, otherwise just treat the thread
1336349cc55cSDimitry Andric // BSS section as the thread data section.
1337349cc55cSDimitry Andric if (ThreadDataSection)
1338349cc55cSDimitry Andric G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
1339349cc55cSDimitry Andric else
1340349cc55cSDimitry Andric ThreadDataSection = ThreadBSSSection;
1341349cc55cSDimitry Andric }
1342349cc55cSDimitry Andric
134381ad6265SDimitry Andric SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;
134481ad6265SDimitry Andric
1345bdd1243dSDimitry Andric // Collect data sections to register.
134606c3fb27SDimitry Andric StringRef DataSections[] = {MachODataDataSectionName,
134706c3fb27SDimitry Andric MachODataCommonSectionName,
134806c3fb27SDimitry Andric MachOEHFrameSectionName};
1349bdd1243dSDimitry Andric for (auto &SecName : DataSections) {
1350bdd1243dSDimitry Andric if (auto *Sec = G.findSectionByName(SecName)) {
1351bdd1243dSDimitry Andric jitlink::SectionRange R(*Sec);
1352bdd1243dSDimitry Andric if (!R.empty())
1353bdd1243dSDimitry Andric MachOPlatformSecs.push_back({SecName, R.getRange()});
1354bdd1243dSDimitry Andric }
1355bdd1243dSDimitry Andric }
1356bdd1243dSDimitry Andric
1357349cc55cSDimitry Andric // Having merged thread BSS (if present) and thread data (if present),
1358349cc55cSDimitry Andric // record the resulting section range.
1359349cc55cSDimitry Andric if (ThreadDataSection) {
1360349cc55cSDimitry Andric jitlink::SectionRange R(*ThreadDataSection);
1361bdd1243dSDimitry Andric if (!R.empty())
136206c3fb27SDimitry Andric MachOPlatformSecs.push_back({MachOThreadDataSectionName, R.getRange()});
136381ad6265SDimitry Andric }
136481ad6265SDimitry Andric
136581ad6265SDimitry Andric // If any platform sections were found then add an allocation action to call
136681ad6265SDimitry Andric // the registration function.
136706c3fb27SDimitry Andric StringRef PlatformSections[] = {MachOModInitFuncSectionName,
136806c3fb27SDimitry Andric ObjCRuntimeObjectSectionName};
136981ad6265SDimitry Andric
137081ad6265SDimitry Andric for (auto &SecName : PlatformSections) {
137181ad6265SDimitry Andric auto *Sec = G.findSectionByName(SecName);
137281ad6265SDimitry Andric if (!Sec)
137381ad6265SDimitry Andric continue;
137481ad6265SDimitry Andric jitlink::SectionRange R(*Sec);
137581ad6265SDimitry Andric if (R.empty())
137681ad6265SDimitry Andric continue;
137781ad6265SDimitry Andric
137881ad6265SDimitry Andric MachOPlatformSecs.push_back({SecName, R.getRange()});
137981ad6265SDimitry Andric }
138081ad6265SDimitry Andric
1381bdd1243dSDimitry Andric std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,
1382bdd1243dSDimitry Andric ExecutorAddrRange>>
1383bdd1243dSDimitry Andric UnwindInfo;
1384bdd1243dSDimitry Andric if (auto UI = findUnwindSectionInfo(G))
1385bdd1243dSDimitry Andric UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,
1386bdd1243dSDimitry Andric UI->CompactUnwindSection);
1387bdd1243dSDimitry Andric
1388bdd1243dSDimitry Andric if (!MachOPlatformSecs.empty() || UnwindInfo) {
138981ad6265SDimitry Andric // Dump the scraped inits.
139081ad6265SDimitry Andric LLVM_DEBUG({
139181ad6265SDimitry Andric dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
139281ad6265SDimitry Andric for (auto &KV : MachOPlatformSecs)
139381ad6265SDimitry Andric dbgs() << " " << KV.first << ": " << KV.second << "\n";
139481ad6265SDimitry Andric });
139581ad6265SDimitry Andric
1396bdd1243dSDimitry Andric using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<
1397bdd1243dSDimitry Andric SPSExecutorAddr,
1398bdd1243dSDimitry Andric SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>,
1399bdd1243dSDimitry Andric SPSExecutorAddrRange, SPSExecutorAddrRange>>,
140081ad6265SDimitry Andric SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;
1401bdd1243dSDimitry Andric
1402bdd1243dSDimitry Andric shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
1403bdd1243dSDimitry Andric ? G.allocActions()
1404bdd1243dSDimitry Andric : MP.Bootstrap.load()->DeferredAAs;
1405bdd1243dSDimitry Andric
14065f757f3fSDimitry Andric ExecutorAddr HeaderAddr;
14075f757f3fSDimitry Andric {
14085f757f3fSDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
14095f757f3fSDimitry Andric auto I = MP.JITDylibToHeaderAddr.find(&JD);
14105f757f3fSDimitry Andric assert(I != MP.JITDylibToHeaderAddr.end() &&
14115f757f3fSDimitry Andric "No header registered for JD");
14125f757f3fSDimitry Andric assert(I->second && "Null header registered for JD");
14135f757f3fSDimitry Andric HeaderAddr = I->second;
14145f757f3fSDimitry Andric }
1415bdd1243dSDimitry Andric allocActions.push_back(
141604eeddc0SDimitry Andric {cantFail(
141781ad6265SDimitry Andric WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1418bdd1243dSDimitry Andric MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo,
141981ad6265SDimitry Andric MachOPlatformSecs)),
142004eeddc0SDimitry Andric cantFail(
142181ad6265SDimitry Andric WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1422bdd1243dSDimitry Andric MP.DeregisterObjectPlatformSections.Addr, HeaderAddr,
1423bdd1243dSDimitry Andric UnwindInfo, MachOPlatformSecs))});
1424349cc55cSDimitry Andric }
142581ad6265SDimitry Andric
1426349cc55cSDimitry Andric return Error::success();
1427349cc55cSDimitry Andric }
1428349cc55cSDimitry Andric
createObjCRuntimeObject(jitlink::LinkGraph & G)142906c3fb27SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
143006c3fb27SDimitry Andric jitlink::LinkGraph &G) {
143106c3fb27SDimitry Andric
143206c3fb27SDimitry Andric bool NeedTextSegment = false;
143306c3fb27SDimitry Andric size_t NumRuntimeSections = 0;
143406c3fb27SDimitry Andric
143506c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)
143606c3fb27SDimitry Andric if (G.findSectionByName(ObjCRuntimeSectionName))
143706c3fb27SDimitry Andric ++NumRuntimeSections;
143806c3fb27SDimitry Andric
143906c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
144006c3fb27SDimitry Andric if (G.findSectionByName(ObjCRuntimeSectionName)) {
144106c3fb27SDimitry Andric ++NumRuntimeSections;
144206c3fb27SDimitry Andric NeedTextSegment = true;
144306c3fb27SDimitry Andric }
144406c3fb27SDimitry Andric }
144506c3fb27SDimitry Andric
144606c3fb27SDimitry Andric // Early out for no runtime sections.
144706c3fb27SDimitry Andric if (NumRuntimeSections == 0)
144806c3fb27SDimitry Andric return Error::success();
144906c3fb27SDimitry Andric
145006c3fb27SDimitry Andric // If there were any runtime sections then we need to add an __objc_imageinfo
145106c3fb27SDimitry Andric // section.
145206c3fb27SDimitry Andric ++NumRuntimeSections;
145306c3fb27SDimitry Andric
145406c3fb27SDimitry Andric size_t MachOSize = sizeof(MachO::mach_header_64) +
145506c3fb27SDimitry Andric (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +
145606c3fb27SDimitry Andric NumRuntimeSections * sizeof(MachO::section_64);
145706c3fb27SDimitry Andric
145806c3fb27SDimitry Andric auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,
145906c3fb27SDimitry Andric MemProt::Read | MemProt::Write);
146006c3fb27SDimitry Andric G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);
146106c3fb27SDimitry Andric
146206c3fb27SDimitry Andric return Error::success();
146306c3fb27SDimitry Andric }
146406c3fb27SDimitry Andric
populateObjCRuntimeObject(jitlink::LinkGraph & G,MaterializationResponsibility & MR)146506c3fb27SDimitry Andric Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
146606c3fb27SDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
146706c3fb27SDimitry Andric
146806c3fb27SDimitry Andric auto *ObjCRuntimeObjectSec =
146906c3fb27SDimitry Andric G.findSectionByName(ObjCRuntimeObjectSectionName);
147006c3fb27SDimitry Andric
147106c3fb27SDimitry Andric if (!ObjCRuntimeObjectSec)
147206c3fb27SDimitry Andric return Error::success();
147306c3fb27SDimitry Andric
147406c3fb27SDimitry Andric switch (G.getTargetTriple().getArch()) {
147506c3fb27SDimitry Andric case Triple::aarch64:
147606c3fb27SDimitry Andric case Triple::x86_64:
147706c3fb27SDimitry Andric // Supported.
147806c3fb27SDimitry Andric break;
147906c3fb27SDimitry Andric default:
148006c3fb27SDimitry Andric return make_error<StringError>("Unrecognized MachO arch in triple " +
148106c3fb27SDimitry Andric G.getTargetTriple().str(),
148206c3fb27SDimitry Andric inconvertibleErrorCode());
148306c3fb27SDimitry Andric }
148406c3fb27SDimitry Andric
148506c3fb27SDimitry Andric auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();
148606c3fb27SDimitry Andric
148706c3fb27SDimitry Andric struct SecDesc {
148806c3fb27SDimitry Andric MachO::section_64 Sec;
148906c3fb27SDimitry Andric unique_function<void(size_t RecordOffset)> AddFixups;
149006c3fb27SDimitry Andric };
149106c3fb27SDimitry Andric
149206c3fb27SDimitry Andric std::vector<SecDesc> TextSections, DataSections;
149306c3fb27SDimitry Andric auto AddSection = [&](SecDesc &SD, jitlink::Section &GraphSec) {
149406c3fb27SDimitry Andric jitlink::SectionRange SR(GraphSec);
149506c3fb27SDimitry Andric StringRef FQName = GraphSec.getName();
149606c3fb27SDimitry Andric memset(&SD.Sec, 0, sizeof(MachO::section_64));
149706c3fb27SDimitry Andric memcpy(SD.Sec.sectname, FQName.drop_front(7).data(), FQName.size() - 7);
149806c3fb27SDimitry Andric memcpy(SD.Sec.segname, FQName.data(), 6);
149906c3fb27SDimitry Andric SD.Sec.addr = SR.getStart() - SecBlock.getAddress();
150006c3fb27SDimitry Andric SD.Sec.size = SR.getSize();
150106c3fb27SDimitry Andric SD.Sec.flags = MachO::S_REGULAR;
150206c3fb27SDimitry Andric };
150306c3fb27SDimitry Andric
150406c3fb27SDimitry Andric // Add the __objc_imageinfo section.
150506c3fb27SDimitry Andric {
150606c3fb27SDimitry Andric DataSections.push_back({});
150706c3fb27SDimitry Andric auto &SD = DataSections.back();
150806c3fb27SDimitry Andric memset(&SD.Sec, 0, sizeof(SD.Sec));
150906c3fb27SDimitry Andric memcpy(SD.Sec.sectname, "__objc_imageinfo", 16);
151006c3fb27SDimitry Andric strcpy(SD.Sec.segname, "__DATA");
151106c3fb27SDimitry Andric SD.Sec.size = 8;
151206c3fb27SDimitry Andric SD.AddFixups = [&](size_t RecordOffset) {
15135f757f3fSDimitry Andric auto PointerEdge = getPointerEdgeKind(G);
151406c3fb27SDimitry Andric
151506c3fb27SDimitry Andric // Look for an existing __objc_imageinfo symbol.
151606c3fb27SDimitry Andric jitlink::Symbol *ObjCImageInfoSym = nullptr;
151706c3fb27SDimitry Andric for (auto *Sym : G.external_symbols())
151806c3fb27SDimitry Andric if (Sym->getName() == ObjCImageInfoSymbolName) {
151906c3fb27SDimitry Andric ObjCImageInfoSym = Sym;
152006c3fb27SDimitry Andric break;
152106c3fb27SDimitry Andric }
152206c3fb27SDimitry Andric if (!ObjCImageInfoSym)
152306c3fb27SDimitry Andric for (auto *Sym : G.absolute_symbols())
152406c3fb27SDimitry Andric if (Sym->getName() == ObjCImageInfoSymbolName) {
152506c3fb27SDimitry Andric ObjCImageInfoSym = Sym;
152606c3fb27SDimitry Andric break;
152706c3fb27SDimitry Andric }
152806c3fb27SDimitry Andric if (!ObjCImageInfoSym)
152906c3fb27SDimitry Andric for (auto *Sym : G.defined_symbols())
153006c3fb27SDimitry Andric if (Sym->hasName() && Sym->getName() == ObjCImageInfoSymbolName) {
153106c3fb27SDimitry Andric ObjCImageInfoSym = Sym;
15325f757f3fSDimitry Andric std::optional<uint32_t> Flags;
15335f757f3fSDimitry Andric {
15345f757f3fSDimitry Andric std::lock_guard<std::mutex> Lock(PluginMutex);
15355f757f3fSDimitry Andric auto It = ObjCImageInfos.find(&MR.getTargetJITDylib());
15365f757f3fSDimitry Andric if (It != ObjCImageInfos.end()) {
15375f757f3fSDimitry Andric It->second.Finalized = true;
15385f757f3fSDimitry Andric Flags = It->second.Flags;
15395f757f3fSDimitry Andric }
15405f757f3fSDimitry Andric }
15415f757f3fSDimitry Andric
15425f757f3fSDimitry Andric if (Flags) {
15435f757f3fSDimitry Andric // We own the definition of __objc_image_info; write the final
15445f757f3fSDimitry Andric // merged flags value.
15455f757f3fSDimitry Andric auto Content = Sym->getBlock().getMutableContent(G);
15465f757f3fSDimitry Andric assert(Content.size() == 8 &&
15475f757f3fSDimitry Andric "__objc_image_info size should have been verified already");
15485f757f3fSDimitry Andric support::endian::write32(&Content[4], *Flags, G.getEndianness());
15495f757f3fSDimitry Andric }
155006c3fb27SDimitry Andric break;
155106c3fb27SDimitry Andric }
155206c3fb27SDimitry Andric if (!ObjCImageInfoSym)
155306c3fb27SDimitry Andric ObjCImageInfoSym =
155406c3fb27SDimitry Andric &G.addExternalSymbol(ObjCImageInfoSymbolName, 8, false);
155506c3fb27SDimitry Andric
155606c3fb27SDimitry Andric SecBlock.addEdge(PointerEdge,
155706c3fb27SDimitry Andric RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec),
155806c3fb27SDimitry Andric *ObjCImageInfoSym, -SecBlock.getAddress().getValue());
155906c3fb27SDimitry Andric };
156006c3fb27SDimitry Andric }
156106c3fb27SDimitry Andric
156206c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {
156306c3fb27SDimitry Andric if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
156406c3fb27SDimitry Andric DataSections.push_back({});
156506c3fb27SDimitry Andric AddSection(DataSections.back(), *GraphSec);
156606c3fb27SDimitry Andric }
156706c3fb27SDimitry Andric }
156806c3fb27SDimitry Andric
156906c3fb27SDimitry Andric for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
157006c3fb27SDimitry Andric if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
157106c3fb27SDimitry Andric TextSections.push_back({});
157206c3fb27SDimitry Andric AddSection(TextSections.back(), *GraphSec);
157306c3fb27SDimitry Andric }
157406c3fb27SDimitry Andric }
157506c3fb27SDimitry Andric
157606c3fb27SDimitry Andric assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&
157706c3fb27SDimitry Andric "Unexpected number of blocks in runtime sections object");
157806c3fb27SDimitry Andric
157906c3fb27SDimitry Andric // Build the header struct up-front. This also gives us a chance to check
158006c3fb27SDimitry Andric // that the triple is supported, which we'll assume below.
158106c3fb27SDimitry Andric MachO::mach_header_64 Hdr;
158206c3fb27SDimitry Andric Hdr.magic = MachO::MH_MAGIC_64;
158306c3fb27SDimitry Andric switch (G.getTargetTriple().getArch()) {
158406c3fb27SDimitry Andric case Triple::aarch64:
158506c3fb27SDimitry Andric Hdr.cputype = MachO::CPU_TYPE_ARM64;
158606c3fb27SDimitry Andric Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
158706c3fb27SDimitry Andric break;
158806c3fb27SDimitry Andric case Triple::x86_64:
158906c3fb27SDimitry Andric Hdr.cputype = MachO::CPU_TYPE_X86_64;
159006c3fb27SDimitry Andric Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
159106c3fb27SDimitry Andric break;
159206c3fb27SDimitry Andric default:
159306c3fb27SDimitry Andric llvm_unreachable("Unsupported architecture");
159406c3fb27SDimitry Andric }
159506c3fb27SDimitry Andric
159606c3fb27SDimitry Andric Hdr.filetype = MachO::MH_DYLIB;
159706c3fb27SDimitry Andric Hdr.ncmds = 1 + !TextSections.empty();
159806c3fb27SDimitry Andric Hdr.sizeofcmds =
159906c3fb27SDimitry Andric Hdr.ncmds * sizeof(MachO::segment_command_64) +
160006c3fb27SDimitry Andric (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64);
160106c3fb27SDimitry Andric Hdr.flags = 0;
160206c3fb27SDimitry Andric Hdr.reserved = 0;
160306c3fb27SDimitry Andric
160406c3fb27SDimitry Andric auto SecContent = SecBlock.getAlreadyMutableContent();
160506c3fb27SDimitry Andric char *P = SecContent.data();
160606c3fb27SDimitry Andric auto WriteMachOStruct = [&](auto S) {
16075f757f3fSDimitry Andric if (G.getEndianness() != llvm::endianness::native)
160806c3fb27SDimitry Andric MachO::swapStruct(S);
160906c3fb27SDimitry Andric memcpy(P, &S, sizeof(S));
161006c3fb27SDimitry Andric P += sizeof(S);
161106c3fb27SDimitry Andric };
161206c3fb27SDimitry Andric
161306c3fb27SDimitry Andric auto WriteSegment = [&](StringRef Name, std::vector<SecDesc> &Secs) {
161406c3fb27SDimitry Andric MachO::segment_command_64 SegLC;
161506c3fb27SDimitry Andric memset(&SegLC, 0, sizeof(SegLC));
161606c3fb27SDimitry Andric memcpy(SegLC.segname, Name.data(), Name.size());
161706c3fb27SDimitry Andric SegLC.cmd = MachO::LC_SEGMENT_64;
161806c3fb27SDimitry Andric SegLC.cmdsize = sizeof(MachO::segment_command_64) +
161906c3fb27SDimitry Andric Secs.size() * sizeof(MachO::section_64);
162006c3fb27SDimitry Andric SegLC.nsects = Secs.size();
162106c3fb27SDimitry Andric WriteMachOStruct(SegLC);
162206c3fb27SDimitry Andric for (auto &SD : Secs) {
162306c3fb27SDimitry Andric if (SD.AddFixups)
162406c3fb27SDimitry Andric SD.AddFixups(P - SecContent.data());
162506c3fb27SDimitry Andric WriteMachOStruct(SD.Sec);
162606c3fb27SDimitry Andric }
162706c3fb27SDimitry Andric };
162806c3fb27SDimitry Andric
162906c3fb27SDimitry Andric WriteMachOStruct(Hdr);
163006c3fb27SDimitry Andric if (!TextSections.empty())
163106c3fb27SDimitry Andric WriteSegment("__TEXT", TextSections);
163206c3fb27SDimitry Andric if (!DataSections.empty())
163306c3fb27SDimitry Andric WriteSegment("__DATA", DataSections);
163406c3fb27SDimitry Andric
163506c3fb27SDimitry Andric assert(P == SecContent.end() && "Underflow writing ObjC runtime object");
163606c3fb27SDimitry Andric return Error::success();
163706c3fb27SDimitry Andric }
163806c3fb27SDimitry Andric
prepareSymbolTableRegistration(jitlink::LinkGraph & G,JITSymTabVector & JITSymTabInfo)16395f757f3fSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::prepareSymbolTableRegistration(
16405f757f3fSDimitry Andric jitlink::LinkGraph &G, JITSymTabVector &JITSymTabInfo) {
16415f757f3fSDimitry Andric
16425f757f3fSDimitry Andric auto *CStringSec = G.findSectionByName(MachOCStringSectionName);
16435f757f3fSDimitry Andric if (!CStringSec)
16445f757f3fSDimitry Andric CStringSec = &G.createSection(MachOCStringSectionName,
16455f757f3fSDimitry Andric MemProt::Read | MemProt::Exec);
16465f757f3fSDimitry Andric
16475f757f3fSDimitry Andric // Make a map of existing strings so that we can re-use them:
16485f757f3fSDimitry Andric DenseMap<StringRef, jitlink::Symbol *> ExistingStrings;
16495f757f3fSDimitry Andric for (auto *Sym : CStringSec->symbols()) {
16505f757f3fSDimitry Andric
16515f757f3fSDimitry Andric // The LinkGraph builder should have created single strings blocks, and all
16525f757f3fSDimitry Andric // plugins should have maintained this invariant.
16535f757f3fSDimitry Andric auto Content = Sym->getBlock().getContent();
16545f757f3fSDimitry Andric ExistingStrings.insert(
16555f757f3fSDimitry Andric std::make_pair(StringRef(Content.data(), Content.size()), Sym));
16565f757f3fSDimitry Andric }
16575f757f3fSDimitry Andric
16585f757f3fSDimitry Andric // Add all symbol names to the string section, and record the symbols for
16595f757f3fSDimitry Andric // those names.
16605f757f3fSDimitry Andric {
16615f757f3fSDimitry Andric SmallVector<jitlink::Symbol *> SymsToProcess;
16625f757f3fSDimitry Andric for (auto *Sym : G.defined_symbols())
16635f757f3fSDimitry Andric SymsToProcess.push_back(Sym);
16641db9f3b2SDimitry Andric for (auto *Sym : G.absolute_symbols())
16651db9f3b2SDimitry Andric SymsToProcess.push_back(Sym);
16665f757f3fSDimitry Andric
16675f757f3fSDimitry Andric for (auto *Sym : SymsToProcess) {
16685f757f3fSDimitry Andric if (!Sym->hasName())
16695f757f3fSDimitry Andric continue;
16705f757f3fSDimitry Andric
16715f757f3fSDimitry Andric auto I = ExistingStrings.find(Sym->getName());
16725f757f3fSDimitry Andric if (I == ExistingStrings.end()) {
16735f757f3fSDimitry Andric auto &NameBlock = G.createMutableContentBlock(
16745f757f3fSDimitry Andric *CStringSec, G.allocateCString(Sym->getName()), orc::ExecutorAddr(),
16755f757f3fSDimitry Andric 1, 0);
16765f757f3fSDimitry Andric auto &SymbolNameSym = G.addAnonymousSymbol(
16775f757f3fSDimitry Andric NameBlock, 0, NameBlock.getSize(), false, true);
16785f757f3fSDimitry Andric JITSymTabInfo.push_back({Sym, &SymbolNameSym});
16795f757f3fSDimitry Andric } else
16805f757f3fSDimitry Andric JITSymTabInfo.push_back({Sym, I->second});
16815f757f3fSDimitry Andric }
16825f757f3fSDimitry Andric }
16835f757f3fSDimitry Andric
16845f757f3fSDimitry Andric return Error::success();
16855f757f3fSDimitry Andric }
16865f757f3fSDimitry Andric
addSymbolTableRegistration(jitlink::LinkGraph & G,MaterializationResponsibility & MR,JITSymTabVector & JITSymTabInfo,bool InBootstrapPhase)16875f757f3fSDimitry Andric Error MachOPlatform::MachOPlatformPlugin::addSymbolTableRegistration(
16885f757f3fSDimitry Andric jitlink::LinkGraph &G, MaterializationResponsibility &MR,
16895f757f3fSDimitry Andric JITSymTabVector &JITSymTabInfo, bool InBootstrapPhase) {
16905f757f3fSDimitry Andric
16915f757f3fSDimitry Andric ExecutorAddr HeaderAddr;
16925f757f3fSDimitry Andric {
16935f757f3fSDimitry Andric std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
16945f757f3fSDimitry Andric auto I = MP.JITDylibToHeaderAddr.find(&MR.getTargetJITDylib());
16955f757f3fSDimitry Andric assert(I != MP.JITDylibToHeaderAddr.end() && "No header registered for JD");
16965f757f3fSDimitry Andric assert(I->second && "Null header registered for JD");
16975f757f3fSDimitry Andric HeaderAddr = I->second;
16985f757f3fSDimitry Andric }
16995f757f3fSDimitry Andric
17005f757f3fSDimitry Andric SymbolTableVector LocalSymTab;
17015f757f3fSDimitry Andric auto &SymTab = LLVM_LIKELY(!InBootstrapPhase) ? LocalSymTab
17025f757f3fSDimitry Andric : MP.Bootstrap.load()->SymTab;
17035f757f3fSDimitry Andric for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo)
17045f757f3fSDimitry Andric SymTab.push_back({NameSym->getAddress(), OriginalSymbol->getAddress(),
17055f757f3fSDimitry Andric flagsForSymbol(*OriginalSymbol)});
17065f757f3fSDimitry Andric
17075f757f3fSDimitry Andric // Bail out if we're in the bootstrap phase -- registration of thees symbols
17085f757f3fSDimitry Andric // will be attached to the bootstrap graph.
17095f757f3fSDimitry Andric if (LLVM_UNLIKELY(InBootstrapPhase))
17105f757f3fSDimitry Andric return Error::success();
17115f757f3fSDimitry Andric
17125f757f3fSDimitry Andric shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
17135f757f3fSDimitry Andric ? G.allocActions()
17145f757f3fSDimitry Andric : MP.Bootstrap.load()->DeferredAAs;
17155f757f3fSDimitry Andric allocActions.push_back(
17165f757f3fSDimitry Andric {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
17175f757f3fSDimitry Andric MP.RegisterObjectSymbolTable.Addr, HeaderAddr, SymTab)),
17185f757f3fSDimitry Andric cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
17195f757f3fSDimitry Andric MP.DeregisterObjectSymbolTable.Addr, HeaderAddr, SymTab))});
17205f757f3fSDimitry Andric
17215f757f3fSDimitry Andric return Error::success();
17225f757f3fSDimitry Andric }
17235f757f3fSDimitry Andric
17245f757f3fSDimitry Andric template <typename MachOTraits>
createHeaderBlock(MachOPlatform & MOP,const MachOPlatform::HeaderOptions & Opts,JITDylib & JD,jitlink::LinkGraph & G,jitlink::Section & HeaderSection)17257a6dacacSDimitry Andric jitlink::Block &createHeaderBlock(MachOPlatform &MOP,
17267a6dacacSDimitry Andric const MachOPlatform::HeaderOptions &Opts,
17277a6dacacSDimitry Andric JITDylib &JD, jitlink::LinkGraph &G,
17285f757f3fSDimitry Andric jitlink::Section &HeaderSection) {
17295f757f3fSDimitry Andric auto HdrInfo =
17305f757f3fSDimitry Andric getMachOHeaderInfoFromTriple(MOP.getExecutionSession().getTargetTriple());
17315f757f3fSDimitry Andric MachOBuilder<MachOTraits> B(HdrInfo.PageSize);
17325f757f3fSDimitry Andric
17335f757f3fSDimitry Andric B.Header.filetype = MachO::MH_DYLIB;
17345f757f3fSDimitry Andric B.Header.cputype = HdrInfo.CPUType;
17355f757f3fSDimitry Andric B.Header.cpusubtype = HdrInfo.CPUSubType;
17365f757f3fSDimitry Andric
17377a6dacacSDimitry Andric if (Opts.IDDylib)
17387a6dacacSDimitry Andric B.template addLoadCommand<MachO::LC_ID_DYLIB>(
17397a6dacacSDimitry Andric Opts.IDDylib->Name, Opts.IDDylib->Timestamp,
17407a6dacacSDimitry Andric Opts.IDDylib->CurrentVersion, Opts.IDDylib->CompatibilityVersion);
17417a6dacacSDimitry Andric else
17427a6dacacSDimitry Andric B.template addLoadCommand<MachO::LC_ID_DYLIB>(JD.getName(), 0, 0, 0);
17437a6dacacSDimitry Andric
1744*0fca6ea1SDimitry Andric for (auto &BV : Opts.BuildVersions)
1745*0fca6ea1SDimitry Andric B.template addLoadCommand<MachO::LC_BUILD_VERSION>(
1746*0fca6ea1SDimitry Andric BV.Platform, BV.MinOS, BV.SDK, static_cast<uint32_t>(0));
17477a6dacacSDimitry Andric for (auto &D : Opts.LoadDylibs)
17487a6dacacSDimitry Andric B.template addLoadCommand<MachO::LC_LOAD_DYLIB>(
17497a6dacacSDimitry Andric D.Name, D.Timestamp, D.CurrentVersion, D.CompatibilityVersion);
17507a6dacacSDimitry Andric for (auto &P : Opts.RPaths)
17517a6dacacSDimitry Andric B.template addLoadCommand<MachO::LC_RPATH>(P);
17527a6dacacSDimitry Andric
17535f757f3fSDimitry Andric auto HeaderContent = G.allocateBuffer(B.layout());
17545f757f3fSDimitry Andric B.write(HeaderContent);
17555f757f3fSDimitry Andric
17565f757f3fSDimitry Andric return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
17575f757f3fSDimitry Andric 0);
17585f757f3fSDimitry Andric }
17595f757f3fSDimitry Andric
SimpleMachOHeaderMU(MachOPlatform & MOP,SymbolStringPtr HeaderStartSymbol,MachOPlatform::HeaderOptions Opts)17605f757f3fSDimitry Andric SimpleMachOHeaderMU::SimpleMachOHeaderMU(MachOPlatform &MOP,
17617a6dacacSDimitry Andric SymbolStringPtr HeaderStartSymbol,
17627a6dacacSDimitry Andric MachOPlatform::HeaderOptions Opts)
17635f757f3fSDimitry Andric : MaterializationUnit(
17645f757f3fSDimitry Andric createHeaderInterface(MOP, std::move(HeaderStartSymbol))),
17657a6dacacSDimitry Andric MOP(MOP), Opts(std::move(Opts)) {}
17665f757f3fSDimitry Andric
materialize(std::unique_ptr<MaterializationResponsibility> R)17675f757f3fSDimitry Andric void SimpleMachOHeaderMU::materialize(
17685f757f3fSDimitry Andric std::unique_ptr<MaterializationResponsibility> R) {
17695f757f3fSDimitry Andric auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");
17705f757f3fSDimitry Andric addMachOHeader(R->getTargetJITDylib(), *G, R->getInitializerSymbol());
17715f757f3fSDimitry Andric MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
17725f757f3fSDimitry Andric }
17735f757f3fSDimitry Andric
discard(const JITDylib & JD,const SymbolStringPtr & Sym)17745f757f3fSDimitry Andric void SimpleMachOHeaderMU::discard(const JITDylib &JD,
17755f757f3fSDimitry Andric const SymbolStringPtr &Sym) {}
17765f757f3fSDimitry Andric
addMachOHeader(JITDylib & JD,jitlink::LinkGraph & G,const SymbolStringPtr & InitializerSymbol)17775f757f3fSDimitry Andric void SimpleMachOHeaderMU::addMachOHeader(
17785f757f3fSDimitry Andric JITDylib &JD, jitlink::LinkGraph &G,
17795f757f3fSDimitry Andric const SymbolStringPtr &InitializerSymbol) {
17805f757f3fSDimitry Andric auto &HeaderSection = G.createSection("__header", MemProt::Read);
17815f757f3fSDimitry Andric auto &HeaderBlock = createHeaderBlock(JD, G, HeaderSection);
17825f757f3fSDimitry Andric
17835f757f3fSDimitry Andric // Init symbol is header-start symbol.
17845f757f3fSDimitry Andric G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, HeaderBlock.getSize(),
17855f757f3fSDimitry Andric jitlink::Linkage::Strong, jitlink::Scope::Default, false,
17865f757f3fSDimitry Andric true);
17875f757f3fSDimitry Andric for (auto &HS : AdditionalHeaderSymbols)
17885f757f3fSDimitry Andric G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),
17895f757f3fSDimitry Andric jitlink::Linkage::Strong, jitlink::Scope::Default, false,
17905f757f3fSDimitry Andric true);
17915f757f3fSDimitry Andric }
17925f757f3fSDimitry Andric
17935f757f3fSDimitry Andric jitlink::Block &
createHeaderBlock(JITDylib & JD,jitlink::LinkGraph & G,jitlink::Section & HeaderSection)17945f757f3fSDimitry Andric SimpleMachOHeaderMU::createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,
17955f757f3fSDimitry Andric jitlink::Section &HeaderSection) {
17965f757f3fSDimitry Andric switch (MOP.getExecutionSession().getTargetTriple().getArch()) {
17975f757f3fSDimitry Andric case Triple::aarch64:
17985f757f3fSDimitry Andric case Triple::x86_64:
17997a6dacacSDimitry Andric return ::createHeaderBlock<MachO64LE>(MOP, Opts, JD, G, HeaderSection);
18005f757f3fSDimitry Andric default:
18015f757f3fSDimitry Andric llvm_unreachable("Unsupported architecture");
18025f757f3fSDimitry Andric }
18035f757f3fSDimitry Andric }
18045f757f3fSDimitry Andric
createHeaderInterface(MachOPlatform & MOP,const SymbolStringPtr & HeaderStartSymbol)18055f757f3fSDimitry Andric MaterializationUnit::Interface SimpleMachOHeaderMU::createHeaderInterface(
18065f757f3fSDimitry Andric MachOPlatform &MOP, const SymbolStringPtr &HeaderStartSymbol) {
18075f757f3fSDimitry Andric SymbolFlagsMap HeaderSymbolFlags;
18085f757f3fSDimitry Andric
18095f757f3fSDimitry Andric HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
18105f757f3fSDimitry Andric for (auto &HS : AdditionalHeaderSymbols)
18115f757f3fSDimitry Andric HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
18125f757f3fSDimitry Andric JITSymbolFlags::Exported;
18135f757f3fSDimitry Andric
18145f757f3fSDimitry Andric return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
18155f757f3fSDimitry Andric HeaderStartSymbol);
18165f757f3fSDimitry Andric }
18175f757f3fSDimitry Andric
getMachOHeaderInfoFromTriple(const Triple & TT)18185f757f3fSDimitry Andric MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT) {
18195f757f3fSDimitry Andric switch (TT.getArch()) {
18205f757f3fSDimitry Andric case Triple::aarch64:
18215f757f3fSDimitry Andric return {/* PageSize = */ 16 * 1024,
18225f757f3fSDimitry Andric /* CPUType = */ MachO::CPU_TYPE_ARM64,
18235f757f3fSDimitry Andric /* CPUSubType = */ MachO::CPU_SUBTYPE_ARM64_ALL};
18245f757f3fSDimitry Andric case Triple::x86_64:
18255f757f3fSDimitry Andric return {/* PageSize = */ 4 * 1024,
18265f757f3fSDimitry Andric /* CPUType = */ MachO::CPU_TYPE_X86_64,
18275f757f3fSDimitry Andric /* CPUSubType = */ MachO::CPU_SUBTYPE_X86_64_ALL};
18285f757f3fSDimitry Andric default:
18295f757f3fSDimitry Andric llvm_unreachable("Unrecognized architecture");
18305f757f3fSDimitry Andric }
18315f757f3fSDimitry Andric }
18325f757f3fSDimitry Andric
18335ffd83dbSDimitry Andric } // End namespace orc.
18345ffd83dbSDimitry Andric } // End namespace llvm.
1835