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