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 
add16(uint8_t * p,int16_t v)35480093f4SDimitry Andric static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); }
or32le(void * P,int32_t V)36480093f4SDimitry Andric static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); }
37480093f4SDimitry Andric 
write32AArch64Imm(uint8_t * T,uint64_t imm,uint32_t rangeLimit)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 
write32AArch64Ldr(uint8_t * T,uint64_t imm)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 
write32AArch64Addr(void * T,uint64_t s,uint64_t p,int shift)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
getImageBase()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:
RuntimeDyldCOFFAArch64(RuntimeDyld::MemoryManager & MM,JITSymbolResolver & Resolver)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 
getStubAlignment()96bdd1243dSDimitry Andric   Align getStubAlignment() override { return Align(8); }
97480093f4SDimitry Andric 
getMaxStubSize()98480093f4SDimitry Andric   unsigned getMaxStubSize() const override { return 20; }
99480093f4SDimitry Andric 
100480093f4SDimitry Andric   std::tuple<uint64_t, uint64_t, uint64_t>
generateRelocationStub(unsigned SectionID,StringRef TargetName,uint64_t Offset,uint64_t RelType,uint64_t Addend,StubMap & Stubs)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>
processRelocationRef(unsigned SectionID,object::relocation_iterator RelI,const object::ObjectFile & Obj,ObjSectionToIDMap & ObjSectionToID,StubMap & Stubs)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 
resolveRelocation(const RelocationEntry & RE,uint64_t Value)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 
registerEHFrames()372480093f4SDimitry Andric   void registerEHFrames() override {}
373480093f4SDimitry Andric };
374480093f4SDimitry Andric 
375480093f4SDimitry Andric } // End namespace llvm
376480093f4SDimitry Andric 
377480093f4SDimitry Andric #endif
378