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 void encodeBranch26(uint32_t *loc, const Reloc &r, uint32_t base, 44 uint64_t va) { 45 checkInt(loc, r, va, 28); 46 // Since branch destinations are 4-byte aligned, the 2 least- 47 // significant bits are 0. They are right shifted off the end. 48 llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0)); 49 } 50 51 inline void encodeBranch26(uint32_t *loc, SymbolDiagnostic d, uint32_t base, 52 uint64_t va) { 53 checkInt(loc, d, va, 28); 54 llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0)); 55 } 56 57 // 30 29 23 5 58 // +-+---+---------+-------------------------------------+---------+ 59 // | |ilo| | immhi | | 60 // +-+---+---------+-------------------------------------+---------+ 61 62 inline void encodePage21(uint32_t *loc, const Reloc &r, uint32_t base, 63 uint64_t va) { 64 checkInt(loc, r, va, 35); 65 llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) | 66 bitField(va, 14, 19, 5)); 67 } 68 69 inline void encodePage21(uint32_t *loc, SymbolDiagnostic d, uint32_t base, 70 uint64_t va) { 71 checkInt(loc, d, va, 35); 72 llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) | 73 bitField(va, 14, 19, 5)); 74 } 75 76 // 21 10 77 // +-------------------+-----------------------+-------------------+ 78 // | | imm12 | | 79 // +-------------------+-----------------------+-------------------+ 80 81 inline void encodePageOff12(uint32_t *loc, uint32_t base, uint64_t va) { 82 int scale = 0; 83 if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store 84 scale = base >> 30; 85 if (scale == 0 && (base & 0x0480'0000) == 0x0480'0000) // 128-bit variant 86 scale = 4; 87 } 88 89 // TODO(gkm): extract embedded addend and warn if != 0 90 // uint64_t addend = ((base & 0x003FFC00) >> 10); 91 llvm::support::endian::write32le(loc, 92 base | bitField(va, scale, 12 - scale, 10)); 93 } 94 95 inline uint64_t pageBits(uint64_t address) { 96 const uint64_t pageMask = ~0xfffull; 97 return address & pageMask; 98 } 99 100 template <class LP> 101 inline void writeStub(uint8_t *buf8, const uint32_t stubCode[3], 102 const macho::Symbol &sym) { 103 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 104 constexpr size_t stubCodeSize = 3 * sizeof(uint32_t); 105 uint64_t pcPageBits = 106 pageBits(in.stubs->addr + sym.stubsIndex * stubCodeSize); 107 uint64_t lazyPointerVA = 108 in.lazyPointers->addr + sym.stubsIndex * LP::wordSize; 109 encodePage21(&buf32[0], {&sym, "stub"}, stubCode[0], 110 pageBits(lazyPointerVA) - pcPageBits); 111 encodePageOff12(&buf32[1], stubCode[1], lazyPointerVA); 112 buf32[2] = stubCode[2]; 113 } 114 115 template <class LP> 116 inline void writeStubHelperHeader(uint8_t *buf8, 117 const uint32_t stubHelperHeaderCode[6]) { 118 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 119 auto pcPageBits = [](int i) { 120 return pageBits(in.stubHelper->addr + i * sizeof(uint32_t)); 121 }; 122 uint64_t loaderVA = in.imageLoaderCache->getVA(); 123 SymbolDiagnostic d = {nullptr, "stub header helper"}; 124 encodePage21(&buf32[0], d, stubHelperHeaderCode[0], 125 pageBits(loaderVA) - pcPageBits(0)); 126 encodePageOff12(&buf32[1], stubHelperHeaderCode[1], loaderVA); 127 buf32[2] = stubHelperHeaderCode[2]; 128 uint64_t binderVA = 129 in.got->addr + in.stubHelper->stubBinder->gotIndex * LP::wordSize; 130 encodePage21(&buf32[3], d, stubHelperHeaderCode[3], 131 pageBits(binderVA) - pcPageBits(3)); 132 encodePageOff12(&buf32[4], stubHelperHeaderCode[4], binderVA); 133 buf32[5] = stubHelperHeaderCode[5]; 134 } 135 136 inline void writeStubHelperEntry(uint8_t *buf8, 137 const uint32_t stubHelperEntryCode[3], 138 const Symbol &sym, uint64_t entryVA) { 139 auto *buf32 = reinterpret_cast<uint32_t *>(buf8); 140 auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); }; 141 uint64_t stubHelperHeaderVA = in.stubHelper->addr; 142 buf32[0] = stubHelperEntryCode[0]; 143 encodeBranch26(&buf32[1], {&sym, "stub helper"}, stubHelperEntryCode[1], 144 stubHelperHeaderVA - pcVA(1)); 145 buf32[2] = sym.lazyBindOffset; 146 } 147 148 } // namespace macho 149 } // namespace lld 150 151 #endif 152