11cf9926bSpatrick //===- ARM64Common.h --------------------------------------------*- C++ -*-===//
21cf9926bSpatrick //
31cf9926bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41cf9926bSpatrick // See https://llvm.org/LICENSE.txt for license information.
51cf9926bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61cf9926bSpatrick //
71cf9926bSpatrick //===----------------------------------------------------------------------===//
81cf9926bSpatrick
91cf9926bSpatrick #ifndef LLD_MACHO_ARCH_ARM64COMMON_H
101cf9926bSpatrick #define LLD_MACHO_ARCH_ARM64COMMON_H
111cf9926bSpatrick
121cf9926bSpatrick #include "InputFiles.h"
131cf9926bSpatrick #include "Symbols.h"
141cf9926bSpatrick #include "SyntheticSections.h"
151cf9926bSpatrick #include "Target.h"
161cf9926bSpatrick
171cf9926bSpatrick #include "llvm/BinaryFormat/MachO.h"
181cf9926bSpatrick
19*dfe94b16Srobert namespace lld::macho {
201cf9926bSpatrick
211cf9926bSpatrick struct ARM64Common : TargetInfo {
ARM64CommonARM64Common221cf9926bSpatrick template <class LP> ARM64Common(LP lp) : TargetInfo(lp) {}
231cf9926bSpatrick
241cf9926bSpatrick int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset,
251cf9926bSpatrick const llvm::MachO::relocation_info) const override;
261cf9926bSpatrick void relocateOne(uint8_t *loc, const Reloc &, uint64_t va,
271cf9926bSpatrick uint64_t pc) const override;
281cf9926bSpatrick
291cf9926bSpatrick void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
getPageSizeARM64Common301cf9926bSpatrick uint64_t getPageSize() const override { return 16 * 1024; }
31*dfe94b16Srobert
32*dfe94b16Srobert void handleDtraceReloc(const Symbol *sym, const Reloc &r,
33*dfe94b16Srobert uint8_t *loc) const override;
341cf9926bSpatrick };
351cf9926bSpatrick
bitField(uint64_t value,int right,int width,int left)361cf9926bSpatrick inline uint64_t bitField(uint64_t value, int right, int width, int left) {
371cf9926bSpatrick return ((value >> right) & ((1 << width) - 1)) << left;
381cf9926bSpatrick }
391cf9926bSpatrick
401cf9926bSpatrick // 25 0
411cf9926bSpatrick // +-----------+---------------------------------------------------+
421cf9926bSpatrick // | | imm26 |
431cf9926bSpatrick // +-----------+---------------------------------------------------+
441cf9926bSpatrick
encodeBranch26(uint32_t * loc,const Reloc & r,uint32_t base,uint64_t va)45*dfe94b16Srobert inline void encodeBranch26(uint32_t *loc, const Reloc &r, uint32_t base,
46*dfe94b16Srobert uint64_t va) {
47*dfe94b16Srobert checkInt(loc, r, va, 28);
481cf9926bSpatrick // Since branch destinations are 4-byte aligned, the 2 least-
491cf9926bSpatrick // significant bits are 0. They are right shifted off the end.
50*dfe94b16Srobert llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0));
511cf9926bSpatrick }
521cf9926bSpatrick
encodeBranch26(uint32_t * loc,SymbolDiagnostic d,uint32_t base,uint64_t va)53*dfe94b16Srobert inline void encodeBranch26(uint32_t *loc, SymbolDiagnostic d, uint32_t base,
54*dfe94b16Srobert uint64_t va) {
55*dfe94b16Srobert checkInt(loc, d, va, 28);
56*dfe94b16Srobert llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0));
571cf9926bSpatrick }
581cf9926bSpatrick
591cf9926bSpatrick // 30 29 23 5
601cf9926bSpatrick // +-+---+---------+-------------------------------------+---------+
611cf9926bSpatrick // | |ilo| | immhi | |
621cf9926bSpatrick // +-+---+---------+-------------------------------------+---------+
631cf9926bSpatrick
encodePage21(uint32_t * loc,const Reloc & r,uint32_t base,uint64_t va)64*dfe94b16Srobert inline void encodePage21(uint32_t *loc, const Reloc &r, uint32_t base,
65*dfe94b16Srobert uint64_t va) {
66*dfe94b16Srobert checkInt(loc, r, va, 35);
67*dfe94b16Srobert llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) |
68*dfe94b16Srobert bitField(va, 14, 19, 5));
691cf9926bSpatrick }
701cf9926bSpatrick
encodePage21(uint32_t * loc,SymbolDiagnostic d,uint32_t base,uint64_t va)71*dfe94b16Srobert inline void encodePage21(uint32_t *loc, SymbolDiagnostic d, uint32_t base,
72*dfe94b16Srobert uint64_t va) {
73*dfe94b16Srobert checkInt(loc, d, va, 35);
74*dfe94b16Srobert llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) |
75*dfe94b16Srobert bitField(va, 14, 19, 5));
761cf9926bSpatrick }
771cf9926bSpatrick
78*dfe94b16Srobert void reportUnalignedLdrStr(void *loc, const Reloc &, uint64_t va, int align);
79*dfe94b16Srobert void reportUnalignedLdrStr(void *loc, SymbolDiagnostic, uint64_t va, int align);
80*dfe94b16Srobert
811cf9926bSpatrick // 21 10
821cf9926bSpatrick // +-------------------+-----------------------+-------------------+
831cf9926bSpatrick // | | imm12 | |
841cf9926bSpatrick // +-------------------+-----------------------+-------------------+
851cf9926bSpatrick
86*dfe94b16Srobert template <typename Target>
encodePageOff12(uint32_t * loc,Target t,uint32_t base,uint64_t va)87*dfe94b16Srobert inline void encodePageOff12(uint32_t *loc, Target t, uint32_t base,
88*dfe94b16Srobert uint64_t va) {
891cf9926bSpatrick int scale = 0;
901cf9926bSpatrick if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store
911cf9926bSpatrick scale = base >> 30;
921cf9926bSpatrick if (scale == 0 && (base & 0x0480'0000) == 0x0480'0000) // 128-bit variant
931cf9926bSpatrick scale = 4;
941cf9926bSpatrick }
95*dfe94b16Srobert const int size = 1 << scale;
96*dfe94b16Srobert if ((va & (size - 1)) != 0)
97*dfe94b16Srobert reportUnalignedLdrStr(loc, t, va, size);
981cf9926bSpatrick
991cf9926bSpatrick // TODO(gkm): extract embedded addend and warn if != 0
1001cf9926bSpatrick // uint64_t addend = ((base & 0x003FFC00) >> 10);
101*dfe94b16Srobert llvm::support::endian::write32le(loc,
102*dfe94b16Srobert base | bitField(va, scale, 12 - scale, 10));
1031cf9926bSpatrick }
1041cf9926bSpatrick
pageBits(uint64_t address)1051cf9926bSpatrick inline uint64_t pageBits(uint64_t address) {
1061cf9926bSpatrick const uint64_t pageMask = ~0xfffull;
1071cf9926bSpatrick return address & pageMask;
1081cf9926bSpatrick }
1091cf9926bSpatrick
writeStub(uint8_t * buf8,const uint32_t stubCode[3],const macho::Symbol & sym,uint64_t pointerVA)1101cf9926bSpatrick inline void writeStub(uint8_t *buf8, const uint32_t stubCode[3],
111*dfe94b16Srobert const macho::Symbol &sym, uint64_t pointerVA) {
1121cf9926bSpatrick auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
1131cf9926bSpatrick constexpr size_t stubCodeSize = 3 * sizeof(uint32_t);
114*dfe94b16Srobert SymbolDiagnostic d = {&sym, "stub"};
1151cf9926bSpatrick uint64_t pcPageBits =
1161cf9926bSpatrick pageBits(in.stubs->addr + sym.stubsIndex * stubCodeSize);
117*dfe94b16Srobert encodePage21(&buf32[0], d, stubCode[0], pageBits(pointerVA) - pcPageBits);
118*dfe94b16Srobert encodePageOff12(&buf32[1], d, stubCode[1], pointerVA);
1191cf9926bSpatrick buf32[2] = stubCode[2];
1201cf9926bSpatrick }
1211cf9926bSpatrick
1221cf9926bSpatrick template <class LP>
writeStubHelperHeader(uint8_t * buf8,const uint32_t stubHelperHeaderCode[6])1231cf9926bSpatrick inline void writeStubHelperHeader(uint8_t *buf8,
1241cf9926bSpatrick const uint32_t stubHelperHeaderCode[6]) {
1251cf9926bSpatrick auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
1261cf9926bSpatrick auto pcPageBits = [](int i) {
1271cf9926bSpatrick return pageBits(in.stubHelper->addr + i * sizeof(uint32_t));
1281cf9926bSpatrick };
1291cf9926bSpatrick uint64_t loaderVA = in.imageLoaderCache->getVA();
1301cf9926bSpatrick SymbolDiagnostic d = {nullptr, "stub header helper"};
131*dfe94b16Srobert encodePage21(&buf32[0], d, stubHelperHeaderCode[0],
1321cf9926bSpatrick pageBits(loaderVA) - pcPageBits(0));
133*dfe94b16Srobert encodePageOff12(&buf32[1], d, stubHelperHeaderCode[1], loaderVA);
1341cf9926bSpatrick buf32[2] = stubHelperHeaderCode[2];
1351cf9926bSpatrick uint64_t binderVA =
1361cf9926bSpatrick in.got->addr + in.stubHelper->stubBinder->gotIndex * LP::wordSize;
137*dfe94b16Srobert encodePage21(&buf32[3], d, stubHelperHeaderCode[3],
1381cf9926bSpatrick pageBits(binderVA) - pcPageBits(3));
139*dfe94b16Srobert encodePageOff12(&buf32[4], d, stubHelperHeaderCode[4], binderVA);
1401cf9926bSpatrick buf32[5] = stubHelperHeaderCode[5];
1411cf9926bSpatrick }
1421cf9926bSpatrick
writeStubHelperEntry(uint8_t * buf8,const uint32_t stubHelperEntryCode[3],const Symbol & sym,uint64_t entryVA)1431cf9926bSpatrick inline void writeStubHelperEntry(uint8_t *buf8,
1441cf9926bSpatrick const uint32_t stubHelperEntryCode[3],
145*dfe94b16Srobert const Symbol &sym, uint64_t entryVA) {
1461cf9926bSpatrick auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
1471cf9926bSpatrick auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); };
1481cf9926bSpatrick uint64_t stubHelperHeaderVA = in.stubHelper->addr;
1491cf9926bSpatrick buf32[0] = stubHelperEntryCode[0];
150*dfe94b16Srobert encodeBranch26(&buf32[1], {&sym, "stub helper"}, stubHelperEntryCode[1],
1511cf9926bSpatrick stubHelperHeaderVA - pcVA(1));
1521cf9926bSpatrick buf32[2] = sym.lazyBindOffset;
1531cf9926bSpatrick }
1541cf9926bSpatrick
155*dfe94b16Srobert template <class LP>
156*dfe94b16Srobert inline void
writeObjCMsgSendStub(uint8_t * buf,const uint32_t objcStubsFastCode[8],Symbol * sym,uint64_t stubsAddr,uint64_t stubOffset,uint64_t selrefsVA,uint64_t selectorIndex,uint64_t gotAddr,uint64_t msgSendIndex)157*dfe94b16Srobert writeObjCMsgSendStub(uint8_t *buf, const uint32_t objcStubsFastCode[8],
158*dfe94b16Srobert Symbol *sym, uint64_t stubsAddr, uint64_t stubOffset,
159*dfe94b16Srobert uint64_t selrefsVA, uint64_t selectorIndex,
160*dfe94b16Srobert uint64_t gotAddr, uint64_t msgSendIndex) {
161*dfe94b16Srobert SymbolDiagnostic d = {sym, sym->getName()};
162*dfe94b16Srobert auto *buf32 = reinterpret_cast<uint32_t *>(buf);
163*dfe94b16Srobert
164*dfe94b16Srobert auto pcPageBits = [stubsAddr, stubOffset](int i) {
165*dfe94b16Srobert return pageBits(stubsAddr + stubOffset + i * sizeof(uint32_t));
166*dfe94b16Srobert };
167*dfe94b16Srobert
168*dfe94b16Srobert uint64_t selectorOffset = selectorIndex * LP::wordSize;
169*dfe94b16Srobert encodePage21(&buf32[0], d, objcStubsFastCode[0],
170*dfe94b16Srobert pageBits(selrefsVA + selectorOffset) - pcPageBits(0));
171*dfe94b16Srobert encodePageOff12(&buf32[1], d, objcStubsFastCode[1],
172*dfe94b16Srobert selrefsVA + selectorOffset);
173*dfe94b16Srobert encodePage21(&buf32[2], d, objcStubsFastCode[2],
174*dfe94b16Srobert pageBits(gotAddr) - pcPageBits(2));
175*dfe94b16Srobert encodePage21(&buf32[3], d, objcStubsFastCode[3], msgSendIndex * LP::wordSize);
176*dfe94b16Srobert buf32[4] = objcStubsFastCode[4];
177*dfe94b16Srobert buf32[5] = objcStubsFastCode[5];
178*dfe94b16Srobert buf32[6] = objcStubsFastCode[6];
179*dfe94b16Srobert buf32[7] = objcStubsFastCode[7];
180*dfe94b16Srobert }
181*dfe94b16Srobert
182*dfe94b16Srobert } // namespace lld::macho
1831cf9926bSpatrick
1841cf9926bSpatrick #endif
185