[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / ExecutionEngine / RuntimeDyld / Targets / RuntimeDyldCOFFAArch64.h
blob14510e56b35a70d56d247b2ecdc94b5f4a42b4cd
1 //===-- RuntimeDyldCOFFAArch64.h --- COFF/AArch64 specific code ---*- C++
2 //-*-===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // COFF AArch64 support for MC-JIT runtime dynamic linker.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H
15 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H
17 #include "../RuntimeDyldCOFF.h"
18 #include "llvm/BinaryFormat/COFF.h"
19 #include "llvm/Object/COFF.h"
20 #include "llvm/Support/Endian.h"
22 #define DEBUG_TYPE "dyld"
24 using namespace llvm::support::endian;
26 namespace llvm {
28 // This relocation type is used for handling long branch instruction
29 // throught the Stub.
30 enum InternalRelocationType : unsigned {
31 INTERNAL_REL_ARM64_LONG_BRANCH26 = 0x111,
34 static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); }
35 static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); }
37 static void write32AArch64Imm(uint8_t *T, uint64_t imm, uint32_t rangeLimit) {
38 uint32_t orig = read32le(T);
39 orig &= ~(0xFFF << 10);
40 write32le(T, orig | ((imm & (0xFFF >> rangeLimit)) << 10));
43 static void write32AArch64Ldr(uint8_t *T, uint64_t imm) {
44 uint32_t orig = read32le(T);
45 uint32_t size = orig >> 30;
46 // 0x04000000 indicates SIMD/FP registers
47 // 0x00800000 indicates 128 bit
48 if ((orig & 0x04800000) == 0x04800000)
49 size += 4;
50 if ((imm & ((1 << size) - 1)) != 0)
51 assert(0 && "misaligned ldr/str offset");
52 write32AArch64Imm(T, imm >> size, size);
55 static void write32AArch64Addr(void *T, uint64_t s, uint64_t p, int shift) {
56 uint64_t Imm = (s >> shift) - (p >> shift);
57 uint32_t ImmLo = (Imm & 0x3) << 29;
58 uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
59 uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
60 write32le(T, (read32le(T) & ~Mask) | ImmLo | ImmHi);
63 class RuntimeDyldCOFFAArch64 : public RuntimeDyldCOFF {
65 private:
66 // When a module is loaded we save the SectionID of the unwind
67 // sections in a table until we receive a request to register all
68 // unregisteredEH frame sections with the memory manager.
69 SmallVector<SID, 2> UnregisteredEHFrameSections;
70 SmallVector<SID, 2> RegisteredEHFrameSections;
71 uint64_t ImageBase;
73 // Fake an __ImageBase pointer by returning the section with the lowest adress
74 uint64_t getImageBase() {
75 if (!ImageBase) {
76 ImageBase = std::numeric_limits<uint64_t>::max();
77 for (const SectionEntry &Section : Sections)
78 // The Sections list may contain sections that weren't loaded for
79 // whatever reason: they may be debug sections, and ProcessAllSections
80 // is false, or they may be sections that contain 0 bytes. If the
81 // section isn't loaded, the load address will be 0, and it should not
82 // be included in the ImageBase calculation.
83 if (Section.getLoadAddress() != 0)
84 ImageBase = std::min(ImageBase, Section.getLoadAddress());
86 return ImageBase;
89 public:
90 RuntimeDyldCOFFAArch64(RuntimeDyld::MemoryManager &MM,
91 JITSymbolResolver &Resolver)
92 : RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_ARM64_ADDR64),
93 ImageBase(0) {}
95 unsigned getStubAlignment() override { return 8; }
97 unsigned getMaxStubSize() const override { return 20; }
99 std::tuple<uint64_t, uint64_t, uint64_t>
100 generateRelocationStub(unsigned SectionID, StringRef TargetName,
101 uint64_t Offset, uint64_t RelType, uint64_t Addend,
102 StubMap &Stubs) {
103 uintptr_t StubOffset;
104 SectionEntry &Section = Sections[SectionID];
106 RelocationValueRef OriginalRelValueRef;
107 OriginalRelValueRef.SectionID = SectionID;
108 OriginalRelValueRef.Offset = Offset;
109 OriginalRelValueRef.Addend = Addend;
110 OriginalRelValueRef.SymbolName = TargetName.data();
112 auto Stub = Stubs.find(OriginalRelValueRef);
113 if (Stub == Stubs.end()) {
114 LLVM_DEBUG(dbgs() << " Create a new stub function for "
115 << TargetName.data() << "\n");
117 StubOffset = Section.getStubOffset();
118 Stubs[OriginalRelValueRef] = StubOffset;
119 createStubFunction(Section.getAddressWithOffset(StubOffset));
120 Section.advanceStubOffset(getMaxStubSize());
121 } else {
122 LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data()
123 << "\n");
124 StubOffset = Stub->second;
127 // Resolve original relocation to stub function.
128 const RelocationEntry RE(SectionID, Offset, RelType, Addend);
129 resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset));
131 // adjust relocation info so resolution writes to the stub function
132 // Here an internal relocation type is used for resolving long branch via
133 // stub instruction.
134 Addend = 0;
135 Offset = StubOffset;
136 RelType = INTERNAL_REL_ARM64_LONG_BRANCH26;
138 return std::make_tuple(Offset, RelType, Addend);
141 Expected<object::relocation_iterator>
142 processRelocationRef(unsigned SectionID, object::relocation_iterator RelI,
143 const object::ObjectFile &Obj,
144 ObjSectionToIDMap &ObjSectionToID,
145 StubMap &Stubs) override {
147 auto Symbol = RelI->getSymbol();
148 if (Symbol == Obj.symbol_end())
149 report_fatal_error("Unknown symbol in relocation");
151 Expected<StringRef> TargetNameOrErr = Symbol->getName();
152 if (!TargetNameOrErr)
153 return TargetNameOrErr.takeError();
154 StringRef TargetName = *TargetNameOrErr;
156 auto SectionOrErr = Symbol->getSection();
157 if (!SectionOrErr)
158 return SectionOrErr.takeError();
159 auto Section = *SectionOrErr;
161 uint64_t RelType = RelI->getType();
162 uint64_t Offset = RelI->getOffset();
164 // If there is no section, this must be an external reference.
165 bool IsExtern = Section == Obj.section_end();
167 // Determine the Addend used to adjust the relocation value.
168 uint64_t Addend = 0;
169 SectionEntry &AddendSection = Sections[SectionID];
170 uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
171 uint8_t *Displacement = (uint8_t *)ObjTarget;
173 unsigned TargetSectionID = -1;
174 uint64_t TargetOffset = -1;
176 if (TargetName.startswith(getImportSymbolPrefix())) {
177 TargetSectionID = SectionID;
178 TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName);
179 TargetName = StringRef();
180 IsExtern = false;
181 } else if (!IsExtern) {
182 if (auto TargetSectionIDOrErr = findOrEmitSection(
183 Obj, *Section, Section->isText(), ObjSectionToID))
184 TargetSectionID = *TargetSectionIDOrErr;
185 else
186 return TargetSectionIDOrErr.takeError();
188 TargetOffset = getSymbolOffset(*Symbol);
191 switch (RelType) {
192 case COFF::IMAGE_REL_ARM64_ADDR32:
193 case COFF::IMAGE_REL_ARM64_ADDR32NB:
194 case COFF::IMAGE_REL_ARM64_REL32:
195 case COFF::IMAGE_REL_ARM64_SECREL:
196 Addend = read32le(Displacement);
197 break;
198 case COFF::IMAGE_REL_ARM64_BRANCH26: {
199 uint32_t orig = read32le(Displacement);
200 Addend = (orig & 0x03FFFFFF) << 2;
202 if (IsExtern)
203 std::tie(Offset, RelType, Addend) = generateRelocationStub(
204 SectionID, TargetName, Offset, RelType, Addend, Stubs);
205 break;
207 case COFF::IMAGE_REL_ARM64_BRANCH19: {
208 uint32_t orig = read32le(Displacement);
209 Addend = (orig & 0x00FFFFE0) >> 3;
210 break;
212 case COFF::IMAGE_REL_ARM64_BRANCH14: {
213 uint32_t orig = read32le(Displacement);
214 Addend = (orig & 0x000FFFE0) >> 3;
215 break;
217 case COFF::IMAGE_REL_ARM64_REL21:
218 case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: {
219 uint32_t orig = read32le(Displacement);
220 Addend = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC);
221 break;
223 case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L:
224 case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: {
225 uint32_t orig = read32le(Displacement);
226 Addend = ((orig >> 10) & 0xFFF);
227 break;
229 case COFF::IMAGE_REL_ARM64_ADDR64: {
230 Addend = read64le(Displacement);
231 break;
233 default:
234 break;
237 #if !defined(NDEBUG)
238 SmallString<32> RelTypeName;
239 RelI->getTypeName(RelTypeName);
241 LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
242 << " RelType: " << RelTypeName << " TargetName: "
243 << TargetName << " Addend " << Addend << "\n");
244 #endif
246 if (IsExtern) {
247 RelocationEntry RE(SectionID, Offset, RelType, Addend);
248 addRelocationForSymbol(RE, TargetName);
249 } else {
250 RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
251 addRelocationForSection(RE, TargetSectionID);
253 return ++RelI;
256 void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
257 const auto Section = Sections[RE.SectionID];
258 uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
259 uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
261 switch (RE.RelType) {
262 default:
263 llvm_unreachable("unsupported relocation type");
264 case COFF::IMAGE_REL_ARM64_ABSOLUTE: {
265 // This relocation is ignored.
266 break;
268 case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: {
269 // The page base of the target, for ADRP instruction.
270 Value += RE.Addend;
271 write32AArch64Addr(Target, Value, FinalAddress, 12);
272 break;
274 case COFF::IMAGE_REL_ARM64_REL21: {
275 // The 12-bit relative displacement to the target, for instruction ADR
276 Value += RE.Addend;
277 write32AArch64Addr(Target, Value, FinalAddress, 0);
278 break;
280 case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: {
281 // The 12-bit page offset of the target,
282 // for instructions ADD/ADDS (immediate) with zero shift.
283 Value += RE.Addend;
284 write32AArch64Imm(Target, Value & 0xFFF, 0);
285 break;
287 case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L: {
288 // The 12-bit page offset of the target,
289 // for instruction LDR (indexed, unsigned immediate).
290 Value += RE.Addend;
291 write32AArch64Ldr(Target, Value & 0xFFF);
292 break;
294 case COFF::IMAGE_REL_ARM64_ADDR32: {
295 // The 32-bit VA of the target.
296 uint32_t VA = Value + RE.Addend;
297 write32le(Target, VA);
298 break;
300 case COFF::IMAGE_REL_ARM64_ADDR32NB: {
301 // The target's 32-bit RVA.
302 uint64_t RVA = Value + RE.Addend - getImageBase();
303 write32le(Target, RVA);
304 break;
306 case INTERNAL_REL_ARM64_LONG_BRANCH26: {
307 // Encode the immadiate value for generated Stub instruction (MOVZ)
308 or32le(Target + 12, ((Value + RE.Addend) & 0xFFFF) << 5);
309 or32le(Target + 8, ((Value + RE.Addend) & 0xFFFF0000) >> 11);
310 or32le(Target + 4, ((Value + RE.Addend) & 0xFFFF00000000) >> 27);
311 or32le(Target + 0, ((Value + RE.Addend) & 0xFFFF000000000000) >> 43);
312 break;
314 case COFF::IMAGE_REL_ARM64_BRANCH26: {
315 // The 26-bit relative displacement to the target, for B and BL
316 // instructions.
317 uint64_t PCRelVal = Value + RE.Addend - FinalAddress;
318 assert(isInt<28>(PCRelVal) && "Branch target is out of range.");
319 write32le(Target, (read32le(Target) & ~(0x03FFFFFF)) |
320 (PCRelVal & 0x0FFFFFFC) >> 2);
321 break;
323 case COFF::IMAGE_REL_ARM64_BRANCH19: {
324 // The 19-bit offset to the relocation target,
325 // for conditional B instruction.
326 uint64_t PCRelVal = Value + RE.Addend - FinalAddress;
327 assert(isInt<21>(PCRelVal) && "Branch target is out of range.");
328 write32le(Target, (read32le(Target) & ~(0x00FFFFE0)) |
329 (PCRelVal & 0x001FFFFC) << 3);
330 break;
332 case COFF::IMAGE_REL_ARM64_BRANCH14: {
333 // The 14-bit offset to the relocation target,
334 // for instructions TBZ and TBNZ.
335 uint64_t PCRelVal = Value + RE.Addend - FinalAddress;
336 assert(isInt<16>(PCRelVal) && "Branch target is out of range.");
337 write32le(Target, (read32le(Target) & ~(0x000FFFE0)) |
338 (PCRelVal & 0x0000FFFC) << 3);
339 break;
341 case COFF::IMAGE_REL_ARM64_ADDR64: {
342 // The 64-bit VA of the relocation target.
343 write64le(Target, Value + RE.Addend);
344 break;
346 case COFF::IMAGE_REL_ARM64_SECTION: {
347 // 16-bit section index of the section that contains the target.
348 assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
349 "relocation overflow");
350 add16(Target, RE.SectionID);
351 break;
353 case COFF::IMAGE_REL_ARM64_SECREL: {
354 // 32-bit offset of the target from the beginning of its section.
355 assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
356 "Relocation overflow");
357 assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
358 "Relocation underflow");
359 write32le(Target, RE.Addend);
360 break;
362 case COFF::IMAGE_REL_ARM64_REL32: {
363 // The 32-bit relative address from the byte following the relocation.
364 uint64_t Result = Value - FinalAddress - 4;
365 write32le(Target, Result + RE.Addend);
366 break;
371 void registerEHFrames() override {}
374 } // End namespace llvm
376 #endif