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::macho { 20 21 struct ARM64Common : TargetInfo { 22 template <class LP> ARM64Common(LP lp) : TargetInfo(lp) {} 23 24 int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, 25 const llvm::MachO::relocation_info) const override; 26 void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, 27 uint64_t pc) const override; 28 29 void relaxGotLoad(uint8_t *loc, uint8_t type) const override; 30 uint64_t getPageSize() const override { return 16 * 1024; } 31 32 void handleDtraceReloc(const Symbol *sym, const Reloc &r, 33 uint8_t *loc) const override; 34 }; 35 36 inline uint64_t bitField(uint64_t value, int right, int width, int left) { 37 return ((value >> right) & ((1 << width) - 1)) << left; 38 } 39 40 // 25 0 41 // +-----------+---------------------------------------------------+ 42 // | | imm26 | 43 // +-----------+---------------------------------------------------+ 44 45 inline void encodeBranch26(uint32_t *loc, const Reloc &r, uint32_t base, 46 uint64_t va) { 47 checkInt(loc, r, va, 28); 48 // Since branch destinations are 4-byte aligned, the 2 least- 49 // significant bits are 0. They are right shifted off the end. 50 llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0)); 51 } 52 53 inline void encodeBranch26(uint32_t *loc, SymbolDiagnostic d, uint32_t base, 54 uint64_t va) { 55 checkInt(loc, d, va, 28); 56 llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0)); 57 } 58 59 // 30 29 23 5 60 // +-+---+---------+-------------------------------------+---------+ 61 // | |ilo| | immhi | | 62 // +-+---+---------+-------------------------------------+---------+ 63 64 inline void encodePage21(uint32_t *loc, const Reloc &r, uint32_t base, 65 uint64_t va) { 66 checkInt(loc, r, va, 35); 67 llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) | 68 bitField(va, 14, 19, 5)); 69 } 70 71 inline void encodePage21(uint32_t *loc, SymbolDiagnostic d, uint32_t base, 72 uint64_t va) { 73 checkInt(loc, d, va, 35); 74 llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) | 75 bitField(va, 14, 19, 5)); 76 } 77 78 void reportUnalignedLdrStr(void *loc, const Reloc &, uint64_t va, int align); 79 void reportUnalignedLdrStr(void *loc, SymbolDiagnostic, uint64_t va, int align); 80 81 // 21 10 82 // +-------------------+-----------------------+-------------------+ 83 // | | imm12 | | 84 // +-------------------+-----------------------+-------------------+ 85 86 template <typename Target> 87 inline void encodePageOff12(uint32_t *loc, Target t, uint32_t base, 88 uint64_t va) { 89 int scale = 0; 90 if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store 91 scale = base >> 30; 92 if (scale == 0 && (base & 0x0480'0000) == 0x0480'0000) // 128-bit variant 93 scale = 4; 94 } 95 const int size = 1 << scale; 96 if ((va & (size - 1)) != 0) 97 reportUnalignedLdrStr(loc, t, va, size); 98 99 // TODO(gkm): extract embedded addend and warn if != 0 100 // uint64_t addend = ((base & 0x003FFC00) >> 10); 101 llvm::support::endian::write32le(loc, 102 base | bitField(va, scale, 12 - scale, 10)); 103 } 104 105 inline uint64_t pageBits(uint64_t address) { 106 const uint64_t pageMask = ~0xfffull; 107 return address & pageMask; 108 } 109 110 inline void writeStub(uint8_t *buf8, const uint32_t stubCode[3], 111 const macho::Symbol &sym, uint64_t pointerVA) { 112 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 113 constexpr size_t stubCodeSize = 3 * sizeof(uint32_t); 114 SymbolDiagnostic d = {&sym, "stub"}; 115 uint64_t pcPageBits = 116 pageBits(in.stubs->addr + sym.stubsIndex * stubCodeSize); 117 encodePage21(&buf32[0], d, stubCode[0], pageBits(pointerVA) - pcPageBits); 118 encodePageOff12(&buf32[1], d, stubCode[1], pointerVA); 119 buf32[2] = stubCode[2]; 120 } 121 122 template <class LP> 123 inline void writeStubHelperHeader(uint8_t *buf8, 124 const uint32_t stubHelperHeaderCode[6]) { 125 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 126 auto pcPageBits = [](int i) { 127 return pageBits(in.stubHelper->addr + i * sizeof(uint32_t)); 128 }; 129 uint64_t loaderVA = in.imageLoaderCache->getVA(); 130 SymbolDiagnostic d = {nullptr, "stub header helper"}; 131 encodePage21(&buf32[0], d, stubHelperHeaderCode[0], 132 pageBits(loaderVA) - pcPageBits(0)); 133 encodePageOff12(&buf32[1], d, stubHelperHeaderCode[1], loaderVA); 134 buf32[2] = stubHelperHeaderCode[2]; 135 uint64_t binderVA = 136 in.got->addr + in.stubHelper->stubBinder->gotIndex * LP::wordSize; 137 encodePage21(&buf32[3], d, stubHelperHeaderCode[3], 138 pageBits(binderVA) - pcPageBits(3)); 139 encodePageOff12(&buf32[4], d, stubHelperHeaderCode[4], binderVA); 140 buf32[5] = stubHelperHeaderCode[5]; 141 } 142 143 inline void writeStubHelperEntry(uint8_t *buf8, 144 const uint32_t stubHelperEntryCode[3], 145 const Symbol &sym, uint64_t entryVA) { 146 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 147 auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); }; 148 uint64_t stubHelperHeaderVA = in.stubHelper->addr; 149 buf32[0] = stubHelperEntryCode[0]; 150 encodeBranch26(&buf32[1], {&sym, "stub helper"}, stubHelperEntryCode[1], 151 stubHelperHeaderVA - pcVA(1)); 152 buf32[2] = sym.lazyBindOffset; 153 } 154 155 template <class LP> 156 inline void 157 writeObjCMsgSendFastStub(uint8_t *buf, const uint32_t objcStubsFastCode[8], 158 Symbol *sym, uint64_t stubsAddr, uint64_t stubOffset, 159 uint64_t selrefsVA, uint64_t selectorIndex, 160 uint64_t gotAddr, uint64_t msgSendIndex) { 161 SymbolDiagnostic d = {sym, sym->getName()}; 162 auto *buf32 = reinterpret_cast<uint32_t *>(buf); 163 164 auto pcPageBits = [stubsAddr, stubOffset](int i) { 165 return pageBits(stubsAddr + stubOffset + i * sizeof(uint32_t)); 166 }; 167 168 uint64_t selectorOffset = selectorIndex * LP::wordSize; 169 encodePage21(&buf32[0], d, objcStubsFastCode[0], 170 pageBits(selrefsVA + selectorOffset) - pcPageBits(0)); 171 encodePageOff12(&buf32[1], d, objcStubsFastCode[1], 172 selrefsVA + selectorOffset); 173 uint64_t gotOffset = msgSendIndex * LP::wordSize; 174 encodePage21(&buf32[2], d, objcStubsFastCode[2], 175 pageBits(gotAddr + gotOffset) - pcPageBits(2)); 176 encodePageOff12(&buf32[3], d, objcStubsFastCode[3], gotAddr + gotOffset); 177 buf32[4] = objcStubsFastCode[4]; 178 buf32[5] = objcStubsFastCode[5]; 179 buf32[6] = objcStubsFastCode[6]; 180 buf32[7] = objcStubsFastCode[7]; 181 } 182 183 template <class LP> 184 inline void 185 writeObjCMsgSendSmallStub(uint8_t *buf, const uint32_t objcStubsSmallCode[3], 186 Symbol *sym, uint64_t stubsAddr, uint64_t stubOffset, 187 uint64_t selrefsVA, uint64_t selectorIndex, 188 uint64_t msgSendAddr, uint64_t msgSendIndex) { 189 SymbolDiagnostic d = {sym, sym->getName()}; 190 auto *buf32 = reinterpret_cast<uint32_t *>(buf); 191 192 auto pcPageBits = [stubsAddr, stubOffset](int i) { 193 return pageBits(stubsAddr + stubOffset + i * sizeof(uint32_t)); 194 }; 195 196 uint64_t selectorOffset = selectorIndex * LP::wordSize; 197 encodePage21(&buf32[0], d, objcStubsSmallCode[0], 198 pageBits(selrefsVA + selectorOffset) - pcPageBits(0)); 199 encodePageOff12(&buf32[1], d, objcStubsSmallCode[1], 200 selrefsVA + selectorOffset); 201 uint64_t msgSendStubVA = msgSendAddr + msgSendIndex * target->stubSize; 202 uint64_t pcVA = stubsAddr + stubOffset + 2 * sizeof(uint32_t); 203 encodeBranch26(&buf32[2], {nullptr, "objc_msgSend stub"}, 204 objcStubsSmallCode[2], msgSendStubVA - pcVA); 205 } 206 207 } // namespace lld::macho 208 209 #endif 210