1274955Ssvnmir//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
2274955Ssvnmir//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6274955Ssvnmir//
7274955Ssvnmir//===----------------------------------------------------------------------===//
8274955Ssvnmir
9280031Sdim#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
10280031Sdim#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
11274955Ssvnmir
12274955Ssvnmir#include "../RuntimeDyldMachO.h"
13280031Sdim#include "llvm/Support/Endian.h"
14274955Ssvnmir
15274955Ssvnmir#define DEBUG_TYPE "dyld"
16274955Ssvnmir
17274955Ssvnmirnamespace llvm {
18274955Ssvnmir
19274955Ssvnmirclass RuntimeDyldMachOAArch64
20274955Ssvnmir    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> {
21274955Ssvnmirpublic:
22280031Sdim
23280031Sdim  typedef uint64_t TargetPtrT;
24280031Sdim
25288943Sdim  RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager &MM,
26314564Sdim                          JITSymbolResolver &Resolver)
27288943Sdim      : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
28274955Ssvnmir
29353358Sdim  unsigned getMaxStubSize() const override { return 8; }
30274955Ssvnmir
31274955Ssvnmir  unsigned getStubAlignment() override { return 8; }
32274955Ssvnmir
33280031Sdim  /// Extract the addend encoded in the instruction / memory location.
34341825Sdim  Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
35280031Sdim    const SectionEntry &Section = Sections[RE.SectionID];
36296417Sdim    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
37280031Sdim    unsigned NumBytes = 1 << RE.Size;
38280031Sdim    int64_t Addend = 0;
39280031Sdim    // Verify that the relocation has the correct size and alignment.
40280031Sdim    switch (RE.RelType) {
41341825Sdim    default: {
42341825Sdim      std::string ErrMsg;
43341825Sdim      {
44341825Sdim        raw_string_ostream ErrStream(ErrMsg);
45341825Sdim        ErrStream << "Unsupported relocation type: "
46341825Sdim                  << getRelocName(RE.RelType);
47341825Sdim      }
48341825Sdim      return make_error<StringError>(std::move(ErrMsg),
49341825Sdim                                     inconvertibleErrorCode());
50341825Sdim    }
51341825Sdim    case MachO::ARM64_RELOC_POINTER_TO_GOT:
52341825Sdim    case MachO::ARM64_RELOC_UNSIGNED: {
53341825Sdim      if (NumBytes != 4 && NumBytes != 8) {
54341825Sdim        std::string ErrMsg;
55341825Sdim        {
56341825Sdim          raw_string_ostream ErrStream(ErrMsg);
57341825Sdim          ErrStream << "Invalid relocation size for relocation "
58341825Sdim                    << getRelocName(RE.RelType);
59341825Sdim        }
60341825Sdim        return make_error<StringError>(std::move(ErrMsg),
61341825Sdim                                       inconvertibleErrorCode());
62341825Sdim      }
63280031Sdim      break;
64341825Sdim    }
65280031Sdim    case MachO::ARM64_RELOC_BRANCH26:
66280031Sdim    case MachO::ARM64_RELOC_PAGE21:
67280031Sdim    case MachO::ARM64_RELOC_PAGEOFF12:
68280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
69280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
70280031Sdim      assert(NumBytes == 4 && "Invalid relocation size.");
71280031Sdim      assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
72280031Sdim             "Instruction address is not aligned to 4 bytes.");
73280031Sdim      break;
74280031Sdim    }
75280031Sdim
76280031Sdim    switch (RE.RelType) {
77280031Sdim    default:
78280031Sdim      llvm_unreachable("Unsupported relocation type!");
79341825Sdim    case MachO::ARM64_RELOC_POINTER_TO_GOT:
80280031Sdim    case MachO::ARM64_RELOC_UNSIGNED:
81280031Sdim      // This could be an unaligned memory location.
82280031Sdim      if (NumBytes == 4)
83280031Sdim        Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress);
84280031Sdim      else
85280031Sdim        Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress);
86280031Sdim      break;
87280031Sdim    case MachO::ARM64_RELOC_BRANCH26: {
88341825Sdim      // Verify that the relocation points to a B/BL instruction.
89280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
90341825Sdim      assert(((*p & 0xFC000000) == 0x14000000 ||
91341825Sdim              (*p & 0xFC000000) == 0x94000000) &&
92341825Sdim             "Expected branch instruction.");
93280031Sdim
94280031Sdim      // Get the 26 bit addend encoded in the branch instruction and sign-extend
95280031Sdim      // to 64 bit. The lower 2 bits are always zeros and are therefore implicit
96280031Sdim      // (<< 2).
97280031Sdim      Addend = (*p & 0x03FFFFFF) << 2;
98280031Sdim      Addend = SignExtend64(Addend, 28);
99280031Sdim      break;
100280031Sdim    }
101280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
102280031Sdim    case MachO::ARM64_RELOC_PAGE21: {
103280031Sdim      // Verify that the relocation points to the expected adrp instruction.
104280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
105280031Sdim      assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
106280031Sdim
107280031Sdim      // Get the 21 bit addend encoded in the adrp instruction and sign-extend
108280031Sdim      // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are
109280031Sdim      // therefore implicit (<< 12).
110280031Sdim      Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12;
111280031Sdim      Addend = SignExtend64(Addend, 33);
112280031Sdim      break;
113280031Sdim    }
114280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
115280031Sdim      // Verify that the relocation points to one of the expected load / store
116280031Sdim      // instructions.
117280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
118280031Sdim      (void)p;
119280031Sdim      assert((*p & 0x3B000000) == 0x39000000 &&
120280031Sdim             "Only expected load / store instructions.");
121314564Sdim      LLVM_FALLTHROUGH;
122314564Sdim    }
123280031Sdim    case MachO::ARM64_RELOC_PAGEOFF12: {
124280031Sdim      // Verify that the relocation points to one of the expected load / store
125280031Sdim      // or add / sub instructions.
126280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
127280031Sdim      assert((((*p & 0x3B000000) == 0x39000000) ||
128280031Sdim              ((*p & 0x11C00000) == 0x11000000)   ) &&
129280031Sdim             "Expected load / store  or add/sub instruction.");
130280031Sdim
131280031Sdim      // Get the 12 bit addend encoded in the instruction.
132280031Sdim      Addend = (*p & 0x003FFC00) >> 10;
133280031Sdim
134280031Sdim      // Check which instruction we are decoding to obtain the implicit shift
135280031Sdim      // factor of the instruction.
136280031Sdim      int ImplicitShift = 0;
137280031Sdim      if ((*p & 0x3B000000) == 0x39000000) { // << load / store
138280031Sdim        // For load / store instructions the size is encoded in bits 31:30.
139280031Sdim        ImplicitShift = ((*p >> 30) & 0x3);
140280031Sdim        if (ImplicitShift == 0) {
141280031Sdim          // Check if this a vector op to get the correct shift value.
142280031Sdim          if ((*p & 0x04800000) == 0x04800000)
143280031Sdim            ImplicitShift = 4;
144280031Sdim        }
145280031Sdim      }
146280031Sdim      // Compensate for implicit shift.
147280031Sdim      Addend <<= ImplicitShift;
148280031Sdim      break;
149280031Sdim    }
150280031Sdim    }
151280031Sdim    return Addend;
152280031Sdim  }
153280031Sdim
154280031Sdim  /// Extract the addend encoded in the instruction.
155280031Sdim  void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes,
156280031Sdim                    MachO::RelocationInfoType RelType, int64_t Addend) const {
157280031Sdim    // Verify that the relocation has the correct alignment.
158280031Sdim    switch (RelType) {
159280031Sdim    default:
160280031Sdim      llvm_unreachable("Unsupported relocation type!");
161341825Sdim    case MachO::ARM64_RELOC_POINTER_TO_GOT:
162280031Sdim    case MachO::ARM64_RELOC_UNSIGNED:
163280031Sdim      assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
164280031Sdim      break;
165280031Sdim    case MachO::ARM64_RELOC_BRANCH26:
166280031Sdim    case MachO::ARM64_RELOC_PAGE21:
167280031Sdim    case MachO::ARM64_RELOC_PAGEOFF12:
168280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
169280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
170280031Sdim      assert(NumBytes == 4 && "Invalid relocation size.");
171280031Sdim      assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
172280031Sdim             "Instruction address is not aligned to 4 bytes.");
173280031Sdim      break;
174280031Sdim    }
175280031Sdim
176280031Sdim    switch (RelType) {
177280031Sdim    default:
178280031Sdim      llvm_unreachable("Unsupported relocation type!");
179341825Sdim    case MachO::ARM64_RELOC_POINTER_TO_GOT:
180280031Sdim    case MachO::ARM64_RELOC_UNSIGNED:
181280031Sdim      // This could be an unaligned memory location.
182280031Sdim      if (NumBytes == 4)
183280031Sdim        *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend;
184280031Sdim      else
185280031Sdim        *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend;
186280031Sdim      break;
187280031Sdim    case MachO::ARM64_RELOC_BRANCH26: {
188280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
189280031Sdim      // Verify that the relocation points to the expected branch instruction.
190341825Sdim      assert(((*p & 0xFC000000) == 0x14000000 ||
191341825Sdim              (*p & 0xFC000000) == 0x94000000) &&
192341825Sdim             "Expected branch instruction.");
193280031Sdim
194280031Sdim      // Verify addend value.
195280031Sdim      assert((Addend & 0x3) == 0 && "Branch target is not aligned");
196280031Sdim      assert(isInt<28>(Addend) && "Branch target is out of range.");
197280031Sdim
198280031Sdim      // Encode the addend as 26 bit immediate in the branch instruction.
199280031Sdim      *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
200280031Sdim      break;
201280031Sdim    }
202280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
203280031Sdim    case MachO::ARM64_RELOC_PAGE21: {
204280031Sdim      // Verify that the relocation points to the expected adrp instruction.
205280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
206280031Sdim      assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
207280031Sdim
208280031Sdim      // Check that the addend fits into 21 bits (+ 12 lower bits).
209280031Sdim      assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
210280031Sdim      assert(isInt<33>(Addend) && "Invalid page reloc value.");
211280031Sdim
212280031Sdim      // Encode the addend into the instruction.
213280031Sdim      uint32_t ImmLoValue = ((uint64_t)Addend << 17) & 0x60000000;
214280031Sdim      uint32_t ImmHiValue = ((uint64_t)Addend >> 9) & 0x00FFFFE0;
215280031Sdim      *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
216280031Sdim      break;
217280031Sdim    }
218280031Sdim    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
219280031Sdim      // Verify that the relocation points to one of the expected load / store
220280031Sdim      // instructions.
221280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
222280031Sdim      assert((*p & 0x3B000000) == 0x39000000 &&
223280031Sdim             "Only expected load / store instructions.");
224280031Sdim      (void)p;
225314564Sdim      LLVM_FALLTHROUGH;
226314564Sdim    }
227280031Sdim    case MachO::ARM64_RELOC_PAGEOFF12: {
228280031Sdim      // Verify that the relocation points to one of the expected load / store
229280031Sdim      // or add / sub instructions.
230280031Sdim      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
231280031Sdim      assert((((*p & 0x3B000000) == 0x39000000) ||
232280031Sdim              ((*p & 0x11C00000) == 0x11000000)   ) &&
233280031Sdim             "Expected load / store  or add/sub instruction.");
234280031Sdim
235280031Sdim      // Check which instruction we are decoding to obtain the implicit shift
236280031Sdim      // factor of the instruction and verify alignment.
237280031Sdim      int ImplicitShift = 0;
238280031Sdim      if ((*p & 0x3B000000) == 0x39000000) { // << load / store
239280031Sdim        // For load / store instructions the size is encoded in bits 31:30.
240280031Sdim        ImplicitShift = ((*p >> 30) & 0x3);
241280031Sdim        switch (ImplicitShift) {
242280031Sdim        case 0:
243280031Sdim          // Check if this a vector op to get the correct shift value.
244280031Sdim          if ((*p & 0x04800000) == 0x04800000) {
245280031Sdim            ImplicitShift = 4;
246280031Sdim            assert(((Addend & 0xF) == 0) &&
247280031Sdim                   "128-bit LDR/STR not 16-byte aligned.");
248280031Sdim          }
249280031Sdim          break;
250280031Sdim        case 1:
251280031Sdim          assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
252280031Sdim          break;
253280031Sdim        case 2:
254280031Sdim          assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
255280031Sdim          break;
256280031Sdim        case 3:
257280031Sdim          assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
258280031Sdim          break;
259280031Sdim        }
260280031Sdim      }
261280031Sdim      // Compensate for implicit shift.
262280031Sdim      Addend >>= ImplicitShift;
263280031Sdim      assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
264280031Sdim
265280031Sdim      // Encode the addend into the instruction.
266280031Sdim      *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
267280031Sdim      break;
268280031Sdim    }
269280031Sdim    }
270280031Sdim  }
271280031Sdim
272309124Sdim  Expected<relocation_iterator>
273274955Ssvnmir  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
274280031Sdim                       const ObjectFile &BaseObjT,
275280031Sdim                       ObjSectionToIDMap &ObjSectionToID,
276280031Sdim                       StubMap &Stubs) override {
277274955Ssvnmir    const MachOObjectFile &Obj =
278280031Sdim      static_cast<const MachOObjectFile &>(BaseObjT);
279274955Ssvnmir    MachO::any_relocation_info RelInfo =
280274955Ssvnmir        Obj.getRelocation(RelI->getRawDataRefImpl());
281274955Ssvnmir
282309124Sdim    if (Obj.isRelocationScattered(RelInfo))
283309124Sdim      return make_error<RuntimeDyldError>("Scattered relocations not supported "
284309124Sdim                                          "for MachO AArch64");
285274955Ssvnmir
286274955Ssvnmir    // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit
287274955Ssvnmir    // addend for the following relocation. If found: (1) store the associated
288274955Ssvnmir    // addend, (2) consume the next relocation, and (3) use the stored addend to
289274955Ssvnmir    // override the addend.
290274955Ssvnmir    int64_t ExplicitAddend = 0;
291274955Ssvnmir    if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) {
292274955Ssvnmir      assert(!Obj.getPlainRelocationExternal(RelInfo));
293274955Ssvnmir      assert(!Obj.getAnyRelocationPCRel(RelInfo));
294274955Ssvnmir      assert(Obj.getAnyRelocationLength(RelInfo) == 2);
295274955Ssvnmir      int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo);
296274955Ssvnmir      // Sign-extend the 24-bit to 64-bit.
297280031Sdim      ExplicitAddend = SignExtend64(RawAddend, 24);
298274955Ssvnmir      ++RelI;
299274955Ssvnmir      RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
300274955Ssvnmir    }
301274955Ssvnmir
302309124Sdim    if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_SUBTRACTOR)
303309124Sdim      return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID);
304309124Sdim
305280031Sdim    RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
306274955Ssvnmir
307341825Sdim    if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
308341825Sdim      bool Valid =
309341825Sdim          (RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel);
310341825Sdim      if (!Valid)
311341825Sdim        return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports "
312341825Sdim                                       "32-bit pc-rel or 64-bit absolute only",
313341825Sdim                                       inconvertibleErrorCode());
314341825Sdim    }
315341825Sdim
316341825Sdim    if (auto Addend = decodeAddend(RE))
317341825Sdim      RE.Addend = *Addend;
318341825Sdim    else
319341825Sdim      return Addend.takeError();
320341825Sdim
321280031Sdim    assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\
322280031Sdim      "ARM64_RELOC_ADDEND and embedded addend in the instruction.");
323296417Sdim    if (ExplicitAddend)
324274955Ssvnmir      RE.Addend = ExplicitAddend;
325274955Ssvnmir
326309124Sdim    RelocationValueRef Value;
327309124Sdim    if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
328309124Sdim      Value = *ValueOrErr;
329309124Sdim    else
330309124Sdim      return ValueOrErr.takeError();
331296417Sdim
332274955Ssvnmir    bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
333341825Sdim    if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
334341825Sdim      // We'll take care of the offset in processGOTRelocation.
335341825Sdim      Value.Offset = 0;
336341825Sdim    } else if (!IsExtern && RE.IsPCRel)
337288943Sdim      makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
338274955Ssvnmir
339280031Sdim    RE.Addend = Value.Offset;
340274955Ssvnmir
341274955Ssvnmir    if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
342341825Sdim        RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 ||
343341825Sdim        RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT)
344274955Ssvnmir      processGOTRelocation(RE, Value, Stubs);
345274955Ssvnmir    else {
346274955Ssvnmir      if (Value.SymbolName)
347274955Ssvnmir        addRelocationForSymbol(RE, Value.SymbolName);
348274955Ssvnmir      else
349274955Ssvnmir        addRelocationForSection(RE, Value.SectionID);
350274955Ssvnmir    }
351274955Ssvnmir
352274955Ssvnmir    return ++RelI;
353274955Ssvnmir  }
354274955Ssvnmir
355280031Sdim  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
356341825Sdim    LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
357274955Ssvnmir
358274955Ssvnmir    const SectionEntry &Section = Sections[RE.SectionID];
359296417Sdim    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
360280031Sdim    MachO::RelocationInfoType RelType =
361280031Sdim      static_cast<MachO::RelocationInfoType>(RE.RelType);
362274955Ssvnmir
363280031Sdim    switch (RelType) {
364274955Ssvnmir    default:
365274955Ssvnmir      llvm_unreachable("Invalid relocation type!");
366274955Ssvnmir    case MachO::ARM64_RELOC_UNSIGNED: {
367274955Ssvnmir      assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported");
368274955Ssvnmir      // Mask in the target value a byte at a time (we don't have an alignment
369274955Ssvnmir      // guarantee for the target address, so this is safest).
370274955Ssvnmir      if (RE.Size < 2)
371274955Ssvnmir        llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED");
372274955Ssvnmir
373280031Sdim      encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend);
374274955Ssvnmir      break;
375274955Ssvnmir    }
376341825Sdim
377341825Sdim    case MachO::ARM64_RELOC_POINTER_TO_GOT: {
378341825Sdim      assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) &&
379341825Sdim             "ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit "
380341825Sdim             "absolute");
381341825Sdim      // Addend is the GOT entry address and RE.Offset the target of the
382341825Sdim      // relocation.
383341825Sdim      uint64_t Result =
384341825Sdim          RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend);
385341825Sdim      encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result);
386341825Sdim      break;
387341825Sdim    }
388341825Sdim
389274955Ssvnmir    case MachO::ARM64_RELOC_BRANCH26: {
390274955Ssvnmir      assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
391274955Ssvnmir      // Check if branch is in range.
392296417Sdim      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
393280031Sdim      int64_t PCRelVal = Value - FinalAddress + RE.Addend;
394280031Sdim      encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
395274955Ssvnmir      break;
396274955Ssvnmir    }
397274955Ssvnmir    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
398274955Ssvnmir    case MachO::ARM64_RELOC_PAGE21: {
399274955Ssvnmir      assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
400274955Ssvnmir      // Adjust for PC-relative relocation and offset.
401296417Sdim      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
402280031Sdim      int64_t PCRelVal =
403280031Sdim        ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
404280031Sdim      encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
405274955Ssvnmir      break;
406274955Ssvnmir    }
407274955Ssvnmir    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
408274955Ssvnmir    case MachO::ARM64_RELOC_PAGEOFF12: {
409274955Ssvnmir      assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
410274955Ssvnmir      // Add the offset from the symbol.
411274955Ssvnmir      Value += RE.Addend;
412274955Ssvnmir      // Mask out the page address and only use the lower 12 bits.
413274955Ssvnmir      Value &= 0xFFF;
414280031Sdim      encodeAddend(LocalAddress, /*Size=*/4, RelType, Value);
415274955Ssvnmir      break;
416274955Ssvnmir    }
417309124Sdim    case MachO::ARM64_RELOC_SUBTRACTOR: {
418309124Sdim      uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
419309124Sdim      uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
420309124Sdim      assert((Value == SectionABase || Value == SectionBBase) &&
421309124Sdim             "Unexpected SUBTRACTOR relocation value.");
422309124Sdim      Value = SectionABase - SectionBBase + RE.Addend;
423309124Sdim      writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
424309124Sdim      break;
425309124Sdim    }
426341825Sdim
427274955Ssvnmir    case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
428274955Ssvnmir    case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
429280031Sdim      llvm_unreachable("Relocation type not yet implemented!");
430274955Ssvnmir    case MachO::ARM64_RELOC_ADDEND:
431274955Ssvnmir      llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
432274955Ssvnmir                       "processRelocationRef!");
433274955Ssvnmir    }
434274955Ssvnmir  }
435274955Ssvnmir
436309124Sdim  Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
437309124Sdim                       const SectionRef &Section) {
438309124Sdim    return Error::success();
439309124Sdim  }
440274955Ssvnmir
441274955Ssvnmirprivate:
442274955Ssvnmir  void processGOTRelocation(const RelocationEntry &RE,
443274955Ssvnmir                            RelocationValueRef &Value, StubMap &Stubs) {
444341825Sdim    assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT &&
445341825Sdim            (RE.Size == 2 || RE.Size == 3)) ||
446341825Sdim           RE.Size == 2);
447274955Ssvnmir    SectionEntry &Section = Sections[RE.SectionID];
448274955Ssvnmir    StubMap::const_iterator i = Stubs.find(Value);
449280031Sdim    int64_t Offset;
450274955Ssvnmir    if (i != Stubs.end())
451280031Sdim      Offset = static_cast<int64_t>(i->second);
452274955Ssvnmir    else {
453274955Ssvnmir      // FIXME: There must be a better way to do this then to check and fix the
454274955Ssvnmir      // alignment every time!!!
455296417Sdim      uintptr_t BaseAddress = uintptr_t(Section.getAddress());
456274955Ssvnmir      uintptr_t StubAlignment = getStubAlignment();
457274955Ssvnmir      uintptr_t StubAddress =
458296417Sdim          (BaseAddress + Section.getStubOffset() + StubAlignment - 1) &
459274955Ssvnmir          -StubAlignment;
460274955Ssvnmir      unsigned StubOffset = StubAddress - BaseAddress;
461274955Ssvnmir      Stubs[Value] = StubOffset;
462274955Ssvnmir      assert(((StubAddress % getStubAlignment()) == 0) &&
463274955Ssvnmir             "GOT entry not aligned");
464274955Ssvnmir      RelocationEntry GOTRE(RE.SectionID, StubOffset,
465280031Sdim                            MachO::ARM64_RELOC_UNSIGNED, Value.Offset,
466274955Ssvnmir                            /*IsPCRel=*/false, /*Size=*/3);
467274955Ssvnmir      if (Value.SymbolName)
468274955Ssvnmir        addRelocationForSymbol(GOTRE, Value.SymbolName);
469274955Ssvnmir      else
470274955Ssvnmir        addRelocationForSection(GOTRE, Value.SectionID);
471296417Sdim      Section.advanceStubOffset(getMaxStubSize());
472280031Sdim      Offset = static_cast<int64_t>(StubOffset);
473274955Ssvnmir    }
474280031Sdim    RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset,
475274955Ssvnmir                             RE.IsPCRel, RE.Size);
476280031Sdim    addRelocationForSection(TargetRE, RE.SectionID);
477274955Ssvnmir  }
478309124Sdim
479309124Sdim  Expected<relocation_iterator>
480309124Sdim  processSubtractRelocation(unsigned SectionID, relocation_iterator RelI,
481309124Sdim                            const ObjectFile &BaseObjT,
482309124Sdim                            ObjSectionToIDMap &ObjSectionToID) {
483309124Sdim    const MachOObjectFile &Obj =
484309124Sdim        static_cast<const MachOObjectFile&>(BaseObjT);
485309124Sdim    MachO::any_relocation_info RE =
486309124Sdim        Obj.getRelocation(RelI->getRawDataRefImpl());
487309124Sdim
488309124Sdim    unsigned Size = Obj.getAnyRelocationLength(RE);
489309124Sdim    uint64_t Offset = RelI->getOffset();
490309124Sdim    uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset);
491309124Sdim    unsigned NumBytes = 1 << Size;
492309124Sdim
493309124Sdim    Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName();
494309124Sdim    if (!SubtrahendNameOrErr)
495309124Sdim      return SubtrahendNameOrErr.takeError();
496309124Sdim    auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr);
497309124Sdim    unsigned SectionBID = SubtrahendI->second.getSectionID();
498309124Sdim    uint64_t SectionBOffset = SubtrahendI->second.getOffset();
499309124Sdim    int64_t Addend =
500309124Sdim      SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8);
501309124Sdim
502309124Sdim    ++RelI;
503309124Sdim    Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName();
504309124Sdim    if (!MinuendNameOrErr)
505309124Sdim      return MinuendNameOrErr.takeError();
506309124Sdim    auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr);
507309124Sdim    unsigned SectionAID = MinuendI->second.getSectionID();
508309124Sdim    uint64_t SectionAOffset = MinuendI->second.getOffset();
509309124Sdim
510309124Sdim    RelocationEntry R(SectionID, Offset, MachO::ARM64_RELOC_SUBTRACTOR, (uint64_t)Addend,
511309124Sdim                      SectionAID, SectionAOffset, SectionBID, SectionBOffset,
512309124Sdim                      false, Size);
513309124Sdim
514309124Sdim    addRelocationForSection(R, SectionAID);
515309124Sdim
516309124Sdim    return ++RelI;
517309124Sdim  }
518309124Sdim
519341825Sdim  static const char *getRelocName(uint32_t RelocType) {
520341825Sdim    switch (RelocType) {
521341825Sdim      case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED";
522341825Sdim      case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR";
523341825Sdim      case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26";
524341825Sdim      case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21";
525341825Sdim      case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12";
526341825Sdim      case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21";
527341825Sdim      case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12";
528341825Sdim      case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT";
529341825Sdim      case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21";
530341825Sdim      case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12";
531341825Sdim      case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND";
532341825Sdim    }
533341825Sdim    return "Unrecognized arm64 addend";
534341825Sdim  }
535341825Sdim
536274955Ssvnmir};
537274955Ssvnmir}
538274955Ssvnmir
539274955Ssvnmir#undef DEBUG_TYPE
540274955Ssvnmir
541280031Sdim#endif
542