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:
MachOLinkGraphBuilder_arm64(const object::MachOObjectFile & Obj,SubtargetFeatures Features)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>
getRelocationKind(const MachO::relocation_info & RI)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>
parsePairRelocation(Block & BlockToFix,Edge::Kind SubtractorKind,const MachO::relocation_info & SubRI,orc::ExecutorAddr FixupAddress,const char * FixupContent,object::relocation_iterator & UnsignedRelItr,object::relocation_iterator & RelEnd)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 
192     bool FixingFromSymbol = true;
193     if (&BlockToFix == &FromSymbol->getAddressable()) {
194       if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) {
195         // From and To are symbols in the same block. Decide direction by offset
196         // instead.
197         if (ToSymbol->getAddress() > FixupAddress)
198           FixingFromSymbol = true;
199         else if (FromSymbol->getAddress() > FixupAddress)
200           FixingFromSymbol = false;
201         else
202           FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress();
203       } else
204         FixingFromSymbol = true;
205     } else {
206       if (&BlockToFix == &ToSymbol->getAddressable())
207         FixingFromSymbol = false;
208       else {
209         // BlockToFix was neither FromSymbol nor ToSymbol.
210         return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
211                                         "either 'A' or 'B' (or a symbol in one "
212                                         "of their alt-entry groups)");
213       }
214     }
215 
216     if (FixingFromSymbol) {
217       TargetSymbol = ToSymbol;
218       DeltaKind = (SubRI.r_length == 3) ? aarch64::Delta64 : aarch64::Delta32;
219       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
220       // FIXME: handle extern 'from'.
221     } else {
222       TargetSymbol = &*FromSymbol;
223       DeltaKind =
224           (SubRI.r_length == 3) ? aarch64::NegDelta64 : aarch64::NegDelta32;
225       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
226     }
227 
228     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
229   }
230 
addRelocations()231   Error addRelocations() override {
232     using namespace support;
233     auto &Obj = getObject();
234 
235     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
236 
237     for (auto &S : Obj.sections()) {
238 
239       orc::ExecutorAddr SectionAddress(S.getAddress());
240 
241       // Skip relocations virtual sections.
242       if (S.isVirtual()) {
243         if (S.relocation_begin() != S.relocation_end())
244           return make_error<JITLinkError>("Virtual section contains "
245                                           "relocations");
246         continue;
247       }
248 
249       auto NSec =
250           findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
251       if (!NSec)
252         return NSec.takeError();
253 
254       // Skip relocations for MachO sections without corresponding graph
255       // sections.
256       {
257         if (!NSec->GraphSection) {
258           LLVM_DEBUG({
259             dbgs() << "  Skipping relocations for MachO section "
260                    << NSec->SegName << "/" << NSec->SectName
261                    << " which has no associated graph section\n";
262           });
263           continue;
264         }
265       }
266 
267       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
268            RelItr != RelEnd; ++RelItr) {
269 
270         MachO::relocation_info RI = getRelocationInfo(RelItr);
271 
272         // Validate the relocation kind.
273         auto MachORelocKind = getRelocationKind(RI);
274         if (!MachORelocKind)
275           return MachORelocKind.takeError();
276 
277         // Find the address of the value to fix up.
278         orc::ExecutorAddr FixupAddress =
279             SectionAddress + (uint32_t)RI.r_address;
280         LLVM_DEBUG({
281           dbgs() << "  " << NSec->SectName << " + "
282                  << formatv("{0:x8}", RI.r_address) << ":\n";
283         });
284 
285         // Find the block that the fixup points to.
286         Block *BlockToFix = nullptr;
287         {
288           auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
289           if (!SymbolToFixOrErr)
290             return SymbolToFixOrErr.takeError();
291           BlockToFix = &SymbolToFixOrErr->getBlock();
292         }
293 
294         if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
295             BlockToFix->getAddress() + BlockToFix->getContent().size())
296           return make_error<JITLinkError>(
297               "Relocation content extends past end of fixup block");
298 
299         Edge::Kind Kind = Edge::Invalid;
300 
301         // Get a pointer to the fixup content.
302         const char *FixupContent = BlockToFix->getContent().data() +
303                                    (FixupAddress - BlockToFix->getAddress());
304 
305         // The target symbol and addend will be populated by the switch below.
306         Symbol *TargetSymbol = nullptr;
307         uint64_t Addend = 0;
308 
309         if (*MachORelocKind == MachOPairedAddend) {
310           // If this is an Addend relocation then process it and move to the
311           // paired reloc.
312 
313           Addend = SignExtend64(RI.r_symbolnum, 24);
314 
315           if (RelItr == RelEnd)
316             return make_error<JITLinkError>("Unpaired Addend reloc at " +
317                                             formatv("{0:x16}", FixupAddress));
318           ++RelItr;
319           RI = getRelocationInfo(RelItr);
320 
321           MachORelocKind = getRelocationKind(RI);
322           if (!MachORelocKind)
323             return MachORelocKind.takeError();
324 
325           if (*MachORelocKind != MachOBranch26 &&
326               *MachORelocKind != MachOPage21 &&
327               *MachORelocKind != MachOPageOffset12)
328             return make_error<JITLinkError>(
329                 "Invalid relocation pair: Addend + " +
330                 StringRef(getMachOARM64RelocationKindName(*MachORelocKind)));
331 
332           LLVM_DEBUG({
333             dbgs() << "    Addend: value = " << formatv("{0:x6}", Addend)
334                    << ", pair is "
335                    << getMachOARM64RelocationKindName(*MachORelocKind) << "\n";
336           });
337 
338           // Find the address of the value to fix up.
339           orc::ExecutorAddr PairedFixupAddress =
340               SectionAddress + (uint32_t)RI.r_address;
341           if (PairedFixupAddress != FixupAddress)
342             return make_error<JITLinkError>("Paired relocation points at "
343                                             "different target");
344         }
345 
346         switch (*MachORelocKind) {
347         case MachOBranch26: {
348           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
349             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
350           else
351             return TargetSymbolOrErr.takeError();
352           uint32_t Instr = *(const ulittle32_t *)FixupContent;
353           if ((Instr & 0x7fffffff) != 0x14000000)
354             return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
355                                             "instruction with a zero addend");
356           Kind = aarch64::Branch26PCRel;
357           break;
358         }
359         case MachOPointer32:
360           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
361             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
362           else
363             return TargetSymbolOrErr.takeError();
364           Addend = *(const ulittle32_t *)FixupContent;
365           Kind = aarch64::Pointer32;
366           break;
367         case MachOPointer64:
368           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
369             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
370           else
371             return TargetSymbolOrErr.takeError();
372           Addend = *(const ulittle64_t *)FixupContent;
373           Kind = aarch64::Pointer64;
374           break;
375         case MachOPointer64Anon: {
376           orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
377           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
378           if (!TargetNSec)
379             return TargetNSec.takeError();
380           if (auto TargetSymbolOrErr =
381                   findSymbolByAddress(*TargetNSec, TargetAddress))
382             TargetSymbol = &*TargetSymbolOrErr;
383           else
384             return TargetSymbolOrErr.takeError();
385           Addend = TargetAddress - TargetSymbol->getAddress();
386           Kind = aarch64::Pointer64;
387           break;
388         }
389         case MachOPage21:
390         case MachOGOTPage21:
391         case MachOTLVPage21: {
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           if ((Instr & 0xffffffe0) != 0x90000000)
398             return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
399                                             "ADRP instruction with a zero "
400                                             "addend");
401 
402           if (*MachORelocKind == MachOPage21) {
403             Kind = aarch64::Page21;
404           } else if (*MachORelocKind == MachOGOTPage21) {
405             Kind = aarch64::RequestGOTAndTransformToPage21;
406           } else if (*MachORelocKind == MachOTLVPage21) {
407             Kind = aarch64::RequestTLVPAndTransformToPage21;
408           }
409           break;
410         }
411         case MachOPageOffset12: {
412           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
413             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
414           else
415             return TargetSymbolOrErr.takeError();
416           uint32_t Instr = *(const ulittle32_t *)FixupContent;
417           uint32_t EncodedAddend = (Instr & 0x003FFC00) >> 10;
418           if (EncodedAddend != 0)
419             return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero "
420                                             "encoded addend");
421           Kind = aarch64::PageOffset12;
422           break;
423         }
424         case MachOGOTPageOffset12:
425         case MachOTLVPageOffset12: {
426           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
427             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
428           else
429             return TargetSymbolOrErr.takeError();
430           uint32_t Instr = *(const ulittle32_t *)FixupContent;
431           if ((Instr & 0xfffffc00) != 0xf9400000)
432             return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
433                                             "immediate instruction with a zero "
434                                             "addend");
435 
436           if (*MachORelocKind == MachOGOTPageOffset12) {
437             Kind = aarch64::RequestGOTAndTransformToPageOffset12;
438           } else if (*MachORelocKind == MachOTLVPageOffset12) {
439             Kind = aarch64::RequestTLVPAndTransformToPageOffset12;
440           }
441           break;
442         }
443         case MachOPointerToGOT:
444           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
445             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
446           else
447             return TargetSymbolOrErr.takeError();
448 
449           Kind = aarch64::RequestGOTAndTransformToDelta32;
450           break;
451         case MachODelta32:
452         case MachODelta64: {
453           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
454           // parsePairRelocation handles the paired reloc, and returns the
455           // edge kind to be used (either Delta32/Delta64, or
456           // NegDelta32/NegDelta64, depending on the direction of the
457           // subtraction) along with the addend.
458           auto PairInfo =
459               parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
460                                   FixupAddress, FixupContent, ++RelItr, RelEnd);
461           if (!PairInfo)
462             return PairInfo.takeError();
463           std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
464           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
465           break;
466         }
467         default:
468           llvm_unreachable("Special relocation kind should not appear in "
469                            "mach-o file");
470         }
471 
472         LLVM_DEBUG({
473           dbgs() << "    ";
474           Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
475                   Addend);
476           printEdge(dbgs(), *BlockToFix, GE, aarch64::getEdgeKindName(Kind));
477           dbgs() << "\n";
478         });
479         BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
480                             *TargetSymbol, Addend);
481       }
482     }
483     return Error::success();
484   }
485 
486   /// Return the string name of the given MachO arm64 edge kind.
getMachOARM64RelocationKindName(Edge::Kind R)487   const char *getMachOARM64RelocationKindName(Edge::Kind R) {
488     switch (R) {
489     case MachOBranch26:
490       return "MachOBranch26";
491     case MachOPointer64:
492       return "MachOPointer64";
493     case MachOPointer64Anon:
494       return "MachOPointer64Anon";
495     case MachOPage21:
496       return "MachOPage21";
497     case MachOPageOffset12:
498       return "MachOPageOffset12";
499     case MachOGOTPage21:
500       return "MachOGOTPage21";
501     case MachOGOTPageOffset12:
502       return "MachOGOTPageOffset12";
503     case MachOTLVPage21:
504       return "MachOTLVPage21";
505     case MachOTLVPageOffset12:
506       return "MachOTLVPageOffset12";
507     case MachOPointerToGOT:
508       return "MachOPointerToGOT";
509     case MachOPairedAddend:
510       return "MachOPairedAddend";
511     case MachOLDRLiteral19:
512       return "MachOLDRLiteral19";
513     case MachODelta32:
514       return "MachODelta32";
515     case MachODelta64:
516       return "MachODelta64";
517     case MachONegDelta32:
518       return "MachONegDelta32";
519     case MachONegDelta64:
520       return "MachONegDelta64";
521     default:
522       return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
523     }
524   }
525 
526   unsigned NumSymbols = 0;
527 };
528 
529 } // namespace
530 
531 namespace llvm {
532 namespace jitlink {
533 
buildTables_MachO_arm64(LinkGraph & G)534 Error buildTables_MachO_arm64(LinkGraph &G) {
535   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
536 
537   aarch64::GOTTableManager GOT;
538   aarch64::PLTTableManager PLT(GOT);
539   visitExistingEdges(G, GOT, PLT);
540   return Error::success();
541 }
542 
543 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
544   friend class JITLinker<MachOJITLinker_arm64>;
545 
546 public:
MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)547   MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
548                        std::unique_ptr<LinkGraph> G,
549                        PassConfiguration PassConfig)
550       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
551 
552 private:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const553   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
554     return aarch64::applyFixup(G, B, E);
555   }
556 
557   uint64_t NullValue = 0;
558 };
559 
560 Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer)561 createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer) {
562   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
563   if (!MachOObj)
564     return MachOObj.takeError();
565 
566   auto Features = (*MachOObj)->getFeatures();
567   if (!Features)
568     return Features.takeError();
569 
570   return MachOLinkGraphBuilder_arm64(**MachOObj, std::move(*Features))
571       .buildGraph();
572 }
573 
link_MachO_arm64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)574 void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
575                       std::unique_ptr<JITLinkContext> Ctx) {
576 
577   PassConfiguration Config;
578 
579   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
580     // Add a mark-live pass.
581     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
582       Config.PrePrunePasses.push_back(std::move(MarkLive));
583     else
584       Config.PrePrunePasses.push_back(markAllSymbolsLive);
585 
586     // Add compact unwind splitter pass.
587     Config.PrePrunePasses.push_back(
588         CompactUnwindSplitter("__LD,__compact_unwind"));
589 
590     // Add eh-frame passes.
591     // FIXME: Prune eh-frames for which compact-unwind is available once
592     // we support compact-unwind registration with libunwind.
593     Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_arm64());
594     Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_arm64());
595 
596     // Add an in-place GOT/Stubs pass.
597     Config.PostPrunePasses.push_back(buildTables_MachO_arm64);
598   }
599 
600   if (auto Err = Ctx->modifyPassConfig(*G, Config))
601     return Ctx->notifyFailed(std::move(Err));
602 
603   // Construct a JITLinker and run the link function.
604   MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config));
605 }
606 
createEHFrameSplitterPass_MachO_arm64()607 LinkGraphPassFunction createEHFrameSplitterPass_MachO_arm64() {
608   return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
609 }
610 
createEHFrameEdgeFixerPass_MachO_arm64()611 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_arm64() {
612   return EHFrameEdgeFixer("__TEXT,__eh_frame", aarch64::PointerSize,
613                           aarch64::Pointer32, aarch64::Pointer64,
614                           aarch64::Delta32, aarch64::Delta64,
615                           aarch64::NegDelta32);
616 }
617 
618 } // end namespace jitlink
619 } // end namespace llvm
620