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