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