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 
15 #include "BasicGOTAndStubsBuilder.h"
16 #include "MachOLinkGraphBuilder.h"
17 
18 #define DEBUG_TYPE "jitlink"
19 
20 using namespace llvm;
21 using namespace llvm::jitlink;
22 using namespace llvm::jitlink::MachO_arm64_Edges;
23 
24 namespace {
25 
26 class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
27 public:
28   MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj)
29       : MachOLinkGraphBuilder(Obj),
30         NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
31 
32 private:
33   static Expected<MachOARM64RelocationKind>
34   getRelocationKind(const MachO::relocation_info &RI) {
35     switch (RI.r_type) {
36     case MachO::ARM64_RELOC_UNSIGNED:
37       if (!RI.r_pcrel) {
38         if (RI.r_length == 3)
39           return RI.r_extern ? Pointer64 : Pointer64Anon;
40         else if (RI.r_length == 2)
41           return Pointer32;
42       }
43       break;
44     case MachO::ARM64_RELOC_SUBTRACTOR:
45       // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
46       // Initially represent SUBTRACTOR relocations with 'Delta<W>'.
47       // They may be turned into NegDelta<W> by parsePairRelocation.
48       if (!RI.r_pcrel && RI.r_extern) {
49         if (RI.r_length == 2)
50           return Delta32;
51         else if (RI.r_length == 3)
52           return Delta64;
53       }
54       break;
55     case MachO::ARM64_RELOC_BRANCH26:
56       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
57         return Branch26;
58       break;
59     case MachO::ARM64_RELOC_PAGE21:
60       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
61         return Page21;
62       break;
63     case MachO::ARM64_RELOC_PAGEOFF12:
64       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
65         return PageOffset12;
66       break;
67     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
68       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
69         return GOTPage21;
70       break;
71     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
72       if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
73         return GOTPageOffset12;
74       break;
75     case MachO::ARM64_RELOC_POINTER_TO_GOT:
76       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
77         return PointerToGOT;
78       break;
79     case MachO::ARM64_RELOC_ADDEND:
80       if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2)
81         return PairedAddend;
82       break;
83     }
84 
85     return make_error<JITLinkError>(
86         "Unsupported arm64 relocation: address=" +
87         formatv("{0:x8}", RI.r_address) +
88         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
89         ", kind=" + formatv("{0:x1}", RI.r_type) +
90         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
91         ", extern=" + (RI.r_extern ? "true" : "false") +
92         ", length=" + formatv("{0:d}", RI.r_length));
93   }
94 
95   using PairRelocInfo =
96       std::tuple<MachOARM64RelocationKind, Symbol *, uint64_t>;
97 
98   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
99   // returns the edge kind and addend to be used.
100   Expected<PairRelocInfo>
101   parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
102                       const MachO::relocation_info &SubRI,
103                       JITTargetAddress FixupAddress, const char *FixupContent,
104                       object::relocation_iterator &UnsignedRelItr,
105                       object::relocation_iterator &RelEnd) {
106     using namespace support;
107 
108     assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
109             (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
110            "Subtractor kind should match length");
111     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
112     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
113 
114     if (UnsignedRelItr == RelEnd)
115       return make_error<JITLinkError>("arm64 SUBTRACTOR without paired "
116                                       "UNSIGNED relocation");
117 
118     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
119 
120     if (SubRI.r_address != UnsignedRI.r_address)
121       return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED "
122                                       "point to different addresses");
123 
124     if (SubRI.r_length != UnsignedRI.r_length)
125       return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired "
126                                       "UNSIGNED reloc must match");
127 
128     Symbol *FromSymbol;
129     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
130       FromSymbol = FromSymbolOrErr->GraphSymbol;
131     else
132       return FromSymbolOrErr.takeError();
133 
134     // Read the current fixup value.
135     uint64_t FixupValue = 0;
136     if (SubRI.r_length == 3)
137       FixupValue = *(const little64_t *)FixupContent;
138     else
139       FixupValue = *(const little32_t *)FixupContent;
140 
141     // Find 'ToSymbol' using symbol number or address, depending on whether the
142     // paired UNSIGNED relocation is extern.
143     Symbol *ToSymbol = nullptr;
144     if (UnsignedRI.r_extern) {
145       // Find target symbol by symbol index.
146       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
147         ToSymbol = ToSymbolOrErr->GraphSymbol;
148       else
149         return ToSymbolOrErr.takeError();
150     } else {
151       auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
152       if (!ToSymbolSec)
153         return ToSymbolSec.takeError();
154       ToSymbol = getSymbolByAddress(ToSymbolSec->Address);
155       assert(ToSymbol && "No symbol for section");
156       FixupValue -= ToSymbol->getAddress();
157     }
158 
159     MachOARM64RelocationKind DeltaKind;
160     Symbol *TargetSymbol;
161     uint64_t Addend;
162     if (&BlockToFix == &FromSymbol->getAddressable()) {
163       TargetSymbol = ToSymbol;
164       DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
165       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
166       // FIXME: handle extern 'from'.
167     } else if (&BlockToFix == &ToSymbol->getAddressable()) {
168       TargetSymbol = &*FromSymbol;
169       DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
170       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
171     } else {
172       // BlockToFix was neither FromSymbol nor ToSymbol.
173       return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
174                                       "either 'A' or 'B' (or a symbol in one "
175                                       "of their alt-entry groups)");
176     }
177 
178     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
179   }
180 
181   Error addRelocations() override {
182     using namespace support;
183     auto &Obj = getObject();
184 
185     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
186 
187     for (auto &S : Obj.sections()) {
188 
189       JITTargetAddress SectionAddress = S.getAddress();
190 
191       // Skip relocations virtual sections.
192       if (S.isVirtual()) {
193         if (S.relocation_begin() != S.relocation_end())
194           return make_error<JITLinkError>("Virtual section contains "
195                                           "relocations");
196         continue;
197       }
198 
199       // Skip relocations for debug symbols.
200       {
201         auto &NSec =
202             getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
203         if (!NSec.GraphSection) {
204           LLVM_DEBUG({
205             dbgs() << "  Skipping relocations for MachO section "
206                    << NSec.SegName << "/" << NSec.SectName
207                    << " which has no associated graph section\n";
208           });
209           continue;
210         }
211       }
212 
213       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
214            RelItr != RelEnd; ++RelItr) {
215 
216         MachO::relocation_info RI = getRelocationInfo(RelItr);
217 
218         // Sanity check the relocation kind.
219         auto Kind = getRelocationKind(RI);
220         if (!Kind)
221           return Kind.takeError();
222 
223         // Find the address of the value to fix up.
224         JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
225 
226         LLVM_DEBUG({
227           auto &NSec =
228               getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
229           dbgs() << "  " << NSec.SectName << " + "
230                  << formatv("{0:x8}", RI.r_address) << ":\n";
231         });
232 
233         // Find the block that the fixup points to.
234         Block *BlockToFix = nullptr;
235         {
236           auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
237           if (!SymbolToFixOrErr)
238             return SymbolToFixOrErr.takeError();
239           BlockToFix = &SymbolToFixOrErr->getBlock();
240         }
241 
242         if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
243             BlockToFix->getAddress() + BlockToFix->getContent().size())
244           return make_error<JITLinkError>(
245               "Relocation content extends past end of fixup block");
246 
247         // Get a pointer to the fixup content.
248         const char *FixupContent = BlockToFix->getContent().data() +
249                                    (FixupAddress - BlockToFix->getAddress());
250 
251         // The target symbol and addend will be populated by the switch below.
252         Symbol *TargetSymbol = nullptr;
253         uint64_t Addend = 0;
254 
255         if (*Kind == PairedAddend) {
256           // If this is an Addend relocation then process it and move to the
257           // paired reloc.
258 
259           Addend = RI.r_symbolnum;
260 
261           if (RelItr == RelEnd)
262             return make_error<JITLinkError>("Unpaired Addend reloc at " +
263                                             formatv("{0:x16}", FixupAddress));
264           ++RelItr;
265           RI = getRelocationInfo(RelItr);
266 
267           Kind = getRelocationKind(RI);
268           if (!Kind)
269             return Kind.takeError();
270 
271           if (*Kind != Branch26 && *Kind != Page21 && *Kind != PageOffset12)
272             return make_error<JITLinkError>(
273                 "Invalid relocation pair: Addend + " +
274                 getMachOARM64RelocationKindName(*Kind));
275           else
276             LLVM_DEBUG({
277               dbgs() << "  pair is " << getMachOARM64RelocationKindName(*Kind)
278                      << "`\n";
279             });
280 
281           // Find the address of the value to fix up.
282           JITTargetAddress PairedFixupAddress =
283               SectionAddress + (uint32_t)RI.r_address;
284           if (PairedFixupAddress != FixupAddress)
285             return make_error<JITLinkError>("Paired relocation points at "
286                                             "different target");
287         }
288 
289         switch (*Kind) {
290         case Branch26: {
291           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
292             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
293           else
294             return TargetSymbolOrErr.takeError();
295           uint32_t Instr = *(const ulittle32_t *)FixupContent;
296           if ((Instr & 0x7fffffff) != 0x14000000)
297             return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
298                                             "instruction with a zero addend");
299           break;
300         }
301         case Pointer32:
302           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
303             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
304           else
305             return TargetSymbolOrErr.takeError();
306           Addend = *(const ulittle32_t *)FixupContent;
307           break;
308         case Pointer64:
309           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
310             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
311           else
312             return TargetSymbolOrErr.takeError();
313           Addend = *(const ulittle64_t *)FixupContent;
314           break;
315         case Pointer64Anon: {
316           JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
317           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
318             TargetSymbol = &*TargetSymbolOrErr;
319           else
320             return TargetSymbolOrErr.takeError();
321           Addend = TargetAddress - TargetSymbol->getAddress();
322           break;
323         }
324         case Page21:
325         case GOTPage21: {
326           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
327             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
328           else
329             return TargetSymbolOrErr.takeError();
330           uint32_t Instr = *(const ulittle32_t *)FixupContent;
331           if ((Instr & 0xffffffe0) != 0x90000000)
332             return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
333                                             "ADRP instruction with a zero "
334                                             "addend");
335           break;
336         }
337         case PageOffset12: {
338           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
339             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
340           else
341             return TargetSymbolOrErr.takeError();
342           break;
343         }
344         case GOTPageOffset12: {
345           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
346             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
347           else
348             return TargetSymbolOrErr.takeError();
349           uint32_t Instr = *(const ulittle32_t *)FixupContent;
350           if ((Instr & 0xfffffc00) != 0xf9400000)
351             return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
352                                             "immediate instruction with a zero "
353                                             "addend");
354           break;
355         }
356         case PointerToGOT:
357           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
358             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
359           else
360             return TargetSymbolOrErr.takeError();
361           break;
362         case Delta32:
363         case Delta64: {
364           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
365           // parsePairRelocation handles the paired reloc, and returns the
366           // edge kind to be used (either Delta32/Delta64, or
367           // NegDelta32/NegDelta64, depending on the direction of the
368           // subtraction) along with the addend.
369           auto PairInfo =
370               parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
371                                   FixupContent, ++RelItr, RelEnd);
372           if (!PairInfo)
373             return PairInfo.takeError();
374           std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
375           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
376           break;
377         }
378         default:
379           llvm_unreachable("Special relocation kind should not appear in "
380                            "mach-o file");
381         }
382 
383         LLVM_DEBUG({
384           dbgs() << "    ";
385           Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
386                   Addend);
387           printEdge(dbgs(), *BlockToFix, GE,
388                     getMachOARM64RelocationKindName(*Kind));
389           dbgs() << "\n";
390         });
391         BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
392                             *TargetSymbol, Addend);
393       }
394     }
395     return Error::success();
396   }
397 
398   unsigned NumSymbols = 0;
399 };
400 
401 class MachO_arm64_GOTAndStubsBuilder
402     : public BasicGOTAndStubsBuilder<MachO_arm64_GOTAndStubsBuilder> {
403 public:
404   MachO_arm64_GOTAndStubsBuilder(LinkGraph &G)
405       : BasicGOTAndStubsBuilder<MachO_arm64_GOTAndStubsBuilder>(G) {}
406 
407   bool isGOTEdge(Edge &E) const {
408     return E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
409            E.getKind() == PointerToGOT;
410   }
411 
412   Symbol &createGOTEntry(Symbol &Target) {
413     auto &GOTEntryBlock = G.createContentBlock(
414         getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
415     GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
416     return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
417   }
418 
419   void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
420     if (E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12) {
421       // Update the target, but leave the edge addend as-is.
422       E.setTarget(GOTEntry);
423     } else if (E.getKind() == PointerToGOT) {
424       E.setTarget(GOTEntry);
425       E.setKind(Delta32);
426     } else
427       llvm_unreachable("Not a GOT edge?");
428   }
429 
430   bool isExternalBranchEdge(Edge &E) {
431     return E.getKind() == Branch26 && !E.getTarget().isDefined();
432   }
433 
434   Symbol &createStub(Symbol &Target) {
435     auto &StubContentBlock =
436         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
437     // Re-use GOT entries for stub targets.
438     auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
439     StubContentBlock.addEdge(LDRLiteral19, 0, GOTEntrySymbol, 0);
440     return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false);
441   }
442 
443   void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
444     assert(E.getKind() == Branch26 && "Not a Branch32 edge?");
445     assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
446     E.setTarget(Stub);
447   }
448 
449 private:
450   Section &getGOTSection() {
451     if (!GOTSection)
452       GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
453     return *GOTSection;
454   }
455 
456   Section &getStubsSection() {
457     if (!StubsSection) {
458       auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
459           sys::Memory::MF_READ | sys::Memory::MF_EXEC);
460       StubsSection = &G.createSection("$__STUBS", StubsProt);
461     }
462     return *StubsSection;
463   }
464 
465   StringRef getGOTEntryBlockContent() {
466     return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
467                      sizeof(NullGOTEntryContent));
468   }
469 
470   StringRef getStubBlockContent() {
471     return StringRef(reinterpret_cast<const char *>(StubContent),
472                      sizeof(StubContent));
473   }
474 
475   static const uint8_t NullGOTEntryContent[8];
476   static const uint8_t StubContent[8];
477   Section *GOTSection = nullptr;
478   Section *StubsSection = nullptr;
479 };
480 
481 const uint8_t MachO_arm64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
482     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
483 const uint8_t MachO_arm64_GOTAndStubsBuilder::StubContent[8] = {
484     0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
485     0x00, 0x02, 0x1f, 0xd6  // BR  x16
486 };
487 
488 } // namespace
489 
490 namespace llvm {
491 namespace jitlink {
492 
493 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
494   friend class JITLinker<MachOJITLinker_arm64>;
495 
496 public:
497   MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
498                        PassConfiguration PassConfig)
499       : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
500 
501 private:
502   StringRef getEdgeKindName(Edge::Kind R) const override {
503     return getMachOARM64RelocationKindName(R);
504   }
505 
506   Expected<std::unique_ptr<LinkGraph>>
507   buildGraph(MemoryBufferRef ObjBuffer) override {
508     auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
509     if (!MachOObj)
510       return MachOObj.takeError();
511     return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
512   }
513 
514   static Error targetOutOfRangeError(const Block &B, const Edge &E) {
515     std::string ErrMsg;
516     {
517       raw_string_ostream ErrStream(ErrMsg);
518       ErrStream << "Relocation target out of range: ";
519       printEdge(ErrStream, B, E, getMachOARM64RelocationKindName(E.getKind()));
520       ErrStream << "\n";
521     }
522     return make_error<JITLinkError>(std::move(ErrMsg));
523   }
524 
525   static unsigned getPageOffset12Shift(uint32_t Instr) {
526     constexpr uint32_t LDRLiteralMask = 0x3ffffc00;
527 
528     // Check for a GPR LDR immediate with a zero embedded literal.
529     // If found, the top two bits contain the shift.
530     if ((Instr & LDRLiteralMask) == 0x39400000)
531       return Instr >> 30;
532 
533     // Check for a Neon LDR immediate of size 64-bit or less with a zero
534     // embedded literal. If found, the top two bits contain the shift.
535     if ((Instr & LDRLiteralMask) == 0x3d400000)
536       return Instr >> 30;
537 
538     // Check for a Neon LDR immediate of size 128-bit with a zero embedded
539     // literal.
540     constexpr uint32_t SizeBitsMask = 0xc0000000;
541     if ((Instr & (LDRLiteralMask | SizeBitsMask)) == 0x3dc00000)
542       return 4;
543 
544     return 0;
545   }
546 
547   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
548     using namespace support;
549 
550     char *FixupPtr = BlockWorkingMem + E.getOffset();
551     JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
552 
553     switch (E.getKind()) {
554     case Branch26: {
555       assert((FixupAddress & 0x3) == 0 && "Branch-inst is not 32-bit aligned");
556 
557       int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
558 
559       if (static_cast<uint64_t>(Value) & 0x3)
560         return make_error<JITLinkError>("Branch26 target is not 32-bit "
561                                         "aligned");
562 
563       if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
564         return targetOutOfRangeError(B, E);
565 
566       uint32_t RawInstr = *(little32_t *)FixupPtr;
567       assert((RawInstr & 0x7fffffff) == 0x14000000 &&
568              "RawInstr isn't a B or BR immediate instruction");
569       uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
570       uint32_t FixedInstr = RawInstr | Imm;
571       *(little32_t *)FixupPtr = FixedInstr;
572       break;
573     }
574     case Pointer32: {
575       uint64_t Value = E.getTarget().getAddress() + E.getAddend();
576       if (Value > std::numeric_limits<uint32_t>::max())
577         return targetOutOfRangeError(B, E);
578       *(ulittle32_t *)FixupPtr = Value;
579       break;
580     }
581     case Pointer64:
582     case Pointer64Anon: {
583       uint64_t Value = E.getTarget().getAddress() + E.getAddend();
584       *(ulittle64_t *)FixupPtr = Value;
585       break;
586     }
587     case Page21:
588     case GOTPage21: {
589       assert(E.getAddend() == 0 && "PAGE21/GOTPAGE21 with non-zero addend");
590       uint64_t TargetPage =
591           E.getTarget().getAddress() & ~static_cast<uint64_t>(4096 - 1);
592       uint64_t PCPage = B.getAddress() & ~static_cast<uint64_t>(4096 - 1);
593 
594       int64_t PageDelta = TargetPage - PCPage;
595       if (PageDelta < -(1 << 30) || PageDelta > ((1 << 30) - 1))
596         return targetOutOfRangeError(B, E);
597 
598       uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
599       assert((RawInstr & 0xffffffe0) == 0x90000000 &&
600              "RawInstr isn't an ADRP instruction");
601       uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
602       uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
603       uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
604       *(ulittle32_t *)FixupPtr = FixedInstr;
605       break;
606     }
607     case PageOffset12: {
608       assert(E.getAddend() == 0 && "PAGEOFF12 with non-zero addend");
609       uint64_t TargetOffset = E.getTarget().getAddress() & 0xfff;
610 
611       uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
612       unsigned ImmShift = getPageOffset12Shift(RawInstr);
613 
614       if (TargetOffset & ((1 << ImmShift) - 1))
615         return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
616 
617       uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
618       uint32_t FixedInstr = RawInstr | EncodedImm;
619       *(ulittle32_t *)FixupPtr = FixedInstr;
620       break;
621     }
622     case GOTPageOffset12: {
623       assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend");
624 
625       uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
626       assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
627              "RawInstr isn't a 64-bit LDR immediate");
628 
629       uint32_t TargetOffset = E.getTarget().getAddress() & 0xfff;
630       assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned");
631       uint32_t EncodedImm = (TargetOffset >> 3) << 10;
632       uint32_t FixedInstr = RawInstr | EncodedImm;
633       *(ulittle32_t *)FixupPtr = FixedInstr;
634       break;
635     }
636     case LDRLiteral19: {
637       assert((FixupAddress & 0x3) == 0 && "LDR is not 32-bit aligned");
638       assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
639       uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
640       assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
641       int64_t Delta = E.getTarget().getAddress() - FixupAddress;
642       if (Delta & 0x3)
643         return make_error<JITLinkError>("LDR literal target is not 32-bit "
644                                         "aligned");
645       if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
646         return targetOutOfRangeError(B, E);
647 
648       uint32_t EncodedImm = (static_cast<uint32_t>(Delta) >> 2) << 5;
649       uint32_t FixedInstr = RawInstr | EncodedImm;
650       *(ulittle32_t *)FixupPtr = FixedInstr;
651       break;
652     }
653     case Delta32:
654     case Delta64:
655     case NegDelta32:
656     case NegDelta64: {
657       int64_t Value;
658       if (E.getKind() == Delta32 || E.getKind() == Delta64)
659         Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
660       else
661         Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
662 
663       if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
664         if (Value < std::numeric_limits<int32_t>::min() ||
665             Value > std::numeric_limits<int32_t>::max())
666           return targetOutOfRangeError(B, E);
667         *(little32_t *)FixupPtr = Value;
668       } else
669         *(little64_t *)FixupPtr = Value;
670       break;
671     }
672     default:
673       llvm_unreachable("Unrecognized edge kind");
674     }
675 
676     return Error::success();
677   }
678 
679   uint64_t NullValue = 0;
680 };
681 
682 void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx) {
683   PassConfiguration Config;
684   Triple TT("arm64-apple-ios");
685 
686   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
687     // Add a mark-live pass.
688     if (auto MarkLive = Ctx->getMarkLivePass(TT))
689       Config.PrePrunePasses.push_back(std::move(MarkLive));
690     else
691       Config.PrePrunePasses.push_back(markAllSymbolsLive);
692 
693     // Add an in-place GOT/Stubs pass.
694     Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
695       MachO_arm64_GOTAndStubsBuilder(G).run();
696       return Error::success();
697     });
698   }
699 
700   if (auto Err = Ctx->modifyPassConfig(TT, Config))
701     return Ctx->notifyFailed(std::move(Err));
702 
703   // Construct a JITLinker and run the link function.
704   MachOJITLinker_arm64::link(std::move(Ctx), std::move(Config));
705 }
706 
707 StringRef getMachOARM64RelocationKindName(Edge::Kind R) {
708   switch (R) {
709   case Branch26:
710     return "Branch26";
711   case Pointer64:
712     return "Pointer64";
713   case Pointer64Anon:
714     return "Pointer64Anon";
715   case Page21:
716     return "Page21";
717   case PageOffset12:
718     return "PageOffset12";
719   case GOTPage21:
720     return "GOTPage21";
721   case GOTPageOffset12:
722     return "GOTPageOffset12";
723   case PointerToGOT:
724     return "PointerToGOT";
725   case PairedAddend:
726     return "PairedAddend";
727   case LDRLiteral19:
728     return "LDRLiteral19";
729   case Delta32:
730     return "Delta32";
731   case Delta64:
732     return "Delta64";
733   case NegDelta32:
734     return "NegDelta32";
735   case NegDelta64:
736     return "NegDelta64";
737   default:
738     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
739   }
740 }
741 
742 } // end namespace jitlink
743 } // end namespace llvm
744