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