10b57cec5SDimitry Andric //===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
100b57cec5SDimitry Andric #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "../RuntimeDyldMachO.h"
130b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #define DEBUG_TYPE "dyld"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric namespace llvm {
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric class RuntimeDyldMachOAArch64
200b57cec5SDimitry Andric     : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> {
210b57cec5SDimitry Andric public:
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric   typedef uint64_t TargetPtrT;
240b57cec5SDimitry Andric 
RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager & MM,JITSymbolResolver & Resolver)250b57cec5SDimitry Andric   RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager &MM,
260b57cec5SDimitry Andric                           JITSymbolResolver &Resolver)
270b57cec5SDimitry Andric       : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
280b57cec5SDimitry Andric 
getMaxStubSize()290b57cec5SDimitry Andric   unsigned getMaxStubSize() const override { return 8; }
300b57cec5SDimitry Andric 
getStubAlignment()31*bdd1243dSDimitry Andric   Align getStubAlignment() override { return Align(8); }
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   /// Extract the addend encoded in the instruction / memory location.
decodeAddend(const RelocationEntry & RE)340b57cec5SDimitry Andric   Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
350b57cec5SDimitry Andric     const SectionEntry &Section = Sections[RE.SectionID];
360b57cec5SDimitry Andric     uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
370b57cec5SDimitry Andric     unsigned NumBytes = 1 << RE.Size;
380b57cec5SDimitry Andric     int64_t Addend = 0;
390b57cec5SDimitry Andric     // Verify that the relocation has the correct size and alignment.
400b57cec5SDimitry Andric     switch (RE.RelType) {
410b57cec5SDimitry Andric     default: {
420b57cec5SDimitry Andric       std::string ErrMsg;
430b57cec5SDimitry Andric       {
440b57cec5SDimitry Andric         raw_string_ostream ErrStream(ErrMsg);
450b57cec5SDimitry Andric         ErrStream << "Unsupported relocation type: "
460b57cec5SDimitry Andric                   << getRelocName(RE.RelType);
470b57cec5SDimitry Andric       }
480b57cec5SDimitry Andric       return make_error<StringError>(std::move(ErrMsg),
490b57cec5SDimitry Andric                                      inconvertibleErrorCode());
500b57cec5SDimitry Andric     }
510b57cec5SDimitry Andric     case MachO::ARM64_RELOC_POINTER_TO_GOT:
520b57cec5SDimitry Andric     case MachO::ARM64_RELOC_UNSIGNED: {
530b57cec5SDimitry Andric       if (NumBytes != 4 && NumBytes != 8) {
540b57cec5SDimitry Andric         std::string ErrMsg;
550b57cec5SDimitry Andric         {
560b57cec5SDimitry Andric           raw_string_ostream ErrStream(ErrMsg);
570b57cec5SDimitry Andric           ErrStream << "Invalid relocation size for relocation "
580b57cec5SDimitry Andric                     << getRelocName(RE.RelType);
590b57cec5SDimitry Andric         }
600b57cec5SDimitry Andric         return make_error<StringError>(std::move(ErrMsg),
610b57cec5SDimitry Andric                                        inconvertibleErrorCode());
620b57cec5SDimitry Andric       }
630b57cec5SDimitry Andric       break;
640b57cec5SDimitry Andric     }
650b57cec5SDimitry Andric     case MachO::ARM64_RELOC_BRANCH26:
660b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGE21:
670b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGEOFF12:
680b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
690b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
700b57cec5SDimitry Andric       assert(NumBytes == 4 && "Invalid relocation size.");
710b57cec5SDimitry Andric       assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
720b57cec5SDimitry Andric              "Instruction address is not aligned to 4 bytes.");
730b57cec5SDimitry Andric       break;
740b57cec5SDimitry Andric     }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric     switch (RE.RelType) {
770b57cec5SDimitry Andric     default:
780b57cec5SDimitry Andric       llvm_unreachable("Unsupported relocation type!");
790b57cec5SDimitry Andric     case MachO::ARM64_RELOC_POINTER_TO_GOT:
800b57cec5SDimitry Andric     case MachO::ARM64_RELOC_UNSIGNED:
810b57cec5SDimitry Andric       // This could be an unaligned memory location.
820b57cec5SDimitry Andric       if (NumBytes == 4)
830b57cec5SDimitry Andric         Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress);
840b57cec5SDimitry Andric       else
850b57cec5SDimitry Andric         Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress);
860b57cec5SDimitry Andric       break;
870b57cec5SDimitry Andric     case MachO::ARM64_RELOC_BRANCH26: {
880b57cec5SDimitry Andric       // Verify that the relocation points to a B/BL instruction.
890b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
900b57cec5SDimitry Andric       assert(((*p & 0xFC000000) == 0x14000000 ||
910b57cec5SDimitry Andric               (*p & 0xFC000000) == 0x94000000) &&
920b57cec5SDimitry Andric              "Expected branch instruction.");
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric       // Get the 26 bit addend encoded in the branch instruction and sign-extend
950b57cec5SDimitry Andric       // to 64 bit. The lower 2 bits are always zeros and are therefore implicit
960b57cec5SDimitry Andric       // (<< 2).
970b57cec5SDimitry Andric       Addend = (*p & 0x03FFFFFF) << 2;
980b57cec5SDimitry Andric       Addend = SignExtend64(Addend, 28);
990b57cec5SDimitry Andric       break;
1000b57cec5SDimitry Andric     }
1010b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
1020b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGE21: {
1030b57cec5SDimitry Andric       // Verify that the relocation points to the expected adrp instruction.
1040b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
1050b57cec5SDimitry Andric       assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric       // Get the 21 bit addend encoded in the adrp instruction and sign-extend
1080b57cec5SDimitry Andric       // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are
1090b57cec5SDimitry Andric       // therefore implicit (<< 12).
1100b57cec5SDimitry Andric       Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12;
1110b57cec5SDimitry Andric       Addend = SignExtend64(Addend, 33);
1120b57cec5SDimitry Andric       break;
1130b57cec5SDimitry Andric     }
1140b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
1150b57cec5SDimitry Andric       // Verify that the relocation points to one of the expected load / store
1160b57cec5SDimitry Andric       // instructions.
1170b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
1180b57cec5SDimitry Andric       (void)p;
1190b57cec5SDimitry Andric       assert((*p & 0x3B000000) == 0x39000000 &&
1200b57cec5SDimitry Andric              "Only expected load / store instructions.");
121*bdd1243dSDimitry Andric       [[fallthrough]];
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGEOFF12: {
1240b57cec5SDimitry Andric       // Verify that the relocation points to one of the expected load / store
1250b57cec5SDimitry Andric       // or add / sub instructions.
1260b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
1270b57cec5SDimitry Andric       assert((((*p & 0x3B000000) == 0x39000000) ||
1280b57cec5SDimitry Andric               ((*p & 0x11C00000) == 0x11000000)   ) &&
1290b57cec5SDimitry Andric              "Expected load / store  or add/sub instruction.");
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric       // Get the 12 bit addend encoded in the instruction.
1320b57cec5SDimitry Andric       Addend = (*p & 0x003FFC00) >> 10;
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric       // Check which instruction we are decoding to obtain the implicit shift
1350b57cec5SDimitry Andric       // factor of the instruction.
1360b57cec5SDimitry Andric       int ImplicitShift = 0;
1370b57cec5SDimitry Andric       if ((*p & 0x3B000000) == 0x39000000) { // << load / store
1380b57cec5SDimitry Andric         // For load / store instructions the size is encoded in bits 31:30.
1390b57cec5SDimitry Andric         ImplicitShift = ((*p >> 30) & 0x3);
1400b57cec5SDimitry Andric         if (ImplicitShift == 0) {
1410b57cec5SDimitry Andric           // Check if this a vector op to get the correct shift value.
1420b57cec5SDimitry Andric           if ((*p & 0x04800000) == 0x04800000)
1430b57cec5SDimitry Andric             ImplicitShift = 4;
1440b57cec5SDimitry Andric         }
1450b57cec5SDimitry Andric       }
1460b57cec5SDimitry Andric       // Compensate for implicit shift.
1470b57cec5SDimitry Andric       Addend <<= ImplicitShift;
1480b57cec5SDimitry Andric       break;
1490b57cec5SDimitry Andric     }
1500b57cec5SDimitry Andric     }
1510b57cec5SDimitry Andric     return Addend;
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   /// Extract the addend encoded in the instruction.
encodeAddend(uint8_t * LocalAddress,unsigned NumBytes,MachO::RelocationInfoType RelType,int64_t Addend)1550b57cec5SDimitry Andric   void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes,
1560b57cec5SDimitry Andric                     MachO::RelocationInfoType RelType, int64_t Addend) const {
1570b57cec5SDimitry Andric     // Verify that the relocation has the correct alignment.
1580b57cec5SDimitry Andric     switch (RelType) {
1590b57cec5SDimitry Andric     default:
1600b57cec5SDimitry Andric       llvm_unreachable("Unsupported relocation type!");
1610b57cec5SDimitry Andric     case MachO::ARM64_RELOC_POINTER_TO_GOT:
1620b57cec5SDimitry Andric     case MachO::ARM64_RELOC_UNSIGNED:
1630b57cec5SDimitry Andric       assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
1640b57cec5SDimitry Andric       break;
1650b57cec5SDimitry Andric     case MachO::ARM64_RELOC_BRANCH26:
1660b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGE21:
1670b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGEOFF12:
1680b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
1690b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
1700b57cec5SDimitry Andric       assert(NumBytes == 4 && "Invalid relocation size.");
1710b57cec5SDimitry Andric       assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
1720b57cec5SDimitry Andric              "Instruction address is not aligned to 4 bytes.");
1730b57cec5SDimitry Andric       break;
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric     switch (RelType) {
1770b57cec5SDimitry Andric     default:
1780b57cec5SDimitry Andric       llvm_unreachable("Unsupported relocation type!");
1790b57cec5SDimitry Andric     case MachO::ARM64_RELOC_POINTER_TO_GOT:
1800b57cec5SDimitry Andric     case MachO::ARM64_RELOC_UNSIGNED:
1810b57cec5SDimitry Andric       // This could be an unaligned memory location.
1820b57cec5SDimitry Andric       if (NumBytes == 4)
1830b57cec5SDimitry Andric         *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend;
1840b57cec5SDimitry Andric       else
1850b57cec5SDimitry Andric         *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend;
1860b57cec5SDimitry Andric       break;
1870b57cec5SDimitry Andric     case MachO::ARM64_RELOC_BRANCH26: {
1880b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
1890b57cec5SDimitry Andric       // Verify that the relocation points to the expected branch instruction.
1900b57cec5SDimitry Andric       assert(((*p & 0xFC000000) == 0x14000000 ||
1910b57cec5SDimitry Andric               (*p & 0xFC000000) == 0x94000000) &&
1920b57cec5SDimitry Andric              "Expected branch instruction.");
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric       // Verify addend value.
1950b57cec5SDimitry Andric       assert((Addend & 0x3) == 0 && "Branch target is not aligned");
1960b57cec5SDimitry Andric       assert(isInt<28>(Addend) && "Branch target is out of range.");
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric       // Encode the addend as 26 bit immediate in the branch instruction.
1990b57cec5SDimitry Andric       *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
2000b57cec5SDimitry Andric       break;
2010b57cec5SDimitry Andric     }
2020b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
2030b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGE21: {
2040b57cec5SDimitry Andric       // Verify that the relocation points to the expected adrp instruction.
2050b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
2060b57cec5SDimitry Andric       assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric       // Check that the addend fits into 21 bits (+ 12 lower bits).
2090b57cec5SDimitry Andric       assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
2100b57cec5SDimitry Andric       assert(isInt<33>(Addend) && "Invalid page reloc value.");
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric       // Encode the addend into the instruction.
2130b57cec5SDimitry Andric       uint32_t ImmLoValue = ((uint64_t)Addend << 17) & 0x60000000;
2140b57cec5SDimitry Andric       uint32_t ImmHiValue = ((uint64_t)Addend >> 9) & 0x00FFFFE0;
2150b57cec5SDimitry Andric       *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
2160b57cec5SDimitry Andric       break;
2170b57cec5SDimitry Andric     }
2180b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
2190b57cec5SDimitry Andric       // Verify that the relocation points to one of the expected load / store
2200b57cec5SDimitry Andric       // instructions.
2210b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
2220b57cec5SDimitry Andric       assert((*p & 0x3B000000) == 0x39000000 &&
2230b57cec5SDimitry Andric              "Only expected load / store instructions.");
2240b57cec5SDimitry Andric       (void)p;
225*bdd1243dSDimitry Andric       [[fallthrough]];
2260b57cec5SDimitry Andric     }
2270b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGEOFF12: {
2280b57cec5SDimitry Andric       // Verify that the relocation points to one of the expected load / store
2290b57cec5SDimitry Andric       // or add / sub instructions.
2300b57cec5SDimitry Andric       auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
2310b57cec5SDimitry Andric       assert((((*p & 0x3B000000) == 0x39000000) ||
2320b57cec5SDimitry Andric               ((*p & 0x11C00000) == 0x11000000)   ) &&
2330b57cec5SDimitry Andric              "Expected load / store  or add/sub instruction.");
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric       // Check which instruction we are decoding to obtain the implicit shift
2360b57cec5SDimitry Andric       // factor of the instruction and verify alignment.
2370b57cec5SDimitry Andric       int ImplicitShift = 0;
2380b57cec5SDimitry Andric       if ((*p & 0x3B000000) == 0x39000000) { // << load / store
2390b57cec5SDimitry Andric         // For load / store instructions the size is encoded in bits 31:30.
2400b57cec5SDimitry Andric         ImplicitShift = ((*p >> 30) & 0x3);
2410b57cec5SDimitry Andric         switch (ImplicitShift) {
2420b57cec5SDimitry Andric         case 0:
2430b57cec5SDimitry Andric           // Check if this a vector op to get the correct shift value.
2440b57cec5SDimitry Andric           if ((*p & 0x04800000) == 0x04800000) {
2450b57cec5SDimitry Andric             ImplicitShift = 4;
2460b57cec5SDimitry Andric             assert(((Addend & 0xF) == 0) &&
2470b57cec5SDimitry Andric                    "128-bit LDR/STR not 16-byte aligned.");
2480b57cec5SDimitry Andric           }
2490b57cec5SDimitry Andric           break;
2500b57cec5SDimitry Andric         case 1:
2510b57cec5SDimitry Andric           assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
2520b57cec5SDimitry Andric           break;
2530b57cec5SDimitry Andric         case 2:
2540b57cec5SDimitry Andric           assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
2550b57cec5SDimitry Andric           break;
2560b57cec5SDimitry Andric         case 3:
2570b57cec5SDimitry Andric           assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
2580b57cec5SDimitry Andric           break;
2590b57cec5SDimitry Andric         }
2600b57cec5SDimitry Andric       }
2610b57cec5SDimitry Andric       // Compensate for implicit shift.
2620b57cec5SDimitry Andric       Addend >>= ImplicitShift;
2630b57cec5SDimitry Andric       assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric       // Encode the addend into the instruction.
2660b57cec5SDimitry Andric       *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
2670b57cec5SDimitry Andric       break;
2680b57cec5SDimitry Andric     }
2690b57cec5SDimitry Andric     }
2700b57cec5SDimitry Andric   }
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   Expected<relocation_iterator>
processRelocationRef(unsigned SectionID,relocation_iterator RelI,const ObjectFile & BaseObjT,ObjSectionToIDMap & ObjSectionToID,StubMap & Stubs)2730b57cec5SDimitry Andric   processRelocationRef(unsigned SectionID, relocation_iterator RelI,
2740b57cec5SDimitry Andric                        const ObjectFile &BaseObjT,
2750b57cec5SDimitry Andric                        ObjSectionToIDMap &ObjSectionToID,
2760b57cec5SDimitry Andric                        StubMap &Stubs) override {
2770b57cec5SDimitry Andric     const MachOObjectFile &Obj =
2780b57cec5SDimitry Andric       static_cast<const MachOObjectFile &>(BaseObjT);
2790b57cec5SDimitry Andric     MachO::any_relocation_info RelInfo =
2800b57cec5SDimitry Andric         Obj.getRelocation(RelI->getRawDataRefImpl());
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric     if (Obj.isRelocationScattered(RelInfo))
2830b57cec5SDimitry Andric       return make_error<RuntimeDyldError>("Scattered relocations not supported "
2840b57cec5SDimitry Andric                                           "for MachO AArch64");
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric     // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit
2870b57cec5SDimitry Andric     // addend for the following relocation. If found: (1) store the associated
2880b57cec5SDimitry Andric     // addend, (2) consume the next relocation, and (3) use the stored addend to
2890b57cec5SDimitry Andric     // override the addend.
2900b57cec5SDimitry Andric     int64_t ExplicitAddend = 0;
2910b57cec5SDimitry Andric     if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) {
2920b57cec5SDimitry Andric       assert(!Obj.getPlainRelocationExternal(RelInfo));
2930b57cec5SDimitry Andric       assert(!Obj.getAnyRelocationPCRel(RelInfo));
2940b57cec5SDimitry Andric       assert(Obj.getAnyRelocationLength(RelInfo) == 2);
2950b57cec5SDimitry Andric       int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo);
2960b57cec5SDimitry Andric       // Sign-extend the 24-bit to 64-bit.
2970b57cec5SDimitry Andric       ExplicitAddend = SignExtend64(RawAddend, 24);
2980b57cec5SDimitry Andric       ++RelI;
2990b57cec5SDimitry Andric       RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
3000b57cec5SDimitry Andric     }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric     if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_SUBTRACTOR)
3030b57cec5SDimitry Andric       return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID);
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric     RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric     if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
3080b57cec5SDimitry Andric       bool Valid =
3090b57cec5SDimitry Andric           (RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel);
3100b57cec5SDimitry Andric       if (!Valid)
3110b57cec5SDimitry Andric         return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports "
3120b57cec5SDimitry Andric                                        "32-bit pc-rel or 64-bit absolute only",
3130b57cec5SDimitry Andric                                        inconvertibleErrorCode());
3140b57cec5SDimitry Andric     }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric     if (auto Addend = decodeAddend(RE))
3170b57cec5SDimitry Andric       RE.Addend = *Addend;
3180b57cec5SDimitry Andric     else
3190b57cec5SDimitry Andric       return Addend.takeError();
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric     assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\
3220b57cec5SDimitry Andric       "ARM64_RELOC_ADDEND and embedded addend in the instruction.");
3230b57cec5SDimitry Andric     if (ExplicitAddend)
3240b57cec5SDimitry Andric       RE.Addend = ExplicitAddend;
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric     RelocationValueRef Value;
3270b57cec5SDimitry Andric     if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
3280b57cec5SDimitry Andric       Value = *ValueOrErr;
3290b57cec5SDimitry Andric     else
3300b57cec5SDimitry Andric       return ValueOrErr.takeError();
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric     bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
3330b57cec5SDimitry Andric     if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
3340b57cec5SDimitry Andric       // We'll take care of the offset in processGOTRelocation.
3350b57cec5SDimitry Andric       Value.Offset = 0;
3360b57cec5SDimitry Andric     } else if (!IsExtern && RE.IsPCRel)
3370b57cec5SDimitry Andric       makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     RE.Addend = Value.Offset;
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric     if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
3420b57cec5SDimitry Andric         RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 ||
3430b57cec5SDimitry Andric         RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT)
3440b57cec5SDimitry Andric       processGOTRelocation(RE, Value, Stubs);
3450b57cec5SDimitry Andric     else {
3460b57cec5SDimitry Andric       if (Value.SymbolName)
3470b57cec5SDimitry Andric         addRelocationForSymbol(RE, Value.SymbolName);
3480b57cec5SDimitry Andric       else
3490b57cec5SDimitry Andric         addRelocationForSection(RE, Value.SectionID);
3500b57cec5SDimitry Andric     }
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric     return ++RelI;
3530b57cec5SDimitry Andric   }
3540b57cec5SDimitry Andric 
resolveRelocation(const RelocationEntry & RE,uint64_t Value)3550b57cec5SDimitry Andric   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
3560b57cec5SDimitry Andric     LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric     const SectionEntry &Section = Sections[RE.SectionID];
3590b57cec5SDimitry Andric     uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
3600b57cec5SDimitry Andric     MachO::RelocationInfoType RelType =
3610b57cec5SDimitry Andric       static_cast<MachO::RelocationInfoType>(RE.RelType);
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric     switch (RelType) {
3640b57cec5SDimitry Andric     default:
3650b57cec5SDimitry Andric       llvm_unreachable("Invalid relocation type!");
3660b57cec5SDimitry Andric     case MachO::ARM64_RELOC_UNSIGNED: {
3670b57cec5SDimitry Andric       assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported");
3680b57cec5SDimitry Andric       // Mask in the target value a byte at a time (we don't have an alignment
3690b57cec5SDimitry Andric       // guarantee for the target address, so this is safest).
3700b57cec5SDimitry Andric       if (RE.Size < 2)
3710b57cec5SDimitry Andric         llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED");
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric       encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend);
3740b57cec5SDimitry Andric       break;
3750b57cec5SDimitry Andric     }
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric     case MachO::ARM64_RELOC_POINTER_TO_GOT: {
3780b57cec5SDimitry Andric       assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) &&
3790b57cec5SDimitry Andric              "ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit "
3800b57cec5SDimitry Andric              "absolute");
3810b57cec5SDimitry Andric       // Addend is the GOT entry address and RE.Offset the target of the
3820b57cec5SDimitry Andric       // relocation.
3830b57cec5SDimitry Andric       uint64_t Result =
3840b57cec5SDimitry Andric           RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend);
3850b57cec5SDimitry Andric       encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result);
3860b57cec5SDimitry Andric       break;
3870b57cec5SDimitry Andric     }
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric     case MachO::ARM64_RELOC_BRANCH26: {
3900b57cec5SDimitry Andric       assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
3910b57cec5SDimitry Andric       // Check if branch is in range.
3920b57cec5SDimitry Andric       uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
3930b57cec5SDimitry Andric       int64_t PCRelVal = Value - FinalAddress + RE.Addend;
3940b57cec5SDimitry Andric       encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
3950b57cec5SDimitry Andric       break;
3960b57cec5SDimitry Andric     }
3970b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
3980b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGE21: {
3990b57cec5SDimitry Andric       assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
4000b57cec5SDimitry Andric       // Adjust for PC-relative relocation and offset.
4010b57cec5SDimitry Andric       uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
4020b57cec5SDimitry Andric       int64_t PCRelVal =
4030b57cec5SDimitry Andric         ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
4040b57cec5SDimitry Andric       encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
4050b57cec5SDimitry Andric       break;
4060b57cec5SDimitry Andric     }
4070b57cec5SDimitry Andric     case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
4080b57cec5SDimitry Andric     case MachO::ARM64_RELOC_PAGEOFF12: {
4090b57cec5SDimitry Andric       assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
4100b57cec5SDimitry Andric       // Add the offset from the symbol.
4110b57cec5SDimitry Andric       Value += RE.Addend;
4120b57cec5SDimitry Andric       // Mask out the page address and only use the lower 12 bits.
4130b57cec5SDimitry Andric       Value &= 0xFFF;
4140b57cec5SDimitry Andric       encodeAddend(LocalAddress, /*Size=*/4, RelType, Value);
4150b57cec5SDimitry Andric       break;
4160b57cec5SDimitry Andric     }
4170b57cec5SDimitry Andric     case MachO::ARM64_RELOC_SUBTRACTOR: {
4180b57cec5SDimitry Andric       uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
4190b57cec5SDimitry Andric       uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
4200b57cec5SDimitry Andric       assert((Value == SectionABase || Value == SectionBBase) &&
4210b57cec5SDimitry Andric              "Unexpected SUBTRACTOR relocation value.");
4220b57cec5SDimitry Andric       Value = SectionABase - SectionBBase + RE.Addend;
4230b57cec5SDimitry Andric       writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
4240b57cec5SDimitry Andric       break;
4250b57cec5SDimitry Andric     }
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric     case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
4280b57cec5SDimitry Andric     case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
4290b57cec5SDimitry Andric       llvm_unreachable("Relocation type not yet implemented!");
4300b57cec5SDimitry Andric     case MachO::ARM64_RELOC_ADDEND:
4310b57cec5SDimitry Andric       llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
4320b57cec5SDimitry Andric                        "processRelocationRef!");
4330b57cec5SDimitry Andric     }
4340b57cec5SDimitry Andric   }
4350b57cec5SDimitry Andric 
finalizeSection(const ObjectFile & Obj,unsigned SectionID,const SectionRef & Section)4360b57cec5SDimitry Andric   Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
4370b57cec5SDimitry Andric                        const SectionRef &Section) {
4380b57cec5SDimitry Andric     return Error::success();
4390b57cec5SDimitry Andric   }
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric private:
processGOTRelocation(const RelocationEntry & RE,RelocationValueRef & Value,StubMap & Stubs)4420b57cec5SDimitry Andric   void processGOTRelocation(const RelocationEntry &RE,
4430b57cec5SDimitry Andric                             RelocationValueRef &Value, StubMap &Stubs) {
4440b57cec5SDimitry Andric     assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT &&
4450b57cec5SDimitry Andric             (RE.Size == 2 || RE.Size == 3)) ||
4460b57cec5SDimitry Andric            RE.Size == 2);
4470b57cec5SDimitry Andric     SectionEntry &Section = Sections[RE.SectionID];
4480b57cec5SDimitry Andric     StubMap::const_iterator i = Stubs.find(Value);
4490b57cec5SDimitry Andric     int64_t Offset;
4500b57cec5SDimitry Andric     if (i != Stubs.end())
4510b57cec5SDimitry Andric       Offset = static_cast<int64_t>(i->second);
4520b57cec5SDimitry Andric     else {
4530b57cec5SDimitry Andric       // FIXME: There must be a better way to do this then to check and fix the
4540b57cec5SDimitry Andric       // alignment every time!!!
4550b57cec5SDimitry Andric       uintptr_t BaseAddress = uintptr_t(Section.getAddress());
456*bdd1243dSDimitry Andric       uintptr_t StubAlignment = getStubAlignment().value();
4570b57cec5SDimitry Andric       uintptr_t StubAddress =
4580b57cec5SDimitry Andric           (BaseAddress + Section.getStubOffset() + StubAlignment - 1) &
4590b57cec5SDimitry Andric           -StubAlignment;
4600b57cec5SDimitry Andric       unsigned StubOffset = StubAddress - BaseAddress;
4610b57cec5SDimitry Andric       Stubs[Value] = StubOffset;
462*bdd1243dSDimitry Andric       assert(isAligned(getStubAlignment(), StubAddress) &&
4630b57cec5SDimitry Andric              "GOT entry not aligned");
4640b57cec5SDimitry Andric       RelocationEntry GOTRE(RE.SectionID, StubOffset,
4650b57cec5SDimitry Andric                             MachO::ARM64_RELOC_UNSIGNED, Value.Offset,
4660b57cec5SDimitry Andric                             /*IsPCRel=*/false, /*Size=*/3);
4670b57cec5SDimitry Andric       if (Value.SymbolName)
4680b57cec5SDimitry Andric         addRelocationForSymbol(GOTRE, Value.SymbolName);
4690b57cec5SDimitry Andric       else
4700b57cec5SDimitry Andric         addRelocationForSection(GOTRE, Value.SectionID);
4710b57cec5SDimitry Andric       Section.advanceStubOffset(getMaxStubSize());
4720b57cec5SDimitry Andric       Offset = static_cast<int64_t>(StubOffset);
4730b57cec5SDimitry Andric     }
4740b57cec5SDimitry Andric     RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset,
4750b57cec5SDimitry Andric                              RE.IsPCRel, RE.Size);
4760b57cec5SDimitry Andric     addRelocationForSection(TargetRE, RE.SectionID);
4770b57cec5SDimitry Andric   }
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric   Expected<relocation_iterator>
processSubtractRelocation(unsigned SectionID,relocation_iterator RelI,const ObjectFile & BaseObjT,ObjSectionToIDMap & ObjSectionToID)4800b57cec5SDimitry Andric   processSubtractRelocation(unsigned SectionID, relocation_iterator RelI,
4810b57cec5SDimitry Andric                             const ObjectFile &BaseObjT,
4820b57cec5SDimitry Andric                             ObjSectionToIDMap &ObjSectionToID) {
4830b57cec5SDimitry Andric     const MachOObjectFile &Obj =
4840b57cec5SDimitry Andric         static_cast<const MachOObjectFile&>(BaseObjT);
4850b57cec5SDimitry Andric     MachO::any_relocation_info RE =
4860b57cec5SDimitry Andric         Obj.getRelocation(RelI->getRawDataRefImpl());
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric     unsigned Size = Obj.getAnyRelocationLength(RE);
4890b57cec5SDimitry Andric     uint64_t Offset = RelI->getOffset();
4900b57cec5SDimitry Andric     uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset);
4910b57cec5SDimitry Andric     unsigned NumBytes = 1 << Size;
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric     Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName();
4940b57cec5SDimitry Andric     if (!SubtrahendNameOrErr)
4950b57cec5SDimitry Andric       return SubtrahendNameOrErr.takeError();
4960b57cec5SDimitry Andric     auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr);
4970b57cec5SDimitry Andric     unsigned SectionBID = SubtrahendI->second.getSectionID();
4980b57cec5SDimitry Andric     uint64_t SectionBOffset = SubtrahendI->second.getOffset();
4990b57cec5SDimitry Andric     int64_t Addend =
5000b57cec5SDimitry Andric       SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8);
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric     ++RelI;
5030b57cec5SDimitry Andric     Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName();
5040b57cec5SDimitry Andric     if (!MinuendNameOrErr)
5050b57cec5SDimitry Andric       return MinuendNameOrErr.takeError();
5060b57cec5SDimitry Andric     auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr);
5070b57cec5SDimitry Andric     unsigned SectionAID = MinuendI->second.getSectionID();
5080b57cec5SDimitry Andric     uint64_t SectionAOffset = MinuendI->second.getOffset();
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric     RelocationEntry R(SectionID, Offset, MachO::ARM64_RELOC_SUBTRACTOR, (uint64_t)Addend,
5110b57cec5SDimitry Andric                       SectionAID, SectionAOffset, SectionBID, SectionBOffset,
5120b57cec5SDimitry Andric                       false, Size);
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric     addRelocationForSection(R, SectionAID);
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric     return ++RelI;
5170b57cec5SDimitry Andric   }
5180b57cec5SDimitry Andric 
getRelocName(uint32_t RelocType)5190b57cec5SDimitry Andric   static const char *getRelocName(uint32_t RelocType) {
5200b57cec5SDimitry Andric     switch (RelocType) {
5210b57cec5SDimitry Andric       case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED";
5220b57cec5SDimitry Andric       case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR";
5230b57cec5SDimitry Andric       case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26";
5240b57cec5SDimitry Andric       case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21";
5250b57cec5SDimitry Andric       case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12";
5260b57cec5SDimitry Andric       case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21";
5270b57cec5SDimitry Andric       case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12";
5280b57cec5SDimitry Andric       case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT";
5290b57cec5SDimitry Andric       case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21";
5300b57cec5SDimitry Andric       case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12";
5310b57cec5SDimitry Andric       case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND";
5320b57cec5SDimitry Andric     }
5330b57cec5SDimitry Andric     return "Unrecognized arm64 addend";
5340b57cec5SDimitry Andric   }
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric };
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric #undef DEBUG_TYPE
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric #endif
542