1 //===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
11 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
13 #include "../RuntimeDyldMachO.h"
14 #include "llvm/Support/Endian.h"
16 #define DEBUG_TYPE "dyld"
20 class RuntimeDyldMachOAArch64
21 : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> {
24 typedef uint64_t TargetPtrT;
26 RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager &MM,
27 JITSymbolResolver &Resolver)
28 : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
30 unsigned getMaxStubSize() override { return 8; }
32 unsigned getStubAlignment() override { return 8; }
34 /// Extract the addend encoded in the instruction / memory location.
35 Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
36 const SectionEntry &Section = Sections[RE.SectionID];
37 uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
38 unsigned NumBytes = 1 << RE.Size;
40 // Verify that the relocation has the correct size and alignment.
45 raw_string_ostream ErrStream(ErrMsg);
46 ErrStream << "Unsupported relocation type: "
47 << getRelocName(RE.RelType);
49 return make_error<StringError>(std::move(ErrMsg),
50 inconvertibleErrorCode());
52 case MachO::ARM64_RELOC_POINTER_TO_GOT:
53 case MachO::ARM64_RELOC_UNSIGNED: {
54 if (NumBytes != 4 && NumBytes != 8) {
57 raw_string_ostream ErrStream(ErrMsg);
58 ErrStream << "Invalid relocation size for relocation "
59 << getRelocName(RE.RelType);
61 return make_error<StringError>(std::move(ErrMsg),
62 inconvertibleErrorCode());
66 case MachO::ARM64_RELOC_BRANCH26:
67 case MachO::ARM64_RELOC_PAGE21:
68 case MachO::ARM64_RELOC_PAGEOFF12:
69 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
70 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
71 assert(NumBytes == 4 && "Invalid relocation size.");
72 assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
73 "Instruction address is not aligned to 4 bytes.");
79 llvm_unreachable("Unsupported relocation type!");
80 case MachO::ARM64_RELOC_POINTER_TO_GOT:
81 case MachO::ARM64_RELOC_UNSIGNED:
82 // This could be an unaligned memory location.
84 Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress);
86 Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress);
88 case MachO::ARM64_RELOC_BRANCH26: {
89 // Verify that the relocation points to a B/BL instruction.
90 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
91 assert(((*p & 0xFC000000) == 0x14000000 ||
92 (*p & 0xFC000000) == 0x94000000) &&
93 "Expected branch instruction.");
95 // Get the 26 bit addend encoded in the branch instruction and sign-extend
96 // to 64 bit. The lower 2 bits are always zeros and are therefore implicit
98 Addend = (*p & 0x03FFFFFF) << 2;
99 Addend = SignExtend64(Addend, 28);
102 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
103 case MachO::ARM64_RELOC_PAGE21: {
104 // Verify that the relocation points to the expected adrp instruction.
105 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
106 assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
108 // Get the 21 bit addend encoded in the adrp instruction and sign-extend
109 // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are
110 // therefore implicit (<< 12).
111 Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12;
112 Addend = SignExtend64(Addend, 33);
115 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
116 // Verify that the relocation points to one of the expected load / store
118 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
120 assert((*p & 0x3B000000) == 0x39000000 &&
121 "Only expected load / store instructions.");
124 case MachO::ARM64_RELOC_PAGEOFF12: {
125 // Verify that the relocation points to one of the expected load / store
126 // or add / sub instructions.
127 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
128 assert((((*p & 0x3B000000) == 0x39000000) ||
129 ((*p & 0x11C00000) == 0x11000000) ) &&
130 "Expected load / store or add/sub instruction.");
132 // Get the 12 bit addend encoded in the instruction.
133 Addend = (*p & 0x003FFC00) >> 10;
135 // Check which instruction we are decoding to obtain the implicit shift
136 // factor of the instruction.
137 int ImplicitShift = 0;
138 if ((*p & 0x3B000000) == 0x39000000) { // << load / store
139 // For load / store instructions the size is encoded in bits 31:30.
140 ImplicitShift = ((*p >> 30) & 0x3);
141 if (ImplicitShift == 0) {
142 // Check if this a vector op to get the correct shift value.
143 if ((*p & 0x04800000) == 0x04800000)
147 // Compensate for implicit shift.
148 Addend <<= ImplicitShift;
155 /// Extract the addend encoded in the instruction.
156 void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes,
157 MachO::RelocationInfoType RelType, int64_t Addend) const {
158 // Verify that the relocation has the correct alignment.
161 llvm_unreachable("Unsupported relocation type!");
162 case MachO::ARM64_RELOC_POINTER_TO_GOT:
163 case MachO::ARM64_RELOC_UNSIGNED:
164 assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
166 case MachO::ARM64_RELOC_BRANCH26:
167 case MachO::ARM64_RELOC_PAGE21:
168 case MachO::ARM64_RELOC_PAGEOFF12:
169 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
170 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
171 assert(NumBytes == 4 && "Invalid relocation size.");
172 assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
173 "Instruction address is not aligned to 4 bytes.");
179 llvm_unreachable("Unsupported relocation type!");
180 case MachO::ARM64_RELOC_POINTER_TO_GOT:
181 case MachO::ARM64_RELOC_UNSIGNED:
182 // This could be an unaligned memory location.
184 *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend;
186 *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend;
188 case MachO::ARM64_RELOC_BRANCH26: {
189 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
190 // Verify that the relocation points to the expected branch instruction.
191 assert(((*p & 0xFC000000) == 0x14000000 ||
192 (*p & 0xFC000000) == 0x94000000) &&
193 "Expected branch instruction.");
195 // Verify addend value.
196 assert((Addend & 0x3) == 0 && "Branch target is not aligned");
197 assert(isInt<28>(Addend) && "Branch target is out of range.");
199 // Encode the addend as 26 bit immediate in the branch instruction.
200 *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
203 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
204 case MachO::ARM64_RELOC_PAGE21: {
205 // Verify that the relocation points to the expected adrp instruction.
206 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
207 assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
209 // Check that the addend fits into 21 bits (+ 12 lower bits).
210 assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
211 assert(isInt<33>(Addend) && "Invalid page reloc value.");
213 // Encode the addend into the instruction.
214 uint32_t ImmLoValue = ((uint64_t)Addend << 17) & 0x60000000;
215 uint32_t ImmHiValue = ((uint64_t)Addend >> 9) & 0x00FFFFE0;
216 *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
219 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
220 // Verify that the relocation points to one of the expected load / store
222 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
223 assert((*p & 0x3B000000) == 0x39000000 &&
224 "Only expected load / store instructions.");
228 case MachO::ARM64_RELOC_PAGEOFF12: {
229 // Verify that the relocation points to one of the expected load / store
230 // or add / sub instructions.
231 auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
232 assert((((*p & 0x3B000000) == 0x39000000) ||
233 ((*p & 0x11C00000) == 0x11000000) ) &&
234 "Expected load / store or add/sub instruction.");
236 // Check which instruction we are decoding to obtain the implicit shift
237 // factor of the instruction and verify alignment.
238 int ImplicitShift = 0;
239 if ((*p & 0x3B000000) == 0x39000000) { // << load / store
240 // For load / store instructions the size is encoded in bits 31:30.
241 ImplicitShift = ((*p >> 30) & 0x3);
242 switch (ImplicitShift) {
244 // Check if this a vector op to get the correct shift value.
245 if ((*p & 0x04800000) == 0x04800000) {
247 assert(((Addend & 0xF) == 0) &&
248 "128-bit LDR/STR not 16-byte aligned.");
252 assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
255 assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
258 assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
262 // Compensate for implicit shift.
263 Addend >>= ImplicitShift;
264 assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
266 // Encode the addend into the instruction.
267 *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
273 Expected<relocation_iterator>
274 processRelocationRef(unsigned SectionID, relocation_iterator RelI,
275 const ObjectFile &BaseObjT,
276 ObjSectionToIDMap &ObjSectionToID,
277 StubMap &Stubs) override {
278 const MachOObjectFile &Obj =
279 static_cast<const MachOObjectFile &>(BaseObjT);
280 MachO::any_relocation_info RelInfo =
281 Obj.getRelocation(RelI->getRawDataRefImpl());
283 if (Obj.isRelocationScattered(RelInfo))
284 return make_error<RuntimeDyldError>("Scattered relocations not supported "
285 "for MachO AArch64");
287 // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit
288 // addend for the following relocation. If found: (1) store the associated
289 // addend, (2) consume the next relocation, and (3) use the stored addend to
290 // override the addend.
291 int64_t ExplicitAddend = 0;
292 if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) {
293 assert(!Obj.getPlainRelocationExternal(RelInfo));
294 assert(!Obj.getAnyRelocationPCRel(RelInfo));
295 assert(Obj.getAnyRelocationLength(RelInfo) == 2);
296 int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo);
297 // Sign-extend the 24-bit to 64-bit.
298 ExplicitAddend = SignExtend64(RawAddend, 24);
300 RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
303 if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_SUBTRACTOR)
304 return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID);
306 RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
308 if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
310 (RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel);
312 return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports "
313 "32-bit pc-rel or 64-bit absolute only",
314 inconvertibleErrorCode());
317 if (auto Addend = decodeAddend(RE))
320 return Addend.takeError();
322 assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\
323 "ARM64_RELOC_ADDEND and embedded addend in the instruction.");
325 RE.Addend = ExplicitAddend;
327 RelocationValueRef Value;
328 if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
331 return ValueOrErr.takeError();
333 bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
334 if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
335 // We'll take care of the offset in processGOTRelocation.
337 } else if (!IsExtern && RE.IsPCRel)
338 makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
340 RE.Addend = Value.Offset;
342 if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
343 RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 ||
344 RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT)
345 processGOTRelocation(RE, Value, Stubs);
347 if (Value.SymbolName)
348 addRelocationForSymbol(RE, Value.SymbolName);
350 addRelocationForSection(RE, Value.SectionID);
356 void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
357 LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
359 const SectionEntry &Section = Sections[RE.SectionID];
360 uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
361 MachO::RelocationInfoType RelType =
362 static_cast<MachO::RelocationInfoType>(RE.RelType);
366 llvm_unreachable("Invalid relocation type!");
367 case MachO::ARM64_RELOC_UNSIGNED: {
368 assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported");
369 // Mask in the target value a byte at a time (we don't have an alignment
370 // guarantee for the target address, so this is safest).
372 llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED");
374 encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend);
378 case MachO::ARM64_RELOC_POINTER_TO_GOT: {
379 assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) &&
380 "ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit "
382 // Addend is the GOT entry address and RE.Offset the target of the
385 RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend);
386 encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result);
390 case MachO::ARM64_RELOC_BRANCH26: {
391 assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
392 // Check if branch is in range.
393 uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
394 int64_t PCRelVal = Value - FinalAddress + RE.Addend;
395 encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
398 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
399 case MachO::ARM64_RELOC_PAGE21: {
400 assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
401 // Adjust for PC-relative relocation and offset.
402 uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
404 ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
405 encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
408 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
409 case MachO::ARM64_RELOC_PAGEOFF12: {
410 assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
411 // Add the offset from the symbol.
413 // Mask out the page address and only use the lower 12 bits.
415 encodeAddend(LocalAddress, /*Size=*/4, RelType, Value);
418 case MachO::ARM64_RELOC_SUBTRACTOR: {
419 uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
420 uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
421 assert((Value == SectionABase || Value == SectionBBase) &&
422 "Unexpected SUBTRACTOR relocation value.");
423 Value = SectionABase - SectionBBase + RE.Addend;
424 writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
428 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
429 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
430 llvm_unreachable("Relocation type not yet implemented!");
431 case MachO::ARM64_RELOC_ADDEND:
432 llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
433 "processRelocationRef!");
437 Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
438 const SectionRef &Section) {
439 return Error::success();
443 void processGOTRelocation(const RelocationEntry &RE,
444 RelocationValueRef &Value, StubMap &Stubs) {
445 assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT &&
446 (RE.Size == 2 || RE.Size == 3)) ||
448 SectionEntry &Section = Sections[RE.SectionID];
449 StubMap::const_iterator i = Stubs.find(Value);
451 if (i != Stubs.end())
452 Offset = static_cast<int64_t>(i->second);
454 // FIXME: There must be a better way to do this then to check and fix the
455 // alignment every time!!!
456 uintptr_t BaseAddress = uintptr_t(Section.getAddress());
457 uintptr_t StubAlignment = getStubAlignment();
458 uintptr_t StubAddress =
459 (BaseAddress + Section.getStubOffset() + StubAlignment - 1) &
461 unsigned StubOffset = StubAddress - BaseAddress;
462 Stubs[Value] = StubOffset;
463 assert(((StubAddress % getStubAlignment()) == 0) &&
464 "GOT entry not aligned");
465 RelocationEntry GOTRE(RE.SectionID, StubOffset,
466 MachO::ARM64_RELOC_UNSIGNED, Value.Offset,
467 /*IsPCRel=*/false, /*Size=*/3);
468 if (Value.SymbolName)
469 addRelocationForSymbol(GOTRE, Value.SymbolName);
471 addRelocationForSection(GOTRE, Value.SectionID);
472 Section.advanceStubOffset(getMaxStubSize());
473 Offset = static_cast<int64_t>(StubOffset);
475 RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset,
476 RE.IsPCRel, RE.Size);
477 addRelocationForSection(TargetRE, RE.SectionID);
480 Expected<relocation_iterator>
481 processSubtractRelocation(unsigned SectionID, relocation_iterator RelI,
482 const ObjectFile &BaseObjT,
483 ObjSectionToIDMap &ObjSectionToID) {
484 const MachOObjectFile &Obj =
485 static_cast<const MachOObjectFile&>(BaseObjT);
486 MachO::any_relocation_info RE =
487 Obj.getRelocation(RelI->getRawDataRefImpl());
489 unsigned Size = Obj.getAnyRelocationLength(RE);
490 uint64_t Offset = RelI->getOffset();
491 uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset);
492 unsigned NumBytes = 1 << Size;
494 Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName();
495 if (!SubtrahendNameOrErr)
496 return SubtrahendNameOrErr.takeError();
497 auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr);
498 unsigned SectionBID = SubtrahendI->second.getSectionID();
499 uint64_t SectionBOffset = SubtrahendI->second.getOffset();
501 SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8);
504 Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName();
505 if (!MinuendNameOrErr)
506 return MinuendNameOrErr.takeError();
507 auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr);
508 unsigned SectionAID = MinuendI->second.getSectionID();
509 uint64_t SectionAOffset = MinuendI->second.getOffset();
511 RelocationEntry R(SectionID, Offset, MachO::ARM64_RELOC_SUBTRACTOR, (uint64_t)Addend,
512 SectionAID, SectionAOffset, SectionBID, SectionBOffset,
515 addRelocationForSection(R, SectionAID);
520 static const char *getRelocName(uint32_t RelocType) {
522 case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED";
523 case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR";
524 case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26";
525 case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21";
526 case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12";
527 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21";
528 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12";
529 case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT";
530 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21";
531 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12";
532 case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND";
534 return "Unrecognized arm64 addend";