1480093f4SDimitry Andric //===-- RuntimeDyldCOFFAArch64.h --- COFF/AArch64 specific code ---*- C++ 2480093f4SDimitry Andric //-*-===// 3480093f4SDimitry Andric // 4480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7480093f4SDimitry Andric // 8480093f4SDimitry Andric //===----------------------------------------------------------------------===// 9480093f4SDimitry Andric // 10480093f4SDimitry Andric // COFF AArch64 support for MC-JIT runtime dynamic linker. 11480093f4SDimitry Andric // 12480093f4SDimitry Andric //===----------------------------------------------------------------------===// 13480093f4SDimitry Andric 14480093f4SDimitry Andric #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H 15480093f4SDimitry Andric #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H 16480093f4SDimitry Andric 17480093f4SDimitry Andric #include "../RuntimeDyldCOFF.h" 1806c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h" 19480093f4SDimitry Andric #include "llvm/BinaryFormat/COFF.h" 20480093f4SDimitry Andric #include "llvm/Object/COFF.h" 21480093f4SDimitry Andric #include "llvm/Support/Endian.h" 22480093f4SDimitry Andric 23480093f4SDimitry Andric #define DEBUG_TYPE "dyld" 24480093f4SDimitry Andric 25480093f4SDimitry Andric using namespace llvm::support::endian; 26480093f4SDimitry Andric 27480093f4SDimitry Andric namespace llvm { 28480093f4SDimitry Andric 29480093f4SDimitry Andric // This relocation type is used for handling long branch instruction 30*5f757f3fSDimitry Andric // through the Stub. 31480093f4SDimitry Andric enum InternalRelocationType : unsigned { 32480093f4SDimitry Andric INTERNAL_REL_ARM64_LONG_BRANCH26 = 0x111, 33480093f4SDimitry Andric }; 34480093f4SDimitry Andric 35480093f4SDimitry Andric static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); } 36480093f4SDimitry Andric static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); } 37480093f4SDimitry Andric 38480093f4SDimitry Andric static void write32AArch64Imm(uint8_t *T, uint64_t imm, uint32_t rangeLimit) { 39480093f4SDimitry Andric uint32_t orig = read32le(T); 40480093f4SDimitry Andric orig &= ~(0xFFF << 10); 41480093f4SDimitry Andric write32le(T, orig | ((imm & (0xFFF >> rangeLimit)) << 10)); 42480093f4SDimitry Andric } 43480093f4SDimitry Andric 44480093f4SDimitry Andric static void write32AArch64Ldr(uint8_t *T, uint64_t imm) { 45480093f4SDimitry Andric uint32_t orig = read32le(T); 46480093f4SDimitry Andric uint32_t size = orig >> 30; 47480093f4SDimitry Andric // 0x04000000 indicates SIMD/FP registers 48480093f4SDimitry Andric // 0x00800000 indicates 128 bit 49480093f4SDimitry Andric if ((orig & 0x04800000) == 0x04800000) 50480093f4SDimitry Andric size += 4; 51480093f4SDimitry Andric if ((imm & ((1 << size) - 1)) != 0) 52480093f4SDimitry Andric assert(0 && "misaligned ldr/str offset"); 53480093f4SDimitry Andric write32AArch64Imm(T, imm >> size, size); 54480093f4SDimitry Andric } 55480093f4SDimitry Andric 56480093f4SDimitry Andric static void write32AArch64Addr(void *T, uint64_t s, uint64_t p, int shift) { 57480093f4SDimitry Andric uint64_t Imm = (s >> shift) - (p >> shift); 58480093f4SDimitry Andric uint32_t ImmLo = (Imm & 0x3) << 29; 59480093f4SDimitry Andric uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; 60480093f4SDimitry Andric uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); 61480093f4SDimitry Andric write32le(T, (read32le(T) & ~Mask) | ImmLo | ImmHi); 62480093f4SDimitry Andric } 63480093f4SDimitry Andric 64480093f4SDimitry Andric class RuntimeDyldCOFFAArch64 : public RuntimeDyldCOFF { 65480093f4SDimitry Andric 66480093f4SDimitry Andric private: 67480093f4SDimitry Andric // When a module is loaded we save the SectionID of the unwind 68480093f4SDimitry Andric // sections in a table until we receive a request to register all 69480093f4SDimitry Andric // unregisteredEH frame sections with the memory manager. 70480093f4SDimitry Andric SmallVector<SID, 2> UnregisteredEHFrameSections; 71480093f4SDimitry Andric SmallVector<SID, 2> RegisteredEHFrameSections; 72480093f4SDimitry Andric uint64_t ImageBase; 73480093f4SDimitry Andric 74480093f4SDimitry Andric // Fake an __ImageBase pointer by returning the section with the lowest adress 75480093f4SDimitry Andric uint64_t getImageBase() { 76480093f4SDimitry Andric if (!ImageBase) { 77480093f4SDimitry Andric ImageBase = std::numeric_limits<uint64_t>::max(); 78480093f4SDimitry Andric for (const SectionEntry &Section : Sections) 79480093f4SDimitry Andric // The Sections list may contain sections that weren't loaded for 80480093f4SDimitry Andric // whatever reason: they may be debug sections, and ProcessAllSections 81480093f4SDimitry Andric // is false, or they may be sections that contain 0 bytes. If the 82480093f4SDimitry Andric // section isn't loaded, the load address will be 0, and it should not 83480093f4SDimitry Andric // be included in the ImageBase calculation. 84480093f4SDimitry Andric if (Section.getLoadAddress() != 0) 85480093f4SDimitry Andric ImageBase = std::min(ImageBase, Section.getLoadAddress()); 86480093f4SDimitry Andric } 87480093f4SDimitry Andric return ImageBase; 88480093f4SDimitry Andric } 89480093f4SDimitry Andric 90480093f4SDimitry Andric public: 91480093f4SDimitry Andric RuntimeDyldCOFFAArch64(RuntimeDyld::MemoryManager &MM, 92480093f4SDimitry Andric JITSymbolResolver &Resolver) 935ffd83dbSDimitry Andric : RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_ARM64_ADDR64), 945ffd83dbSDimitry Andric ImageBase(0) {} 95480093f4SDimitry Andric 96bdd1243dSDimitry Andric Align getStubAlignment() override { return Align(8); } 97480093f4SDimitry Andric 98480093f4SDimitry Andric unsigned getMaxStubSize() const override { return 20; } 99480093f4SDimitry Andric 100480093f4SDimitry Andric std::tuple<uint64_t, uint64_t, uint64_t> 101480093f4SDimitry Andric generateRelocationStub(unsigned SectionID, StringRef TargetName, 102480093f4SDimitry Andric uint64_t Offset, uint64_t RelType, uint64_t Addend, 103480093f4SDimitry Andric StubMap &Stubs) { 104480093f4SDimitry Andric uintptr_t StubOffset; 105480093f4SDimitry Andric SectionEntry &Section = Sections[SectionID]; 106480093f4SDimitry Andric 107480093f4SDimitry Andric RelocationValueRef OriginalRelValueRef; 108480093f4SDimitry Andric OriginalRelValueRef.SectionID = SectionID; 109480093f4SDimitry Andric OriginalRelValueRef.Offset = Offset; 110480093f4SDimitry Andric OriginalRelValueRef.Addend = Addend; 111480093f4SDimitry Andric OriginalRelValueRef.SymbolName = TargetName.data(); 112480093f4SDimitry Andric 113480093f4SDimitry Andric auto Stub = Stubs.find(OriginalRelValueRef); 114480093f4SDimitry Andric if (Stub == Stubs.end()) { 115480093f4SDimitry Andric LLVM_DEBUG(dbgs() << " Create a new stub function for " 116480093f4SDimitry Andric << TargetName.data() << "\n"); 117480093f4SDimitry Andric 118480093f4SDimitry Andric StubOffset = Section.getStubOffset(); 119480093f4SDimitry Andric Stubs[OriginalRelValueRef] = StubOffset; 120480093f4SDimitry Andric createStubFunction(Section.getAddressWithOffset(StubOffset)); 121480093f4SDimitry Andric Section.advanceStubOffset(getMaxStubSize()); 122480093f4SDimitry Andric } else { 123480093f4SDimitry Andric LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data() 124480093f4SDimitry Andric << "\n"); 125480093f4SDimitry Andric StubOffset = Stub->second; 126480093f4SDimitry Andric } 127480093f4SDimitry Andric 128480093f4SDimitry Andric // Resolve original relocation to stub function. 129480093f4SDimitry Andric const RelocationEntry RE(SectionID, Offset, RelType, Addend); 130480093f4SDimitry Andric resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset)); 131480093f4SDimitry Andric 132480093f4SDimitry Andric // adjust relocation info so resolution writes to the stub function 133480093f4SDimitry Andric // Here an internal relocation type is used for resolving long branch via 134480093f4SDimitry Andric // stub instruction. 135480093f4SDimitry Andric Addend = 0; 136480093f4SDimitry Andric Offset = StubOffset; 137480093f4SDimitry Andric RelType = INTERNAL_REL_ARM64_LONG_BRANCH26; 138480093f4SDimitry Andric 139480093f4SDimitry Andric return std::make_tuple(Offset, RelType, Addend); 140480093f4SDimitry Andric } 141480093f4SDimitry Andric 142480093f4SDimitry Andric Expected<object::relocation_iterator> 143480093f4SDimitry Andric processRelocationRef(unsigned SectionID, object::relocation_iterator RelI, 144480093f4SDimitry Andric const object::ObjectFile &Obj, 145480093f4SDimitry Andric ObjSectionToIDMap &ObjSectionToID, 146480093f4SDimitry Andric StubMap &Stubs) override { 147480093f4SDimitry Andric 148480093f4SDimitry Andric auto Symbol = RelI->getSymbol(); 149480093f4SDimitry Andric if (Symbol == Obj.symbol_end()) 150480093f4SDimitry Andric report_fatal_error("Unknown symbol in relocation"); 151480093f4SDimitry Andric 152480093f4SDimitry Andric Expected<StringRef> TargetNameOrErr = Symbol->getName(); 153480093f4SDimitry Andric if (!TargetNameOrErr) 154480093f4SDimitry Andric return TargetNameOrErr.takeError(); 155480093f4SDimitry Andric StringRef TargetName = *TargetNameOrErr; 156480093f4SDimitry Andric 157480093f4SDimitry Andric auto SectionOrErr = Symbol->getSection(); 158480093f4SDimitry Andric if (!SectionOrErr) 159480093f4SDimitry Andric return SectionOrErr.takeError(); 160480093f4SDimitry Andric auto Section = *SectionOrErr; 161480093f4SDimitry Andric 162480093f4SDimitry Andric uint64_t RelType = RelI->getType(); 163480093f4SDimitry Andric uint64_t Offset = RelI->getOffset(); 164480093f4SDimitry Andric 165480093f4SDimitry Andric // If there is no section, this must be an external reference. 1665ffd83dbSDimitry Andric bool IsExtern = Section == Obj.section_end(); 167480093f4SDimitry Andric 168480093f4SDimitry Andric // Determine the Addend used to adjust the relocation value. 169480093f4SDimitry Andric uint64_t Addend = 0; 170480093f4SDimitry Andric SectionEntry &AddendSection = Sections[SectionID]; 171480093f4SDimitry Andric uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; 172480093f4SDimitry Andric uint8_t *Displacement = (uint8_t *)ObjTarget; 173480093f4SDimitry Andric 1745ffd83dbSDimitry Andric unsigned TargetSectionID = -1; 1755ffd83dbSDimitry Andric uint64_t TargetOffset = -1; 1765ffd83dbSDimitry Andric 177*5f757f3fSDimitry Andric if (TargetName.starts_with(getImportSymbolPrefix())) { 1785ffd83dbSDimitry Andric TargetSectionID = SectionID; 1795ffd83dbSDimitry Andric TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName); 1805ffd83dbSDimitry Andric TargetName = StringRef(); 1815ffd83dbSDimitry Andric IsExtern = false; 1825ffd83dbSDimitry Andric } else if (!IsExtern) { 1835ffd83dbSDimitry Andric if (auto TargetSectionIDOrErr = findOrEmitSection( 1845ffd83dbSDimitry Andric Obj, *Section, Section->isText(), ObjSectionToID)) 1855ffd83dbSDimitry Andric TargetSectionID = *TargetSectionIDOrErr; 1865ffd83dbSDimitry Andric else 1875ffd83dbSDimitry Andric return TargetSectionIDOrErr.takeError(); 1885ffd83dbSDimitry Andric 1895ffd83dbSDimitry Andric TargetOffset = getSymbolOffset(*Symbol); 1905ffd83dbSDimitry Andric } 1915ffd83dbSDimitry Andric 192480093f4SDimitry Andric switch (RelType) { 193480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_ADDR32: 194480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_ADDR32NB: 195480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_REL32: 196480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_SECREL: 197480093f4SDimitry Andric Addend = read32le(Displacement); 198480093f4SDimitry Andric break; 199480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_BRANCH26: { 200480093f4SDimitry Andric uint32_t orig = read32le(Displacement); 201480093f4SDimitry Andric Addend = (orig & 0x03FFFFFF) << 2; 202480093f4SDimitry Andric 203480093f4SDimitry Andric if (IsExtern) 204480093f4SDimitry Andric std::tie(Offset, RelType, Addend) = generateRelocationStub( 205480093f4SDimitry Andric SectionID, TargetName, Offset, RelType, Addend, Stubs); 206480093f4SDimitry Andric break; 207480093f4SDimitry Andric } 208480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_BRANCH19: { 209480093f4SDimitry Andric uint32_t orig = read32le(Displacement); 210480093f4SDimitry Andric Addend = (orig & 0x00FFFFE0) >> 3; 211480093f4SDimitry Andric break; 212480093f4SDimitry Andric } 213480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_BRANCH14: { 214480093f4SDimitry Andric uint32_t orig = read32le(Displacement); 215480093f4SDimitry Andric Addend = (orig & 0x000FFFE0) >> 3; 216480093f4SDimitry Andric break; 217480093f4SDimitry Andric } 218480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_REL21: 219480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: { 220480093f4SDimitry Andric uint32_t orig = read32le(Displacement); 221480093f4SDimitry Andric Addend = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC); 222480093f4SDimitry Andric break; 223480093f4SDimitry Andric } 224480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L: 225480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: { 226480093f4SDimitry Andric uint32_t orig = read32le(Displacement); 227480093f4SDimitry Andric Addend = ((orig >> 10) & 0xFFF); 228480093f4SDimitry Andric break; 229480093f4SDimitry Andric } 230480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_ADDR64: { 231480093f4SDimitry Andric Addend = read64le(Displacement); 232480093f4SDimitry Andric break; 233480093f4SDimitry Andric } 234480093f4SDimitry Andric default: 235480093f4SDimitry Andric break; 236480093f4SDimitry Andric } 237480093f4SDimitry Andric 238480093f4SDimitry Andric #if !defined(NDEBUG) 239480093f4SDimitry Andric SmallString<32> RelTypeName; 240480093f4SDimitry Andric RelI->getTypeName(RelTypeName); 241480093f4SDimitry Andric 242480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset 243480093f4SDimitry Andric << " RelType: " << RelTypeName << " TargetName: " 244480093f4SDimitry Andric << TargetName << " Addend " << Addend << "\n"); 245480093f4SDimitry Andric #endif 246480093f4SDimitry Andric 247480093f4SDimitry Andric if (IsExtern) { 248480093f4SDimitry Andric RelocationEntry RE(SectionID, Offset, RelType, Addend); 249480093f4SDimitry Andric addRelocationForSymbol(RE, TargetName); 250480093f4SDimitry Andric } else { 251480093f4SDimitry Andric RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend); 252480093f4SDimitry Andric addRelocationForSection(RE, TargetSectionID); 253480093f4SDimitry Andric } 254480093f4SDimitry Andric return ++RelI; 255480093f4SDimitry Andric } 256480093f4SDimitry Andric 257480093f4SDimitry Andric void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { 258480093f4SDimitry Andric const auto Section = Sections[RE.SectionID]; 259480093f4SDimitry Andric uint8_t *Target = Section.getAddressWithOffset(RE.Offset); 260480093f4SDimitry Andric uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); 261480093f4SDimitry Andric 262480093f4SDimitry Andric switch (RE.RelType) { 263480093f4SDimitry Andric default: 264480093f4SDimitry Andric llvm_unreachable("unsupported relocation type"); 265480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_ABSOLUTE: { 266480093f4SDimitry Andric // This relocation is ignored. 267480093f4SDimitry Andric break; 268480093f4SDimitry Andric } 269480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: { 270480093f4SDimitry Andric // The page base of the target, for ADRP instruction. 271480093f4SDimitry Andric Value += RE.Addend; 272480093f4SDimitry Andric write32AArch64Addr(Target, Value, FinalAddress, 12); 273480093f4SDimitry Andric break; 274480093f4SDimitry Andric } 275480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_REL21: { 276480093f4SDimitry Andric // The 12-bit relative displacement to the target, for instruction ADR 277480093f4SDimitry Andric Value += RE.Addend; 278480093f4SDimitry Andric write32AArch64Addr(Target, Value, FinalAddress, 0); 279480093f4SDimitry Andric break; 280480093f4SDimitry Andric } 281480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: { 282480093f4SDimitry Andric // The 12-bit page offset of the target, 283480093f4SDimitry Andric // for instructions ADD/ADDS (immediate) with zero shift. 284480093f4SDimitry Andric Value += RE.Addend; 285480093f4SDimitry Andric write32AArch64Imm(Target, Value & 0xFFF, 0); 286480093f4SDimitry Andric break; 287480093f4SDimitry Andric } 288480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L: { 289480093f4SDimitry Andric // The 12-bit page offset of the target, 290480093f4SDimitry Andric // for instruction LDR (indexed, unsigned immediate). 291480093f4SDimitry Andric Value += RE.Addend; 292480093f4SDimitry Andric write32AArch64Ldr(Target, Value & 0xFFF); 293480093f4SDimitry Andric break; 294480093f4SDimitry Andric } 295480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_ADDR32: { 296480093f4SDimitry Andric // The 32-bit VA of the target. 297480093f4SDimitry Andric uint32_t VA = Value + RE.Addend; 298480093f4SDimitry Andric write32le(Target, VA); 299480093f4SDimitry Andric break; 300480093f4SDimitry Andric } 301480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_ADDR32NB: { 302480093f4SDimitry Andric // The target's 32-bit RVA. 303480093f4SDimitry Andric uint64_t RVA = Value + RE.Addend - getImageBase(); 304480093f4SDimitry Andric write32le(Target, RVA); 305480093f4SDimitry Andric break; 306480093f4SDimitry Andric } 307480093f4SDimitry Andric case INTERNAL_REL_ARM64_LONG_BRANCH26: { 308480093f4SDimitry Andric // Encode the immadiate value for generated Stub instruction (MOVZ) 309480093f4SDimitry Andric or32le(Target + 12, ((Value + RE.Addend) & 0xFFFF) << 5); 310480093f4SDimitry Andric or32le(Target + 8, ((Value + RE.Addend) & 0xFFFF0000) >> 11); 311480093f4SDimitry Andric or32le(Target + 4, ((Value + RE.Addend) & 0xFFFF00000000) >> 27); 312480093f4SDimitry Andric or32le(Target + 0, ((Value + RE.Addend) & 0xFFFF000000000000) >> 43); 313480093f4SDimitry Andric break; 314480093f4SDimitry Andric } 315480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_BRANCH26: { 316480093f4SDimitry Andric // The 26-bit relative displacement to the target, for B and BL 317480093f4SDimitry Andric // instructions. 318480093f4SDimitry Andric uint64_t PCRelVal = Value + RE.Addend - FinalAddress; 319480093f4SDimitry Andric assert(isInt<28>(PCRelVal) && "Branch target is out of range."); 320480093f4SDimitry Andric write32le(Target, (read32le(Target) & ~(0x03FFFFFF)) | 321480093f4SDimitry Andric (PCRelVal & 0x0FFFFFFC) >> 2); 322480093f4SDimitry Andric break; 323480093f4SDimitry Andric } 324480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_BRANCH19: { 325480093f4SDimitry Andric // The 19-bit offset to the relocation target, 326480093f4SDimitry Andric // for conditional B instruction. 327480093f4SDimitry Andric uint64_t PCRelVal = Value + RE.Addend - FinalAddress; 328480093f4SDimitry Andric assert(isInt<21>(PCRelVal) && "Branch target is out of range."); 329480093f4SDimitry Andric write32le(Target, (read32le(Target) & ~(0x00FFFFE0)) | 330480093f4SDimitry Andric (PCRelVal & 0x001FFFFC) << 3); 331480093f4SDimitry Andric break; 332480093f4SDimitry Andric } 333480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_BRANCH14: { 334480093f4SDimitry Andric // The 14-bit offset to the relocation target, 335480093f4SDimitry Andric // for instructions TBZ and TBNZ. 336480093f4SDimitry Andric uint64_t PCRelVal = Value + RE.Addend - FinalAddress; 337480093f4SDimitry Andric assert(isInt<16>(PCRelVal) && "Branch target is out of range."); 338480093f4SDimitry Andric write32le(Target, (read32le(Target) & ~(0x000FFFE0)) | 339480093f4SDimitry Andric (PCRelVal & 0x0000FFFC) << 3); 340480093f4SDimitry Andric break; 341480093f4SDimitry Andric } 342480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_ADDR64: { 343480093f4SDimitry Andric // The 64-bit VA of the relocation target. 344480093f4SDimitry Andric write64le(Target, Value + RE.Addend); 345480093f4SDimitry Andric break; 346480093f4SDimitry Andric } 347480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_SECTION: { 348480093f4SDimitry Andric // 16-bit section index of the section that contains the target. 349480093f4SDimitry Andric assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && 350480093f4SDimitry Andric "relocation overflow"); 351480093f4SDimitry Andric add16(Target, RE.SectionID); 352480093f4SDimitry Andric break; 353480093f4SDimitry Andric } 354480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_SECREL: { 355480093f4SDimitry Andric // 32-bit offset of the target from the beginning of its section. 356480093f4SDimitry Andric assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && 357480093f4SDimitry Andric "Relocation overflow"); 358480093f4SDimitry Andric assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && 359480093f4SDimitry Andric "Relocation underflow"); 360480093f4SDimitry Andric write32le(Target, RE.Addend); 361480093f4SDimitry Andric break; 362480093f4SDimitry Andric } 363480093f4SDimitry Andric case COFF::IMAGE_REL_ARM64_REL32: { 364480093f4SDimitry Andric // The 32-bit relative address from the byte following the relocation. 365480093f4SDimitry Andric uint64_t Result = Value - FinalAddress - 4; 366480093f4SDimitry Andric write32le(Target, Result + RE.Addend); 367480093f4SDimitry Andric break; 368480093f4SDimitry Andric } 369480093f4SDimitry Andric } 370480093f4SDimitry Andric } 371480093f4SDimitry Andric 372480093f4SDimitry Andric void registerEHFrames() override {} 373480093f4SDimitry Andric }; 374480093f4SDimitry Andric 375480093f4SDimitry Andric } // End namespace llvm 376480093f4SDimitry Andric 377480093f4SDimitry Andric #endif 378