xref: /openbsd-src/gnu/llvm/lld/MachO/Arch/ARM64Common.h (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
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