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