LLVM 18.0.0git
MachOPlatform.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
8
10
20#include "llvm/Support/Debug.h"
21#include <optional>
22
23#define DEBUG_TYPE "orc"
24
25using namespace llvm;
26using namespace llvm::orc;
27using namespace llvm::orc::shared;
28
29namespace llvm {
30namespace orc {
31namespace shared {
32
36
37template <>
39 MachOPlatform::MachOJITDylibDepInfo> {
40public:
41 static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
42 return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
43 }
44
45 static bool serialize(SPSOutputBuffer &OB,
47 return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
48 DDI.DepHeaders);
49 }
50
51 static bool deserialize(SPSInputBuffer &IB,
53 return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
54 DDI.DepHeaders);
55 }
56};
57
58} // namespace shared
59} // namespace orc
60} // namespace llvm
61
62namespace {
63
64std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
65 std::string Name) {
66 unsigned PointerSize;
68 const auto &TT = MOP.getExecutionSession().getTargetTriple();
69
70 switch (TT.getArch()) {
71 case Triple::aarch64:
72 case Triple::x86_64:
73 PointerSize = 8;
74 Endianness = support::endianness::little;
75 break;
76 default:
77 llvm_unreachable("Unrecognized architecture");
78 }
79
80 return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize,
81 Endianness,
83}
84
85// Generates a MachO header.
86class MachOHeaderMaterializationUnit : public MaterializationUnit {
87public:
88 MachOHeaderMaterializationUnit(MachOPlatform &MOP,
89 const SymbolStringPtr &HeaderStartSymbol)
90 : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)),
91 MOP(MOP) {}
92
93 StringRef getName() const override { return "MachOHeaderMU"; }
94
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));
99 }
100
101 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
102
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);
107
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);
116 }
117
118private:
119 struct HeaderSymbol {
120 const char *Name;
122 };
123
124 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
125 {"___mh_executable_header", 0}};
126
127 static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
128 jitlink::Section &HeaderSection) {
131 switch (G.getTargetTriple().getArch()) {
132 case Triple::aarch64:
135 break;
136 case Triple::x86_64:
139 break;
140 default:
141 llvm_unreachable("Unrecognized architecture");
142 }
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;
148
149 if (G.getEndianness() != support::endian::system_endianness())
151
152 auto HeaderContent = G.allocateContent(
153 ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
154
155 return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
156 0);
157 }
158
160 createHeaderInterface(MachOPlatform &MOP,
161 const SymbolStringPtr &HeaderStartSymbol) {
162 SymbolFlagsMap HeaderSymbolFlags;
163
164 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
165 for (auto &HS : AdditionalHeaderSymbols)
166 HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
168
169 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
170 HeaderStartSymbol);
171 }
172
173 MachOPlatform &MOP;
174};
175
176constexpr MachOHeaderMaterializationUnit::HeaderSymbol
177 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
178
179// Creates a Bootstrap-Complete LinkGraph to run deferred actions.
180class MachOPlatformCompleteBootstrapMaterializationUnit
181 : public MaterializationUnit {
182public:
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)
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) {}
198
199 StringRef getName() const override {
200 return "MachOPlatformCompleteBootstrap";
201 }
202
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);
212
213 // Reserve space for the stolen actions, plus two extras.
214 G->allocActions().reserve(DeferredAAs.size() + 2);
215
216 // 1. Bootstrap the platform support code.
217 G->allocActions().push_back(
219 cantFail(
220 WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
221
222 // 2. Register the platform JITDylib.
223 G->allocActions().push_back(
226 RegisterJITDylib, PlatformJDName, MachOHeaderAddr)),
228 DeregisterJITDylib, MachOHeaderAddr))});
229
230 // 3. Add the deferred actions to the graph.
231 std::move(DeferredAAs.begin(), DeferredAAs.end(),
232 std::back_inserter(G->allocActions()));
233
234 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
235 }
236
237 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
238
239private:
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;
249};
250
251static StringRef ObjCRuntimeObjectSectionsData[] = {
255
256static StringRef ObjCRuntimeObjectSectionsText[] = {
262
263static StringRef ObjCRuntimeObjectSectionName =
264 "__llvm_jitlink_ObjCRuntimeRegistrationObject";
265
266static StringRef ObjCImageInfoSymbolName =
267 "__llvm_jitlink_macho_objc_imageinfo";
268
269} // end anonymous namespace
270
271namespace llvm {
272namespace orc {
273
276 JITDylib &PlatformJD,
277 std::unique_ptr<DefinitionGenerator> OrcRuntime,
278 std::optional<SymbolAliasMap> RuntimeAliases) {
279
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(),
285
286 auto &EPC = ES.getExecutorProcessControl();
287
288 // Create default aliases if the caller didn't supply any.
289 if (!RuntimeAliases)
290 RuntimeAliases = standardPlatformAliases(ES);
291
292 // Define the aliases.
293 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
294 return std::move(Err);
295
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,
301 {ES.intern("___orc_rt_jit_dispatch_ctx"),
302 {EPC.getJITDispatchInfo().JITDispatchContext,
304 return std::move(Err);
305
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);
313}
314
317 JITDylib &PlatformJD, const char *OrcRuntimePath,
318 std::optional<SymbolAliasMap> RuntimeAliases) {
319
320 // Create a generator for the ORC runtime archive.
321 auto OrcRuntimeArchiveGenerator =
322 StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
323 if (!OrcRuntimeArchiveGenerator)
324 return OrcRuntimeArchiveGenerator.takeError();
325
326 return Create(ES, ObjLinkingLayer, PlatformJD,
327 std::move(*OrcRuntimeArchiveGenerator),
328 std::move(RuntimeAliases));
329}
330
332 if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
333 *this, MachOHeaderStartSymbol)))
334 return Err;
335
336 return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
337}
338
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);
347 }
348 JITDylibToPThreadKey.erase(&JD);
349 return Error::success();
350}
351
353 const MaterializationUnit &MU) {
354 auto &JD = RT.getJITDylib();
355 const auto &InitSym = MU.getInitializerSymbol();
356 if (!InitSym)
357 return Error::success();
358
359 RegisteredInitSymbols[&JD].add(InitSym,
361 LLVM_DEBUG({
362 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
363 << MU.getName() << "\n";
364 });
365 return Error::success();
366}
367
369 llvm_unreachable("Not supported yet");
370}
371
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),
379 }
380}
381
383 SymbolAliasMap Aliases;
384 addAliases(ES, Aliases, requiredCXXAliases());
386 return Aliases;
387}
388
391 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
392 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
393
394 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
395}
396
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"}};
407
409 StandardRuntimeUtilityAliases);
410}
411
412bool 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;
419 }
420}
421
422MachOPlatform::MachOPlatform(
423 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
424 JITDylib &PlatformJD,
425 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
426 : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) {
428 ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
429 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
430
431 BootstrapInfo BI;
432 Bootstrap = &BI;
433
434 // Bootstrap process -- here be phase-ordering dragons.
435 //
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.
448 //
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.
454 //
455 // The bootstrap steps are as follows:
456 //
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.
460 //
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.
468 //
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.
477 //
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.
483 //
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.
487
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;
494
495 // Step (2) Request runtime registration functions to trigger
496 // materialization..
497 if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
499 {PlatformBootstrap.Name, PlatformShutdown.Name,
500 RegisterJITDylib.Name, DeregisterJITDylib.Name,
501 RegisterObjectPlatformSections.Name,
502 DeregisterObjectPlatformSections.Name,
503 CreatePThreadKey.Name}))
504 .takeError()))
505 return;
506
507 // Step (3) Wait for any incidental linker work to complete.
508 {
509 std::unique_lock<std::mutex> Lock(BI.Mutex);
510 BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
511 Bootstrap = nullptr;
512 }
513
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(
525 std::move(BootstrapCompleteSymbol))
526 .takeError()))
527 return;
528
529 // (5) Associate runtime support functions.
530 if ((Err = associateRuntimeSupportFunctions()))
531 return;
532}
533
534Error MachOPlatform::associateRuntimeSupportFunctions() {
536
537 using PushInitializersSPSSig =
539 WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =
540 ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
541 this, &MachOPlatform::rt_pushInitializers);
542
543 using LookupSymbolSPSSig =
545 WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
546 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
547 &MachOPlatform::rt_lookupSymbol);
548
549 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
550}
551
552void MachOPlatform::pushInitializersLoop(
553 PushInitializersSendResultFn SendResult, JITDylibSP JD) {
556 SmallVector<JITDylib *, 16> Worklist({JD.get()});
557
558 ES.runSessionLocked([&]() {
559 while (!Worklist.empty()) {
560 // FIXME: Check for defunct dylibs.
561
562 auto DepJD = Worklist.back();
563 Worklist.pop_back();
564
565 // If we've already visited this JITDylib on this iteration then continue.
566 if (JDDepMap.count(DepJD))
567 continue;
568
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);
577 }
578 });
579
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);
585 }
586 }
587 });
588
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()) {
592
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.
598 HeaderAddrs.reserve(JDDepMap.size());
599 {
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;
605 }
606 }
607
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);
622 }
623 DIM.push_back(std::make_pair(H, std::move(DepInfo)));
624 }
625 SendResult(DIM);
626 return;
627 }
628
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);
636 },
637 ES, std::move(NewInitSymbols));
638}
639
640void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
641 ExecutorAddr JDHeaderAddr) {
642 JITDylibSP JD;
643 {
644 std::lock_guard<std::mutex> Lock(PlatformMutex);
645 auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
646 if (I != HeaderAddrToJITDylib.end())
647 JD = I->second;
648 }
649
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";
656 });
657
658 if (!JD) {
659 SendResult(make_error<StringError>("No JITDylib with header addr " +
660 formatv("{0:x}", JDHeaderAddr),
662 return;
663 }
664
665 pushInitializersLoop(std::move(SendResult), JD);
666}
667
668void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
669 ExecutorAddr Handle, StringRef SymbolName) {
670 LLVM_DEBUG({
671 dbgs() << "MachOPlatform::rt_lookupSymbol(\"" << Handle << "\")\n";
672 });
673
674 JITDylib *JD = nullptr;
675
676 {
677 std::lock_guard<std::mutex> Lock(PlatformMutex);
678 auto I = HeaderAddrToJITDylib.find(Handle);
679 if (I != HeaderAddrToJITDylib.end())
680 JD = I->second;
681 }
682
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),
688 return;
689 }
690
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());
702 }
703 }
704
705 private:
706 SendSymbolAddressFn SendResult;
707 };
708
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);
715}
716
717Expected<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",
723
725 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
726 CreatePThreadKey.Addr, Result))
727 return std::move(Err);
728 return Result;
729}
730
731void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
734
735 using namespace jitlink;
736
737 bool InBootstrapPhase =
738 &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap;
739
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);
746 });
747 }
748
749 // --- Handle Initializers ---
750 if (auto InitSymbol = MR.getInitializerSymbol()) {
751
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);
758 });
759 return;
760 }
761
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);
769 });
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); });
774 }
775
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);
782 });
783
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);
789 });
790
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); });
796}
797
799MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
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;
808 }
809 return SyntheticSymbolDependenciesMap();
810}
811
812Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart(
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();
818}
819
820Error 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}};
837
838 bool RegisterMachOHeader = false;
839
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",
848
849 if (Sym->getName() == *MP.MachOHeaderStartSymbol)
850 RegisterMachOHeader = true;
851
852 *RTSym.second = Sym->getAddress();
853 }
854 }
855 }
856
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;
865 }
866
867 return Error::success();
868}
869
870Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(
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();
880}
881
882Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
884 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
885 return Sym->getName() == *MP.MachOHeaderStartSymbol;
886 });
887 assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
888
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(
899 MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)),
901 MP.DeregisterJITDylib.Addr, HeaderAddr))});
902 return Error::success();
903}
904
905Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections(
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",
918 G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false,
919 true);
920
921 for (auto *B : ObjCImageInfoSec->blocks())
922 if (!B->edges_empty())
923 return make_error<StringError>("In " + G.getName() + ", " +
925 " contains references to symbols",
927 }
928
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;
938
939 // Skip non-init sections.
940 auto *InitSection = G.findSectionByName(InitSectionName);
941 if (!InitSection)
942 continue;
943
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);
953 }
954 }
955
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));
961 }
962
963 if (!InitSectionSymbols.empty()) {
964 std::lock_guard<std::mutex> Lock(PluginMutex);
965 InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
966 }
967
968 return Error::success();
969}
970
971Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
973
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();
983
984 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
985
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(),
991
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 " +
996 " section in " + G.getName(),
998
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(),
1011 }
1012
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());
1018
1019 // Lock the mutex while we verify / update the ObjCImageInfos map.
1020 std::lock_guard<std::mutex> Lock(PluginMutex);
1021
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",
1031 if (ObjCImageInfoItr->second.Flags != Flags)
1032 return make_error<StringError>("ObjC flags in " + G.getName() +
1033 " do not match first registered flags",
1035
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};
1051 }
1052
1053 return Error::success();
1054}
1055
1056Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1058
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;
1064 }
1065
1066 // Store key in __thread_vars struct fields.
1067 if (auto *ThreadDataSec = G.findSectionByName(MachOThreadVarsSectionName)) {
1068 std::optional<uint64_t> Key;
1069 {
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;
1074 }
1075
1076 if (!Key) {
1077 if (auto KeyOrErr = MP.createPThreadKey())
1078 Key = *KeyOrErr;
1079 else
1080 return KeyOrErr.takeError();
1081 }
1082
1083 uint64_t PlatformKeyBits =
1084 support::endian::byte_swap(*Key, G.getEndianness());
1085
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",
1092
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);
1098 }
1099 }
1100
1101 // Transform any TLV edges into GOT edges.
1102 for (auto *B : G.blocks())
1103 for (auto &E : B->edges())
1104 if (E.getKind() ==
1106 E.setKind(jitlink::x86_64::
1107 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
1108
1109 return Error::success();
1110}
1111
1112std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>
1113MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1115 using namespace jitlink;
1116
1117 UnwindSections US;
1118
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);
1137 }
1138 }
1139 };
1140
1141 if (Section *EHFrameSec = G.findSectionByName(MachOEHFrameSectionName))
1142 ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection);
1143
1144 if (Section *CUInfoSec =
1145 G.findSectionByName(MachOCompactUnwindInfoSectionName))
1146 ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection);
1147
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;
1152
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();
1157 });
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;
1163 }
1164
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";
1183 });
1184
1185 return US;
1186}
1187
1188Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1189 jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) {
1190
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);
1195
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;
1205 }
1206
1208
1209 // Collect data sections to register.
1210 StringRef DataSections[] = {MachODataDataSectionName,
1213 for (auto &SecName : DataSections) {
1214 if (auto *Sec = G.findSectionByName(SecName)) {
1216 if (!R.empty())
1217 MachOPlatformSecs.push_back({SecName, R.getRange()});
1218 }
1219 }
1220
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()});
1227 }
1228
1229 // If any platform sections were found then add an allocation action to call
1230 // the registration function.
1231 StringRef PlatformSections[] = {MachOModInitFuncSectionName,
1232 ObjCRuntimeObjectSectionName};
1233
1234 for (auto &SecName : PlatformSections) {
1235 auto *Sec = G.findSectionByName(SecName);
1236 if (!Sec)
1237 continue;
1239 if (R.empty())
1240 continue;
1241
1242 MachOPlatformSecs.push_back({SecName, R.getRange()});
1243 }
1244
1245 std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,
1247 UnwindInfo;
1248 if (auto UI = findUnwindSectionInfo(G))
1249 UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,
1250 UI->CompactUnwindSection);
1251
1252 if (!MachOPlatformSecs.empty() || UnwindInfo) {
1253 ExecutorAddr HeaderAddr;
1254 {
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;
1260 }
1261
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";
1267 });
1268
1269 using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<
1274
1275 shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
1276 ? G.allocActions()
1277 : MP.Bootstrap.load()->DeferredAAs;
1278
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))});
1288 }
1289
1290 return Error::success();
1291}
1292
1293Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
1295
1296 bool NeedTextSegment = false;
1297 size_t NumRuntimeSections = 0;
1298
1299 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)
1300 if (G.findSectionByName(ObjCRuntimeSectionName))
1301 ++NumRuntimeSections;
1302
1303 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1304 if (G.findSectionByName(ObjCRuntimeSectionName)) {
1305 ++NumRuntimeSections;
1306 NeedTextSegment = true;
1307 }
1308 }
1309
1310 // Early out for no runtime sections.
1311 if (NumRuntimeSections == 0)
1312 return Error::success();
1313
1314 // If there were any runtime sections then we need to add an __objc_imageinfo
1315 // section.
1316 ++NumRuntimeSections;
1317
1318 size_t MachOSize = sizeof(MachO::mach_header_64) +
1319 (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +
1320 NumRuntimeSections * sizeof(MachO::section_64);
1321
1322 auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,
1323 MemProt::Read | MemProt::Write);
1324 G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);
1325
1326 return Error::success();
1327}
1328
1329Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
1331
1332 auto *ObjCRuntimeObjectSec =
1333 G.findSectionByName(ObjCRuntimeObjectSectionName);
1334
1335 if (!ObjCRuntimeObjectSec)
1336 return Error::success();
1337
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(),
1347 }
1348
1349 auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();
1350
1351 struct SecDesc {
1353 unique_function<void(size_t RecordOffset)> AddFixups;
1354 };
1355
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;
1366 };
1367
1368 // Add the __objc_imageinfo section.
1369 {
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) {
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");
1387 }
1388
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;
1395 }
1396 if (!ObjCImageInfoSym)
1397 for (auto *Sym : G.absolute_symbols())
1398 if (Sym->getName() == ObjCImageInfoSymbolName) {
1399 ObjCImageInfoSym = Sym;
1400 break;
1401 }
1402 if (!ObjCImageInfoSym)
1403 for (auto *Sym : G.defined_symbols())
1404 if (Sym->hasName() && Sym->getName() == ObjCImageInfoSymbolName) {
1405 ObjCImageInfoSym = Sym;
1406 break;
1407 }
1408 if (!ObjCImageInfoSym)
1409 ObjCImageInfoSym =
1410 &G.addExternalSymbol(ObjCImageInfoSymbolName, 8, false);
1411
1412 SecBlock.addEdge(PointerEdge,
1413 RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec),
1414 *ObjCImageInfoSym, -SecBlock.getAddress().getValue());
1415 };
1416 }
1417
1418 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {
1419 if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1420 DataSections.push_back({});
1421 AddSection(DataSections.back(), *GraphSec);
1422 }
1423 }
1424
1425 for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1426 if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1427 TextSections.push_back({});
1428 AddSection(TextSections.back(), *GraphSec);
1429 }
1430 }
1431
1432 assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&
1433 "Unexpected number of blocks in runtime sections object");
1434
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.
1439 switch (G.getTargetTriple().getArch()) {
1440 case Triple::aarch64:
1443 break;
1444 case Triple::x86_64:
1447 break;
1448 default:
1449 llvm_unreachable("Unsupported architecture");
1450 }
1451
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;
1459
1460 auto SecContent = SecBlock.getAlreadyMutableContent();
1461 char *P = SecContent.data();
1462 auto WriteMachOStruct = [&](auto S) {
1463 if (G.getEndianness() != support::endian::system_endianness())
1465 memcpy(P, &S, sizeof(S));
1466 P += sizeof(S);
1467 };
1468
1469 auto WriteSegment = [&](StringRef Name, std::vector<SecDesc> &Secs) {
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);
1482 }
1483 };
1484
1485 WriteMachOStruct(Hdr);
1486 if (!TextSections.empty())
1487 WriteSegment("__TEXT", TextSections);
1488 if (!DataSections.empty())
1489 WriteSegment("__DATA", DataSections);
1490
1491 assert(P == SecContent.end() && "Underflow writing ObjC runtime object");
1492 return Error::success();
1493}
1494
1495} // End namespace orc.
1496} // End namespace llvm.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_LIKELY(EXPR)
Definition: Compiler.h:221
#define LLVM_DEBUG(X)
Definition: Debug.h:101
std::string Name
RelaxConfig Config
Definition: ELF_riscv.cpp:495
Symbol * Sym
Definition: ELF_riscv.cpp:468
#define _
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
#define H(x, y, z)
Definition: MD5.cpp:57
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Value * RHS
Value * LHS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:155
unsigned size() const
Definition: DenseMap.h:99
bool empty() const
Definition: DenseMap.h:98
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:151
iterator end()
Definition: DenseMap.h:84
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again.
Definition: DenseMap.h:103
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Helper for Errors used as out-parameters.
Definition: Error.h:1102
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
bool empty() const
Definition: SmallVector.h:94
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:613
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
const std::string & str() const
Definition: Triple.h:414
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition: DenseSet.h:97
An ExecutionSession represents a running JIT program.
Definition: Core.h:1389
ExecutorProcessControl & getExecutorProcessControl()
Get the ExecutorProcessControl object associated with this ExecutionSession.
Definition: Core.h:1432
const Triple & getTargetTriple() const
Return the triple for the executor.
Definition: Core.h:1435
Error callSPSWrapper(ExecutorAddr WrapperFnAddr, WrapperCallArgTs &&...WrapperCallArgs)
Run a wrapper function using SPS to serialize the arguments and deserialize the results.
Definition: Core.h:1652
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
Definition: Core.h:1446
static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H)
Wrap a handler that takes concrete argument types (and a sender for a concrete return type) to produc...
Definition: Core.h:1666
void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, SymbolLookupSet Symbols, SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete, RegisterDependenciesFunction RegisterDependencies)
Search the given JITDylibs for the given symbols.
Definition: Core.cpp:2121
Error registerJITDispatchHandlers(JITDylib &JD, JITDispatchHandlerAssociationMap WFs)
For each tag symbol name, associate the corresponding AsyncHandlerWrapperFunction with the address of...
Definition: Core.cpp:2230
decltype(auto) runSessionLocked(Func &&F)
Run the given lambda with the session mutex locked.
Definition: Core.h:1456
Represents an address in the executor process.
Represents a JIT'd dynamic library.
Definition: Core.h:958
Error define(std::unique_ptr< MaterializationUnitType > &&MU, ResourceTrackerSP RT=nullptr)
Define all symbols provided by the materialization unit to be part of this JITDylib.
Definition: Core.h:1849
GeneratorT & addGenerator(std::unique_ptr< GeneratorT > DefGenerator)
Adds a definition generator to this JITDylib and returns a referenece to it.
Definition: Core.h:1832
Mediates between MachO initialization and ExecutionSession state.
Definition: MachOPlatform.h:30
ObjectLinkingLayer & getObjectLinkingLayer() const
Definition: MachOPlatform.h:92
Error teardownJITDylib(JITDylib &JD) override
This method will be called outside the session lock each time a JITDylib is removed to allow the Plat...
Error setupJITDylib(JITDylib &JD) override
This method will be called outside the session lock each time a JITDylib is created (unless it is cre...
static ArrayRef< std::pair< const char *, const char * > > standardRuntimeUtilityAliases()
Returns the array of standard runtime utility aliases for MachO.
Error notifyAdding(ResourceTracker &RT, const MaterializationUnit &MU) override
This method will be called under the ExecutionSession lock each time a MaterializationUnit is added t...
static Expected< std::unique_ptr< MachOPlatform > > Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, std::unique_ptr< DefinitionGenerator > OrcRuntime, std::optional< SymbolAliasMap > RuntimeAliases=std::nullopt)
Try to create a MachOPlatform instance, adding the ORC runtime to the given JITDylib.
static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES)
Returns an AliasMap containing the default aliases for the MachOPlatform.
ExecutionSession & getExecutionSession() const
Definition: MachOPlatform.h:91
Error notifyRemoving(ResourceTracker &RT) override
This method will be called under the ExecutionSession lock when a ResourceTracker is removed.
static ArrayRef< std::pair< const char *, const char * > > requiredCXXAliases()
Returns the array of required CXX aliases.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition: Core.h:527
Error defineMaterializing(SymbolFlagsMap SymbolFlags)
Attempt to claim responsibility for new definitions.
Definition: Core.h:1978
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization pseudo-symbol, if any.
Definition: Core.h:563
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
Definition: Core.h:549
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
Definition: Core.h:662
virtual StringRef getName() const =0
Return the name of this materialization unit.
virtual void materialize(std::unique_ptr< MaterializationResponsibility > R)=0
Implementations of this method should materialize all symbols in the materialzation unit,...
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization symbol for this MaterializationUnit (if any).
Definition: Core.h:695
An ObjectLayer implementation built on JITLink.
ObjectLinkingLayer & addPlugin(std::unique_ptr< Plugin > P)
Add a pass-config modifier.
void emit(std::unique_ptr< MaterializationResponsibility > R, std::unique_ptr< MemoryBuffer > O) override
Emit an object file.
API to remove / transfer ownership of JIT resources.
Definition: Core.h:56
JITDylib & getJITDylib() const
Return the JITDylib targeted by this tracker.
Definition: Core.h:71
static Expected< std::unique_ptr< StaticLibraryDefinitionGenerator > > Load(ObjectLayer &L, const char *FileName, GetObjectFileInterface GetObjFileInterface=GetObjectFileInterface())
Try to create a StaticLibraryDefinitionGenerator from the given path.
A set of symbols to look up, each associated with a SymbolLookupFlags value.
Definition: Core.h:183
Pointer to a pooled string representing a symbol name.
A utility class for serializing to a blob from a variadic list.
SPS tag type for expecteds, which are either a T or a string representing an error.
Input char buffer with underflow check.
Output char buffer with overflow check.
static bool serialize(SPSOutputBuffer &OB, const MachOPlatform::MachOJITDylibDepInfo &DDI)
static bool deserialize(SPSInputBuffer &IB, MachOPlatform::MachOJITDylibDepInfo &DDI)
Specialize to describe how to serialize/deserialize to/from the given concrete type.
static Expected< WrapperFunctionCall > Create(ExecutorAddr FnAddr, const ArgTs &...Args)
Create a WrapperFunctionCall using the given SPS serializer to serialize the arguments.
unique_function is a type-erasing functor similar to std::function.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
Key
PAL metadata keys.
const uint64_t Version
Definition: InstrProf.h:1021
@ CPU_SUBTYPE_ARM64_ALL
Definition: MachO.h:1647
@ MH_DYLIB
Definition: MachO.h:48
@ MH_MAGIC_64
Definition: MachO.h:32
@ S_REGULAR
S_REGULAR - Regular section.
Definition: MachO.h:127
void swapStruct(fat_header &mh)
Definition: MachO.h:1146
@ CPU_SUBTYPE_X86_64_ALL
Definition: MachO.h:1617
@ CPU_TYPE_ARM64
Definition: MachO.h:1576
@ CPU_TYPE_X86_64
Definition: MachO.h:1572
constexpr support::endianness Endianness
The endianness of all multi-byte encoded values in MessagePack.
Definition: MsgPack.h:24
SPSTuple< SPSExecutorAddr, SPSExecutorAddr > SPSExecutorAddrRange
std::vector< AllocActionCallPair > AllocActions
A vector of allocation actions to be run for this allocation.
StringRef MachOSwift5EntrySectionName
StringRef MachOThreadBSSSectionName
StringRef MachOThreadVarsSectionName
JITDylibSearchOrder makeJITDylibSearchOrder(ArrayRef< JITDylib * > JDs, JITDylibLookupFlags Flags=JITDylibLookupFlags::MatchExportedSymbolsOnly)
Convenience function for creating a search order from an ArrayRef of JITDylib*, all with the same fla...
Definition: Core.h:166
StringRef MachOCompactUnwindInfoSectionName
std::unique_ptr< ReExportsMaterializationUnit > symbolAliases(SymbolAliasMap Aliases)
Create a ReExportsMaterializationUnit with the given aliases.
Definition: Core.h:806
std::unique_ptr< AbsoluteSymbolsMaterializationUnit > absoluteSymbols(SymbolMap Symbols)
Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
Definition: Core.h:760
StringRef MachOSwift5ProtosSectionName
StringRef MachOEHFrameSectionName
StringRef MachOModInitFuncSectionName
StringRef MachOInitSectionNames[19]
StringRef MachOObjCConstSectionName
StringRef MachODataDataSectionName
StringRef MachOSwift5ProtoSectionName
static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, ArrayRef< std::pair< const char *, const char * > > AL)
StringRef MachOObjCCatListSectionName
StringRef MachOObjCClassRefsSectionName
StringRef MachOObjCDataSectionName
StringRef MachOObjCClassNameSectionName
StringRef MachOObjCMethNameSectionName
StringRef MachOObjCClassListSectionName
StringRef MachOObjCSelRefsSectionName
StringRef MachOSwift5FieldMetadataSectionName
StringRef MachOObjCMethTypeSectionName
StringRef MachOSwift5TypesSectionName
StringRef MachOObjCImageInfoSectionName
RegisterDependenciesFunction NoDependenciesToRegister
This can be used as the value for a RegisterDependenciesFunction if there are no dependants to regist...
Definition: Core.cpp:36
StringRef MachOThreadDataSectionName
StringRef MachODataCommonSectionName
StringRef MachOSwift5TypeRefSectionName
value_type byte_swap(value_type value, endianness endian)
Definition: Endian.h:49
uint32_t read32(const void *P, endianness E)
Definition: Endian.h:359
constexpr endianness system_endianness()
Definition: Endian.h:44
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:90
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1652
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:749
OutputIt copy(R &&Range, OutputIt Out)
Definition: STLExtras.h:1829
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1854
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1754
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
Represents an address range in the exceutor process.