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