1 //===- lib/FileFormat/MachO/ArchHandler_arm64.cpp -------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "ArchHandler.h"
11 #include "Atoms.h"
12 #include "MachONormalizedFileBinaryUtils.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/Support/Endian.h"
17 #include "llvm/Support/ErrorHandling.h"
18 #include "llvm/Support/Format.h"
19 
20 using namespace llvm::MachO;
21 using namespace lld::mach_o::normalized;
22 
23 namespace lld {
24 namespace mach_o {
25 
26 using llvm::support::ulittle32_t;
27 using llvm::support::ulittle64_t;
28 
29 using llvm::support::little32_t;
30 using llvm::support::little64_t;
31 
32 class ArchHandler_arm64 : public ArchHandler {
33 public:
34   ArchHandler_arm64() = default;
35   ~ArchHandler_arm64() override = default;
36 
37   const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
38 
39   Reference::KindArch kindArch() override {
40     return Reference::KindArch::AArch64;
41   }
42 
43   /// Used by GOTPass to locate GOT References
44   bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
45     if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
46       return false;
47     assert(ref.kindArch() == Reference::KindArch::AArch64);
48     switch (ref.kindValue()) {
49     case gotPage21:
50     case gotOffset12:
51       canBypassGOT = true;
52       return true;
53     case delta32ToGOT:
54     case unwindCIEToPersonalityFunction:
55     case imageOffsetGot:
56       canBypassGOT = false;
57       return true;
58     default:
59       return false;
60     }
61   }
62 
63   /// Used by GOTPass to update GOT References.
64   void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
65     // If GOT slot was instanciated, transform:
66     //   gotPage21/gotOffset12 -> page21/offset12scale8
67     // If GOT slot optimized away, transform:
68     //   gotPage21/gotOffset12 -> page21/addOffset12
69     assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
70     assert(ref->kindArch() == Reference::KindArch::AArch64);
71     switch (ref->kindValue()) {
72     case gotPage21:
73       const_cast<Reference *>(ref)->setKindValue(page21);
74       break;
75     case gotOffset12:
76       const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
77                                                  offset12scale8 : addOffset12);
78       break;
79     case delta32ToGOT:
80       const_cast<Reference *>(ref)->setKindValue(delta32);
81       break;
82     case imageOffsetGot:
83       const_cast<Reference *>(ref)->setKindValue(imageOffset);
84       break;
85     default:
86       llvm_unreachable("Not a GOT reference");
87     }
88   }
89 
90   const StubInfo &stubInfo() override { return _sStubInfo; }
91 
92   bool isCallSite(const Reference &) override;
93   bool isNonCallBranch(const Reference &) override {
94     return false;
95   }
96 
97   bool isPointer(const Reference &) override;
98   bool isPairedReloc(const normalized::Relocation &) override;
99 
100   bool needsCompactUnwind() override {
101     return true;
102   }
103   Reference::KindValue imageOffsetKind() override {
104     return imageOffset;
105   }
106   Reference::KindValue imageOffsetKindIndirect() override {
107     return imageOffsetGot;
108   }
109 
110   Reference::KindValue unwindRefToPersonalityFunctionKind() override {
111     return unwindCIEToPersonalityFunction;
112   }
113 
114   Reference::KindValue unwindRefToCIEKind() override {
115     return negDelta32;
116   }
117 
118   Reference::KindValue unwindRefToFunctionKind() override {
119     return unwindFDEToFunction;
120   }
121 
122   Reference::KindValue unwindRefToEhFrameKind() override {
123     return unwindInfoToEhFrame;
124   }
125 
126   Reference::KindValue pointerKind() override {
127     return pointer64;
128   }
129 
130   uint32_t dwarfCompactUnwindType() override {
131     return 0x03000000;
132   }
133 
134   llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
135                                const DefinedAtom *inAtom,
136                                uint32_t offsetInAtom,
137                                uint64_t fixupAddress, bool isBig,
138                                FindAtomBySectionAndAddress atomFromAddress,
139                                FindAtomBySymbolIndex atomFromSymbolIndex,
140                                Reference::KindValue *kind,
141                                const lld::Atom **target,
142                                Reference::Addend *addend) override;
143   llvm::Error
144       getPairReferenceInfo(const normalized::Relocation &reloc1,
145                            const normalized::Relocation &reloc2,
146                            const DefinedAtom *inAtom,
147                            uint32_t offsetInAtom,
148                            uint64_t fixupAddress, bool isBig, bool scatterable,
149                            FindAtomBySectionAndAddress atomFromAddress,
150                            FindAtomBySymbolIndex atomFromSymbolIndex,
151                            Reference::KindValue *kind,
152                            const lld::Atom **target,
153                            Reference::Addend *addend) override;
154 
155   bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
156     return (atom->contentType() == DefinedAtom::typeCString);
157   }
158 
159   void generateAtomContent(const DefinedAtom &atom, bool relocatable,
160                            FindAddressForAtom findAddress,
161                            FindAddressForAtom findSectionAddress,
162                            uint64_t imageBaseAddress,
163                     llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
164 
165   void appendSectionRelocations(const DefinedAtom &atom,
166                                 uint64_t atomSectionOffset,
167                                 const Reference &ref,
168                                 FindSymbolIndexForAtom symbolIndexForAtom,
169                                 FindSectionIndexForAtom sectionIndexForAtom,
170                                 FindAddressForAtom addressForAtom,
171                                 normalized::Relocations &relocs) override;
172 
173 private:
174   static const Registry::KindStrings _sKindStrings[];
175   static const StubInfo _sStubInfo;
176 
177   enum Arm64Kind : Reference::KindValue {
178     invalid,               /// for error condition
179 
180     // Kinds found in mach-o .o files:
181     branch26,              /// ex: bl   _foo
182     page21,                /// ex: adrp x1, _foo@PAGE
183     offset12,              /// ex: ldrb w0, [x1, _foo@PAGEOFF]
184     offset12scale2,        /// ex: ldrs w0, [x1, _foo@PAGEOFF]
185     offset12scale4,        /// ex: ldr  w0, [x1, _foo@PAGEOFF]
186     offset12scale8,        /// ex: ldr  x0, [x1, _foo@PAGEOFF]
187     offset12scale16,       /// ex: ldr  q0, [x1, _foo@PAGEOFF]
188     gotPage21,             /// ex: adrp x1, _foo@GOTPAGE
189     gotOffset12,           /// ex: ldr  w0, [x1, _foo@GOTPAGEOFF]
190     tlvPage21,             /// ex: adrp x1, _foo@TLVPAGE
191     tlvOffset12,           /// ex: ldr  w0, [x1, _foo@TLVPAGEOFF]
192 
193     pointer64,             /// ex: .quad _foo
194     delta64,               /// ex: .quad _foo - .
195     delta32,               /// ex: .long _foo - .
196     negDelta32,            /// ex: .long . - _foo
197     pointer64ToGOT,        /// ex: .quad _foo@GOT
198     delta32ToGOT,          /// ex: .long _foo@GOT - .
199 
200     // Kinds introduced by Passes:
201     addOffset12,           /// Location contains LDR to change into ADD.
202     lazyPointer,           /// Location contains a lazy pointer.
203     lazyImmediateLocation, /// Location contains immediate value used in stub.
204     imageOffset,           /// Location contains offset of atom in final image
205     imageOffsetGot,        /// Location contains offset of GOT entry for atom in
206                            /// final image (typically personality function).
207     unwindCIEToPersonalityFunction,   /// Nearly delta32ToGOT, but cannot be
208                            /// rematerialized in relocatable object
209                            /// (yay for implicit contracts!).
210     unwindFDEToFunction,   /// Nearly delta64, but cannot be rematerialized in
211                            /// relocatable object (yay for implicit contracts!).
212     unwindInfoToEhFrame,   /// Fix low 24 bits of compact unwind encoding to
213                            /// refer to __eh_frame entry.
214   };
215 
216   void applyFixupFinal(const Reference &ref, uint8_t *location,
217                        uint64_t fixupAddress, uint64_t targetAddress,
218                        uint64_t inAtomAddress, uint64_t imageBaseAddress,
219                        FindAddressForAtom findSectionAddress);
220 
221   void applyFixupRelocatable(const Reference &ref, uint8_t *location,
222                              uint64_t fixupAddress, uint64_t targetAddress,
223                              uint64_t inAtomAddress, bool targetUnnamed);
224 
225   // Utility functions for inspecting/updating instructions.
226   static uint32_t setDisplacementInBranch26(uint32_t instr, int32_t disp);
227   static uint32_t setDisplacementInADRP(uint32_t instr, int64_t disp);
228   static Arm64Kind offset12KindFromInstruction(uint32_t instr);
229   static uint32_t setImm12(uint32_t instr, uint32_t offset);
230 };
231 
232 const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
233   LLD_KIND_STRING_ENTRY(invalid),
234   LLD_KIND_STRING_ENTRY(branch26),
235   LLD_KIND_STRING_ENTRY(page21),
236   LLD_KIND_STRING_ENTRY(offset12),
237   LLD_KIND_STRING_ENTRY(offset12scale2),
238   LLD_KIND_STRING_ENTRY(offset12scale4),
239   LLD_KIND_STRING_ENTRY(offset12scale8),
240   LLD_KIND_STRING_ENTRY(offset12scale16),
241   LLD_KIND_STRING_ENTRY(gotPage21),
242   LLD_KIND_STRING_ENTRY(gotOffset12),
243   LLD_KIND_STRING_ENTRY(tlvPage21),
244   LLD_KIND_STRING_ENTRY(tlvOffset12),
245   LLD_KIND_STRING_ENTRY(pointer64),
246   LLD_KIND_STRING_ENTRY(delta64),
247   LLD_KIND_STRING_ENTRY(delta32),
248   LLD_KIND_STRING_ENTRY(negDelta32),
249   LLD_KIND_STRING_ENTRY(pointer64ToGOT),
250   LLD_KIND_STRING_ENTRY(delta32ToGOT),
251 
252   LLD_KIND_STRING_ENTRY(addOffset12),
253   LLD_KIND_STRING_ENTRY(lazyPointer),
254   LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
255   LLD_KIND_STRING_ENTRY(imageOffset),
256   LLD_KIND_STRING_ENTRY(imageOffsetGot),
257   LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction),
258   LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
259   LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
260 
261   LLD_KIND_STRING_END
262 };
263 
264 const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
265   "dyld_stub_binder",
266 
267   // Lazy pointer references
268   { Reference::KindArch::AArch64, pointer64, 0, 0 },
269   { Reference::KindArch::AArch64, lazyPointer, 0, 0 },
270 
271   // GOT pointer to dyld_stub_binder
272   { Reference::KindArch::AArch64, pointer64, 0, 0 },
273 
274   // arm64 code alignment 2^1
275   1,
276 
277   // Stub size and code
278   12,
279   { 0x10, 0x00, 0x00, 0x90,   // ADRP  X16, lazy_pointer@page
280     0x10, 0x02, 0x40, 0xF9,   // LDR   X16, [X16, lazy_pointer@pageoff]
281     0x00, 0x02, 0x1F, 0xD6 }, // BR    X16
282   { Reference::KindArch::AArch64, page21, 0, 0 },
283   { true,                         offset12scale8, 4, 0 },
284 
285   // Stub Helper size and code
286   12,
287   { 0x50, 0x00, 0x00, 0x18,   //      LDR   W16, L0
288     0x00, 0x00, 0x00, 0x14,   //      LDR   B  helperhelper
289     0x00, 0x00, 0x00, 0x00 }, // L0: .long 0
290   { Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
291   { Reference::KindArch::AArch64, branch26, 4, 0 },
292 
293   // Stub helper image cache content type
294   DefinedAtom::typeGOT,
295 
296   // Stub Helper-Common size and code
297   24,
298   // Stub helper alignment
299   2,
300   { 0x11, 0x00, 0x00, 0x90,   //  ADRP  X17, dyld_ImageLoaderCache@page
301     0x31, 0x02, 0x00, 0x91,   //  ADD   X17, X17, dyld_ImageLoaderCache@pageoff
302     0xF0, 0x47, 0xBF, 0xA9,   //  STP   X16/X17, [SP, #-16]!
303     0x10, 0x00, 0x00, 0x90,   //  ADRP  X16, _fast_lazy_bind@page
304     0x10, 0x02, 0x40, 0xF9,   //  LDR   X16, [X16,_fast_lazy_bind@pageoff]
305     0x00, 0x02, 0x1F, 0xD6 }, //  BR    X16
306   { Reference::KindArch::AArch64, page21,   0, 0 },
307   { true,                         offset12, 4, 0 },
308   { Reference::KindArch::AArch64, page21,   12, 0 },
309   { true,                         offset12scale8, 16, 0 }
310 };
311 
312 bool ArchHandler_arm64::isCallSite(const Reference &ref) {
313   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
314     return false;
315   assert(ref.kindArch() == Reference::KindArch::AArch64);
316   return (ref.kindValue() == branch26);
317 }
318 
319 bool ArchHandler_arm64::isPointer(const Reference &ref) {
320   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
321     return false;
322   assert(ref.kindArch() == Reference::KindArch::AArch64);
323   Reference::KindValue kind = ref.kindValue();
324   return (kind == pointer64);
325 }
326 
327 bool ArchHandler_arm64::isPairedReloc(const Relocation &r) {
328   return ((r.type == ARM64_RELOC_ADDEND) || (r.type == ARM64_RELOC_SUBTRACTOR));
329 }
330 
331 uint32_t ArchHandler_arm64::setDisplacementInBranch26(uint32_t instr,
332                                                       int32_t displacement) {
333   assert((displacement <= 134217727) && (displacement > (-134217728)) &&
334          "arm64 branch out of range");
335   return (instr & 0xFC000000) | ((uint32_t)(displacement >> 2) & 0x03FFFFFF);
336 }
337 
338 uint32_t ArchHandler_arm64::setDisplacementInADRP(uint32_t instruction,
339                                                   int64_t displacement) {
340   assert((displacement <= 0x100000000LL) && (displacement > (-0x100000000LL)) &&
341          "arm64 ADRP out of range");
342   assert(((instruction & 0x9F000000) == 0x90000000) &&
343          "reloc not on ADRP instruction");
344   uint32_t immhi = (displacement >> 9) & (0x00FFFFE0);
345   uint32_t immlo = (displacement << 17) & (0x60000000);
346   return (instruction & 0x9F00001F) | immlo | immhi;
347 }
348 
349 ArchHandler_arm64::Arm64Kind
350 ArchHandler_arm64::offset12KindFromInstruction(uint32_t instruction) {
351   if (instruction & 0x08000000) {
352     switch ((instruction >> 30) & 0x3) {
353     case 0:
354       if ((instruction & 0x04800000) == 0x04800000)
355         return offset12scale16;
356       return offset12;
357     case 1:
358       return offset12scale2;
359     case 2:
360       return offset12scale4;
361     case 3:
362       return offset12scale8;
363     }
364   }
365   return offset12;
366 }
367 
368 uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
369   assert(((offset & 0xFFFFF000) == 0) && "imm12 offset out of range");
370   uint32_t imm12 = offset << 10;
371   return (instruction & 0xFFC003FF) | imm12;
372 }
373 
374 llvm::Error ArchHandler_arm64::getReferenceInfo(
375     const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
376     uint64_t fixupAddress, bool isBig,
377     FindAtomBySectionAndAddress atomFromAddress,
378     FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
379     const lld::Atom **target, Reference::Addend *addend) {
380   const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
381   switch (relocPattern(reloc)) {
382   case ARM64_RELOC_BRANCH26           | rPcRel | rExtern | rLength4:
383     // ex: bl _foo
384     *kind = branch26;
385     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
386       return ec;
387     *addend = 0;
388     return llvm::Error::success();
389   case ARM64_RELOC_PAGE21             | rPcRel | rExtern | rLength4:
390     // ex: adrp x1, _foo@PAGE
391     *kind = page21;
392     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
393       return ec;
394     *addend = 0;
395     return llvm::Error::success();
396   case ARM64_RELOC_PAGEOFF12                   | rExtern | rLength4:
397     // ex: ldr x0, [x1, _foo@PAGEOFF]
398     *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
399     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
400       return ec;
401     *addend = 0;
402     return llvm::Error::success();
403   case ARM64_RELOC_GOT_LOAD_PAGE21    | rPcRel | rExtern | rLength4:
404     // ex: adrp x1, _foo@GOTPAGE
405     *kind = gotPage21;
406     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
407       return ec;
408     *addend = 0;
409     return llvm::Error::success();
410   case ARM64_RELOC_GOT_LOAD_PAGEOFF12          | rExtern | rLength4:
411     // ex: ldr x0, [x1, _foo@GOTPAGEOFF]
412     *kind = gotOffset12;
413     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
414       return ec;
415     *addend = 0;
416     return llvm::Error::success();
417   case ARM64_RELOC_TLVP_LOAD_PAGE21   | rPcRel | rExtern | rLength4:
418     // ex: adrp x1, _foo@TLVPAGE
419     *kind = tlvPage21;
420     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
421       return ec;
422     *addend = 0;
423     return llvm::Error::success();
424   case ARM64_RELOC_TLVP_LOAD_PAGEOFF12         | rExtern | rLength4:
425     // ex: ldr x0, [x1, _foo@TLVPAGEOFF]
426     *kind = tlvOffset12;
427     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
428       return ec;
429     *addend = 0;
430     return llvm::Error::success();
431   case ARM64_RELOC_UNSIGNED                    | rExtern | rLength8:
432     // ex: .quad _foo + N
433     *kind = pointer64;
434     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
435       return ec;
436     *addend = *(const little64_t *)fixupContent;
437     return llvm::Error::success();
438   case ARM64_RELOC_UNSIGNED                              | rLength8:
439      // ex: .quad Lfoo + N
440      *kind = pointer64;
441      return atomFromAddress(reloc.symbol, *(const little64_t *)fixupContent,
442                             target, addend);
443   case ARM64_RELOC_POINTER_TO_GOT              | rExtern | rLength8:
444     // ex: .quad _foo@GOT
445     *kind = pointer64ToGOT;
446     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
447       return ec;
448     *addend = 0;
449     return llvm::Error::success();
450   case ARM64_RELOC_POINTER_TO_GOT     | rPcRel | rExtern | rLength4:
451     // ex: .long _foo@GOT - .
452 
453     // If we are in an .eh_frame section, then the kind of the relocation should
454     // not be delta32ToGOT.  It may instead be unwindCIEToPersonalityFunction.
455     if (inAtom->contentType() == DefinedAtom::typeCFI)
456       *kind = unwindCIEToPersonalityFunction;
457     else
458       *kind = delta32ToGOT;
459 
460     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
461       return ec;
462     *addend = 0;
463     return llvm::Error::success();
464   default:
465     return llvm::make_error<GenericError>("unsupported arm64 relocation type");
466   }
467 }
468 
469 llvm::Error ArchHandler_arm64::getPairReferenceInfo(
470     const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
471     const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
472     bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress,
473     FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
474     const lld::Atom **target, Reference::Addend *addend) {
475   const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
476   switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
477   case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
478          ARM64_RELOC_BRANCH26           | rPcRel | rExtern | rLength4):
479     // ex: bl _foo+8
480     *kind = branch26;
481     if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
482       return ec;
483     *addend = reloc1.symbol;
484     return llvm::Error::success();
485   case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
486          ARM64_RELOC_PAGE21             | rPcRel | rExtern | rLength4):
487     // ex: adrp x1, _foo@PAGE
488     *kind = page21;
489     if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
490       return ec;
491     *addend = reloc1.symbol;
492     return llvm::Error::success();
493   case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
494          ARM64_RELOC_PAGEOFF12                   | rExtern | rLength4): {
495     // ex: ldr w0, [x1, _foo@PAGEOFF]
496     uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent;
497     *kind = offset12KindFromInstruction(cont32);
498     if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
499       return ec;
500     *addend = reloc1.symbol;
501     return llvm::Error::success();
502   }
503   case ((ARM64_RELOC_SUBTRACTOR                  | rExtern | rLength8) << 16 |
504          ARM64_RELOC_UNSIGNED                    | rExtern | rLength8):
505     // ex: .quad _foo - .
506     if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
507       return ec;
508 
509     // If we are in an .eh_frame section, then the kind of the relocation should
510     // not be delta64.  It may instead be unwindFDEToFunction.
511     if (inAtom->contentType() == DefinedAtom::typeCFI)
512       *kind = unwindFDEToFunction;
513     else
514       *kind = delta64;
515 
516     // The offsets of the 2 relocations must match
517     if (reloc1.offset != reloc2.offset)
518       return llvm::make_error<GenericError>(
519                                     "paired relocs must have the same offset");
520     *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
521     return llvm::Error::success();
522   case ((ARM64_RELOC_SUBTRACTOR                  | rExtern | rLength4) << 16 |
523          ARM64_RELOC_UNSIGNED                    | rExtern | rLength4):
524     // ex: .quad _foo - .
525     *kind = delta32;
526     if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
527       return ec;
528     *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
529     return llvm::Error::success();
530   default:
531     return llvm::make_error<GenericError>("unsupported arm64 relocation pair");
532   }
533 }
534 
535 void ArchHandler_arm64::generateAtomContent(
536     const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
537     FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
538     llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
539   // Copy raw bytes.
540   std::copy(atom.rawContent().begin(), atom.rawContent().end(),
541             atomContentBuffer.begin());
542   // Apply fix-ups.
543 #ifndef NDEBUG
544   if (atom.begin() != atom.end()) {
545     DEBUG_WITH_TYPE("atom-content", llvm::dbgs()
546                     << "Applying fixups to atom:\n"
547                     << "   address="
548                     << llvm::format("    0x%09lX", &atom)
549                     << ", file=#"
550                     << atom.file().ordinal()
551                     << ", atom=#"
552                     << atom.ordinal()
553                     << ", name="
554                     << atom.name()
555                     << ", type="
556                     << atom.contentType()
557                     << "\n");
558   }
559 #endif
560   for (const Reference *ref : atom) {
561     uint32_t offset = ref->offsetInAtom();
562     const Atom *target = ref->target();
563     bool targetUnnamed = target->name().empty();
564     uint64_t targetAddress = 0;
565     if (isa<DefinedAtom>(target))
566       targetAddress = findAddress(*target);
567     uint64_t atomAddress = findAddress(atom);
568     uint64_t fixupAddress = atomAddress + offset;
569     if (relocatable) {
570       applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
571                             targetAddress, atomAddress, targetUnnamed);
572     } else {
573       applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
574                       targetAddress, atomAddress, imageBaseAddress,
575                       findSectionAddress);
576     }
577   }
578 }
579 
580 void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
581                                         uint64_t fixupAddress,
582                                         uint64_t targetAddress,
583                                         uint64_t inAtomAddress,
584                                         uint64_t imageBaseAddress,
585                                         FindAddressForAtom findSectionAddress) {
586   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
587     return;
588   assert(ref.kindArch() == Reference::KindArch::AArch64);
589   ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
590   ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
591   int32_t displacement;
592   uint32_t instruction;
593   uint32_t value32;
594   uint32_t value64;
595   switch (static_cast<Arm64Kind>(ref.kindValue())) {
596   case branch26:
597     displacement = (targetAddress - fixupAddress) + ref.addend();
598     *loc32 = setDisplacementInBranch26(*loc32, displacement);
599     return;
600   case page21:
601   case gotPage21:
602   case tlvPage21:
603     displacement =
604         ((targetAddress + ref.addend()) & (-4096)) - (fixupAddress & (-4096));
605     *loc32 = setDisplacementInADRP(*loc32, displacement);
606     return;
607   case offset12:
608   case gotOffset12:
609   case tlvOffset12:
610     displacement = (targetAddress + ref.addend()) & 0x00000FFF;
611     *loc32 = setImm12(*loc32, displacement);
612     return;
613   case offset12scale2:
614     displacement = (targetAddress + ref.addend()) & 0x00000FFF;
615     assert(((displacement & 0x1) == 0) &&
616            "scaled imm12 not accessing 2-byte aligneds");
617     *loc32 = setImm12(*loc32, displacement >> 1);
618     return;
619   case offset12scale4:
620     displacement = (targetAddress + ref.addend()) & 0x00000FFF;
621     assert(((displacement & 0x3) == 0) &&
622            "scaled imm12 not accessing 4-byte aligned");
623     *loc32 = setImm12(*loc32, displacement >> 2);
624     return;
625   case offset12scale8:
626     displacement = (targetAddress + ref.addend()) & 0x00000FFF;
627     assert(((displacement & 0x7) == 0) &&
628            "scaled imm12 not accessing 8-byte aligned");
629     *loc32 = setImm12(*loc32, displacement >> 3);
630     return;
631   case offset12scale16:
632     displacement = (targetAddress + ref.addend()) & 0x00000FFF;
633     assert(((displacement & 0xF) == 0) &&
634            "scaled imm12 not accessing 16-byte aligned");
635     *loc32 = setImm12(*loc32, displacement >> 4);
636     return;
637   case addOffset12:
638     instruction = *loc32;
639     assert(((instruction & 0xFFC00000) == 0xF9400000) &&
640            "GOT reloc is not an LDR instruction");
641     displacement = (targetAddress + ref.addend()) & 0x00000FFF;
642     value32 = 0x91000000 | (instruction & 0x000003FF);
643     instruction = setImm12(value32, displacement);
644     *loc32 = instruction;
645     return;
646   case pointer64:
647   case pointer64ToGOT:
648     *loc64 = targetAddress + ref.addend();
649     return;
650   case delta64:
651   case unwindFDEToFunction:
652     *loc64 = (targetAddress - fixupAddress) + ref.addend();
653     return;
654   case delta32:
655   case delta32ToGOT:
656   case unwindCIEToPersonalityFunction:
657     *loc32 = (targetAddress - fixupAddress) + ref.addend();
658     return;
659   case negDelta32:
660     *loc32 = fixupAddress - targetAddress + ref.addend();
661     return;
662   case lazyPointer:
663     // Do nothing
664     return;
665   case lazyImmediateLocation:
666     *loc32 = ref.addend();
667     return;
668   case imageOffset:
669     *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
670     return;
671   case imageOffsetGot:
672     llvm_unreachable("imageOffsetGot should have been changed to imageOffset");
673     break;
674   case unwindInfoToEhFrame:
675     value64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
676     assert(value64 < 0xffffffU && "offset in __eh_frame too large");
677     *loc32 = (*loc32 & 0xff000000U) | value64;
678     return;
679   case invalid:
680     // Fall into llvm_unreachable().
681     break;
682   }
683   llvm_unreachable("invalid arm64 Reference Kind");
684 }
685 
686 void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
687                                               uint8_t *loc,
688                                               uint64_t fixupAddress,
689                                               uint64_t targetAddress,
690                                               uint64_t inAtomAddress,
691                                               bool targetUnnamed) {
692   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
693     return;
694   assert(ref.kindArch() == Reference::KindArch::AArch64);
695   ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
696   ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
697   switch (static_cast<Arm64Kind>(ref.kindValue())) {
698   case branch26:
699     *loc32 = setDisplacementInBranch26(*loc32, 0);
700     return;
701   case page21:
702   case gotPage21:
703   case tlvPage21:
704     *loc32 = setDisplacementInADRP(*loc32, 0);
705     return;
706   case offset12:
707   case offset12scale2:
708   case offset12scale4:
709   case offset12scale8:
710   case offset12scale16:
711   case gotOffset12:
712   case tlvOffset12:
713     *loc32 = setImm12(*loc32, 0);
714     return;
715   case pointer64:
716     if (targetUnnamed)
717       *loc64 = targetAddress + ref.addend();
718     else
719       *loc64 = ref.addend();
720     return;
721   case delta64:
722     *loc64 = ref.addend() + inAtomAddress - fixupAddress;
723     return;
724   case unwindFDEToFunction:
725     // We don't emit unwindFDEToFunction in -r mode as they are implicitly
726     // generated from the data in the __eh_frame section.  So here we need
727     // to use the targetAddress so that we can generate the full relocation
728     // when we parse again later.
729     *loc64 = targetAddress - fixupAddress;
730     return;
731   case delta32:
732     *loc32 = ref.addend() + inAtomAddress - fixupAddress;
733     return;
734   case negDelta32:
735     // We don't emit negDelta32 in -r mode as they are implicitly
736     // generated from the data in the __eh_frame section.  So here we need
737     // to use the targetAddress so that we can generate the full relocation
738     // when we parse again later.
739     *loc32 = fixupAddress - targetAddress + ref.addend();
740     return;
741   case pointer64ToGOT:
742     *loc64 = 0;
743     return;
744   case delta32ToGOT:
745     *loc32 = inAtomAddress - fixupAddress;
746     return;
747   case unwindCIEToPersonalityFunction:
748     // We don't emit unwindCIEToPersonalityFunction in -r mode as they are
749     // implicitly generated from the data in the __eh_frame section.  So here we
750     // need to use the targetAddress so that we can generate the full relocation
751     // when we parse again later.
752     *loc32 = targetAddress - fixupAddress;
753     return;
754   case addOffset12:
755     llvm_unreachable("lazy reference kind implies GOT pass was run");
756   case lazyPointer:
757   case lazyImmediateLocation:
758     llvm_unreachable("lazy reference kind implies Stubs pass was run");
759   case imageOffset:
760   case imageOffsetGot:
761   case unwindInfoToEhFrame:
762     llvm_unreachable("fixup implies __unwind_info");
763     return;
764   case invalid:
765     // Fall into llvm_unreachable().
766     break;
767   }
768   llvm_unreachable("unknown arm64 Reference Kind");
769 }
770 
771 void ArchHandler_arm64::appendSectionRelocations(
772     const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref,
773     FindSymbolIndexForAtom symbolIndexForAtom,
774     FindSectionIndexForAtom sectionIndexForAtom,
775     FindAddressForAtom addressForAtom, normalized::Relocations &relocs) {
776   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
777     return;
778   assert(ref.kindArch() == Reference::KindArch::AArch64);
779   uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
780   switch (static_cast<Arm64Kind>(ref.kindValue())) {
781   case branch26:
782     if (ref.addend()) {
783       appendReloc(relocs, sectionOffset, ref.addend(), 0,
784                   ARM64_RELOC_ADDEND | rLength4);
785       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
786                   ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
787      } else {
788       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
789                   ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
790     }
791     return;
792   case page21:
793     if (ref.addend()) {
794       appendReloc(relocs, sectionOffset, ref.addend(), 0,
795                   ARM64_RELOC_ADDEND | rLength4);
796       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
797                   ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
798      } else {
799       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
800                   ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
801     }
802     return;
803   case offset12:
804   case offset12scale2:
805   case offset12scale4:
806   case offset12scale8:
807   case offset12scale16:
808     if (ref.addend()) {
809       appendReloc(relocs, sectionOffset, ref.addend(), 0,
810                   ARM64_RELOC_ADDEND | rLength4);
811       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
812                   ARM64_RELOC_PAGEOFF12  | rExtern | rLength4);
813      } else {
814       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
815                   ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
816     }
817     return;
818   case gotPage21:
819     assert(ref.addend() == 0);
820     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
821                   ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
822     return;
823   case gotOffset12:
824     assert(ref.addend() == 0);
825     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
826                   ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4);
827     return;
828   case tlvPage21:
829     assert(ref.addend() == 0);
830     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
831                   ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
832     return;
833   case tlvOffset12:
834     assert(ref.addend() == 0);
835     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
836                   ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4);
837     return;
838   case pointer64:
839     if (ref.target()->name().empty())
840       appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
841                   ARM64_RELOC_UNSIGNED           | rLength8);
842     else
843       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
844                   ARM64_RELOC_UNSIGNED | rExtern | rLength8);
845     return;
846   case delta64:
847     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
848                 ARM64_RELOC_SUBTRACTOR | rExtern | rLength8);
849     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
850                 ARM64_RELOC_UNSIGNED  | rExtern | rLength8);
851     return;
852   case delta32:
853     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
854                 ARM64_RELOC_SUBTRACTOR | rExtern | rLength4 );
855     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
856                 ARM64_RELOC_UNSIGNED   | rExtern | rLength4 );
857     return;
858   case pointer64ToGOT:
859     assert(ref.addend() == 0);
860     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
861                   ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8);
862     return;
863   case delta32ToGOT:
864     assert(ref.addend() == 0);
865     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
866                   ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4);
867     return;
868   case addOffset12:
869     llvm_unreachable("lazy reference kind implies GOT pass was run");
870   case lazyPointer:
871   case lazyImmediateLocation:
872     llvm_unreachable("lazy reference kind implies Stubs pass was run");
873   case imageOffset:
874   case imageOffsetGot:
875     llvm_unreachable("deltas from mach_header can only be in final images");
876   case unwindCIEToPersonalityFunction:
877   case unwindFDEToFunction:
878   case unwindInfoToEhFrame:
879   case negDelta32:
880     // Do nothing.
881     return;
882   case invalid:
883     // Fall into llvm_unreachable().
884     break;
885   }
886   llvm_unreachable("unknown arm64 Reference Kind");
887 }
888 
889 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm64() {
890   return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm64());
891 }
892 
893 } // namespace mach_o
894 } // namespace lld
895