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