xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp (revision 212cdc9a377a1b3ac96be0da20212592ebd2c818)
1 //===---- MachO_arm64.cpp - JIT linker implementation for MachO/arm64 -----===//
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 // MachO/arm64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h"
14 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
15 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
16 
17 #include "DefineExternalSectionStartAndEndSymbols.h"
18 #include "MachOLinkGraphBuilder.h"
19 
20 #define DEBUG_TYPE "jitlink"
21 
22 using namespace llvm;
23 using namespace llvm::jitlink;
24 
25 namespace {
26 
27 class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
28 public:
29   MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj,
30                               std::shared_ptr<orc::SymbolStringPool> SSP,
31                               SubtargetFeatures Features)
32       : MachOLinkGraphBuilder(Obj, std::move(SSP), getObjectTriple(Obj),
33                               std::move(Features), aarch64::getEdgeKindName),
34         NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
35 
36 private:
37   enum MachOARM64RelocationKind : Edge::Kind {
38     MachOBranch26 = Edge::FirstRelocation,
39     MachOPointer32,
40     MachOPointer64,
41     MachOPointer64Anon,
42     MachOPointer64Authenticated,
43     MachOPage21,
44     MachOPageOffset12,
45     MachOGOTPage21,
46     MachOGOTPageOffset12,
47     MachOTLVPage21,
48     MachOTLVPageOffset12,
49     MachOPointerToGOT,
50     MachOPairedAddend,
51     MachOLDRLiteral19,
52     MachODelta32,
53     MachODelta64,
54     MachONegDelta32,
55     MachONegDelta64,
56   };
57 
58   static Triple getObjectTriple(const object::MachOObjectFile &Obj) {
59     // Get the CPU sub-type from the header.
60     // jitLink_MachO should already have validated that the buffer is big enough
61     // to cover a mach_header64 so this is safe.
62     uint32_t CPUSubType =
63         *(const support::ulittle32_t *)(Obj.getData().data() + 8);
64     CPUSubType &= ~MachO::CPU_SUBTYPE_MASK;
65     if (CPUSubType == MachO::CPU_SUBTYPE_ARM64E)
66       return Triple("arm64e-apple-darwin");
67     return Triple("arm64-apple-darwin");
68   }
69 
70   static Expected<MachOARM64RelocationKind>
71   getRelocationKind(const MachO::relocation_info &RI) {
72     switch (RI.r_type) {
73     case MachO::ARM64_RELOC_UNSIGNED:
74       if (!RI.r_pcrel) {
75         if (RI.r_length == 3)
76           return RI.r_extern ? MachOPointer64 : MachOPointer64Anon;
77         else if (RI.r_length == 2)
78           return MachOPointer32;
79       }
80       break;
81     case MachO::ARM64_RELOC_SUBTRACTOR:
82       // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
83       // Initially represent SUBTRACTOR relocations with 'Delta<W>'.
84       // They may be turned into NegDelta<W> by parsePairRelocation.
85       if (!RI.r_pcrel && RI.r_extern) {
86         if (RI.r_length == 2)
87           return MachODelta32;
88         else if (RI.r_length == 3)
89           return MachODelta64;
90       }
91       break;
92     case MachO::ARM64_RELOC_BRANCH26:
93       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
94         return MachOBranch26;
95       break;
96     case MachO::ARM64_RELOC_PAGE21:
97       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
98         return MachOPage21;
99       break;
100     case MachO::ARM64_RELOC_PAGEOFF12:
101       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
102         return MachOPageOffset12;
103       break;
104     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
105       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
106         return MachOGOTPage21;
107       break;
108     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
109       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
110         return MachOGOTPageOffset12;
111       break;
112     case MachO::ARM64_RELOC_POINTER_TO_GOT:
113       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
114         return MachOPointerToGOT;
115       break;
116     case MachO::ARM64_RELOC_ADDEND:
117       if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2)
118         return MachOPairedAddend;
119       break;
120     case MachO::ARM64_RELOC_AUTHENTICATED_POINTER:
121       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 3)
122         return MachOPointer64Authenticated;
123       break;
124     case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
125       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
126         return MachOTLVPage21;
127       break;
128     case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
129       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
130         return MachOTLVPageOffset12;
131       break;
132     }
133 
134     return make_error<JITLinkError>(
135         "Unsupported arm64 relocation: address=" +
136         formatv("{0:x8}", RI.r_address) +
137         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
138         ", kind=" + formatv("{0:x1}", RI.r_type) +
139         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
140         ", extern=" + (RI.r_extern ? "true" : "false") +
141         ", length=" + formatv("{0:d}", RI.r_length));
142   }
143 
144   using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
145 
146   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
147   // returns the edge kind and addend to be used.
148   Expected<PairRelocInfo>
149   parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
150                       const MachO::relocation_info &SubRI,
151                       orc::ExecutorAddr FixupAddress, const char *FixupContent,
152                       object::relocation_iterator &UnsignedRelItr,
153                       object::relocation_iterator &RelEnd) {
154     using namespace support;
155 
156     assert(((SubtractorKind == MachODelta32 && SubRI.r_length == 2) ||
157             (SubtractorKind == MachODelta64 && SubRI.r_length == 3)) &&
158            "Subtractor kind should match length");
159     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
160     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
161 
162     if (UnsignedRelItr == RelEnd)
163       return make_error<JITLinkError>("arm64 SUBTRACTOR without paired "
164                                       "UNSIGNED relocation");
165 
166     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
167 
168     if (SubRI.r_address != UnsignedRI.r_address)
169       return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED "
170                                       "point to different addresses");
171 
172     if (SubRI.r_length != UnsignedRI.r_length)
173       return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired "
174                                       "UNSIGNED reloc must match");
175 
176     Symbol *FromSymbol;
177     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
178       FromSymbol = FromSymbolOrErr->GraphSymbol;
179     else
180       return FromSymbolOrErr.takeError();
181 
182     // Read the current fixup value.
183     uint64_t FixupValue = 0;
184     if (SubRI.r_length == 3)
185       FixupValue = *(const little64_t *)FixupContent;
186     else
187       FixupValue = *(const little32_t *)FixupContent;
188 
189     // Find 'ToSymbol' using symbol number or address, depending on whether the
190     // paired UNSIGNED relocation is extern.
191     Symbol *ToSymbol = nullptr;
192     if (UnsignedRI.r_extern) {
193       // Find target symbol by symbol index.
194       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
195         ToSymbol = ToSymbolOrErr->GraphSymbol;
196       else
197         return ToSymbolOrErr.takeError();
198     } else {
199       auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
200       if (!ToSymbolSec)
201         return ToSymbolSec.takeError();
202       ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
203       assert(ToSymbol && "No symbol for section");
204       FixupValue -= ToSymbol->getAddress().getValue();
205     }
206 
207     Edge::Kind DeltaKind;
208     Symbol *TargetSymbol;
209     uint64_t Addend;
210 
211     bool FixingFromSymbol = true;
212     if (&BlockToFix == &FromSymbol->getAddressable()) {
213       if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) {
214         // From and To are symbols in the same block. Decide direction by offset
215         // instead.
216         if (ToSymbol->getAddress() > FixupAddress)
217           FixingFromSymbol = true;
218         else if (FromSymbol->getAddress() > FixupAddress)
219           FixingFromSymbol = false;
220         else
221           FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress();
222       } else
223         FixingFromSymbol = true;
224     } else {
225       if (&BlockToFix == &ToSymbol->getAddressable())
226         FixingFromSymbol = false;
227       else {
228         // BlockToFix was neither FromSymbol nor ToSymbol.
229         return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
230                                         "either 'A' or 'B' (or a symbol in one "
231                                         "of their alt-entry groups)");
232       }
233     }
234 
235     if (FixingFromSymbol) {
236       TargetSymbol = ToSymbol;
237       DeltaKind = (SubRI.r_length == 3) ? aarch64::Delta64 : aarch64::Delta32;
238       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
239       // FIXME: handle extern 'from'.
240     } else {
241       TargetSymbol = &*FromSymbol;
242       DeltaKind =
243           (SubRI.r_length == 3) ? aarch64::NegDelta64 : aarch64::NegDelta32;
244       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
245     }
246 
247     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
248   }
249 
250   Error addRelocations() override {
251     using namespace support;
252     auto &Obj = getObject();
253 
254     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
255 
256     for (auto &S : Obj.sections()) {
257 
258       orc::ExecutorAddr SectionAddress(S.getAddress());
259 
260       // Skip relocations virtual sections.
261       if (S.isVirtual()) {
262         if (S.relocation_begin() != S.relocation_end())
263           return make_error<JITLinkError>("Virtual section contains "
264                                           "relocations");
265         continue;
266       }
267 
268       auto NSec =
269           findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
270       if (!NSec)
271         return NSec.takeError();
272 
273       // Skip relocations for MachO sections without corresponding graph
274       // sections.
275       {
276         if (!NSec->GraphSection) {
277           LLVM_DEBUG({
278             dbgs() << "  Skipping relocations for MachO section "
279                    << NSec->SegName << "/" << NSec->SectName
280                    << " which has no associated graph section\n";
281           });
282           continue;
283         }
284       }
285 
286       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
287            RelItr != RelEnd; ++RelItr) {
288 
289         MachO::relocation_info RI = getRelocationInfo(RelItr);
290 
291         // Validate the relocation kind.
292         auto MachORelocKind = getRelocationKind(RI);
293         if (!MachORelocKind)
294           return MachORelocKind.takeError();
295 
296         // Find the address of the value to fix up.
297         orc::ExecutorAddr FixupAddress =
298             SectionAddress + (uint32_t)RI.r_address;
299         LLVM_DEBUG({
300           dbgs() << "  " << NSec->SectName << " + "
301                  << formatv("{0:x8}", RI.r_address) << ":\n";
302         });
303 
304         // Find the block that the fixup points to.
305         Block *BlockToFix = nullptr;
306         {
307           auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
308           if (!SymbolToFixOrErr)
309             return SymbolToFixOrErr.takeError();
310           BlockToFix = &SymbolToFixOrErr->getBlock();
311         }
312 
313         if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
314             BlockToFix->getAddress() + BlockToFix->getContent().size())
315           return make_error<JITLinkError>(
316               "Relocation content extends past end of fixup block");
317 
318         Edge::Kind Kind = Edge::Invalid;
319 
320         // Get a pointer to the fixup content.
321         const char *FixupContent = BlockToFix->getContent().data() +
322                                    (FixupAddress - BlockToFix->getAddress());
323 
324         // The target symbol and addend will be populated by the switch below.
325         Symbol *TargetSymbol = nullptr;
326         uint64_t Addend = 0;
327 
328         if (*MachORelocKind == MachOPairedAddend) {
329           // If this is an Addend relocation then process it and move to the
330           // paired reloc.
331 
332           Addend = SignExtend64(RI.r_symbolnum, 24);
333 
334           ++RelItr;
335           if (RelItr == RelEnd)
336             return make_error<JITLinkError>("Unpaired Addend reloc at " +
337                                             formatv("{0:x16}", FixupAddress));
338           RI = getRelocationInfo(RelItr);
339 
340           MachORelocKind = getRelocationKind(RI);
341           if (!MachORelocKind)
342             return MachORelocKind.takeError();
343 
344           if (*MachORelocKind != MachOBranch26 &&
345               *MachORelocKind != MachOPage21 &&
346               *MachORelocKind != MachOPageOffset12)
347             return make_error<JITLinkError>(
348                 "Invalid relocation pair: Addend + " +
349                 StringRef(getMachOARM64RelocationKindName(*MachORelocKind)));
350 
351           LLVM_DEBUG({
352             dbgs() << "    Addend: value = " << formatv("{0:x6}", Addend)
353                    << ", pair is "
354                    << getMachOARM64RelocationKindName(*MachORelocKind) << "\n";
355           });
356 
357           // Find the address of the value to fix up.
358           orc::ExecutorAddr PairedFixupAddress =
359               SectionAddress + (uint32_t)RI.r_address;
360           if (PairedFixupAddress != FixupAddress)
361             return make_error<JITLinkError>("Paired relocation points at "
362                                             "different target");
363         }
364 
365         switch (*MachORelocKind) {
366         case MachOBranch26: {
367           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
368             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
369           else
370             return TargetSymbolOrErr.takeError();
371           uint32_t Instr = *(const ulittle32_t *)FixupContent;
372           if ((Instr & 0x7fffffff) != 0x14000000)
373             return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
374                                             "instruction with a zero addend");
375           Kind = aarch64::Branch26PCRel;
376           break;
377         }
378         case MachOPointer32:
379           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
380             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
381           else
382             return TargetSymbolOrErr.takeError();
383           Addend = *(const ulittle32_t *)FixupContent;
384           Kind = aarch64::Pointer32;
385           break;
386         case MachOPointer64:
387         case MachOPointer64Authenticated:
388           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
389             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
390           else
391             return TargetSymbolOrErr.takeError();
392           Addend = *(const ulittle64_t *)FixupContent;
393           Kind = *MachORelocKind == MachOPointer64
394                      ? aarch64::Pointer64
395                      : aarch64::Pointer64Authenticated;
396           break;
397         case MachOPointer64Anon: {
398           orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
399           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
400           if (!TargetNSec)
401             return TargetNSec.takeError();
402           if (auto TargetSymbolOrErr =
403                   findSymbolByAddress(*TargetNSec, TargetAddress))
404             TargetSymbol = &*TargetSymbolOrErr;
405           else
406             return TargetSymbolOrErr.takeError();
407           Addend = TargetAddress - TargetSymbol->getAddress();
408           Kind = aarch64::Pointer64;
409           break;
410         }
411         case MachOPage21:
412         case MachOGOTPage21:
413         case MachOTLVPage21: {
414           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
415             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
416           else
417             return TargetSymbolOrErr.takeError();
418           uint32_t Instr = *(const ulittle32_t *)FixupContent;
419           if ((Instr & 0xffffffe0) != 0x90000000)
420             return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
421                                             "ADRP instruction with a zero "
422                                             "addend");
423 
424           if (*MachORelocKind == MachOPage21) {
425             Kind = aarch64::Page21;
426           } else if (*MachORelocKind == MachOGOTPage21) {
427             Kind = aarch64::RequestGOTAndTransformToPage21;
428           } else if (*MachORelocKind == MachOTLVPage21) {
429             Kind = aarch64::RequestTLVPAndTransformToPage21;
430           }
431           break;
432         }
433         case MachOPageOffset12: {
434           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
435             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
436           else
437             return TargetSymbolOrErr.takeError();
438           uint32_t Instr = *(const ulittle32_t *)FixupContent;
439           uint32_t EncodedAddend = (Instr & 0x003FFC00) >> 10;
440           if (EncodedAddend != 0)
441             return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero "
442                                             "encoded addend");
443           Kind = aarch64::PageOffset12;
444           break;
445         }
446         case MachOGOTPageOffset12:
447         case MachOTLVPageOffset12: {
448           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
449             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
450           else
451             return TargetSymbolOrErr.takeError();
452           uint32_t Instr = *(const ulittle32_t *)FixupContent;
453           if ((Instr & 0xfffffc00) != 0xf9400000)
454             return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
455                                             "immediate instruction with a zero "
456                                             "addend");
457 
458           if (*MachORelocKind == MachOGOTPageOffset12) {
459             Kind = aarch64::RequestGOTAndTransformToPageOffset12;
460           } else if (*MachORelocKind == MachOTLVPageOffset12) {
461             Kind = aarch64::RequestTLVPAndTransformToPageOffset12;
462           }
463           break;
464         }
465         case MachOPointerToGOT:
466           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
467             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
468           else
469             return TargetSymbolOrErr.takeError();
470 
471           Kind = aarch64::RequestGOTAndTransformToDelta32;
472           break;
473         case MachODelta32:
474         case MachODelta64: {
475           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
476           // parsePairRelocation handles the paired reloc, and returns the
477           // edge kind to be used (either Delta32/Delta64, or
478           // NegDelta32/NegDelta64, depending on the direction of the
479           // subtraction) along with the addend.
480           auto PairInfo =
481               parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
482                                   FixupAddress, FixupContent, ++RelItr, RelEnd);
483           if (!PairInfo)
484             return PairInfo.takeError();
485           std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
486           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
487           break;
488         }
489         default:
490           llvm_unreachable("Special relocation kind should not appear in "
491                            "mach-o file");
492         }
493 
494         LLVM_DEBUG({
495           dbgs() << "    ";
496           Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
497                   Addend);
498           printEdge(dbgs(), *BlockToFix, GE, aarch64::getEdgeKindName(Kind));
499           dbgs() << "\n";
500         });
501         BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
502                             *TargetSymbol, Addend);
503       }
504     }
505     return Error::success();
506   }
507 
508   /// Return the string name of the given MachO arm64 edge kind.
509   const char *getMachOARM64RelocationKindName(Edge::Kind R) {
510     switch (R) {
511     case MachOBranch26:
512       return "MachOBranch26";
513     case MachOPointer64:
514       return "MachOPointer64";
515     case MachOPointer64Anon:
516       return "MachOPointer64Anon";
517     case MachOPointer64Authenticated:
518       return "MachOPointer64Authenticated";
519     case MachOPage21:
520       return "MachOPage21";
521     case MachOPageOffset12:
522       return "MachOPageOffset12";
523     case MachOGOTPage21:
524       return "MachOGOTPage21";
525     case MachOGOTPageOffset12:
526       return "MachOGOTPageOffset12";
527     case MachOTLVPage21:
528       return "MachOTLVPage21";
529     case MachOTLVPageOffset12:
530       return "MachOTLVPageOffset12";
531     case MachOPointerToGOT:
532       return "MachOPointerToGOT";
533     case MachOPairedAddend:
534       return "MachOPairedAddend";
535     case MachOLDRLiteral19:
536       return "MachOLDRLiteral19";
537     case MachODelta32:
538       return "MachODelta32";
539     case MachODelta64:
540       return "MachODelta64";
541     case MachONegDelta32:
542       return "MachONegDelta32";
543     case MachONegDelta64:
544       return "MachONegDelta64";
545     default:
546       return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
547     }
548   }
549 
550   unsigned NumSymbols = 0;
551 };
552 
553 } // namespace
554 
555 namespace llvm {
556 namespace jitlink {
557 
558 Error buildTables_MachO_arm64(LinkGraph &G) {
559   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
560 
561   aarch64::GOTTableManager GOT(G);
562   aarch64::PLTTableManager PLT(G, GOT);
563   visitExistingEdges(G, GOT, PLT);
564   return Error::success();
565 }
566 
567 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
568   friend class JITLinker<MachOJITLinker_arm64>;
569 
570 public:
571   MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
572                        std::unique_ptr<LinkGraph> G,
573                        PassConfiguration PassConfig)
574       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
575 
576 private:
577   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
578     return aarch64::applyFixup(G, B, E, nullptr);
579   }
580 
581   uint64_t NullValue = 0;
582 };
583 
584 Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromMachOObject_arm64(
585     MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
586   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
587   if (!MachOObj)
588     return MachOObj.takeError();
589 
590   auto Features = (*MachOObj)->getFeatures();
591   if (!Features)
592     return Features.takeError();
593 
594   return MachOLinkGraphBuilder_arm64(**MachOObj, std::move(SSP),
595                                      std::move(*Features))
596       .buildGraph();
597 }
598 
599 static Error applyPACSigningToModInitPointers(LinkGraph &G) {
600   assert(G.getTargetTriple().getSubArch() == Triple::AArch64SubArch_arm64e &&
601          "PAC signing only valid for arm64e");
602 
603   if (auto *ModInitSec = G.findSectionByName("__DATA,__mod_init_func")) {
604     for (auto *B : ModInitSec->blocks()) {
605       for (auto &E : B->edges()) {
606         if (E.getKind() == aarch64::Pointer64) {
607 
608           // Check that we have room to encode pointer signing bits.
609           if (E.getAddend() >> 32)
610             return make_error<JITLinkError>(
611                 "In " + G.getName() + ", __mod_init_func pointer at " +
612                 formatv("{0:x}", B->getFixupAddress(E).getValue()) +
613                 " has data in high bits of addend (addend >= 2^32)");
614 
615           // Change edge to Pointer64Authenticated, encode signing:
616           // key = asia, discriminator = 0, diversity = 0.
617           Edge::AddendT SigningBits = 0x1ULL << 63;
618           E.setKind(aarch64::Pointer64Authenticated);
619           E.setAddend(E.getAddend() | SigningBits);
620         }
621       }
622     }
623   }
624 
625   return Error::success();
626 }
627 
628 void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
629                       std::unique_ptr<JITLinkContext> Ctx) {
630 
631   PassConfiguration Config;
632 
633   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
634     // Add a mark-live pass.
635     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
636       Config.PrePrunePasses.push_back(std::move(MarkLive));
637     else
638       Config.PrePrunePasses.push_back(markAllSymbolsLive);
639 
640     // Add compact unwind splitter pass.
641     Config.PrePrunePasses.push_back(
642         CompactUnwindSplitter("__LD,__compact_unwind"));
643 
644     // Add eh-frame passes.
645     // FIXME: Prune eh-frames for which compact-unwind is available once
646     // we support compact-unwind registration with libunwind.
647     Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_arm64());
648     Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_arm64());
649 
650     // Resolve any external section start / end symbols.
651     Config.PostAllocationPasses.push_back(
652         createDefineExternalSectionStartAndEndSymbolsPass(
653             identifyMachOSectionStartAndEndSymbols));
654 
655     // Add an in-place GOT/Stubs pass.
656     Config.PostPrunePasses.push_back(buildTables_MachO_arm64);
657 
658     // If this is an arm64e graph then add pointer signing passes.
659     if (G->getTargetTriple().isArm64e()) {
660       Config.PostPrunePasses.push_back(applyPACSigningToModInitPointers);
661       Config.PostPrunePasses.push_back(
662           aarch64::createEmptyPointerSigningFunction);
663       Config.PreFixupPasses.push_back(
664           aarch64::lowerPointer64AuthEdgesToSigningFunction);
665     }
666   }
667 
668   if (auto Err = Ctx->modifyPassConfig(*G, Config))
669     return Ctx->notifyFailed(std::move(Err));
670 
671   // Construct a JITLinker and run the link function.
672   MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config));
673 }
674 
675 LinkGraphPassFunction createEHFrameSplitterPass_MachO_arm64() {
676   return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
677 }
678 
679 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_arm64() {
680   return EHFrameEdgeFixer("__TEXT,__eh_frame", aarch64::PointerSize,
681                           aarch64::Pointer32, aarch64::Pointer64,
682                           aarch64::Delta32, aarch64::Delta64,
683                           aarch64::NegDelta32);
684 }
685 
686 } // end namespace jitlink
687 } // end namespace llvm
688