Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / ExecutionEngine / Orc / MachOPlatform.cpp
blobabc0bbbcaad2a39c1380243544809eaf5f410c12
1 //===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
11 #include "llvm/BinaryFormat/MachO.h"
12 #include "llvm/ExecutionEngine/JITLink/MachO.h"
13 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
14 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
15 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
16 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
17 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
18 #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
19 #include "llvm/Support/BinaryByteStream.h"
20 #include "llvm/Support/Debug.h"
21 #include <optional>
23 #define DEBUG_TYPE "orc"
25 using namespace llvm;
26 using namespace llvm::orc;
27 using namespace llvm::orc::shared;
29 namespace llvm {
30 namespace orc {
31 namespace shared {
33 using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
34 using SPSMachOJITDylibDepInfoMap =
35 SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
37 template <>
38 class SPSSerializationTraits<SPSMachOJITDylibDepInfo,
39 MachOPlatform::MachOJITDylibDepInfo> {
40 public:
41 static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
42 return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
45 static bool serialize(SPSOutputBuffer &OB,
46 const MachOPlatform::MachOJITDylibDepInfo &DDI) {
47 return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
48 DDI.DepHeaders);
51 static bool deserialize(SPSInputBuffer &IB,
52 MachOPlatform::MachOJITDylibDepInfo &DDI) {
53 return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
54 DDI.DepHeaders);
58 } // namespace shared
59 } // namespace orc
60 } // namespace llvm
62 namespace {
64 std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
65 std::string Name) {
66 unsigned PointerSize;
67 llvm::endianness Endianness;
68 const auto &TT = MOP.getExecutionSession().getTargetTriple();
70 switch (TT.getArch()) {
71 case Triple::aarch64:
72 case Triple::x86_64:
73 PointerSize = 8;
74 Endianness = llvm::endianness::little;
75 break;
76 default:
77 llvm_unreachable("Unrecognized architecture");
80 return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize,
81 Endianness,
82 jitlink::getGenericEdgeKindName);
85 // Generates a MachO header.
86 class MachOHeaderMaterializationUnit : public MaterializationUnit {
87 public:
88 MachOHeaderMaterializationUnit(MachOPlatform &MOP,
89 const SymbolStringPtr &HeaderStartSymbol)
90 : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)),
91 MOP(MOP) {}
93 StringRef getName() const override { return "MachOHeaderMU"; }
95 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
96 auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");
97 addMachOHeader(*G, MOP, R->getInitializerSymbol());
98 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
101 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
103 static void addMachOHeader(jitlink::LinkGraph &G, MachOPlatform &MOP,
104 const SymbolStringPtr &InitializerSymbol) {
105 auto &HeaderSection = G.createSection("__header", MemProt::Read);
106 auto &HeaderBlock = createHeaderBlock(G, HeaderSection);
108 // Init symbol is header-start symbol.
109 G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol,
110 HeaderBlock.getSize(), jitlink::Linkage::Strong,
111 jitlink::Scope::Default, false, true);
112 for (auto &HS : AdditionalHeaderSymbols)
113 G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),
114 jitlink::Linkage::Strong, jitlink::Scope::Default,
115 false, true);
118 private:
119 struct HeaderSymbol {
120 const char *Name;
121 uint64_t Offset;
124 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
125 {"___mh_executable_header", 0}};
127 static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
128 jitlink::Section &HeaderSection) {
129 MachO::mach_header_64 Hdr;
130 Hdr.magic = MachO::MH_MAGIC_64;
131 switch (G.getTargetTriple().getArch()) {
132 case Triple::aarch64:
133 Hdr.cputype = MachO::CPU_TYPE_ARM64;
134 Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
135 break;
136 case Triple::x86_64:
137 Hdr.cputype = MachO::CPU_TYPE_X86_64;
138 Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
139 break;
140 default:
141 llvm_unreachable("Unrecognized architecture");
143 Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
144 Hdr.ncmds = 0;
145 Hdr.sizeofcmds = 0;
146 Hdr.flags = 0;
147 Hdr.reserved = 0;
149 if (G.getEndianness() != llvm::endianness::native)
150 MachO::swapStruct(Hdr);
152 auto HeaderContent = G.allocateContent(
153 ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
155 return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
159 static MaterializationUnit::Interface
160 createHeaderInterface(MachOPlatform &MOP,
161 const SymbolStringPtr &HeaderStartSymbol) {
162 SymbolFlagsMap HeaderSymbolFlags;
164 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
165 for (auto &HS : AdditionalHeaderSymbols)
166 HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
167 JITSymbolFlags::Exported;
169 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
170 HeaderStartSymbol);
173 MachOPlatform &MOP;
176 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
177 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
179 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
180 class MachOPlatformCompleteBootstrapMaterializationUnit
181 : public MaterializationUnit {
182 public:
183 MachOPlatformCompleteBootstrapMaterializationUnit(
184 MachOPlatform &MOP, StringRef PlatformJDName,
185 SymbolStringPtr CompleteBootstrapSymbol, shared::AllocActions DeferredAAs,
186 ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown,
187 ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib,
188 ExecutorAddr MachOHeaderAddr)
189 : MaterializationUnit(
190 {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),
191 MOP(MOP), PlatformJDName(PlatformJDName),
192 CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),
193 DeferredAAs(std::move(DeferredAAs)),
194 PlatformBootstrap(PlatformBootstrap),
195 PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),
196 DeregisterJITDylib(DeregisterJITDylib),
197 MachOHeaderAddr(MachOHeaderAddr) {}
199 StringRef getName() const override {
200 return "MachOPlatformCompleteBootstrap";
203 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
204 using namespace jitlink;
205 auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>");
206 auto &PlaceholderSection =
207 G->createSection("__orc_rt_cplt_bs", MemProt::Read);
208 auto &PlaceholderBlock =
209 G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0);
210 G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1,
211 Linkage::Strong, Scope::Hidden, false, true);
213 // Reserve space for the stolen actions, plus two extras.
214 G->allocActions().reserve(DeferredAAs.size() + 2);
216 // 1. Bootstrap the platform support code.
217 G->allocActions().push_back(
218 {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)),
219 cantFail(
220 WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
222 // 2. Register the platform JITDylib.
223 G->allocActions().push_back(
224 {cantFail(WrapperFunctionCall::Create<
225 SPSArgList<SPSString, SPSExecutorAddr>>(
226 RegisterJITDylib, PlatformJDName, MachOHeaderAddr)),
227 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
228 DeregisterJITDylib, MachOHeaderAddr))});
230 // 3. Add the deferred actions to the graph.
231 std::move(DeferredAAs.begin(), DeferredAAs.end(),
232 std::back_inserter(G->allocActions()));
234 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
237 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
239 private:
240 MachOPlatform &MOP;
241 StringRef PlatformJDName;
242 SymbolStringPtr CompleteBootstrapSymbol;
243 shared::AllocActions DeferredAAs;
244 ExecutorAddr PlatformBootstrap;
245 ExecutorAddr PlatformShutdown;
246 ExecutorAddr RegisterJITDylib;
247 ExecutorAddr DeregisterJITDylib;
248 ExecutorAddr MachOHeaderAddr;
251 static StringRef ObjCRuntimeObjectSectionsData[] = {
252 MachOObjCCatListSectionName, MachOObjCClassListSectionName,
253 MachOObjCClassRefsSectionName, MachOObjCConstSectionName,
254 MachOObjCDataSectionName, MachOObjCSelRefsSectionName};
256 static StringRef ObjCRuntimeObjectSectionsText[] = {
257 MachOObjCClassNameSectionName, MachOObjCMethNameSectionName,
258 MachOObjCMethTypeSectionName, MachOSwift5TypesSectionName,
259 MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
260 MachOSwift5EntrySectionName, MachOSwift5ProtoSectionName,
261 MachOSwift5ProtosSectionName};
263 static StringRef ObjCRuntimeObjectSectionName =
264 "__llvm_jitlink_ObjCRuntimeRegistrationObject";
266 static StringRef ObjCImageInfoSymbolName =
267 "__llvm_jitlink_macho_objc_imageinfo";
269 } // end anonymous namespace
271 namespace llvm {
272 namespace orc {
274 Expected<std::unique_ptr<MachOPlatform>>
275 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
276 JITDylib &PlatformJD,
277 std::unique_ptr<DefinitionGenerator> OrcRuntime,
278 std::optional<SymbolAliasMap> RuntimeAliases) {
280 // If the target is not supported then bail out immediately.
281 if (!supportedTarget(ES.getTargetTriple()))
282 return make_error<StringError>("Unsupported MachOPlatform triple: " +
283 ES.getTargetTriple().str(),
284 inconvertibleErrorCode());
286 auto &EPC = ES.getExecutorProcessControl();
288 // Create default aliases if the caller didn't supply any.
289 if (!RuntimeAliases)
290 RuntimeAliases = standardPlatformAliases(ES);
292 // Define the aliases.
293 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
294 return std::move(Err);
296 // Add JIT-dispatch function support symbols.
297 if (auto Err = PlatformJD.define(
298 absoluteSymbols({{ES.intern("___orc_rt_jit_dispatch"),
299 {EPC.getJITDispatchInfo().JITDispatchFunction,
300 JITSymbolFlags::Exported}},
301 {ES.intern("___orc_rt_jit_dispatch_ctx"),
302 {EPC.getJITDispatchInfo().JITDispatchContext,
303 JITSymbolFlags::Exported}}})))
304 return std::move(Err);
306 // Create the instance.
307 Error Err = Error::success();
308 auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform(
309 ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err));
310 if (Err)
311 return std::move(Err);
312 return std::move(P);
315 Expected<std::unique_ptr<MachOPlatform>>
316 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
317 JITDylib &PlatformJD, const char *OrcRuntimePath,
318 std::optional<SymbolAliasMap> RuntimeAliases) {
320 // Create a generator for the ORC runtime archive.
321 auto OrcRuntimeArchiveGenerator =
322 StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
323 if (!OrcRuntimeArchiveGenerator)
324 return OrcRuntimeArchiveGenerator.takeError();
326 return Create(ES, ObjLinkingLayer, PlatformJD,
327 std::move(*OrcRuntimeArchiveGenerator),
328 std::move(RuntimeAliases));
331 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
332 if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
333 *this, MachOHeaderStartSymbol)))
334 return Err;
336 return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
339 Error MachOPlatform::teardownJITDylib(JITDylib &JD) {
340 std::lock_guard<std::mutex> Lock(PlatformMutex);
341 auto I = JITDylibToHeaderAddr.find(&JD);
342 if (I != JITDylibToHeaderAddr.end()) {
343 assert(HeaderAddrToJITDylib.count(I->second) &&
344 "HeaderAddrToJITDylib missing entry");
345 HeaderAddrToJITDylib.erase(I->second);
346 JITDylibToHeaderAddr.erase(I);
348 JITDylibToPThreadKey.erase(&JD);
349 return Error::success();
352 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
353 const MaterializationUnit &MU) {
354 auto &JD = RT.getJITDylib();
355 const auto &InitSym = MU.getInitializerSymbol();
356 if (!InitSym)
357 return Error::success();
359 RegisteredInitSymbols[&JD].add(InitSym,
360 SymbolLookupFlags::WeaklyReferencedSymbol);
361 LLVM_DEBUG({
362 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
363 << MU.getName() << "\n";
365 return Error::success();
368 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
369 llvm_unreachable("Not supported yet");
372 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
373 ArrayRef<std::pair<const char *, const char *>> AL) {
374 for (auto &KV : AL) {
375 auto AliasName = ES.intern(KV.first);
376 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
377 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
378 JITSymbolFlags::Exported};
382 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
383 SymbolAliasMap Aliases;
384 addAliases(ES, Aliases, requiredCXXAliases());
385 addAliases(ES, Aliases, standardRuntimeUtilityAliases());
386 return Aliases;
389 ArrayRef<std::pair<const char *, const char *>>
390 MachOPlatform::requiredCXXAliases() {
391 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
392 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
394 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
397 ArrayRef<std::pair<const char *, const char *>>
398 MachOPlatform::standardRuntimeUtilityAliases() {
399 static const std::pair<const char *, const char *>
400 StandardRuntimeUtilityAliases[] = {
401 {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
402 {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
403 {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
404 {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
405 {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
406 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
408 return ArrayRef<std::pair<const char *, const char *>>(
409 StandardRuntimeUtilityAliases);
412 bool MachOPlatform::supportedTarget(const Triple &TT) {
413 switch (TT.getArch()) {
414 case Triple::aarch64:
415 case Triple::x86_64:
416 return true;
417 default:
418 return false;
422 MachOPlatform::MachOPlatform(
423 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
424 JITDylib &PlatformJD,
425 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
426 : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) {
427 ErrorAsOutParameter _(&Err);
428 ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
429 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
431 BootstrapInfo BI;
432 Bootstrap = &BI;
434 // Bootstrap process -- here be phase-ordering dragons.
436 // The MachOPlatform class uses allocation actions to register metadata
437 // sections with the ORC runtime, however the runtime contains metadata
438 // registration functions that have their own metadata that they need to
439 // register (e.g. the frame-info registration functions have frame-info).
440 // We can't use an ordinary lookup to find these registration functions
441 // because their address is needed during the link of the containing graph
442 // itself (to build the allocation actions that will call the registration
443 // functions). Further complicating the situation (a) the graph containing
444 // the registration functions is allowed to depend on other graphs (e.g. the
445 // graph containing the ORC runtime RTTI support) so we need to handle with
446 // an unknown set of dependencies during bootstrap, and (b) these graphs may
447 // be linked concurrently if the user has installed a concurrent dispatcher.
449 // We satisfy these constraint by implementing a bootstrap phase during which
450 // allocation actions generated by MachOPlatform are appended to a list of
451 // deferred allocation actions, rather than to the graphs themselves. At the
452 // end of the bootstrap process the deferred actions are attached to a final
453 // "complete-bootstrap" graph that causes them to be run.
455 // The bootstrap steps are as follows:
457 // 1. Request the graph containing the mach header. This graph is guaranteed
458 // not to have any metadata so the fact that the registration functions
459 // are not available yet is not a problem.
461 // 2. Look up the registration functions and discard the results. This will
462 // trigger linking of the graph containing these functions, and
463 // consequently any graphs that it depends on. We do not use the lookup
464 // result to find the addresses of the functions requested (as described
465 // above the lookup will return too late for that), instead we capture the
466 // addresses in a post-allocation pass injected by the platform runtime
467 // during bootstrap only.
469 // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of
470 // graphs being linked (potentially concurrently), and we block until all
471 // of these graphs have completed linking. This is to avoid a race on the
472 // deferred-actions vector: the lookup for the runtime registration
473 // functions may return while some functions (those that are being
474 // incidentally linked in, but aren't reachable via the runtime functions)
475 // are still being linked, and we need to capture any allocation actions
476 // for this incidental code before we proceed.
478 // 4. Once all active links are complete we transfer the deferred actions to
479 // a newly added CompleteBootstrap graph and then request a symbol from
480 // the CompleteBootstrap graph to trigger materialization. This will cause
481 // all deferred actions to be run, and once this lookup returns we can
482 // proceed.
484 // 5. Finally, we associate runtime support methods in MachOPlatform with
485 // the corresponding jit-dispatch tag variables in the ORC runtime to make
486 // the support methods callable. The bootstrap is now complete.
488 // Step (1) Add header materialization unit and request.
489 if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>(
490 *this, MachOHeaderStartSymbol))))
491 return;
492 if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))
493 return;
495 // Step (2) Request runtime registration functions to trigger
496 // materialization..
497 if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
498 SymbolLookupSet(
499 {PlatformBootstrap.Name, PlatformShutdown.Name,
500 RegisterJITDylib.Name, DeregisterJITDylib.Name,
501 RegisterObjectPlatformSections.Name,
502 DeregisterObjectPlatformSections.Name,
503 CreatePThreadKey.Name}))
504 .takeError()))
505 return;
507 // Step (3) Wait for any incidental linker work to complete.
509 std::unique_lock<std::mutex> Lock(BI.Mutex);
510 BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
511 Bootstrap = nullptr;
514 // Step (4) Add complete-bootstrap materialization unit and request.
515 auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap");
516 if ((Err = PlatformJD.define(
517 std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>(
518 *this, PlatformJD.getName(), BootstrapCompleteSymbol,
519 std::move(BI.DeferredAAs), PlatformBootstrap.Addr,
520 PlatformShutdown.Addr, RegisterJITDylib.Addr,
521 DeregisterJITDylib.Addr, BI.MachOHeaderAddr))))
522 return;
523 if ((Err = ES.lookup(makeJITDylibSearchOrder(
524 &PlatformJD, JITDylibLookupFlags::MatchAllSymbols),
525 std::move(BootstrapCompleteSymbol))
526 .takeError()))
527 return;
529 // (5) Associate runtime support functions.
530 if ((Err = associateRuntimeSupportFunctions()))
531 return;
534 Error MachOPlatform::associateRuntimeSupportFunctions() {
535 ExecutionSession::JITDispatchHandlerAssociationMap WFs;
537 using PushInitializersSPSSig =
538 SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr);
539 WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =
540 ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
541 this, &MachOPlatform::rt_pushInitializers);
543 using LookupSymbolSPSSig =
544 SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
545 WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
546 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
547 &MachOPlatform::rt_lookupSymbol);
549 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
552 void MachOPlatform::pushInitializersLoop(
553 PushInitializersSendResultFn SendResult, JITDylibSP JD) {
554 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
555 DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;
556 SmallVector<JITDylib *, 16> Worklist({JD.get()});
558 ES.runSessionLocked([&]() {
559 while (!Worklist.empty()) {
560 // FIXME: Check for defunct dylibs.
562 auto DepJD = Worklist.back();
563 Worklist.pop_back();
565 // If we've already visited this JITDylib on this iteration then continue.
566 if (JDDepMap.count(DepJD))
567 continue;
569 // Add dep info.
570 auto &DM = JDDepMap[DepJD];
571 DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
572 for (auto &KV : O) {
573 if (KV.first == DepJD)
574 continue;
575 DM.push_back(KV.first);
576 Worklist.push_back(KV.first);
580 // Add any registered init symbols.
581 auto RISItr = RegisteredInitSymbols.find(DepJD);
582 if (RISItr != RegisteredInitSymbols.end()) {
583 NewInitSymbols[DepJD] = std::move(RISItr->second);
584 RegisteredInitSymbols.erase(RISItr);
589 // If there are no further init symbols to look up then send the link order
590 // (as a list of header addresses) to the caller.
591 if (NewInitSymbols.empty()) {
593 // To make the list intelligible to the runtime we need to convert all
594 // JITDylib pointers to their header addresses. Only include JITDylibs
595 // that appear in the JITDylibToHeaderAddr map (i.e. those that have been
596 // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.
597 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
598 HeaderAddrs.reserve(JDDepMap.size());
600 std::lock_guard<std::mutex> Lock(PlatformMutex);
601 for (auto &KV : JDDepMap) {
602 auto I = JITDylibToHeaderAddr.find(KV.first);
603 if (I != JITDylibToHeaderAddr.end())
604 HeaderAddrs[KV.first] = I->second;
608 // Build the dep info map to return.
609 MachOJITDylibDepInfoMap DIM;
610 DIM.reserve(JDDepMap.size());
611 for (auto &KV : JDDepMap) {
612 auto HI = HeaderAddrs.find(KV.first);
613 // Skip unmanaged JITDylibs.
614 if (HI == HeaderAddrs.end())
615 continue;
616 auto H = HI->second;
617 MachOJITDylibDepInfo DepInfo;
618 for (auto &Dep : KV.second) {
619 auto HJ = HeaderAddrs.find(Dep);
620 if (HJ != HeaderAddrs.end())
621 DepInfo.DepHeaders.push_back(HJ->second);
623 DIM.push_back(std::make_pair(H, std::move(DepInfo)));
625 SendResult(DIM);
626 return;
629 // Otherwise issue a lookup and re-run this phase when it completes.
630 lookupInitSymbolsAsync(
631 [this, SendResult = std::move(SendResult), JD](Error Err) mutable {
632 if (Err)
633 SendResult(std::move(Err));
634 else
635 pushInitializersLoop(std::move(SendResult), JD);
637 ES, std::move(NewInitSymbols));
640 void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
641 ExecutorAddr JDHeaderAddr) {
642 JITDylibSP JD;
644 std::lock_guard<std::mutex> Lock(PlatformMutex);
645 auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
646 if (I != HeaderAddrToJITDylib.end())
647 JD = I->second;
650 LLVM_DEBUG({
651 dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
652 if (JD)
653 dbgs() << "pushing initializers for " << JD->getName() << "\n";
654 else
655 dbgs() << "No JITDylib for header address.\n";
658 if (!JD) {
659 SendResult(make_error<StringError>("No JITDylib with header addr " +
660 formatv("{0:x}", JDHeaderAddr),
661 inconvertibleErrorCode()));
662 return;
665 pushInitializersLoop(std::move(SendResult), JD);
668 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
669 ExecutorAddr Handle, StringRef SymbolName) {
670 LLVM_DEBUG({
671 dbgs() << "MachOPlatform::rt_lookupSymbol(\"" << Handle << "\")\n";
674 JITDylib *JD = nullptr;
677 std::lock_guard<std::mutex> Lock(PlatformMutex);
678 auto I = HeaderAddrToJITDylib.find(Handle);
679 if (I != HeaderAddrToJITDylib.end())
680 JD = I->second;
683 if (!JD) {
684 LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n");
685 SendResult(make_error<StringError>("No JITDylib associated with handle " +
686 formatv("{0:x}", Handle),
687 inconvertibleErrorCode()));
688 return;
691 // Use functor class to work around XL build compiler issue on AIX.
692 class RtLookupNotifyComplete {
693 public:
694 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
695 : SendResult(std::move(SendResult)) {}
696 void operator()(Expected<SymbolMap> Result) {
697 if (Result) {
698 assert(Result->size() == 1 && "Unexpected result map count");
699 SendResult(Result->begin()->second.getAddress());
700 } else {
701 SendResult(Result.takeError());
705 private:
706 SendSymbolAddressFn SendResult;
709 // FIXME: Proper mangling.
710 auto MangledName = ("_" + SymbolName).str();
711 ES.lookup(
712 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
713 SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
714 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
717 Expected<uint64_t> MachOPlatform::createPThreadKey() {
718 if (!CreatePThreadKey.Addr)
719 return make_error<StringError>(
720 "Attempting to create pthread key in target, but runtime support has "
721 "not been loaded yet",
722 inconvertibleErrorCode());
724 Expected<uint64_t> Result(0);
725 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
726 CreatePThreadKey.Addr, Result))
727 return std::move(Err);
728 return Result;
731 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
732 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
733 jitlink::PassConfiguration &Config) {
735 using namespace jitlink;
737 bool InBootstrapPhase =
738 &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap;
740 // If we're in the bootstrap phase then increment the active graphs.
741 if (InBootstrapPhase) {
742 Config.PrePrunePasses.push_back(
743 [this](LinkGraph &G) { return bootstrapPipelineStart(G); });
744 Config.PostAllocationPasses.push_back([this](LinkGraph &G) {
745 return bootstrapPipelineRecordRuntimeFunctions(G);
749 // --- Handle Initializers ---
750 if (auto InitSymbol = MR.getInitializerSymbol()) {
752 // If the initializer symbol is the MachOHeader start symbol then just
753 // register it and then bail out -- the header materialization unit
754 // definitely doesn't need any other passes.
755 if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) {
756 Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {
757 return associateJITDylibHeaderSymbol(G, MR);
759 return;
762 // If the object contains an init symbol other than the header start symbol
763 // then add passes to preserve, process and register the init
764 // sections/symbols.
765 Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
766 if (auto Err = preserveImportantSections(G, MR))
767 return Err;
768 return processObjCImageInfo(G, MR);
770 Config.PostPrunePasses.push_back(
771 [this](LinkGraph &G) { return createObjCRuntimeObject(G); });
772 Config.PostAllocationPasses.push_back(
773 [this, &MR](LinkGraph &G) { return populateObjCRuntimeObject(G, MR); });
776 // Insert TLV lowering at the start of the PostPrunePasses, since we want
777 // it to run before GOT/PLT lowering.
778 Config.PostPrunePasses.insert(
779 Config.PostPrunePasses.begin(),
780 [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) {
781 return fixTLVSectionsAndEdges(G, JD);
784 // Add a pass to register the final addresses of any special sections in the
785 // object with the runtime.
786 Config.PostAllocationPasses.push_back(
787 [this, &JD = MR.getTargetJITDylib(), InBootstrapPhase](LinkGraph &G) {
788 return registerObjectPlatformSections(G, JD, InBootstrapPhase);
791 // If we're in the bootstrap phase then steal allocation actions and then
792 // decrement the active graphs.
793 if (InBootstrapPhase)
794 Config.PostFixupPasses.push_back(
795 [this](LinkGraph &G) { return bootstrapPipelineEnd(G); });
798 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
799 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
800 MaterializationResponsibility &MR) {
801 std::lock_guard<std::mutex> Lock(PluginMutex);
802 auto I = InitSymbolDeps.find(&MR);
803 if (I != InitSymbolDeps.end()) {
804 SyntheticSymbolDependenciesMap Result;
805 Result[MR.getInitializerSymbol()] = std::move(I->second);
806 InitSymbolDeps.erase(&MR);
807 return Result;
809 return SyntheticSymbolDependenciesMap();
812 Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart(
813 jitlink::LinkGraph &G) {
814 // Increment the active graphs count in BootstrapInfo.
815 std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
816 ++MP.Bootstrap.load()->ActiveGraphs;
817 return Error::success();
820 Error MachOPlatform::MachOPlatformPlugin::
821 bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) {
822 // Record bootstrap function names.
823 std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = {
824 {*MP.MachOHeaderStartSymbol, &MP.Bootstrap.load()->MachOHeaderAddr},
825 {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr},
826 {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr},
827 {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr},
828 {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr},
829 {*MP.RegisterObjectPlatformSections.Name,
830 &MP.RegisterObjectPlatformSections.Addr},
831 {*MP.DeregisterObjectPlatformSections.Name,
832 &MP.DeregisterObjectPlatformSections.Addr},
833 {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr},
834 {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr},
835 {*MP.DeregisterObjCRuntimeObject.Name,
836 &MP.DeregisterObjCRuntimeObject.Addr}};
838 bool RegisterMachOHeader = false;
840 for (auto *Sym : G.defined_symbols()) {
841 for (auto &RTSym : RuntimeSymbols) {
842 if (Sym->hasName() && Sym->getName() == RTSym.first) {
843 if (*RTSym.second)
844 return make_error<StringError>(
845 "Duplicate " + RTSym.first +
846 " detected during MachOPlatform bootstrap",
847 inconvertibleErrorCode());
849 if (Sym->getName() == *MP.MachOHeaderStartSymbol)
850 RegisterMachOHeader = true;
852 *RTSym.second = Sym->getAddress();
857 if (RegisterMachOHeader) {
858 // If this graph defines the macho header symbol then create the internal
859 // mapping between it and PlatformJD.
860 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
861 MP.JITDylibToHeaderAddr[&MP.PlatformJD] =
862 MP.Bootstrap.load()->MachOHeaderAddr;
863 MP.HeaderAddrToJITDylib[MP.Bootstrap.load()->MachOHeaderAddr] =
864 &MP.PlatformJD;
867 return Error::success();
870 Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(
871 jitlink::LinkGraph &G) {
872 std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
873 assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed");
874 --MP.Bootstrap.load()->ActiveGraphs;
875 // Notify Bootstrap->CV while holding the mutex because the mutex is
876 // also keeping Bootstrap->CV alive.
877 if (MP.Bootstrap.load()->ActiveGraphs == 0)
878 MP.Bootstrap.load()->CV.notify_all();
879 return Error::success();
882 Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
883 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
884 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
885 return Sym->getName() == *MP.MachOHeaderStartSymbol;
887 assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
889 auto &JD = MR.getTargetJITDylib();
890 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
891 auto HeaderAddr = (*I)->getAddress();
892 MP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
893 MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
894 // We can unconditionally add these actions to the Graph because this pass
895 // isn't used during bootstrap.
896 G.allocActions().push_back(
897 {cantFail(
898 WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>(
899 MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)),
900 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
901 MP.DeregisterJITDylib.Addr, HeaderAddr))});
902 return Error::success();
905 Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections(
906 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
907 // __objc_imageinfo is "important": we want to preserve it and record its
908 // address in the first graph that it appears in, then verify and discard it
909 // in all subsequent graphs. In this pass we preserve unconditionally -- we'll
910 // manually throw it away in the processObjCImageInfo pass.
911 if (auto *ObjCImageInfoSec =
912 G.findSectionByName(MachOObjCImageInfoSectionName)) {
913 if (ObjCImageInfoSec->blocks_size() != 1)
914 return make_error<StringError>(
915 "In " + G.getName() +
916 "__DATA,__objc_imageinfo contains multiple blocks",
917 inconvertibleErrorCode());
918 G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false,
919 true);
921 for (auto *B : ObjCImageInfoSec->blocks())
922 if (!B->edges_empty())
923 return make_error<StringError>("In " + G.getName() + ", " +
924 MachOObjCImageInfoSectionName +
925 " contains references to symbols",
926 inconvertibleErrorCode());
929 // Init sections are important: We need to preserve them and so that their
930 // addresses can be captured and reported to the ORC runtime in
931 // registerObjectPlatformSections.
932 JITLinkSymbolSet InitSectionSymbols;
933 for (auto &InitSectionName : MachOInitSectionNames) {
934 // Skip ObjCImageInfo -- this shouldn't have any dependencies, and we may
935 // remove it later.
936 if (InitSectionName == MachOObjCImageInfoSectionName)
937 continue;
939 // Skip non-init sections.
940 auto *InitSection = G.findSectionByName(InitSectionName);
941 if (!InitSection)
942 continue;
944 // Make a pass over live symbols in the section: those blocks are already
945 // preserved.
946 DenseSet<jitlink::Block *> AlreadyLiveBlocks;
947 for (auto &Sym : InitSection->symbols()) {
948 auto &B = Sym->getBlock();
949 if (Sym->isLive() && Sym->getOffset() == 0 &&
950 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
951 InitSectionSymbols.insert(Sym);
952 AlreadyLiveBlocks.insert(&B);
956 // Add anonymous symbols to preserve any not-already-preserved blocks.
957 for (auto *B : InitSection->blocks())
958 if (!AlreadyLiveBlocks.count(B))
959 InitSectionSymbols.insert(
960 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
963 if (!InitSectionSymbols.empty()) {
964 std::lock_guard<std::mutex> Lock(PluginMutex);
965 InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
968 return Error::success();
971 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
972 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
974 // If there's an ObjC imagine info then either
975 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
976 // this case we name and record it.
977 // OR
978 // (2) We already have a recorded __objc_imageinfo for this JITDylib,
979 // in which case we just verify it.
980 auto *ObjCImageInfo = G.findSectionByName(MachOObjCImageInfoSectionName);
981 if (!ObjCImageInfo)
982 return Error::success();
984 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
986 // Check that the section is not empty if present.
987 if (ObjCImageInfoBlocks.empty())
988 return make_error<StringError>("Empty " + MachOObjCImageInfoSectionName +
989 " section in " + G.getName(),
990 inconvertibleErrorCode());
992 // Check that there's only one block in the section.
993 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
994 return make_error<StringError>("Multiple blocks in " +
995 MachOObjCImageInfoSectionName +
996 " section in " + G.getName(),
997 inconvertibleErrorCode());
999 // Check that the __objc_imageinfo section is unreferenced.
1000 // FIXME: We could optimize this check if Symbols had a ref-count.
1001 for (auto &Sec : G.sections()) {
1002 if (&Sec != ObjCImageInfo)
1003 for (auto *B : Sec.blocks())
1004 for (auto &E : B->edges())
1005 if (E.getTarget().isDefined() &&
1006 &E.getTarget().getBlock().getSection() == ObjCImageInfo)
1007 return make_error<StringError>(MachOObjCImageInfoSectionName +
1008 " is referenced within file " +
1009 G.getName(),
1010 inconvertibleErrorCode());
1013 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
1014 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
1015 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
1016 auto Flags =
1017 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
1019 // Lock the mutex while we verify / update the ObjCImageInfos map.
1020 std::lock_guard<std::mutex> Lock(PluginMutex);
1022 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
1023 if (ObjCImageInfoItr != ObjCImageInfos.end()) {
1024 // We've already registered an __objc_imageinfo section. Verify the
1025 // content of this new section matches, then delete it.
1026 if (ObjCImageInfoItr->second.Version != Version)
1027 return make_error<StringError>(
1028 "ObjC version in " + G.getName() +
1029 " does not match first registered version",
1030 inconvertibleErrorCode());
1031 if (ObjCImageInfoItr->second.Flags != Flags)
1032 return make_error<StringError>("ObjC flags in " + G.getName() +
1033 " do not match first registered flags",
1034 inconvertibleErrorCode());
1036 // __objc_imageinfo is valid. Delete the block.
1037 for (auto *S : ObjCImageInfo->symbols())
1038 G.removeDefinedSymbol(*S);
1039 G.removeBlock(ObjCImageInfoBlock);
1040 } else {
1041 // We haven't registered an __objc_imageinfo section yet. Register and
1042 // move on. The section should already be marked no-dead-strip.
1043 G.addDefinedSymbol(ObjCImageInfoBlock, 0, ObjCImageInfoSymbolName,
1044 ObjCImageInfoBlock.getSize(), jitlink::Linkage::Strong,
1045 jitlink::Scope::Hidden, false, true);
1046 if (auto Err = MR.defineMaterializing(
1047 {{MR.getExecutionSession().intern(ObjCImageInfoSymbolName),
1048 JITSymbolFlags()}}))
1049 return Err;
1050 ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags};
1053 return Error::success();
1056 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1057 jitlink::LinkGraph &G, JITDylib &JD) {
1059 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
1060 for (auto *Sym : G.external_symbols())
1061 if (Sym->getName() == "__tlv_bootstrap") {
1062 Sym->setName("___orc_rt_macho_tlv_get_addr");
1063 break;
1066 // Store key in __thread_vars struct fields.
1067 if (auto *ThreadDataSec = G.findSectionByName(MachOThreadVarsSectionName)) {
1068 std::optional<uint64_t> Key;
1070 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1071 auto I = MP.JITDylibToPThreadKey.find(&JD);
1072 if (I != MP.JITDylibToPThreadKey.end())
1073 Key = I->second;
1076 if (!Key) {
1077 if (auto KeyOrErr = MP.createPThreadKey())
1078 Key = *KeyOrErr;
1079 else
1080 return KeyOrErr.takeError();
1083 uint64_t PlatformKeyBits =
1084 support::endian::byte_swap(*Key, G.getEndianness());
1086 for (auto *B : ThreadDataSec->blocks()) {
1087 if (B->getSize() != 3 * G.getPointerSize())
1088 return make_error<StringError>("__thread_vars block at " +
1089 formatv("{0:x}", B->getAddress()) +
1090 " has unexpected size",
1091 inconvertibleErrorCode());
1093 auto NewBlockContent = G.allocateBuffer(B->getSize());
1094 llvm::copy(B->getContent(), NewBlockContent.data());
1095 memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
1096 G.getPointerSize());
1097 B->setContent(NewBlockContent);
1101 // Transform any TLV edges into GOT edges.
1102 for (auto *B : G.blocks())
1103 for (auto &E : B->edges())
1104 if (E.getKind() ==
1105 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
1106 E.setKind(jitlink::x86_64::
1107 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
1109 return Error::success();
1112 std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>
1113 MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1114 jitlink::LinkGraph &G) {
1115 using namespace jitlink;
1117 UnwindSections US;
1119 // ScanSection records a section range and adds any executable blocks that
1120 // that section points to to the CodeBlocks vector.
1121 SmallVector<Block *> CodeBlocks;
1122 auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) {
1123 if (Sec.blocks().empty())
1124 return;
1125 SecRange = (*Sec.blocks().begin())->getRange();
1126 for (auto *B : Sec.blocks()) {
1127 auto R = B->getRange();
1128 SecRange.Start = std::min(SecRange.Start, R.Start);
1129 SecRange.End = std::max(SecRange.End, R.End);
1130 for (auto &E : B->edges()) {
1131 if (!E.getTarget().isDefined())
1132 continue;
1133 auto &TargetBlock = E.getTarget().getBlock();
1134 auto &TargetSection = TargetBlock.getSection();
1135 if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec)
1136 CodeBlocks.push_back(&TargetBlock);
1141 if (Section *EHFrameSec = G.findSectionByName(MachOEHFrameSectionName))
1142 ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection);
1144 if (Section *CUInfoSec =
1145 G.findSectionByName(MachOCompactUnwindInfoSectionName))
1146 ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection);
1148 // If we didn't find any pointed-to code-blocks then there's no need to
1149 // register any info.
1150 if (CodeBlocks.empty())
1151 return std::nullopt;
1153 // We have info to register. Sort the code blocks into address order and
1154 // build a list of contiguous address ranges covering them all.
1155 llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) {
1156 return LHS->getAddress() < RHS->getAddress();
1158 for (auto *B : CodeBlocks) {
1159 if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress())
1160 US.CodeRanges.push_back(B->getRange());
1161 else
1162 US.CodeRanges.back().End = B->getRange().End;
1165 LLVM_DEBUG({
1166 dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n"
1167 << " DWARF: ";
1168 if (US.DwarfSection.Start)
1169 dbgs() << US.DwarfSection << "\n";
1170 else
1171 dbgs() << "none\n";
1172 dbgs() << " Compact-unwind: ";
1173 if (US.CompactUnwindSection.Start)
1174 dbgs() << US.CompactUnwindSection << "\n";
1175 else
1176 dbgs() << "none\n"
1177 << "for code ranges:\n";
1178 for (auto &CR : US.CodeRanges)
1179 dbgs() << " " << CR << "\n";
1180 if (US.CodeRanges.size() >= G.sections_size())
1181 dbgs() << "WARNING: High number of discontiguous code ranges! "
1182 "Padding may be interfering with coalescing.\n";
1185 return US;
1188 Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1189 jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) {
1191 // Get a pointer to the thread data section if there is one. It will be used
1192 // below.
1193 jitlink::Section *ThreadDataSection =
1194 G.findSectionByName(MachOThreadDataSectionName);
1196 // Handle thread BSS section if there is one.
1197 if (auto *ThreadBSSSection = G.findSectionByName(MachOThreadBSSSectionName)) {
1198 // If there's already a thread data section in this graph then merge the
1199 // thread BSS section content into it, otherwise just treat the thread
1200 // BSS section as the thread data section.
1201 if (ThreadDataSection)
1202 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
1203 else
1204 ThreadDataSection = ThreadBSSSection;
1207 SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;
1209 // Collect data sections to register.
1210 StringRef DataSections[] = {MachODataDataSectionName,
1211 MachODataCommonSectionName,
1212 MachOEHFrameSectionName};
1213 for (auto &SecName : DataSections) {
1214 if (auto *Sec = G.findSectionByName(SecName)) {
1215 jitlink::SectionRange R(*Sec);
1216 if (!R.empty())
1217 MachOPlatformSecs.push_back({SecName, R.getRange()});
1221 // Having merged thread BSS (if present) and thread data (if present),
1222 // record the resulting section range.
1223 if (ThreadDataSection) {
1224 jitlink::SectionRange R(*ThreadDataSection);
1225 if (!R.empty())
1226 MachOPlatformSecs.push_back({MachOThreadDataSectionName, R.getRange()});
1229 // If any platform sections were found then add an allocation action to call
1230 // the registration function.
1231 StringRef PlatformSections[] = {MachOModInitFuncSectionName,
1232 ObjCRuntimeObjectSectionName};
1234 for (auto &SecName : PlatformSections) {
1235 auto *Sec = G.findSectionByName(SecName);
1236 if (!Sec)
1237 continue;
1238 jitlink::SectionRange R(*Sec);
1239 if (R.empty())
1240 continue;
1242 MachOPlatformSecs.push_back({SecName, R.getRange()});
1245 std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,
1246 ExecutorAddrRange>>
1247 UnwindInfo;
1248 if (auto UI = findUnwindSectionInfo(G))
1249 UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,
1250 UI->CompactUnwindSection);
1252 if (!MachOPlatformSecs.empty() || UnwindInfo) {
1253 ExecutorAddr HeaderAddr;
1255 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1256 auto I = MP.JITDylibToHeaderAddr.find(&JD);
1257 assert(I != MP.JITDylibToHeaderAddr.end() &&
1258 "Missing header for JITDylib");
1259 HeaderAddr = I->second;
1262 // Dump the scraped inits.
1263 LLVM_DEBUG({
1264 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
1265 for (auto &KV : MachOPlatformSecs)
1266 dbgs() << " " << KV.first << ": " << KV.second << "\n";
1269 using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<
1270 SPSExecutorAddr,
1271 SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>,
1272 SPSExecutorAddrRange, SPSExecutorAddrRange>>,
1273 SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;
1275 shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
1276 ? G.allocActions()
1277 : MP.Bootstrap.load()->DeferredAAs;
1279 allocActions.push_back(
1280 {cantFail(
1281 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1282 MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo,
1283 MachOPlatformSecs)),
1284 cantFail(
1285 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1286 MP.DeregisterObjectPlatformSections.Addr, HeaderAddr,
1287 UnwindInfo, MachOPlatformSecs))});
1290 return Error::success();
1293 Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
1294 jitlink::LinkGraph &G) {
1296 bool NeedTextSegment = false;
1297 size_t NumRuntimeSections = 0;
1299 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)
1300 if (G.findSectionByName(ObjCRuntimeSectionName))
1301 ++NumRuntimeSections;
1303 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1304 if (G.findSectionByName(ObjCRuntimeSectionName)) {
1305 ++NumRuntimeSections;
1306 NeedTextSegment = true;
1310 // Early out for no runtime sections.
1311 if (NumRuntimeSections == 0)
1312 return Error::success();
1314 // If there were any runtime sections then we need to add an __objc_imageinfo
1315 // section.
1316 ++NumRuntimeSections;
1318 size_t MachOSize = sizeof(MachO::mach_header_64) +
1319 (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +
1320 NumRuntimeSections * sizeof(MachO::section_64);
1322 auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,
1323 MemProt::Read | MemProt::Write);
1324 G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);
1326 return Error::success();
1329 Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
1330 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
1332 auto *ObjCRuntimeObjectSec =
1333 G.findSectionByName(ObjCRuntimeObjectSectionName);
1335 if (!ObjCRuntimeObjectSec)
1336 return Error::success();
1338 switch (G.getTargetTriple().getArch()) {
1339 case Triple::aarch64:
1340 case Triple::x86_64:
1341 // Supported.
1342 break;
1343 default:
1344 return make_error<StringError>("Unrecognized MachO arch in triple " +
1345 G.getTargetTriple().str(),
1346 inconvertibleErrorCode());
1349 auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();
1351 struct SecDesc {
1352 MachO::section_64 Sec;
1353 unique_function<void(size_t RecordOffset)> AddFixups;
1356 std::vector<SecDesc> TextSections, DataSections;
1357 auto AddSection = [&](SecDesc &SD, jitlink::Section &GraphSec) {
1358 jitlink::SectionRange SR(GraphSec);
1359 StringRef FQName = GraphSec.getName();
1360 memset(&SD.Sec, 0, sizeof(MachO::section_64));
1361 memcpy(SD.Sec.sectname, FQName.drop_front(7).data(), FQName.size() - 7);
1362 memcpy(SD.Sec.segname, FQName.data(), 6);
1363 SD.Sec.addr = SR.getStart() - SecBlock.getAddress();
1364 SD.Sec.size = SR.getSize();
1365 SD.Sec.flags = MachO::S_REGULAR;
1368 // Add the __objc_imageinfo section.
1370 DataSections.push_back({});
1371 auto &SD = DataSections.back();
1372 memset(&SD.Sec, 0, sizeof(SD.Sec));
1373 memcpy(SD.Sec.sectname, "__objc_imageinfo", 16);
1374 strcpy(SD.Sec.segname, "__DATA");
1375 SD.Sec.size = 8;
1376 SD.AddFixups = [&](size_t RecordOffset) {
1377 jitlink::Edge::Kind PointerEdge = jitlink::Edge::Invalid;
1378 switch (G.getTargetTriple().getArch()) {
1379 case Triple::aarch64:
1380 PointerEdge = jitlink::aarch64::Pointer64;
1381 break;
1382 case Triple::x86_64:
1383 PointerEdge = jitlink::x86_64::Pointer64;
1384 break;
1385 default:
1386 llvm_unreachable("Unsupported architecture");
1389 // Look for an existing __objc_imageinfo symbol.
1390 jitlink::Symbol *ObjCImageInfoSym = nullptr;
1391 for (auto *Sym : G.external_symbols())
1392 if (Sym->getName() == ObjCImageInfoSymbolName) {
1393 ObjCImageInfoSym = Sym;
1394 break;
1396 if (!ObjCImageInfoSym)
1397 for (auto *Sym : G.absolute_symbols())
1398 if (Sym->getName() == ObjCImageInfoSymbolName) {
1399 ObjCImageInfoSym = Sym;
1400 break;
1402 if (!ObjCImageInfoSym)
1403 for (auto *Sym : G.defined_symbols())
1404 if (Sym->hasName() && Sym->getName() == ObjCImageInfoSymbolName) {
1405 ObjCImageInfoSym = Sym;
1406 break;
1408 if (!ObjCImageInfoSym)
1409 ObjCImageInfoSym =
1410 &G.addExternalSymbol(ObjCImageInfoSymbolName, 8, false);
1412 SecBlock.addEdge(PointerEdge,
1413 RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec),
1414 *ObjCImageInfoSym, -SecBlock.getAddress().getValue());
1418 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {
1419 if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1420 DataSections.push_back({});
1421 AddSection(DataSections.back(), *GraphSec);
1425 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1426 if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1427 TextSections.push_back({});
1428 AddSection(TextSections.back(), *GraphSec);
1432 assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&
1433 "Unexpected number of blocks in runtime sections object");
1435 // Build the header struct up-front. This also gives us a chance to check
1436 // that the triple is supported, which we'll assume below.
1437 MachO::mach_header_64 Hdr;
1438 Hdr.magic = MachO::MH_MAGIC_64;
1439 switch (G.getTargetTriple().getArch()) {
1440 case Triple::aarch64:
1441 Hdr.cputype = MachO::CPU_TYPE_ARM64;
1442 Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
1443 break;
1444 case Triple::x86_64:
1445 Hdr.cputype = MachO::CPU_TYPE_X86_64;
1446 Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
1447 break;
1448 default:
1449 llvm_unreachable("Unsupported architecture");
1452 Hdr.filetype = MachO::MH_DYLIB;
1453 Hdr.ncmds = 1 + !TextSections.empty();
1454 Hdr.sizeofcmds =
1455 Hdr.ncmds * sizeof(MachO::segment_command_64) +
1456 (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64);
1457 Hdr.flags = 0;
1458 Hdr.reserved = 0;
1460 auto SecContent = SecBlock.getAlreadyMutableContent();
1461 char *P = SecContent.data();
1462 auto WriteMachOStruct = [&](auto S) {
1463 if (G.getEndianness() != llvm::endianness::native)
1464 MachO::swapStruct(S);
1465 memcpy(P, &S, sizeof(S));
1466 P += sizeof(S);
1469 auto WriteSegment = [&](StringRef Name, std::vector<SecDesc> &Secs) {
1470 MachO::segment_command_64 SegLC;
1471 memset(&SegLC, 0, sizeof(SegLC));
1472 memcpy(SegLC.segname, Name.data(), Name.size());
1473 SegLC.cmd = MachO::LC_SEGMENT_64;
1474 SegLC.cmdsize = sizeof(MachO::segment_command_64) +
1475 Secs.size() * sizeof(MachO::section_64);
1476 SegLC.nsects = Secs.size();
1477 WriteMachOStruct(SegLC);
1478 for (auto &SD : Secs) {
1479 if (SD.AddFixups)
1480 SD.AddFixups(P - SecContent.data());
1481 WriteMachOStruct(SD.Sec);
1485 WriteMachOStruct(Hdr);
1486 if (!TextSections.empty())
1487 WriteSegment("__TEXT", TextSections);
1488 if (!DataSections.empty())
1489 WriteSegment("__DATA", DataSections);
1491 assert(P == SecContent.end() && "Underflow writing ObjC runtime object");
1492 return Error::success();
1495 } // End namespace orc.
1496 } // End namespace llvm.