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
19 #define DEBUG_TYPE "orc"
20
21 using namespace llvm;
22 using namespace llvm::orc;
23 using namespace llvm::orc::shared;
24
25 namespace llvm {
26 namespace orc {
27 namespace shared {
28
29 using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
30 using SPSMachOJITDylibDepInfoMap =
31 SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
32
33 template <>
34 class SPSSerializationTraits<SPSMachOJITDylibDepInfo,
35 MachOPlatform::MachOJITDylibDepInfo> {
36 public:
size(const MachOPlatform::MachOJITDylibDepInfo & DDI)37 static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
38 return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
39 }
40
serialize(SPSOutputBuffer & OB,const MachOPlatform::MachOJITDylibDepInfo & DDI)41 static bool serialize(SPSOutputBuffer &OB,
42 const MachOPlatform::MachOJITDylibDepInfo &DDI) {
43 return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
44 DDI.DepHeaders);
45 }
46
deserialize(SPSInputBuffer & IB,MachOPlatform::MachOJITDylibDepInfo & DDI)47 static bool deserialize(SPSInputBuffer &IB,
48 MachOPlatform::MachOJITDylibDepInfo &DDI) {
49 return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
50 DDI.DepHeaders);
51 }
52 };
53
54 } // namespace shared
55 } // namespace orc
56 } // namespace llvm
57
58 namespace {
59
60 class MachOHeaderMaterializationUnit : public MaterializationUnit {
61 public:
MachOHeaderMaterializationUnit(MachOPlatform & MOP,const SymbolStringPtr & HeaderStartSymbol)62 MachOHeaderMaterializationUnit(MachOPlatform &MOP,
63 const SymbolStringPtr &HeaderStartSymbol)
64 : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)),
65 MOP(MOP) {}
66
getName() const67 StringRef getName() const override { return "MachOHeaderMU"; }
68
materialize(std::unique_ptr<MaterializationResponsibility> R)69 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
70 unsigned PointerSize;
71 support::endianness Endianness;
72 const auto &TT =
73 MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
74
75 switch (TT.getArch()) {
76 case Triple::aarch64:
77 case Triple::x86_64:
78 PointerSize = 8;
79 Endianness = support::endianness::little;
80 break;
81 default:
82 llvm_unreachable("Unrecognized architecture");
83 }
84
85 auto G = std::make_unique<jitlink::LinkGraph>(
86 "<MachOHeaderMU>", TT, PointerSize, Endianness,
87 jitlink::getGenericEdgeKindName);
88 auto &HeaderSection = G->createSection("__header", jitlink::MemProt::Read);
89 auto &HeaderBlock = createHeaderBlock(*G, HeaderSection);
90
91 // Init symbol is header-start symbol.
92 G->addDefinedSymbol(HeaderBlock, 0, *R->getInitializerSymbol(),
93 HeaderBlock.getSize(), jitlink::Linkage::Strong,
94 jitlink::Scope::Default, false, true);
95 for (auto &HS : AdditionalHeaderSymbols)
96 G->addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name,
97 HeaderBlock.getSize(), jitlink::Linkage::Strong,
98 jitlink::Scope::Default, false, true);
99
100 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
101 }
102
discard(const JITDylib & JD,const SymbolStringPtr & Sym)103 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
104
105 private:
106 struct HeaderSymbol {
107 const char *Name;
108 uint64_t Offset;
109 };
110
111 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
112 {"___mh_executable_header", 0}};
113
createHeaderBlock(jitlink::LinkGraph & G,jitlink::Section & HeaderSection)114 static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
115 jitlink::Section &HeaderSection) {
116 MachO::mach_header_64 Hdr;
117 Hdr.magic = MachO::MH_MAGIC_64;
118 switch (G.getTargetTriple().getArch()) {
119 case Triple::aarch64:
120 Hdr.cputype = MachO::CPU_TYPE_ARM64;
121 Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
122 break;
123 case Triple::x86_64:
124 Hdr.cputype = MachO::CPU_TYPE_X86_64;
125 Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
126 break;
127 default:
128 llvm_unreachable("Unrecognized architecture");
129 }
130 Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
131 Hdr.ncmds = 0;
132 Hdr.sizeofcmds = 0;
133 Hdr.flags = 0;
134 Hdr.reserved = 0;
135
136 if (G.getEndianness() != support::endian::system_endianness())
137 MachO::swapStruct(Hdr);
138
139 auto HeaderContent = G.allocateString(
140 StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
141
142 return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
143 0);
144 }
145
146 static MaterializationUnit::Interface
createHeaderInterface(MachOPlatform & MOP,const SymbolStringPtr & HeaderStartSymbol)147 createHeaderInterface(MachOPlatform &MOP,
148 const SymbolStringPtr &HeaderStartSymbol) {
149 SymbolFlagsMap HeaderSymbolFlags;
150
151 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
152 for (auto &HS : AdditionalHeaderSymbols)
153 HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
154 JITSymbolFlags::Exported;
155
156 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
157 HeaderStartSymbol);
158 }
159
160 MachOPlatform &MOP;
161 };
162
163 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
164 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
165
166 StringRef EHFrameSectionName = "__TEXT,__eh_frame";
167 StringRef ModInitFuncSectionName = "__DATA,__mod_init_func";
168 StringRef ObjCClassListSectionName = "__DATA,__objc_classlist";
169 StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info";
170 StringRef ObjCSelRefsSectionName = "__DATA,__objc_selrefs";
171 StringRef Swift5ProtoSectionName = "__TEXT,__swift5_proto";
172 StringRef Swift5ProtosSectionName = "__TEXT,__swift5_protos";
173 StringRef Swift5TypesSectionName = "__TEXT,__swift5_types";
174 StringRef ThreadBSSSectionName = "__DATA,__thread_bss";
175 StringRef ThreadDataSectionName = "__DATA,__thread_data";
176 StringRef ThreadVarsSectionName = "__DATA,__thread_vars";
177
178 StringRef InitSectionNames[] = {
179 ModInitFuncSectionName, ObjCSelRefsSectionName, ObjCClassListSectionName,
180 Swift5ProtosSectionName, Swift5ProtoSectionName, Swift5TypesSectionName};
181
182 } // end anonymous namespace
183
184 namespace llvm {
185 namespace orc {
186
187 Expected<std::unique_ptr<MachOPlatform>>
Create(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,const char * OrcRuntimePath,Optional<SymbolAliasMap> RuntimeAliases)188 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
189 JITDylib &PlatformJD, const char *OrcRuntimePath,
190 Optional<SymbolAliasMap> RuntimeAliases) {
191
192 auto &EPC = ES.getExecutorProcessControl();
193
194 // If the target is not supported then bail out immediately.
195 if (!supportedTarget(EPC.getTargetTriple()))
196 return make_error<StringError>("Unsupported MachOPlatform triple: " +
197 EPC.getTargetTriple().str(),
198 inconvertibleErrorCode());
199
200 // Create default aliases if the caller didn't supply any.
201 if (!RuntimeAliases)
202 RuntimeAliases = standardPlatformAliases(ES);
203
204 // Define the aliases.
205 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
206 return std::move(Err);
207
208 // Add JIT-dispatch function support symbols.
209 if (auto Err = PlatformJD.define(absoluteSymbols(
210 {{ES.intern("___orc_rt_jit_dispatch"),
211 {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
212 JITSymbolFlags::Exported}},
213 {ES.intern("___orc_rt_jit_dispatch_ctx"),
214 {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
215 JITSymbolFlags::Exported}}})))
216 return std::move(Err);
217
218 // Create a generator for the ORC runtime archive.
219 auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
220 ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
221 if (!OrcRuntimeArchiveGenerator)
222 return OrcRuntimeArchiveGenerator.takeError();
223
224 // Create the instance.
225 Error Err = Error::success();
226 auto P = std::unique_ptr<MachOPlatform>(
227 new MachOPlatform(ES, ObjLinkingLayer, PlatformJD,
228 std::move(*OrcRuntimeArchiveGenerator), Err));
229 if (Err)
230 return std::move(Err);
231 return std::move(P);
232 }
233
setupJITDylib(JITDylib & JD)234 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
235 if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
236 *this, MachOHeaderStartSymbol)))
237 return Err;
238
239 return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
240 }
241
teardownJITDylib(JITDylib & JD)242 Error MachOPlatform::teardownJITDylib(JITDylib &JD) {
243 std::lock_guard<std::mutex> Lock(PlatformMutex);
244 auto I = JITDylibToHeaderAddr.find(&JD);
245 if (I != JITDylibToHeaderAddr.end()) {
246 assert(HeaderAddrToJITDylib.count(I->second) &&
247 "HeaderAddrToJITDylib missing entry");
248 HeaderAddrToJITDylib.erase(I->second);
249 JITDylibToHeaderAddr.erase(I);
250 }
251 JITDylibToPThreadKey.erase(&JD);
252 return Error::success();
253 }
254
notifyAdding(ResourceTracker & RT,const MaterializationUnit & MU)255 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
256 const MaterializationUnit &MU) {
257 auto &JD = RT.getJITDylib();
258 const auto &InitSym = MU.getInitializerSymbol();
259 if (!InitSym)
260 return Error::success();
261
262 RegisteredInitSymbols[&JD].add(InitSym,
263 SymbolLookupFlags::WeaklyReferencedSymbol);
264 LLVM_DEBUG({
265 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
266 << MU.getName() << "\n";
267 });
268 return Error::success();
269 }
270
notifyRemoving(ResourceTracker & RT)271 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
272 llvm_unreachable("Not supported yet");
273 }
274
addAliases(ExecutionSession & ES,SymbolAliasMap & Aliases,ArrayRef<std::pair<const char *,const char * >> AL)275 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
276 ArrayRef<std::pair<const char *, const char *>> AL) {
277 for (auto &KV : AL) {
278 auto AliasName = ES.intern(KV.first);
279 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
280 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
281 JITSymbolFlags::Exported};
282 }
283 }
284
standardPlatformAliases(ExecutionSession & ES)285 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
286 SymbolAliasMap Aliases;
287 addAliases(ES, Aliases, requiredCXXAliases());
288 addAliases(ES, Aliases, standardRuntimeUtilityAliases());
289 return Aliases;
290 }
291
292 ArrayRef<std::pair<const char *, const char *>>
requiredCXXAliases()293 MachOPlatform::requiredCXXAliases() {
294 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
295 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
296
297 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
298 }
299
300 ArrayRef<std::pair<const char *, const char *>>
standardRuntimeUtilityAliases()301 MachOPlatform::standardRuntimeUtilityAliases() {
302 static const std::pair<const char *, const char *>
303 StandardRuntimeUtilityAliases[] = {
304 {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
305 {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
306 {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
307 {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
308 {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
309 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
310
311 return ArrayRef<std::pair<const char *, const char *>>(
312 StandardRuntimeUtilityAliases);
313 }
314
isInitializerSection(StringRef SegName,StringRef SectName)315 bool MachOPlatform::isInitializerSection(StringRef SegName,
316 StringRef SectName) {
317 for (auto &Name : InitSectionNames) {
318 if (Name.startswith(SegName) && Name.substr(7) == SectName)
319 return true;
320 }
321 return false;
322 }
323
supportedTarget(const Triple & TT)324 bool MachOPlatform::supportedTarget(const Triple &TT) {
325 switch (TT.getArch()) {
326 case Triple::aarch64:
327 case Triple::x86_64:
328 return true;
329 default:
330 return false;
331 }
332 }
333
MachOPlatform(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,Error & Err)334 MachOPlatform::MachOPlatform(
335 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
336 JITDylib &PlatformJD,
337 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
338 : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
339 MachOHeaderStartSymbol(ES.intern("___dso_handle")) {
340 ErrorAsOutParameter _(&Err);
341
342 ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
343
344 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
345
346 // Force linking of eh-frame registration functions.
347 if (auto Err2 = lookupAndRecordAddrs(
348 ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
349 {{ES.intern("___orc_rt_macho_register_ehframe_section"),
350 &orc_rt_macho_register_ehframe_section},
351 {ES.intern("___orc_rt_macho_deregister_ehframe_section"),
352 &orc_rt_macho_deregister_ehframe_section}})) {
353 Err = std::move(Err2);
354 return;
355 }
356
357 State = BootstrapPhase2;
358
359 // Associate wrapper function tags with JIT-side function implementations.
360 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
361 Err = std::move(E2);
362 return;
363 }
364
365 // Lookup addresses of runtime functions callable by the platform,
366 // call the platform bootstrap function to initialize the platform-state
367 // object in the executor.
368 if (auto E2 = bootstrapMachORuntime(PlatformJD)) {
369 Err = std::move(E2);
370 return;
371 }
372
373 // PlatformJD hasn't been set up by the platform yet (since we're creating
374 // the platform now), so set it up.
375 if (auto E2 = setupJITDylib(PlatformJD)) {
376 Err = std::move(E2);
377 return;
378 }
379
380 State = Initialized;
381 }
382
associateRuntimeSupportFunctions(JITDylib & PlatformJD)383 Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
384 ExecutionSession::JITDispatchHandlerAssociationMap WFs;
385
386 using PushInitializersSPSSig =
387 SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr);
388 WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =
389 ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
390 this, &MachOPlatform::rt_pushInitializers);
391
392 using LookupSymbolSPSSig =
393 SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
394 WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
395 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
396 &MachOPlatform::rt_lookupSymbol);
397
398 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
399 }
400
pushInitializersLoop(PushInitializersSendResultFn SendResult,JITDylibSP JD)401 void MachOPlatform::pushInitializersLoop(
402 PushInitializersSendResultFn SendResult, JITDylibSP JD) {
403 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
404 DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;
405 SmallVector<JITDylib *, 16> Worklist({JD.get()});
406
407 ES.runSessionLocked([&]() {
408 while (!Worklist.empty()) {
409 // FIXME: Check for defunct dylibs.
410
411 auto DepJD = Worklist.back();
412 Worklist.pop_back();
413
414 // If we've already visited this JITDylib on this iteration then continue.
415 if (JDDepMap.count(DepJD))
416 continue;
417
418 // Add dep info.
419 auto &DM = JDDepMap[DepJD];
420 DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
421 for (auto &KV : O) {
422 if (KV.first == DepJD)
423 continue;
424 DM.push_back(KV.first);
425 Worklist.push_back(KV.first);
426 }
427 });
428
429 // Add any registered init symbols.
430 auto RISItr = RegisteredInitSymbols.find(DepJD);
431 if (RISItr != RegisteredInitSymbols.end()) {
432 NewInitSymbols[DepJD] = std::move(RISItr->second);
433 RegisteredInitSymbols.erase(RISItr);
434 }
435 }
436 });
437
438 // If there are no further init symbols to look up then send the link order
439 // (as a list of header addresses) to the caller.
440 if (NewInitSymbols.empty()) {
441
442 // To make the list intelligible to the runtime we need to convert all
443 // JITDylib pointers to their header addresses.
444 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
445 HeaderAddrs.reserve(JDDepMap.size());
446 {
447 std::lock_guard<std::mutex> Lock(PlatformMutex);
448 for (auto &KV : JDDepMap) {
449 auto I = JITDylibToHeaderAddr.find(KV.first);
450 if (I == JITDylibToHeaderAddr.end()) {
451 // The header address should have been materialized by the previous
452 // round, but we need to handle the pathalogical case where someone
453 // removes the symbol on another thread while we're running.
454 SendResult(
455 make_error<StringError>("JITDylib " + KV.first->getName() +
456 " has no registered header address",
457 inconvertibleErrorCode()));
458 return;
459 }
460 HeaderAddrs[KV.first] = I->second;
461 }
462 }
463
464 // Build the dep info map to return.
465 MachOJITDylibDepInfoMap DIM;
466 DIM.reserve(JDDepMap.size());
467 for (auto &KV : JDDepMap) {
468 assert(HeaderAddrs.count(KV.first) && "Missing header addr");
469 auto H = HeaderAddrs[KV.first];
470 MachOJITDylibDepInfo DepInfo;
471 for (auto &Dep : KV.second) {
472 assert(HeaderAddrs.count(Dep) && "Missing header addr");
473 DepInfo.DepHeaders.push_back(HeaderAddrs[Dep]);
474 }
475 DIM.push_back(std::make_pair(H, std::move(DepInfo)));
476 }
477 SendResult(DIM);
478 return;
479 }
480
481 // Otherwise issue a lookup and re-run this phase when it completes.
482 lookupInitSymbolsAsync(
483 [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
484 if (Err)
485 SendResult(std::move(Err));
486 else
487 pushInitializersLoop(std::move(SendResult), JD);
488 },
489 ES, std::move(NewInitSymbols));
490 }
491
rt_pushInitializers(PushInitializersSendResultFn SendResult,ExecutorAddr JDHeaderAddr)492 void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
493 ExecutorAddr JDHeaderAddr) {
494 JITDylibSP JD;
495 {
496 std::lock_guard<std::mutex> Lock(PlatformMutex);
497 auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
498 if (I != HeaderAddrToJITDylib.end())
499 JD = I->second;
500 }
501
502 LLVM_DEBUG({
503 dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
504 if (JD)
505 dbgs() << "pushing initializers for " << JD->getName() << "\n";
506 else
507 dbgs() << "No JITDylib for header address.\n";
508 });
509
510 if (!JD) {
511 SendResult(
512 make_error<StringError>("No JITDylib with header addr " +
513 formatv("{0:x}", JDHeaderAddr.getValue()),
514 inconvertibleErrorCode()));
515 return;
516 }
517
518 pushInitializersLoop(std::move(SendResult), JD);
519 }
520
rt_lookupSymbol(SendSymbolAddressFn SendResult,ExecutorAddr Handle,StringRef SymbolName)521 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
522 ExecutorAddr Handle, StringRef SymbolName) {
523 LLVM_DEBUG({
524 dbgs() << "MachOPlatform::rt_lookupSymbol(\""
525 << formatv("{0:x}", Handle.getValue()) << "\")\n";
526 });
527
528 JITDylib *JD = nullptr;
529
530 {
531 std::lock_guard<std::mutex> Lock(PlatformMutex);
532 auto I = HeaderAddrToJITDylib.find(Handle);
533 if (I != HeaderAddrToJITDylib.end())
534 JD = I->second;
535 }
536
537 if (!JD) {
538 LLVM_DEBUG({
539 dbgs() << " No JITDylib for handle "
540 << formatv("{0:x}", Handle.getValue()) << "\n";
541 });
542 SendResult(make_error<StringError>("No JITDylib associated with handle " +
543 formatv("{0:x}", Handle.getValue()),
544 inconvertibleErrorCode()));
545 return;
546 }
547
548 // Use functor class to work around XL build compiler issue on AIX.
549 class RtLookupNotifyComplete {
550 public:
551 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
552 : SendResult(std::move(SendResult)) {}
553 void operator()(Expected<SymbolMap> Result) {
554 if (Result) {
555 assert(Result->size() == 1 && "Unexpected result map count");
556 SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
557 } else {
558 SendResult(Result.takeError());
559 }
560 }
561
562 private:
563 SendSymbolAddressFn SendResult;
564 };
565
566 // FIXME: Proper mangling.
567 auto MangledName = ("_" + SymbolName).str();
568 ES.lookup(
569 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
570 SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
571 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
572 }
573
bootstrapMachORuntime(JITDylib & PlatformJD)574 Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) {
575 if (auto Err = lookupAndRecordAddrs(
576 ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
577 {{ES.intern("___orc_rt_macho_platform_bootstrap"),
578 &orc_rt_macho_platform_bootstrap},
579 {ES.intern("___orc_rt_macho_platform_shutdown"),
580 &orc_rt_macho_platform_shutdown},
581 {ES.intern("___orc_rt_macho_register_jitdylib"),
582 &orc_rt_macho_register_jitdylib},
583 {ES.intern("___orc_rt_macho_deregister_jitdylib"),
584 &orc_rt_macho_deregister_jitdylib},
585 {ES.intern("___orc_rt_macho_register_object_platform_sections"),
586 &orc_rt_macho_register_object_platform_sections},
587 {ES.intern("___orc_rt_macho_deregister_object_platform_sections"),
588 &orc_rt_macho_deregister_object_platform_sections},
589 {ES.intern("___orc_rt_macho_create_pthread_key"),
590 &orc_rt_macho_create_pthread_key}}))
591 return Err;
592
593 return ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap);
594 }
595
createPThreadKey()596 Expected<uint64_t> MachOPlatform::createPThreadKey() {
597 if (!orc_rt_macho_create_pthread_key)
598 return make_error<StringError>(
599 "Attempting to create pthread key in target, but runtime support has "
600 "not been loaded yet",
601 inconvertibleErrorCode());
602
603 Expected<uint64_t> Result(0);
604 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
605 orc_rt_macho_create_pthread_key, Result))
606 return std::move(Err);
607 return Result;
608 }
609
modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & LG,jitlink::PassConfiguration & Config)610 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
611 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
612 jitlink::PassConfiguration &Config) {
613
614 auto PS = MP.State.load();
615
616 // --- Handle Initializers ---
617 if (auto InitSymbol = MR.getInitializerSymbol()) {
618
619 // If the initializer symbol is the MachOHeader start symbol then just
620 // register it and then bail out -- the header materialization unit
621 // definitely doesn't need any other passes.
622 if (InitSymbol == MP.MachOHeaderStartSymbol) {
623 Config.PostAllocationPasses.push_back([this, &MR](jitlink::LinkGraph &G) {
624 return associateJITDylibHeaderSymbol(G, MR);
625 });
626 return;
627 }
628
629 // If the object contains an init symbol other than the header start symbol
630 // then add passes to preserve, process and register the init
631 // sections/symbols.
632 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) {
633 if (auto Err = preserveInitSections(G, MR))
634 return Err;
635 return processObjCImageInfo(G, MR);
636 });
637 }
638
639 // --- Add passes for eh-frame and TLV support ---
640 if (PS == MachOPlatform::BootstrapPhase1) {
641 Config.PostFixupPasses.push_back(
642 [this](jitlink::LinkGraph &G) { return registerEHSectionsPhase1(G); });
643 return;
644 }
645
646 // Insert TLV lowering at the start of the PostPrunePasses, since we want
647 // it to run before GOT/PLT lowering.
648 Config.PostPrunePasses.insert(
649 Config.PostPrunePasses.begin(),
650 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
651 return fixTLVSectionsAndEdges(G, JD);
652 });
653
654 // Add a pass to register the final addresses of any special sections in the
655 // object with the runtime.
656 Config.PostAllocationPasses.push_back(
657 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
658 return registerObjectPlatformSections(G, JD);
659 });
660 }
661
662 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
getSyntheticSymbolDependencies(MaterializationResponsibility & MR)663 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
664 MaterializationResponsibility &MR) {
665 std::lock_guard<std::mutex> Lock(PluginMutex);
666 auto I = InitSymbolDeps.find(&MR);
667 if (I != InitSymbolDeps.end()) {
668 SyntheticSymbolDependenciesMap Result;
669 Result[MR.getInitializerSymbol()] = std::move(I->second);
670 InitSymbolDeps.erase(&MR);
671 return Result;
672 }
673 return SyntheticSymbolDependenciesMap();
674 }
675
associateJITDylibHeaderSymbol(jitlink::LinkGraph & G,MaterializationResponsibility & MR)676 Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
677 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
678 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
679 return Sym->getName() == *MP.MachOHeaderStartSymbol;
680 });
681 assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
682
683 auto &JD = MR.getTargetJITDylib();
684 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
685 auto HeaderAddr = (*I)->getAddress();
686 MP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
687 MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
688 G.allocActions().push_back(
689 {cantFail(
690 WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>(
691 MP.orc_rt_macho_register_jitdylib, JD.getName(), HeaderAddr)),
692 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
693 MP.orc_rt_macho_deregister_jitdylib, HeaderAddr))});
694 return Error::success();
695 }
696
preserveInitSections(jitlink::LinkGraph & G,MaterializationResponsibility & MR)697 Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
698 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
699
700 JITLinkSymbolSet InitSectionSymbols;
701 for (auto &InitSectionName : InitSectionNames) {
702 // Skip non-init sections.
703 auto *InitSection = G.findSectionByName(InitSectionName);
704 if (!InitSection)
705 continue;
706
707 // Make a pass over live symbols in the section: those blocks are already
708 // preserved.
709 DenseSet<jitlink::Block *> AlreadyLiveBlocks;
710 for (auto &Sym : InitSection->symbols()) {
711 auto &B = Sym->getBlock();
712 if (Sym->isLive() && Sym->getOffset() == 0 &&
713 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
714 InitSectionSymbols.insert(Sym);
715 AlreadyLiveBlocks.insert(&B);
716 }
717 }
718
719 // Add anonymous symbols to preserve any not-already-preserved blocks.
720 for (auto *B : InitSection->blocks())
721 if (!AlreadyLiveBlocks.count(B))
722 InitSectionSymbols.insert(
723 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
724 }
725
726 if (!InitSectionSymbols.empty()) {
727 std::lock_guard<std::mutex> Lock(PluginMutex);
728 InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
729 }
730
731 return Error::success();
732 }
733
processObjCImageInfo(jitlink::LinkGraph & G,MaterializationResponsibility & MR)734 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
735 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
736
737 // If there's an ObjC imagine info then either
738 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
739 // this case we name and record it.
740 // OR
741 // (2) We already have a recorded __objc_imageinfo for this JITDylib,
742 // in which case we just verify it.
743 auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName);
744 if (!ObjCImageInfo)
745 return Error::success();
746
747 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
748
749 // Check that the section is not empty if present.
750 if (llvm::empty(ObjCImageInfoBlocks))
751 return make_error<StringError>("Empty " + ObjCImageInfoSectionName +
752 " section in " + G.getName(),
753 inconvertibleErrorCode());
754
755 // Check that there's only one block in the section.
756 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
757 return make_error<StringError>("Multiple blocks in " +
758 ObjCImageInfoSectionName +
759 " section in " + G.getName(),
760 inconvertibleErrorCode());
761
762 // Check that the __objc_imageinfo section is unreferenced.
763 // FIXME: We could optimize this check if Symbols had a ref-count.
764 for (auto &Sec : G.sections()) {
765 if (&Sec != ObjCImageInfo)
766 for (auto *B : Sec.blocks())
767 for (auto &E : B->edges())
768 if (E.getTarget().isDefined() &&
769 &E.getTarget().getBlock().getSection() == ObjCImageInfo)
770 return make_error<StringError>(ObjCImageInfoSectionName +
771 " is referenced within file " +
772 G.getName(),
773 inconvertibleErrorCode());
774 }
775
776 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
777 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
778 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
779 auto Flags =
780 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
781
782 // Lock the mutex while we verify / update the ObjCImageInfos map.
783 std::lock_guard<std::mutex> Lock(PluginMutex);
784
785 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
786 if (ObjCImageInfoItr != ObjCImageInfos.end()) {
787 // We've already registered an __objc_imageinfo section. Verify the
788 // content of this new section matches, then delete it.
789 if (ObjCImageInfoItr->second.first != Version)
790 return make_error<StringError>(
791 "ObjC version in " + G.getName() +
792 " does not match first registered version",
793 inconvertibleErrorCode());
794 if (ObjCImageInfoItr->second.second != Flags)
795 return make_error<StringError>("ObjC flags in " + G.getName() +
796 " do not match first registered flags",
797 inconvertibleErrorCode());
798
799 // __objc_imageinfo is valid. Delete the block.
800 for (auto *S : ObjCImageInfo->symbols())
801 G.removeDefinedSymbol(*S);
802 G.removeBlock(ObjCImageInfoBlock);
803 } else {
804 // We haven't registered an __objc_imageinfo section yet. Register and
805 // move on. The section should already be marked no-dead-strip.
806 ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
807 }
808
809 return Error::success();
810 }
811
fixTLVSectionsAndEdges(jitlink::LinkGraph & G,JITDylib & JD)812 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
813 jitlink::LinkGraph &G, JITDylib &JD) {
814
815 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
816 for (auto *Sym : G.external_symbols())
817 if (Sym->getName() == "__tlv_bootstrap") {
818 Sym->setName("___orc_rt_macho_tlv_get_addr");
819 break;
820 }
821
822 // Store key in __thread_vars struct fields.
823 if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) {
824 Optional<uint64_t> Key;
825 {
826 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
827 auto I = MP.JITDylibToPThreadKey.find(&JD);
828 if (I != MP.JITDylibToPThreadKey.end())
829 Key = I->second;
830 }
831
832 if (!Key) {
833 if (auto KeyOrErr = MP.createPThreadKey())
834 Key = *KeyOrErr;
835 else
836 return KeyOrErr.takeError();
837 }
838
839 uint64_t PlatformKeyBits =
840 support::endian::byte_swap(*Key, G.getEndianness());
841
842 for (auto *B : ThreadDataSec->blocks()) {
843 if (B->getSize() != 3 * G.getPointerSize())
844 return make_error<StringError>("__thread_vars block at " +
845 formatv("{0:x}", B->getAddress()) +
846 " has unexpected size",
847 inconvertibleErrorCode());
848
849 auto NewBlockContent = G.allocateBuffer(B->getSize());
850 llvm::copy(B->getContent(), NewBlockContent.data());
851 memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
852 G.getPointerSize());
853 B->setContent(NewBlockContent);
854 }
855 }
856
857 // Transform any TLV edges into GOT edges.
858 for (auto *B : G.blocks())
859 for (auto &E : B->edges())
860 if (E.getKind() ==
861 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
862 E.setKind(jitlink::x86_64::
863 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
864
865 return Error::success();
866 }
867
registerObjectPlatformSections(jitlink::LinkGraph & G,JITDylib & JD)868 Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
869 jitlink::LinkGraph &G, JITDylib &JD) {
870
871 // Add an action to register the eh-frame.
872 if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) {
873 jitlink::SectionRange R(*EHFrameSection);
874 if (!R.empty())
875 G.allocActions().push_back(
876 {cantFail(
877 WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
878 MP.orc_rt_macho_register_ehframe_section, R.getRange())),
879 cantFail(
880 WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
881 MP.orc_rt_macho_deregister_ehframe_section, R.getRange()))});
882 }
883
884 // Get a pointer to the thread data section if there is one. It will be used
885 // below.
886 jitlink::Section *ThreadDataSection =
887 G.findSectionByName(ThreadDataSectionName);
888
889 // Handle thread BSS section if there is one.
890 if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) {
891 // If there's already a thread data section in this graph then merge the
892 // thread BSS section content into it, otherwise just treat the thread
893 // BSS section as the thread data section.
894 if (ThreadDataSection)
895 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
896 else
897 ThreadDataSection = ThreadBSSSection;
898 }
899
900 SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;
901
902 // Having merged thread BSS (if present) and thread data (if present),
903 // record the resulting section range.
904 if (ThreadDataSection) {
905 jitlink::SectionRange R(*ThreadDataSection);
906 if (!R.empty()) {
907 if (MP.State != MachOPlatform::Initialized)
908 return make_error<StringError>("__thread_data section encountered, but "
909 "MachOPlatform has not finished booting",
910 inconvertibleErrorCode());
911
912 MachOPlatformSecs.push_back({ThreadDataSectionName, R.getRange()});
913 }
914 }
915
916 // If any platform sections were found then add an allocation action to call
917 // the registration function.
918 StringRef PlatformSections[] = {
919 ModInitFuncSectionName, ObjCClassListSectionName,
920 ObjCImageInfoSectionName, ObjCSelRefsSectionName,
921 Swift5ProtoSectionName, Swift5ProtosSectionName,
922 Swift5TypesSectionName,
923 };
924
925 for (auto &SecName : PlatformSections) {
926 auto *Sec = G.findSectionByName(SecName);
927 if (!Sec)
928 continue;
929 jitlink::SectionRange R(*Sec);
930 if (R.empty())
931 continue;
932
933 MachOPlatformSecs.push_back({SecName, R.getRange()});
934 }
935
936 if (!MachOPlatformSecs.empty()) {
937 Optional<ExecutorAddr> HeaderAddr;
938 {
939 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
940 auto I = MP.JITDylibToHeaderAddr.find(&JD);
941 if (I != MP.JITDylibToHeaderAddr.end())
942 HeaderAddr = I->second;
943 }
944
945 if (!HeaderAddr)
946 return make_error<StringError>("Missing header for " + JD.getName(),
947 inconvertibleErrorCode());
948
949 // Dump the scraped inits.
950 LLVM_DEBUG({
951 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
952 for (auto &KV : MachOPlatformSecs)
953 dbgs() << " " << KV.first << ": " << KV.second << "\n";
954 });
955
956 using SPSRegisterObjectPlatformSectionsArgs =
957 SPSArgList<SPSExecutorAddr,
958 SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;
959 G.allocActions().push_back(
960 {cantFail(
961 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
962 MP.orc_rt_macho_register_object_platform_sections, *HeaderAddr,
963 MachOPlatformSecs)),
964 cantFail(
965 WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
966 MP.orc_rt_macho_deregister_object_platform_sections,
967 *HeaderAddr, MachOPlatformSecs))});
968 }
969
970 return Error::success();
971 }
972
registerEHSectionsPhase1(jitlink::LinkGraph & G)973 Error MachOPlatform::MachOPlatformPlugin::registerEHSectionsPhase1(
974 jitlink::LinkGraph &G) {
975
976 // If there's no eh-frame there's nothing to do.
977 auto *EHFrameSection = G.findSectionByName(EHFrameSectionName);
978 if (!EHFrameSection)
979 return Error::success();
980
981 // If the eh-frame section is empty there's nothing to do.
982 jitlink::SectionRange R(*EHFrameSection);
983 if (R.empty())
984 return Error::success();
985
986 // Since we're linking the object containing the registration code now the
987 // addresses won't be ready in the platform. We'll have to find them in this
988 // graph instead.
989 ExecutorAddr orc_rt_macho_register_ehframe_section;
990 ExecutorAddr orc_rt_macho_deregister_ehframe_section;
991 for (auto *Sym : G.defined_symbols()) {
992 if (!Sym->hasName())
993 continue;
994 if (Sym->getName() == "___orc_rt_macho_register_ehframe_section")
995 orc_rt_macho_register_ehframe_section = ExecutorAddr(Sym->getAddress());
996 else if (Sym->getName() == "___orc_rt_macho_deregister_ehframe_section")
997 orc_rt_macho_deregister_ehframe_section = ExecutorAddr(Sym->getAddress());
998
999 if (orc_rt_macho_register_ehframe_section &&
1000 orc_rt_macho_deregister_ehframe_section)
1001 break;
1002 }
1003
1004 // If we failed to find the required functions then bail out.
1005 if (!orc_rt_macho_register_ehframe_section ||
1006 !orc_rt_macho_deregister_ehframe_section)
1007 return make_error<StringError>("Could not find eh-frame registration "
1008 "functions during platform bootstrap",
1009 inconvertibleErrorCode());
1010
1011 // Otherwise, add allocation actions to the graph to register eh-frames for
1012 // this object.
1013 G.allocActions().push_back(
1014 {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
1015 orc_rt_macho_register_ehframe_section, R.getRange())),
1016 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
1017 orc_rt_macho_deregister_ehframe_section, R.getRange()))});
1018
1019 return Error::success();
1020 }
1021
1022 } // End namespace orc.
1023 } // End namespace llvm.
1024