1 //===- ARM64Common.h --------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLD_MACHO_ARCH_ARM64COMMON_H 10 #define LLD_MACHO_ARCH_ARM64COMMON_H 11 12 #include "InputFiles.h" 13 #include "Symbols.h" 14 #include "SyntheticSections.h" 15 #include "Target.h" 16 17 #include "llvm/BinaryFormat/MachO.h" 18 19 namespace lld { 20 namespace macho { 21 22 struct ARM64Common : TargetInfo { 23 template <class LP> ARM64Common(LP lp) : TargetInfo(lp) {} 24 25 int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, 26 const llvm::MachO::relocation_info) const override; 27 void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, 28 uint64_t pc) const override; 29 30 void relaxGotLoad(uint8_t *loc, uint8_t type) const override; 31 uint64_t getPageSize() const override { return 16 * 1024; } 32 }; 33 34 inline uint64_t bitField(uint64_t value, int right, int width, int left) { 35 return ((value >> right) & ((1 << width) - 1)) << left; 36 } 37 38 // 25 0 39 // +-----------+---------------------------------------------------+ 40 // | | imm26 | 41 // +-----------+---------------------------------------------------+ 42 43 inline uint64_t encodeBranch26(const Reloc &r, uint64_t base, uint64_t va) { 44 checkInt(r, va, 28); 45 // Since branch destinations are 4-byte aligned, the 2 least- 46 // significant bits are 0. They are right shifted off the end. 47 return (base | bitField(va, 2, 26, 0)); 48 } 49 50 inline uint64_t encodeBranch26(SymbolDiagnostic d, uint64_t base, uint64_t va) { 51 checkInt(d, va, 28); 52 return (base | bitField(va, 2, 26, 0)); 53 } 54 55 // 30 29 23 5 56 // +-+---+---------+-------------------------------------+---------+ 57 // | |ilo| | immhi | | 58 // +-+---+---------+-------------------------------------+---------+ 59 60 inline uint64_t encodePage21(const Reloc &r, uint64_t base, uint64_t va) { 61 checkInt(r, va, 35); 62 return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5)); 63 } 64 65 inline uint64_t encodePage21(SymbolDiagnostic d, uint64_t base, uint64_t va) { 66 checkInt(d, va, 35); 67 return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5)); 68 } 69 70 // 21 10 71 // +-------------------+-----------------------+-------------------+ 72 // | | imm12 | | 73 // +-------------------+-----------------------+-------------------+ 74 75 inline uint64_t encodePageOff12(uint32_t base, uint64_t va) { 76 int scale = 0; 77 if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store 78 scale = base >> 30; 79 if (scale == 0 && (base & 0x0480'0000) == 0x0480'0000) // 128-bit variant 80 scale = 4; 81 } 82 83 // TODO(gkm): extract embedded addend and warn if != 0 84 // uint64_t addend = ((base & 0x003FFC00) >> 10); 85 return (base | bitField(va, scale, 12 - scale, 10)); 86 } 87 88 inline uint64_t pageBits(uint64_t address) { 89 const uint64_t pageMask = ~0xfffull; 90 return address & pageMask; 91 } 92 93 template <class LP> 94 inline void writeStub(uint8_t *buf8, const uint32_t stubCode[3], 95 const macho::Symbol &sym) { 96 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 97 constexpr size_t stubCodeSize = 3 * sizeof(uint32_t); 98 uint64_t pcPageBits = 99 pageBits(in.stubs->addr + sym.stubsIndex * stubCodeSize); 100 uint64_t lazyPointerVA = 101 in.lazyPointers->addr + sym.stubsIndex * LP::wordSize; 102 buf32[0] = encodePage21({&sym, "stub"}, stubCode[0], 103 pageBits(lazyPointerVA) - pcPageBits); 104 buf32[1] = encodePageOff12(stubCode[1], lazyPointerVA); 105 buf32[2] = stubCode[2]; 106 } 107 108 template <class LP> 109 inline void writeStubHelperHeader(uint8_t *buf8, 110 const uint32_t stubHelperHeaderCode[6]) { 111 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 112 auto pcPageBits = [](int i) { 113 return pageBits(in.stubHelper->addr + i * sizeof(uint32_t)); 114 }; 115 uint64_t loaderVA = in.imageLoaderCache->getVA(); 116 SymbolDiagnostic d = {nullptr, "stub header helper"}; 117 buf32[0] = encodePage21(d, stubHelperHeaderCode[0], 118 pageBits(loaderVA) - pcPageBits(0)); 119 buf32[1] = encodePageOff12(stubHelperHeaderCode[1], loaderVA); 120 buf32[2] = stubHelperHeaderCode[2]; 121 uint64_t binderVA = 122 in.got->addr + in.stubHelper->stubBinder->gotIndex * LP::wordSize; 123 buf32[3] = encodePage21(d, stubHelperHeaderCode[3], 124 pageBits(binderVA) - pcPageBits(3)); 125 buf32[4] = encodePageOff12(stubHelperHeaderCode[4], binderVA); 126 buf32[5] = stubHelperHeaderCode[5]; 127 } 128 129 inline void writeStubHelperEntry(uint8_t *buf8, 130 const uint32_t stubHelperEntryCode[3], 131 const DylibSymbol &sym, uint64_t entryVA) { 132 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 133 auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); }; 134 uint64_t stubHelperHeaderVA = in.stubHelper->addr; 135 buf32[0] = stubHelperEntryCode[0]; 136 buf32[1] = encodeBranch26({&sym, "stub helper"}, stubHelperEntryCode[1], 137 stubHelperHeaderVA - pcVA(1)); 138 buf32[2] = sym.lazyBindOffset; 139 } 140 141 } // namespace macho 142 } // namespace lld 143 144 #endif 145