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