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