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
9 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
10
11 #include "llvm/BinaryFormat/MachO.h"
12 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
13 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
14 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
15 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
16 #include "llvm/Support/BinaryByteStream.h"
17 #include "llvm/Support/Debug.h"
18 #include <optional>
19
20 #define DEBUG_TYPE "orc"
21
22 using namespace llvm;
23 using namespace llvm::orc;
24 using namespace llvm::orc::shared;
25
26 namespace llvm {
27 namespace orc {
28 namespace shared {
29
30 using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
31 using SPSMachOJITDylibDepInfoMap =
32 SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
33
34 template <>
35 class SPSSerializationTraits<SPSMachOJITDylibDepInfo,
36 MachOPlatform::MachOJITDylibDepInfo> {
37 public:
size(const MachOPlatform::MachOJITDylibDepInfo & DDI)38 static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
39 return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
40 }
41
serialize(SPSOutputBuffer & OB,const MachOPlatform::MachOJITDylibDepInfo & DDI)42 static bool serialize(SPSOutputBuffer &OB,
43 const MachOPlatform::MachOJITDylibDepInfo &DDI) {
44 return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
45 DDI.DepHeaders);
46 }
47
deserialize(SPSInputBuffer & IB,MachOPlatform::MachOJITDylibDepInfo & DDI)48 static bool deserialize(SPSInputBuffer &IB,
49 MachOPlatform::MachOJITDylibDepInfo &DDI) {
50 return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
51 DDI.DepHeaders);
52 }
53 };
54
55 } // namespace shared
56 } // namespace orc
57 } // namespace llvm
58
59 namespace {
60
createPlatformGraph(MachOPlatform & MOP,std::string Name)61 std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
62 std::string Name) {
63 unsigned PointerSize;
64 support::endianness Endianness;
65 const auto &TT =
66 MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
67
68 switch (TT.getArch()) {
69 case Triple::aarch64:
70 case Triple::x86_64:
71 PointerSize = 8;
72 Endianness = support::endianness::little;
73 break;
74 default:
75 llvm_unreachable("Unrecognized architecture");
76 }
77
78 return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize,
79 Endianness,
80 jitlink::getGenericEdgeKindName);
81 }
82
83 // Generates a MachO header.
84 class MachOHeaderMaterializationUnit : public MaterializationUnit {
85 public:
MachOHeaderMaterializationUnit(MachOPlatform & MOP,const SymbolStringPtr & HeaderStartSymbol)86 MachOHeaderMaterializationUnit(MachOPlatform &MOP,
87 const SymbolStringPtr &HeaderStartSymbol)
88 : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)),
89 MOP(MOP) {}
90
getName() const91 StringRef getName() const override { return "MachOHeaderMU"; }
92
materialize(std::unique_ptr<MaterializationResponsibility> R)93 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
94 auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");
95 addMachOHeader(*G, MOP, R->getInitializerSymbol());
96 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
97 }
98
discard(const JITDylib & JD,const SymbolStringPtr & Sym)99 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
100
addMachOHeader(jitlink::LinkGraph & G,MachOPlatform & MOP,const SymbolStringPtr & InitializerSymbol)101 static void addMachOHeader(jitlink::LinkGraph &G, MachOPlatform &MOP,
102 const SymbolStringPtr &InitializerSymbol) {
103 auto &HeaderSection = G.createSection("__header", MemProt::Read);
104 auto &HeaderBlock = createHeaderBlock(G, HeaderSection);
105
106 // Init symbol is header-start symbol.
107 G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol,
108 HeaderBlock.getSize(), jitlink::Linkage::Strong,
109 jitlink::Scope::Default, false, true);
110 for (auto &HS : AdditionalHeaderSymbols)
111 G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),
112 jitlink::Linkage::Strong, jitlink::Scope::Default,
113 false, true);
114 }
115
116 private:
117 struct HeaderSymbol {
118 const char *Name;
119 uint64_t Offset;
120 };
121
122 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
123 {"___mh_executable_header", 0}};
124
createHeaderBlock(jitlink::LinkGraph & G,jitlink::Section & HeaderSection)125 static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
126 jitlink::Section &HeaderSection) {
127 MachO::mach_header_64 Hdr;
128 Hdr.magic = MachO::MH_MAGIC_64;
129 switch (G.getTargetTriple().getArch()) {
130 case Triple::aarch64:
131 Hdr.cputype = MachO::CPU_TYPE_ARM64;
132 Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
133 break;
134 case Triple::x86_64:
135 Hdr.cputype = MachO::CPU_TYPE_X86_64;
136 Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
137 break;
138 default:
139 llvm_unreachable("Unrecognized architecture");
140 }
141 Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
142 Hdr.ncmds = 0;
143 Hdr.sizeofcmds = 0;
144 Hdr.flags = 0;
145 Hdr.reserved = 0;
146
147 if (G.getEndianness() != support::endian::system_endianness())
148 MachO::swapStruct(Hdr);
149
150 auto HeaderContent = G.allocateString(
151 StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
152
153 return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
154 0);
155 }
156
157 static MaterializationUnit::Interface
createHeaderInterface(MachOPlatform & MOP,const SymbolStringPtr & HeaderStartSymbol)158 createHeaderInterface(MachOPlatform &MOP,
159 const SymbolStringPtr &HeaderStartSymbol) {
160 SymbolFlagsMap HeaderSymbolFlags;
161
162 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
163 for (auto &HS : AdditionalHeaderSymbols)
164 HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
165 JITSymbolFlags::Exported;
166
167 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
168 HeaderStartSymbol);
169 }
170
171 MachOPlatform &MOP;
172 };
173
174 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
175 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
176
177 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
178 class MachOPlatformCompleteBootstrapMaterializationUnit
179 : public MaterializationUnit {
180 public:
MachOPlatformCompleteBootstrapMaterializationUnit(MachOPlatform & MOP,StringRef PlatformJDName,SymbolStringPtr CompleteBootstrapSymbol,shared::AllocActions DeferredAAs,ExecutorAddr PlatformBootstrap,ExecutorAddr PlatformShutdown,ExecutorAddr RegisterJITDylib,ExecutorAddr DeregisterJITDylib,ExecutorAddr MachOHeaderAddr)181 MachOPlatformCompleteBootstrapMaterializationUnit(
182 MachOPlatform &MOP, StringRef PlatformJDName,
183 SymbolStringPtr CompleteBootstrapSymbol, shared::AllocActions DeferredAAs,
184 ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown,
185 ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib,
186 ExecutorAddr MachOHeaderAddr)
187 : MaterializationUnit(
188 {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),
189 MOP(MOP), PlatformJDName(PlatformJDName),
190 CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),
191 DeferredAAs(std::move(DeferredAAs)),
192 PlatformBootstrap(PlatformBootstrap),
193 PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),
194 DeregisterJITDylib(DeregisterJITDylib),
195 MachOHeaderAddr(MachOHeaderAddr) {}
196
getName() const197 StringRef getName() const override {
198 return "MachOPlatformCompleteBootstrap";
199 }
200
materialize(std::unique_ptr<MaterializationResponsibility> R)201 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
202 using namespace jitlink;
203 auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>");
204 auto &PlaceholderSection =
205 G->createSection("__orc_rt_cplt_bs", MemProt::Read);
206 auto &PlaceholderBlock =
207 G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0);
208 G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1,
209 Linkage::Strong, Scope::Hidden, false, true);
210
211 // Reserve space for the stolen actions, plus two extras.
212 G->allocActions().reserve(DeferredAAs.size() + 2);
213
214 // 1. Bootstrap the platform support code.
215 G->allocActions().push_back(
216 {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)),
217 cantFail(
218 WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
219
220 // 2. Register the platform JITDylib.
221 G->allocActions().push_back(
222 {cantFail(WrapperFunctionCall::Create<
223 SPSArgList<SPSString, SPSExecutorAddr>>(
224 RegisterJITDylib, PlatformJDName, MachOHeaderAddr)),
225 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
226 DeregisterJITDylib, MachOHeaderAddr))});
227
228 // 3. Add the deferred actions to the graph.
229 std::move(DeferredAAs.begin(), DeferredAAs.end(),
230 std::back_inserter(G->allocActions()));
231
232 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
233 }
234
discard(const JITDylib & JD,const SymbolStringPtr & Sym)235 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
236
237 private:
238 MachOPlatform &MOP;
239 StringRef PlatformJDName;
240 SymbolStringPtr CompleteBootstrapSymbol;
241 shared::AllocActions DeferredAAs;
242 ExecutorAddr PlatformBootstrap;
243 ExecutorAddr PlatformShutdown;
244 ExecutorAddr RegisterJITDylib;
245 ExecutorAddr DeregisterJITDylib;
246 ExecutorAddr MachOHeaderAddr;
247 };
248
249 StringRef DataCommonSectionName = "__DATA,__common";
250 StringRef DataDataSectionName = "__DATA,__data";
251 StringRef EHFrameSectionName = "__TEXT,__eh_frame";
252 StringRef CompactUnwindInfoSectionName = "__TEXT,__unwind_info";
253 StringRef ModInitFuncSectionName = "__DATA,__mod_init_func";
254 StringRef ObjCClassListSectionName = "__DATA,__objc_classlist";
255 StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info";
256 StringRef ObjCSelRefsSectionName = "__DATA,__objc_selrefs";
257 StringRef Swift5ProtoSectionName = "__TEXT,__swift5_proto";
258 StringRef Swift5ProtosSectionName = "__TEXT,__swift5_protos";
259 StringRef Swift5TypesSectionName = "__TEXT,__swift5_types";
260 StringRef ThreadBSSSectionName = "__DATA,__thread_bss";
261 StringRef ThreadDataSectionName = "__DATA,__thread_data";
262 StringRef ThreadVarsSectionName = "__DATA,__thread_vars";
263
264 StringRef InitSectionNames[] = {
265 ModInitFuncSectionName, ObjCSelRefsSectionName, ObjCClassListSectionName,
266 Swift5ProtosSectionName, Swift5ProtoSectionName, Swift5TypesSectionName};
267
268 } // end anonymous namespace
269
270 namespace llvm {
271 namespace orc {
272
273 Expected<std::unique_ptr<MachOPlatform>>
Create(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,const char * OrcRuntimePath,std::optional<SymbolAliasMap> RuntimeAliases)274 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
275 JITDylib &PlatformJD, const char *OrcRuntimePath,
276 std::optional<SymbolAliasMap> RuntimeAliases) {
277
278 auto &EPC = ES.getExecutorProcessControl();
279
280 // If the target is not supported then bail out immediately.
281 if (!supportedTarget(EPC.getTargetTriple()))
282 return make_error<StringError>("Unsupported MachOPlatform triple: " +
283 EPC.getTargetTriple().str(),
284 inconvertibleErrorCode());
285
286 // Create default aliases if the caller didn't supply any.
287 if (!RuntimeAliases)
288 RuntimeAliases = standardPlatformAliases(ES);
289
290 // Define the aliases.
291 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
292 return std::move(Err);
293
294 // Add JIT-dispatch function support symbols.
295 if (auto Err = PlatformJD.define(absoluteSymbols(
296 {{ES.intern("___orc_rt_jit_dispatch"),
297 {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
298 JITSymbolFlags::Exported}},
299 {ES.intern("___orc_rt_jit_dispatch_ctx"),
300 {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
301 JITSymbolFlags::Exported}}})))
302 return std::move(Err);
303
304 // Create a generator for the ORC runtime archive.
305 auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
306 ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
307 if (!OrcRuntimeArchiveGenerator)
308 return OrcRuntimeArchiveGenerator.takeError();
309
310 // Create the instance.
311 Error Err = Error::success();
312 auto P = std::unique_ptr<MachOPlatform>(
313 new MachOPlatform(ES, ObjLinkingLayer, PlatformJD,
314 std::move(*OrcRuntimeArchiveGenerator), Err));
315 if (Err)
316 return std::move(Err);
317 return std::move(P);
318 }
319
setupJITDylib(JITDylib & JD)320 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
321 if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
322 *this, MachOHeaderStartSymbol)))
323 return Err;
324
325 return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
326 }
327
teardownJITDylib(JITDylib & JD)328 Error MachOPlatform::teardownJITDylib(JITDylib &JD) {
329 std::lock_guard<std::mutex> Lock(PlatformMutex);
330 auto I = JITDylibToHeaderAddr.find(&JD);
331 if (I != JITDylibToHeaderAddr.end()) {
332 assert(HeaderAddrToJITDylib.count(I->second) &&
333 "HeaderAddrToJITDylib missing entry");
334 HeaderAddrToJITDylib.erase(I->second);
335 JITDylibToHeaderAddr.erase(I);
336 }
337 JITDylibToPThreadKey.erase(&JD);
338 return Error::success();
339 }
340
notifyAdding(ResourceTracker & RT,const MaterializationUnit & MU)341 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
342 const MaterializationUnit &MU) {
343 auto &JD = RT.getJITDylib();
344 const auto &InitSym = MU.getInitializerSymbol();
345 if (!InitSym)
346 return Error::success();
347
348 RegisteredInitSymbols[&JD].add(InitSym,
349 SymbolLookupFlags::WeaklyReferencedSymbol);
350 LLVM_DEBUG({
351 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
352 << MU.getName() << "\n";
353 });
354 return Error::success();
355 }
356
notifyRemoving(ResourceTracker & RT)357 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
358 llvm_unreachable("Not supported yet");
359 }
360
addAliases(ExecutionSession & ES,SymbolAliasMap & Aliases,ArrayRef<std::pair<const char *,const char * >> AL)361 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
362 ArrayRef<std::pair<const char *, const char *>> AL) {
363 for (auto &KV : AL) {
364 auto AliasName = ES.intern(KV.first);
365 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
366 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
367 JITSymbolFlags::Exported};
368 }
369 }
370
standardPlatformAliases(ExecutionSession & ES)371 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
372 SymbolAliasMap Aliases;
373 addAliases(ES, Aliases, requiredCXXAliases());
374 addAliases(ES, Aliases, standardRuntimeUtilityAliases());
375 return Aliases;
376 }
377
378 ArrayRef<std::pair<const char *, const char *>>
requiredCXXAliases()379 MachOPlatform::requiredCXXAliases() {
380 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
381 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
382
383 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
384 }
385
386 ArrayRef<std::pair<const char *, const char *>>
standardRuntimeUtilityAliases()387 MachOPlatform::standardRuntimeUtilityAliases() {
388 static const std::pair<const char *, const char *>
389 StandardRuntimeUtilityAliases[] = {
390 {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
391 {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
392 {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
393 {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
394 {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
395 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
396
397 return ArrayRef<std::pair<const char *, const char *>>(
398 StandardRuntimeUtilityAliases);
399 }
400
isInitializerSection(StringRef SegName,StringRef SectName)401 bool MachOPlatform::isInitializerSection(StringRef SegName,
402 StringRef SectName) {
403 for (auto &Name : InitSectionNames) {
404 if (Name.startswith(SegName) && Name.substr(7) == SectName)
405 return true;
406 }
407 return false;
408 }
409
supportedTarget(const Triple & TT)410 bool MachOPlatform::supportedTarget(const Triple &TT) {
411 switch (TT.getArch()) {
412 case Triple::aarch64:
413 case Triple::x86_64:
414 return true;
415 default:
416 return false;
417 }
418 }
419
MachOPlatform(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,Error & Err)420 MachOPlatform::MachOPlatform(
421 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
422 JITDylib &PlatformJD,
423 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
424 : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) {
425 ErrorAsOutParameter _(&Err);
426 ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
427 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
428
429 BootstrapInfo BI;
430 Bootstrap = &BI;
431
432 // Bootstrap process -- here be phase-ordering dragons.
433 //
434 // The MachOPlatform class uses allocation actions to register metadata
435 // sections with the ORC runtime, however the runtime contains metadata
436 // registration functions that have their own metadata that they need to
437 // register (e.g. the frame-info registration functions have frame-info).
438 // We can't use an ordinary lookup to find these registration functions
439 // because their address is needed during the link of the containing graph
440 // itself (to build the allocation actions that will call the registration
441 // functions). Further complicating the situation (a) the graph containing
442 // the registration functions is allowed to depend on other graphs (e.g. the
443 // graph containing the ORC runtime RTTI support) so we need to handle with
444 // an unknown set of dependencies during bootstrap, and (b) these graphs may
445 // be linked concurrently if the user has installed a concurrent dispatcher.
446 //
447 // We satisfy these constraint by implementing a bootstrap phase during which
448 // allocation actions generated by MachOPlatform are appended to a list of
449 // deferred allocation actions, rather than to the graphs themselves. At the
450 // end of the bootstrap process the deferred actions are attached to a final
451 // "complete-bootstrap" graph that causes them to be run.
452 //
453 // The bootstrap steps are as follows:
454 //
455 // 1. Request the graph containing the mach header. This graph is guaranteed
456 // not to have any metadata so the fact that the registration functions
457 // are not available yet is not a problem.
458 //
459 // 2. Look up the registration functions and discard the results. This will
460 // trigger linking of the graph containing these functions, and
461 // consequently any graphs that it depends on. We do not use the lookup
462 // result to find the addresses of the functions requested (as described
463 // above the lookup will return too late for that), instead we capture the
464 // addresses in a post-allocation pass injected by the platform runtime
465 // during bootstrap only.
466 //
467 // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of
468 // graphs being linked (potentially concurrently), and we block until all
469 // of these graphs have completed linking. This is to avoid a race on the
470 // deferred-actions vector: the lookup for the runtime registration
471 // functions may return while some functions (those that are being
472 // incidentally linked in, but aren't reachable via the runtime functions)
473 // are still being linked, and we need to capture any allocation actions
474 // for this incidental code before we proceed.
475 //
476 // 4. Once all active links are complete we transfer the deferred actions to
477 // a newly added CompleteBootstrap graph and then request a symbol from
478 // the CompleteBootstrap graph to trigger materialization. This will cause
479 // all deferred actions to be run, and once this lookup returns we can
480 // proceed.
481 //
482 // 5. Finally, we associate runtime support methods in MachOPlatform with
483 // the corresponding jit-dispatch tag variables in the ORC runtime to make
484 // the support methods callable. The bootstrap is now complete.
485
486 // Step (1) Add header materialization unit and request.
487 if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>(
488 *this, MachOHeaderStartSymbol))))
489 return;
490 if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))
491 return;
492
493 // Step (2) Request runtime registration functions to trigger
494 // materialization..
495 if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
496 SymbolLookupSet(
497 {PlatformBootstrap.Name, PlatformShutdown.Name,
498 RegisterJITDylib.Name, DeregisterJITDylib.Name,
499 RegisterObjectPlatformSections.Name,
500 DeregisterObjectPlatformSections.Name,
501 CreatePThreadKey.Name}))
502 .takeError()))
503 return;
504
505 // Step (3) Wait for any incidental linker work to complete.
506 {
507 std::unique_lock<std::mutex> Lock(BI.Mutex);
508 BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
509 Bootstrap = nullptr;
510 }
511
512 // Step (4) Add complete-bootstrap materialization unit and request.
513 auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap");
514 if ((Err = PlatformJD.define(
515 std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>(
516 *this, PlatformJD.getName(), BootstrapCompleteSymbol,
517 std::move(BI.DeferredAAs), PlatformBootstrap.Addr,
518 PlatformShutdown.Addr, RegisterJITDylib.Addr,
519 DeregisterJITDylib.Addr, BI.MachOHeaderAddr))))
520 return;
521 if ((Err = ES.lookup(makeJITDylibSearchOrder(
522 &PlatformJD, JITDylibLookupFlags::MatchAllSymbols),
523 std::move(BootstrapCompleteSymbol))
524 .takeError()))
525 return;
526
527 // (5) Associate runtime support functions.
528 if ((Err = associateRuntimeSupportFunctions()))
529 return;
530 }
531
associateRuntimeSupportFunctions()532 Error MachOPlatform::associateRuntimeSupportFunctions() {
533 ExecutionSession::JITDispatchHandlerAssociationMap WFs;
534
535 using PushInitializersSPSSig =
536 SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr);
537 WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =
538 ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
539 this, &MachOPlatform::rt_pushInitializers);
540
541 using LookupSymbolSPSSig =
542 SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
543 WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
544 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
545 &MachOPlatform::rt_lookupSymbol);
546
547 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
548 }
549
pushInitializersLoop(PushInitializersSendResultFn SendResult,JITDylibSP JD)550 void MachOPlatform::pushInitializersLoop(
551 PushInitializersSendResultFn SendResult, JITDylibSP JD) {
552 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
553 DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;
554 SmallVector<JITDylib *, 16> Worklist({JD.get()});
555
556 ES.runSessionLocked([&]() {
557 while (!Worklist.empty()) {
558 // FIXME: Check for defunct dylibs.
559
560 auto DepJD = Worklist.back();
561 Worklist.pop_back();
562
563 // If we've already visited this JITDylib on this iteration then continue.
564 if (JDDepMap.count(DepJD))
565 continue;
566
567 // Add dep info.
568 auto &DM = JDDepMap[DepJD];
569 DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
570 for (auto &KV : O) {
571 if (KV.first == DepJD)
572 continue;
573 DM.push_back(KV.first);
574 Worklist.push_back(KV.first);
575 }
576 });
577
578 // Add any registered init symbols.
579 auto RISItr = RegisteredInitSymbols.find(DepJD);
580 if (RISItr != RegisteredInitSymbols.end()) {
581 NewInitSymbols[DepJD] = std::move(RISItr->second);
582 RegisteredInitSymbols.erase(RISItr);
583 }
584 }
585 });
586
587 // If there are no further init symbols to look up then send the link order
588 // (as a list of header addresses) to the caller.
589 if (NewInitSymbols.empty()) {
590
591 // To make the list intelligible to the runtime we need to convert all
592 // JITDylib pointers to their header addresses. Only include JITDylibs
593 // that appear in the JITDylibToHeaderAddr map (i.e. those that have been
594 // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.
595 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
596 HeaderAddrs.reserve(JDDepMap.size());
597 {
598 std::lock_guard<std::mutex> Lock(PlatformMutex);
599 for (auto &KV : JDDepMap) {
600 auto I = JITDylibToHeaderAddr.find(KV.first);
601 if (I != JITDylibToHeaderAddr.end())
602 HeaderAddrs[KV.first] = I->second;
603 }
604 }
605
606 // Build the dep info map to return.
607 MachOJITDylibDepInfoMap DIM;
608 DIM.reserve(JDDepMap.size());
609 for (auto &KV : JDDepMap) {
610 auto HI = HeaderAddrs.find(KV.first);
611 // Skip unmanaged JITDylibs.
612 if (HI == HeaderAddrs.end())
613 continue;
614 auto H = HI->second;
615 MachOJITDylibDepInfo DepInfo;
616 for (auto &Dep : KV.second) {
617 auto HJ = HeaderAddrs.find(Dep);
618 if (HJ != HeaderAddrs.end())
619 DepInfo.DepHeaders.push_back(HJ->second);
620 }
621 DIM.push_back(std::make_pair(H, std::move(DepInfo)));
622 }
623 SendResult(DIM);
624 return;
625 }
626
627 // Otherwise issue a lookup and re-run this phase when it completes.
628 lookupInitSymbolsAsync(
629 [this, SendResult = std::move(SendResult), JD](Error Err) mutable {
630 if (Err)
631 SendResult(std::move(Err));
632 else
633 pushInitializersLoop(std::move(SendResult), JD);
634 },
635 ES, std::move(NewInitSymbols));
636 }
637
rt_pushInitializers(PushInitializersSendResultFn SendResult,ExecutorAddr JDHeaderAddr)638 void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
639 ExecutorAddr JDHeaderAddr) {
640 JITDylibSP JD;
641 {
642 std::lock_guard<std::mutex> Lock(PlatformMutex);
643 auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
644 if (I != HeaderAddrToJITDylib.end())
645 JD = I->second;
646 }
647
648 LLVM_DEBUG({
649 dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
650 if (JD)
651 dbgs() << "pushing initializers for " << JD->getName() << "\n";
652 else
653 dbgs() << "No JITDylib for header address.\n";
654 });
655
656 if (!JD) {
657 SendResult(
658 make_error<StringError>("No JITDylib with header addr " +
659 formatv("{0:x}", JDHeaderAddr.getValue()),
660 inconvertibleErrorCode()));
661 return;
662 }
663
664 pushInitializersLoop(std::move(SendResult), JD);
665 }
666
rt_lookupSymbol(SendSymbolAddressFn SendResult,ExecutorAddr Handle,StringRef SymbolName)667 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
668 ExecutorAddr Handle, StringRef SymbolName) {
669 LLVM_DEBUG({
670 dbgs() << "MachOPlatform::rt_lookupSymbol(\""
671 << formatv("{0:x}", Handle.getValue()) << "\")\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({
685 dbgs() << " No JITDylib for handle "
686 << formatv("{0:x}", Handle.getValue()) << "\n";
687 });
688 SendResult(make_error<StringError>("No JITDylib associated with handle " +
689 formatv("{0:x}", Handle.getValue()),
690 inconvertibleErrorCode()));
691 return;
692 }
693
694 // Use functor class to work around XL build compiler issue on AIX.
695 class RtLookupNotifyComplete {
696 public:
697 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
698 : SendResult(std::move(SendResult)) {}
699 void operator()(Expected<SymbolMap> Result) {
700 if (Result) {
701 assert(Result->size() == 1 && "Unexpected result map count");
702 SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
703 } else {
704 SendResult(Result.takeError());
705 }
706 }
707
708 private:
709 SendSymbolAddressFn SendResult;
710 };
711
712 // FIXME: Proper mangling.
713 auto MangledName = ("_" + SymbolName).str();
714 ES.lookup(
715 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
716 SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
717 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
718 }
719
createPThreadKey()720 Expected<uint64_t> MachOPlatform::createPThreadKey() {
721 if (!CreatePThreadKey.Addr)
722 return make_error<StringError>(
723 "Attempting to create pthread key in target, but runtime support has "
724 "not been loaded yet",
725 inconvertibleErrorCode());
726
727 Expected<uint64_t> Result(0);
728 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
729 CreatePThreadKey.Addr, Result))
730 return std::move(Err);
731 return Result;
732 }
733
modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & LG,jitlink::PassConfiguration & Config)734 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
735 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
736 jitlink::PassConfiguration &Config) {
737
738 using namespace jitlink;
739
740 bool InBootstrapPhase =
741 &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap;
742
743 // If we're in the bootstrap phase then increment the active graphs.
744 if (InBootstrapPhase) {
745 Config.PrePrunePasses.push_back(
746 [this](LinkGraph &G) { return bootstrapPipelineStart(G); });
747 Config.PostAllocationPasses.push_back([this](LinkGraph &G) {
748 return bootstrapPipelineRecordRuntimeFunctions(G);
749 });
750 }
751
752 // --- Handle Initializers ---
753 if (auto InitSymbol = MR.getInitializerSymbol()) {
754
755 // If the initializer symbol is the MachOHeader start symbol then just
756 // register it and then bail out -- the header materialization unit
757 // definitely doesn't need any other passes.
758 if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) {
759 Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {
760 return associateJITDylibHeaderSymbol(G, MR);
761 });
762 return;
763 }
764
765 // If the object contains an init symbol other than the header start symbol
766 // then add passes to preserve, process and register the init
767 // sections/symbols.
768 Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
769 if (auto Err = preserveInitSections(G, MR))
770 return Err;
771 return processObjCImageInfo(G, MR);
772 });
773 }
774
775 // Insert TLV lowering at the start of the PostPrunePasses, since we want
776 // it to run before GOT/PLT lowering.
777 Config.PostPrunePasses.insert(
778 Config.PostPrunePasses.begin(),
779 [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) {
780 return fixTLVSectionsAndEdges(G, JD);
781 });
782
783 // Add a pass to register the final addresses of any special sections in the
784 // object with the runtime.
785 Config.PostAllocationPasses.push_back(
786 [this, &JD = MR.getTargetJITDylib(), InBootstrapPhase](LinkGraph &G) {
787 return registerObjectPlatformSections(G, JD, InBootstrapPhase);
788 });
789
790 // If we're in the bootstrap phase then steal allocation actions and then
791 // decrement the active graphs.
792 if (InBootstrapPhase)
793 Config.PostFixupPasses.push_back(
794 [this](LinkGraph &G) { return bootstrapPipelineEnd(G); });
795 }
796
797 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
getSyntheticSymbolDependencies(MaterializationResponsibility & MR)798 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
799 MaterializationResponsibility &MR) {
800 std::lock_guard<std::mutex> Lock(PluginMutex);
801 auto I = InitSymbolDeps.find(&MR);
802 if (I != InitSymbolDeps.end()) {
803 SyntheticSymbolDependenciesMap Result;
804 Result[MR.getInitializerSymbol()] = std::move(I->second);
805 InitSymbolDeps.erase(&MR);
806 return Result;
807 }
808 return SyntheticSymbolDependenciesMap();
809 }
810
bootstrapPipelineStart(jitlink::LinkGraph & G)811 Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart(
812 jitlink::LinkGraph &G) {
813 // Increment the active graphs count in BootstrapInfo.
814 std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
815 ++MP.Bootstrap.load()->ActiveGraphs;
816 return Error::success();
817 }
818
819 Error MachOPlatform::MachOPlatformPlugin::
bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph & G)820 bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) {
821 // Record bootstrap function names.
822 std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = {
823 {*MP.MachOHeaderStartSymbol, &MP.Bootstrap.load()->MachOHeaderAddr},
824 {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr},
825 {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr},
826 {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr},
827 {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr},
828 {*MP.RegisterObjectPlatformSections.Name,
829 &MP.RegisterObjectPlatformSections.Addr},
830 {*MP.DeregisterObjectPlatformSections.Name,
831 &MP.DeregisterObjectPlatformSections.Addr},
832 {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}};
833
834 bool RegisterMachOHeader = false;
835
836 for (auto *Sym : G.defined_symbols()) {
837 for (auto &RTSym : RuntimeSymbols) {
838 if (Sym->hasName() && Sym->getName() == RTSym.first) {
839 if (*RTSym.second)
840 return make_error<StringError>(
841 "Duplicate " + RTSym.first +
842 " detected during MachOPlatform bootstrap",
843 inconvertibleErrorCode());
844
845 if (Sym->getName() == *MP.MachOHeaderStartSymbol)
846 RegisterMachOHeader = true;
847
848 *RTSym.second = Sym->getAddress();
849 }
850 }
851 }
852
853 if (RegisterMachOHeader) {
854 // If this graph defines the macho header symbol then create the internal
855 // mapping between it and PlatformJD.
856 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
857 MP.JITDylibToHeaderAddr[&MP.PlatformJD] =
858 MP.Bootstrap.load()->MachOHeaderAddr;
859 MP.HeaderAddrToJITDylib[MP.Bootstrap.load()->MachOHeaderAddr] =
860 &MP.PlatformJD;
861 }
862
863 return Error::success();
864 }
865
bootstrapPipelineEnd(jitlink::LinkGraph & G)866 Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(
867 jitlink::LinkGraph &G) {
868 std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
869 assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed");
870 --MP.Bootstrap.load()->ActiveGraphs;
871 // Notify Bootstrap->CV while holding the mutex because the mutex is
872 // also keeping Bootstrap->CV alive.
873 if (MP.Bootstrap.load()->ActiveGraphs == 0)
874 MP.Bootstrap.load()->CV.notify_all();
875 return Error::success();
876 }
877
associateJITDylibHeaderSymbol(jitlink::LinkGraph & G,MaterializationResponsibility & MR)878 Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
879 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
880 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
881 return Sym->getName() == *MP.MachOHeaderStartSymbol;
882 });
883 assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
884
885 auto &JD = MR.getTargetJITDylib();
886 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
887 auto HeaderAddr = (*I)->getAddress();
888 MP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
889 MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
890 // We can unconditionally add these actions to the Graph because this pass
891 // isn't used during bootstrap.
892 G.allocActions().push_back(
893 {cantFail(
894 WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>(
895 MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)),
896 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
897 MP.DeregisterJITDylib.Addr, HeaderAddr))});
898 return Error::success();
899 }
900
preserveInitSections(jitlink::LinkGraph & G,MaterializationResponsibility & MR)901 Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
902 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
903
904 JITLinkSymbolSet InitSectionSymbols;
905 for (auto &InitSectionName : InitSectionNames) {
906 // Skip non-init sections.
907 auto *InitSection = G.findSectionByName(InitSectionName);
908 if (!InitSection)
909 continue;
910
911 // Make a pass over live symbols in the section: those blocks are already
912 // preserved.
913 DenseSet<jitlink::Block *> AlreadyLiveBlocks;
914 for (auto &Sym : InitSection->symbols()) {
915 auto &B = Sym->getBlock();
916 if (Sym->isLive() && Sym->getOffset() == 0 &&
917 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
918 InitSectionSymbols.insert(Sym);
919 AlreadyLiveBlocks.insert(&B);
920 }
921 }
922
923 // Add anonymous symbols to preserve any not-already-preserved blocks.
924 for (auto *B : InitSection->blocks())
925 if (!AlreadyLiveBlocks.count(B))
926 InitSectionSymbols.insert(
927 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
928 }
929
930 if (!InitSectionSymbols.empty()) {
931 std::lock_guard<std::mutex> Lock(PluginMutex);
932 InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
933 }
934
935 return Error::success();
936 }
937
processObjCImageInfo(jitlink::LinkGraph & G,MaterializationResponsibility & MR)938 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
939 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
940
941 // If there's an ObjC imagine info then either
942 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
943 // this case we name and record it.
944 // OR
945 // (2) We already have a recorded __objc_imageinfo for this JITDylib,
946 // in which case we just verify it.
947 auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName);
948 if (!ObjCImageInfo)
949 return Error::success();
950
951 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
952
953 // Check that the section is not empty if present.
954 if (ObjCImageInfoBlocks.empty())
955 return make_error<StringError>("Empty " + ObjCImageInfoSectionName +
956 " section in " + G.getName(),
957 inconvertibleErrorCode());
958
959 // Check that there's only one block in the section.
960 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
961 return make_error<StringError>("Multiple blocks in " +
962 ObjCImageInfoSectionName +
963 " section in " + G.getName(),
964 inconvertibleErrorCode());
965
966 // Check that the __objc_imageinfo section is unreferenced.
967 // FIXME: We could optimize this check if Symbols had a ref-count.
968 for (auto &Sec : G.sections()) {
969 if (&Sec != ObjCImageInfo)
970 for (auto *B : Sec.blocks())
971 for (auto &E : B->edges())
972 if (E.getTarget().isDefined() &&
973 &E.getTarget().getBlock().getSection() == ObjCImageInfo)
974 return make_error<StringError>(ObjCImageInfoSectionName +
975 " is referenced within file " +
976 G.getName(),
977 inconvertibleErrorCode());
978 }
979
980 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
981 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
982 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
983 auto Flags =
984 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
985
986 // Lock the mutex while we verify / update the ObjCImageInfos map.
987 std::lock_guard<std::mutex> Lock(PluginMutex);
988
989 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
990 if (ObjCImageInfoItr != ObjCImageInfos.end()) {
991 // We've already registered an __objc_imageinfo section. Verify the
992 // content of this new section matches, then delete it.
993 if (ObjCImageInfoItr->second.first != Version)
994 return make_error<StringError>(
995 "ObjC version in " + G.getName() +
996 " does not match first registered version",
997 inconvertibleErrorCode());
998 if (ObjCImageInfoItr->second.second != Flags)
999 return make_error<StringError>("ObjC flags in " + G.getName() +
1000 " do not match first registered flags",
1001 inconvertibleErrorCode());
1002
1003 // __objc_imageinfo is valid. Delete the block.
1004 for (auto *S : ObjCImageInfo->symbols())
1005 G.removeDefinedSymbol(*S);
1006 G.removeBlock(ObjCImageInfoBlock);
1007 } else {
1008 // We haven't registered an __objc_imageinfo section yet. Register and
1009 // move on. The section should already be marked no-dead-strip.
1010 ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
1011 }
1012
1013 return Error::success();
1014 }
1015
fixTLVSectionsAndEdges(jitlink::LinkGraph & G,JITDylib & JD)1016 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1017 jitlink::LinkGraph &G, JITDylib &JD) {
1018
1019 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
1020 for (auto *Sym : G.external_symbols())
1021 if (Sym->getName() == "__tlv_bootstrap") {
1022 Sym->setName("___orc_rt_macho_tlv_get_addr");
1023 break;
1024 }
1025
1026 // Store key in __thread_vars struct fields.
1027 if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) {
1028 std::optional<uint64_t> Key;
1029 {
1030 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1031 auto I = MP.JITDylibToPThreadKey.find(&JD);
1032 if (I != MP.JITDylibToPThreadKey.end())
1033 Key = I->second;
1034 }
1035
1036 if (!Key) {
1037 if (auto KeyOrErr = MP.createPThreadKey())
1038 Key = *KeyOrErr;
1039 else
1040 return KeyOrErr.takeError();
1041 }
1042
1043 uint64_t PlatformKeyBits =
1044 support::endian::byte_swap(*Key, G.getEndianness());
1045
1046 for (auto *B : ThreadDataSec->blocks()) {
1047 if (B->getSize() != 3 * G.getPointerSize())
1048 return make_error<StringError>("__thread_vars block at " +
1049 formatv("{0:x}", B->getAddress()) +
1050 " has unexpected size",
1051 inconvertibleErrorCode());
1052
1053 auto NewBlockContent = G.allocateBuffer(B->getSize());
1054 llvm::copy(B->getContent(), NewBlockContent.data());
1055 memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
1056 G.getPointerSize());
1057 B->setContent(NewBlockContent);
1058 }
1059 }
1060
1061 // Transform any TLV edges into GOT edges.
1062 for (auto *B : G.blocks())
1063 for (auto &E : B->edges())
1064 if (E.getKind() ==
1065 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
1066 E.setKind(jitlink::x86_64::
1067 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
1068
1069 return Error::success();
1070 }
1071
1072 std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>
findUnwindSectionInfo(jitlink::LinkGraph & G)1073 MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1074 jitlink::LinkGraph &G) {
1075 using namespace jitlink;
1076
1077 UnwindSections US;
1078
1079 // ScanSection records a section range and adds any executable blocks that
1080 // that section points to to the CodeBlocks vector.
1081 SmallVector<Block *> CodeBlocks;
1082 auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) {
1083 if (Sec.blocks().empty())
1084 return;
1085 SecRange = (*Sec.blocks().begin())->getRange();
1086 for (auto *B : Sec.blocks()) {
1087 auto R = B->getRange();
1088 SecRange.Start = std::min(SecRange.Start, R.Start);
1089 SecRange.End = std::max(SecRange.End, R.End);
1090 for (auto &E : B->edges()) {
1091 if (!E.getTarget().isDefined())
1092 continue;
1093 auto &TargetBlock = E.getTarget().getBlock();
1094 auto &TargetSection = TargetBlock.getSection();
1095 if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec)
1096 CodeBlocks.push_back(&TargetBlock);
1097 }
1098 }
1099 };
1100
1101 if (Section *EHFrameSec = G.findSectionByName(EHFrameSectionName))
1102 ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection);
1103
1104 if (Section *CUInfoSec = G.findSectionByName(CompactUnwindInfoSectionName))
1105 ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection);
1106
1107 // If we didn't find any pointed-to code-blocks then there's no need to
1108 // register any info.
1109 if (CodeBlocks.empty())
1110 return std::nullopt;
1111
1112 // We have info to register. Sort the code blocks into address order and
1113 // build a list of contiguous address ranges covering them all.
1114 llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) {
1115 return LHS->getAddress() < RHS->getAddress();
1116 });
1117 for (auto *B : CodeBlocks) {
1118 if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress())
1119 US.CodeRanges.push_back(B->getRange());
1120 else
1121 US.CodeRanges.back().End = B->getRange().End;
1122 }
1123
1124 LLVM_DEBUG({
1125 dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n"
1126 << " DWARF: ";
1127 if (US.DwarfSection.Start)
1128 dbgs() << US.DwarfSection << "\n";
1129 else
1130 dbgs() << "none\n";
1131 dbgs() << " Compact-unwind: ";
1132 if (US.CompactUnwindSection.Start)
1133 dbgs() << US.CompactUnwindSection << "\n";
1134 else
1135 dbgs() << "none\n"
1136 << "for code ranges:\n";
1137 for (auto &CR : US.CodeRanges)
1138 dbgs() << " " << CR << "\n";
1139 if (US.CodeRanges.size() >= G.sections_size())
1140 dbgs() << "WARNING: High number of discontiguous code ranges! "
1141 "Padding may be interfering with coalescing.\n";
1142 });
1143
1144 return US;
1145 }
1146
registerObjectPlatformSections(jitlink::LinkGraph & G,JITDylib & JD,bool InBootstrapPhase)1147 Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1148 jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) {
1149
1150 // Get a pointer to the thread data section if there is one. It will be used
1151 // below.
1152 jitlink::Section *ThreadDataSection =
1153 G.findSectionByName(ThreadDataSectionName);
1154
1155 // Handle thread BSS section if there is one.
1156 if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) {
1157 // If there's already a thread data section in this graph then merge the
1158 // thread BSS section content into it, otherwise just treat the thread
1159 // BSS section as the thread data section.
1160 if (ThreadDataSection)
1161 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
1162 else
1163 ThreadDataSection = ThreadBSSSection;
1164 }
1165
1166 SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;
1167
1168 // Collect data sections to register.
1169 StringRef DataSections[] = {DataDataSectionName, DataCommonSectionName,
1170 EHFrameSectionName};
1171 for (auto &SecName : DataSections) {
1172 if (auto *Sec = G.findSectionByName(SecName)) {
1173 jitlink::SectionRange R(*Sec);
1174 if (!R.empty())
1175 MachOPlatformSecs.push_back({SecName, R.getRange()});
1176 }
1177 }
1178
1179 // Having merged thread BSS (if present) and thread data (if present),
1180 // record the resulting section range.
1181 if (ThreadDataSection) {
1182 jitlink::SectionRange R(*ThreadDataSection);
1183 if (!R.empty())
1184 MachOPlatformSecs.push_back({ThreadDataSectionName, R.getRange()});
1185 }
1186
1187 // If any platform sections were found then add an allocation action to call
1188 // the registration function.
1189 StringRef PlatformSections[] = {
1190 ModInitFuncSectionName, ObjCClassListSectionName,
1191 ObjCImageInfoSectionName, ObjCSelRefsSectionName,
1192 Swift5ProtoSectionName, Swift5ProtosSectionName,
1193 Swift5TypesSectionName,
1194 };
1195
1196 for (auto &SecName : PlatformSections) {
1197 auto *Sec = G.findSectionByName(SecName);
1198 if (!Sec)
1199 continue;
1200 jitlink::SectionRange R(*Sec);
1201 if (R.empty())
1202 continue;
1203
1204 MachOPlatformSecs.push_back({SecName, R.getRange()});
1205 }
1206
1207 std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,
1208 ExecutorAddrRange>>
1209 UnwindInfo;
1210 if (auto UI = findUnwindSectionInfo(G))
1211 UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,
1212 UI->CompactUnwindSection);
1213
1214 if (!MachOPlatformSecs.empty() || UnwindInfo) {
1215 ExecutorAddr HeaderAddr;
1216 {
1217 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1218 auto I = MP.JITDylibToHeaderAddr.find(&JD);
1219 assert(I != MP.JITDylibToHeaderAddr.end() &&
1220 "Missing header for JITDylib");
1221 HeaderAddr = I->second;
1222 }
1223
1224 // Dump the scraped inits.
1225 LLVM_DEBUG({
1226 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
1227 for (auto &KV : MachOPlatformSecs)
1228 dbgs() << " " << KV.first << ": " << KV.second << "\n";
1229 });
1230
1231 using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<
1232 SPSExecutorAddr,
1233 SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>,
1234 SPSExecutorAddrRange, SPSExecutorAddrRange>>,
1235 SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;
1236
1237 shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
1238 ? G.allocActions()
1239 : MP.Bootstrap.load()->DeferredAAs;
1240
1241 allocActions.push_back(
1242 {cantFail(
1243 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1244 MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo,
1245 MachOPlatformSecs)),
1246 cantFail(
1247 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1248 MP.DeregisterObjectPlatformSections.Addr, HeaderAddr,
1249 UnwindInfo, MachOPlatformSecs))});
1250 }
1251
1252 return Error::success();
1253 }
1254
1255 } // End namespace orc.
1256 } // End namespace llvm.
1257