xref: /freebsd/contrib/llvm-project/lld/ELF/Arch/AArch64.cpp (revision 297eecfb02bb25902531dbb5c3b9a88caf8adf29)
10b57cec5SDimitry Andric //===- AArch64.cpp --------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
95f757f3fSDimitry Andric #include "InputFiles.h"
10bdd1243dSDimitry Andric #include "OutputSections.h"
110b57cec5SDimitry Andric #include "Symbols.h"
120b57cec5SDimitry Andric #include "SyntheticSections.h"
130b57cec5SDimitry Andric #include "Target.h"
140b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
1581ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
160b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace llvm;
190b57cec5SDimitry Andric using namespace llvm::support::endian;
200b57cec5SDimitry Andric using namespace llvm::ELF;
215ffd83dbSDimitry Andric using namespace lld;
225ffd83dbSDimitry Andric using namespace lld::elf;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric // Page(Expr) is the page address of the expression Expr, defined
250b57cec5SDimitry Andric // as (Expr & ~0xFFF). (This applies even if the machine page size
260b57cec5SDimitry Andric // supported by the platform has a different value.)
275ffd83dbSDimitry Andric uint64_t elf::getAArch64Page(uint64_t expr) {
280b57cec5SDimitry Andric   return expr & ~static_cast<uint64_t>(0xFFF);
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace {
320b57cec5SDimitry Andric class AArch64 : public TargetInfo {
330b57cec5SDimitry Andric public:
340b57cec5SDimitry Andric   AArch64();
350b57cec5SDimitry Andric   RelExpr getRelExpr(RelType type, const Symbol &s,
360b57cec5SDimitry Andric                      const uint8_t *loc) const override;
370b57cec5SDimitry Andric   RelType getDynRel(RelType type) const override;
38fe6060f1SDimitry Andric   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
390b57cec5SDimitry Andric   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
40bdd1243dSDimitry Andric   void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
410b57cec5SDimitry Andric   void writePltHeader(uint8_t *buf) const override;
42480093f4SDimitry Andric   void writePlt(uint8_t *buf, const Symbol &sym,
43480093f4SDimitry Andric                 uint64_t pltEntryAddr) const override;
440b57cec5SDimitry Andric   bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
45480093f4SDimitry Andric                   uint64_t branchAddr, const Symbol &s,
46480093f4SDimitry Andric                   int64_t a) const override;
470b57cec5SDimitry Andric   uint32_t getThunkSectionSpacing() const override;
480b57cec5SDimitry Andric   bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
490b57cec5SDimitry Andric   bool usesOnlyLowPageBits(RelType type) const override;
505ffd83dbSDimitry Andric   void relocate(uint8_t *loc, const Relocation &rel,
515ffd83dbSDimitry Andric                 uint64_t val) const override;
52e8d8bef9SDimitry Andric   RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
53bdd1243dSDimitry Andric   void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
54bdd1243dSDimitry Andric 
55bdd1243dSDimitry Andric private:
56bdd1243dSDimitry Andric   void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
57bdd1243dSDimitry Andric   void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
58bdd1243dSDimitry Andric   void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
59bdd1243dSDimitry Andric };
60bdd1243dSDimitry Andric 
61bdd1243dSDimitry Andric struct AArch64Relaxer {
62bdd1243dSDimitry Andric   bool safeToRelaxAdrpLdr = false;
63bdd1243dSDimitry Andric 
64bdd1243dSDimitry Andric   AArch64Relaxer(ArrayRef<Relocation> relocs);
65bdd1243dSDimitry Andric   bool tryRelaxAdrpAdd(const Relocation &adrpRel, const Relocation &addRel,
66bdd1243dSDimitry Andric                        uint64_t secAddr, uint8_t *buf) const;
67bdd1243dSDimitry Andric   bool tryRelaxAdrpLdr(const Relocation &adrpRel, const Relocation &ldrRel,
68bdd1243dSDimitry Andric                        uint64_t secAddr, uint8_t *buf) const;
690b57cec5SDimitry Andric };
700b57cec5SDimitry Andric } // namespace
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric AArch64::AArch64() {
730b57cec5SDimitry Andric   copyRel = R_AARCH64_COPY;
740b57cec5SDimitry Andric   relativeRel = R_AARCH64_RELATIVE;
750b57cec5SDimitry Andric   iRelativeRel = R_AARCH64_IRELATIVE;
760b57cec5SDimitry Andric   gotRel = R_AARCH64_GLOB_DAT;
770b57cec5SDimitry Andric   pltRel = R_AARCH64_JUMP_SLOT;
780b57cec5SDimitry Andric   symbolicRel = R_AARCH64_ABS64;
790b57cec5SDimitry Andric   tlsDescRel = R_AARCH64_TLSDESC;
800b57cec5SDimitry Andric   tlsGotRel = R_AARCH64_TLS_TPREL64;
810b57cec5SDimitry Andric   pltHeaderSize = 32;
82480093f4SDimitry Andric   pltEntrySize = 16;
83480093f4SDimitry Andric   ipltEntrySize = 16;
840b57cec5SDimitry Andric   defaultMaxPageSize = 65536;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   // Align to the 2 MiB page size (known as a superpage or huge page).
870b57cec5SDimitry Andric   // FreeBSD automatically promotes 2 MiB-aligned allocations.
880b57cec5SDimitry Andric   defaultImageBase = 0x200000;
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   needsThunks = true;
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
940b57cec5SDimitry Andric                             const uint8_t *loc) const {
950b57cec5SDimitry Andric   switch (type) {
9685868e8aSDimitry Andric   case R_AARCH64_ABS16:
9785868e8aSDimitry Andric   case R_AARCH64_ABS32:
9885868e8aSDimitry Andric   case R_AARCH64_ABS64:
9985868e8aSDimitry Andric   case R_AARCH64_ADD_ABS_LO12_NC:
10085868e8aSDimitry Andric   case R_AARCH64_LDST128_ABS_LO12_NC:
10185868e8aSDimitry Andric   case R_AARCH64_LDST16_ABS_LO12_NC:
10285868e8aSDimitry Andric   case R_AARCH64_LDST32_ABS_LO12_NC:
10385868e8aSDimitry Andric   case R_AARCH64_LDST64_ABS_LO12_NC:
10485868e8aSDimitry Andric   case R_AARCH64_LDST8_ABS_LO12_NC:
10585868e8aSDimitry Andric   case R_AARCH64_MOVW_SABS_G0:
10685868e8aSDimitry Andric   case R_AARCH64_MOVW_SABS_G1:
10785868e8aSDimitry Andric   case R_AARCH64_MOVW_SABS_G2:
10885868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G0:
10985868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G0_NC:
11085868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G1:
11185868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G1_NC:
11285868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G2:
11385868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G2_NC:
11485868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G3:
11585868e8aSDimitry Andric     return R_ABS;
1160b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
1170b57cec5SDimitry Andric     return R_AARCH64_TLSDESC_PAGE;
1180b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
1190b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
1200b57cec5SDimitry Andric     return R_TLSDESC;
1210b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_CALL:
1220b57cec5SDimitry Andric     return R_TLSDESC_CALL;
1230b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_HI12:
1240b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
1250b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
1260b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
1270b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
1280b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
1290b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
13085868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G0:
13185868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
13285868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G1:
13385868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
13485868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G2:
135e8d8bef9SDimitry Andric     return R_TPREL;
1360b57cec5SDimitry Andric   case R_AARCH64_CALL26:
1370b57cec5SDimitry Andric   case R_AARCH64_CONDBR19:
1380b57cec5SDimitry Andric   case R_AARCH64_JUMP26:
1390b57cec5SDimitry Andric   case R_AARCH64_TSTBR14:
14006c3fb27SDimitry Andric     return R_PLT_PC;
1415ffd83dbSDimitry Andric   case R_AARCH64_PLT32:
14206c3fb27SDimitry Andric     const_cast<Symbol &>(s).thunkAccessed = true;
1430b57cec5SDimitry Andric     return R_PLT_PC;
1440b57cec5SDimitry Andric   case R_AARCH64_PREL16:
1450b57cec5SDimitry Andric   case R_AARCH64_PREL32:
1460b57cec5SDimitry Andric   case R_AARCH64_PREL64:
1470b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_LO21:
1480b57cec5SDimitry Andric   case R_AARCH64_LD_PREL_LO19:
14985868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G0:
15085868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G0_NC:
15185868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G1:
15285868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G1_NC:
15385868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G2:
15485868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G2_NC:
15585868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G3:
1560b57cec5SDimitry Andric     return R_PC;
1570b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21:
1580b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21_NC:
1590b57cec5SDimitry Andric     return R_AARCH64_PAGE_PC;
1600b57cec5SDimitry Andric   case R_AARCH64_LD64_GOT_LO12_NC:
1610b57cec5SDimitry Andric   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
1620b57cec5SDimitry Andric     return R_GOT;
163e8d8bef9SDimitry Andric   case R_AARCH64_LD64_GOTPAGE_LO15:
164e8d8bef9SDimitry Andric     return R_AARCH64_GOT_PAGE;
1650b57cec5SDimitry Andric   case R_AARCH64_ADR_GOT_PAGE:
1660b57cec5SDimitry Andric   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
1670b57cec5SDimitry Andric     return R_AARCH64_GOT_PAGE_PC;
168*297eecfbSDimitry Andric   case R_AARCH64_GOTPCREL32:
169*297eecfbSDimitry Andric     return R_GOT_PC;
1700b57cec5SDimitry Andric   case R_AARCH64_NONE:
1710b57cec5SDimitry Andric     return R_NONE;
1720b57cec5SDimitry Andric   default:
17385868e8aSDimitry Andric     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
17485868e8aSDimitry Andric           ") against symbol " + toString(s));
17585868e8aSDimitry Andric     return R_NONE;
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
179e8d8bef9SDimitry Andric RelExpr AArch64::adjustTlsExpr(RelType type, RelExpr expr) const {
1800b57cec5SDimitry Andric   if (expr == R_RELAX_TLS_GD_TO_IE) {
1810b57cec5SDimitry Andric     if (type == R_AARCH64_TLSDESC_ADR_PAGE21)
1820b57cec5SDimitry Andric       return R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC;
1830b57cec5SDimitry Andric     return R_RELAX_TLS_GD_TO_IE_ABS;
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric   return expr;
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric bool AArch64::usesOnlyLowPageBits(RelType type) const {
1890b57cec5SDimitry Andric   switch (type) {
1900b57cec5SDimitry Andric   default:
1910b57cec5SDimitry Andric     return false;
1920b57cec5SDimitry Andric   case R_AARCH64_ADD_ABS_LO12_NC:
1930b57cec5SDimitry Andric   case R_AARCH64_LD64_GOT_LO12_NC:
1940b57cec5SDimitry Andric   case R_AARCH64_LDST128_ABS_LO12_NC:
1950b57cec5SDimitry Andric   case R_AARCH64_LDST16_ABS_LO12_NC:
1960b57cec5SDimitry Andric   case R_AARCH64_LDST32_ABS_LO12_NC:
1970b57cec5SDimitry Andric   case R_AARCH64_LDST64_ABS_LO12_NC:
1980b57cec5SDimitry Andric   case R_AARCH64_LDST8_ABS_LO12_NC:
1990b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
2000b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
2010b57cec5SDimitry Andric   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
2020b57cec5SDimitry Andric     return true;
2030b57cec5SDimitry Andric   }
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric RelType AArch64::getDynRel(RelType type) const {
2070b57cec5SDimitry Andric   if (type == R_AARCH64_ABS64)
2080b57cec5SDimitry Andric     return type;
2090b57cec5SDimitry Andric   return R_AARCH64_NONE;
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric 
212fe6060f1SDimitry Andric int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
213fe6060f1SDimitry Andric   switch (type) {
214fe6060f1SDimitry Andric   case R_AARCH64_TLSDESC:
215fe6060f1SDimitry Andric     return read64(buf + 8);
216298c3e8dSDimitry Andric   case R_AARCH64_NONE:
217bdd1243dSDimitry Andric   case R_AARCH64_GLOB_DAT:
218bdd1243dSDimitry Andric   case R_AARCH64_JUMP_SLOT:
219298c3e8dSDimitry Andric     return 0;
220298c3e8dSDimitry Andric   case R_AARCH64_PREL32:
221298c3e8dSDimitry Andric     return SignExtend64<32>(read32(buf));
222298c3e8dSDimitry Andric   case R_AARCH64_ABS64:
223298c3e8dSDimitry Andric   case R_AARCH64_PREL64:
224bdd1243dSDimitry Andric   case R_AARCH64_RELATIVE:
225bdd1243dSDimitry Andric   case R_AARCH64_IRELATIVE:
226bdd1243dSDimitry Andric   case R_AARCH64_TLS_TPREL64:
227298c3e8dSDimitry Andric     return read64(buf);
228fe6060f1SDimitry Andric   default:
229fe6060f1SDimitry Andric     internalLinkerError(getErrorLocation(buf),
230fe6060f1SDimitry Andric                         "cannot read addend for relocation " + toString(type));
231fe6060f1SDimitry Andric     return 0;
232fe6060f1SDimitry Andric   }
233fe6060f1SDimitry Andric }
234fe6060f1SDimitry Andric 
2350b57cec5SDimitry Andric void AArch64::writeGotPlt(uint8_t *buf, const Symbol &) const {
236fe6060f1SDimitry Andric   write64(buf, in.plt->getVA());
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
239bdd1243dSDimitry Andric void AArch64::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
240bdd1243dSDimitry Andric   if (config->writeAddends)
241bdd1243dSDimitry Andric     write64(buf, s.getVA());
242bdd1243dSDimitry Andric }
243bdd1243dSDimitry Andric 
2440b57cec5SDimitry Andric void AArch64::writePltHeader(uint8_t *buf) const {
2450b57cec5SDimitry Andric   const uint8_t pltData[] = {
2460b57cec5SDimitry Andric       0xf0, 0x7b, 0xbf, 0xa9, // stp    x16, x30, [sp,#-16]!
247bdd1243dSDimitry Andric       0x10, 0x00, 0x00, 0x90, // adrp   x16, Page(&(.got.plt[2]))
248bdd1243dSDimitry Andric       0x11, 0x02, 0x40, 0xf9, // ldr    x17, [x16, Offset(&(.got.plt[2]))]
249bdd1243dSDimitry Andric       0x10, 0x02, 0x00, 0x91, // add    x16, x16, Offset(&(.got.plt[2]))
2500b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6, // br     x17
2510b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5, // nop
2520b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5, // nop
2530b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5  // nop
2540b57cec5SDimitry Andric   };
2550b57cec5SDimitry Andric   memcpy(buf, pltData, sizeof(pltData));
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   uint64_t got = in.gotPlt->getVA();
2580b57cec5SDimitry Andric   uint64_t plt = in.plt->getVA();
2595ffd83dbSDimitry Andric   relocateNoSym(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
2600b57cec5SDimitry Andric                 getAArch64Page(got + 16) - getAArch64Page(plt + 4));
2615ffd83dbSDimitry Andric   relocateNoSym(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
2625ffd83dbSDimitry Andric   relocateNoSym(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
265480093f4SDimitry Andric void AArch64::writePlt(uint8_t *buf, const Symbol &sym,
266480093f4SDimitry Andric                        uint64_t pltEntryAddr) const {
2670b57cec5SDimitry Andric   const uint8_t inst[] = {
268bdd1243dSDimitry Andric       0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.got.plt[n]))
269bdd1243dSDimitry Andric       0x11, 0x02, 0x40, 0xf9, // ldr  x17, [x16, Offset(&(.got.plt[n]))]
270bdd1243dSDimitry Andric       0x10, 0x02, 0x00, 0x91, // add  x16, x16, Offset(&(.got.plt[n]))
2710b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6  // br   x17
2720b57cec5SDimitry Andric   };
2730b57cec5SDimitry Andric   memcpy(buf, inst, sizeof(inst));
2740b57cec5SDimitry Andric 
275480093f4SDimitry Andric   uint64_t gotPltEntryAddr = sym.getGotPltVA();
2765ffd83dbSDimitry Andric   relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
2770b57cec5SDimitry Andric                 getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
2785ffd83dbSDimitry Andric   relocateNoSym(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
2795ffd83dbSDimitry Andric   relocateNoSym(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric bool AArch64::needsThunk(RelExpr expr, RelType type, const InputFile *file,
283480093f4SDimitry Andric                          uint64_t branchAddr, const Symbol &s,
284480093f4SDimitry Andric                          int64_t a) const {
2852a66634dSDimitry Andric   // If s is an undefined weak symbol and does not have a PLT entry then it will
2862a66634dSDimitry Andric   // be resolved as a branch to the next instruction. If it is hidden, its
2872a66634dSDimitry Andric   // binding has been converted to local, so we just check isUndefined() here. A
2882a66634dSDimitry Andric   // undefined non-weak symbol will have been errored.
2892a66634dSDimitry Andric   if (s.isUndefined() && !s.isInPlt())
290480093f4SDimitry Andric     return false;
2910b57cec5SDimitry Andric   // ELF for the ARM 64-bit architecture, section Call and Jump relocations
2920b57cec5SDimitry Andric   // only permits range extension thunks for R_AARCH64_CALL26 and
2930b57cec5SDimitry Andric   // R_AARCH64_JUMP26 relocation types.
2945ffd83dbSDimitry Andric   if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
2955ffd83dbSDimitry Andric       type != R_AARCH64_PLT32)
2960b57cec5SDimitry Andric     return false;
297480093f4SDimitry Andric   uint64_t dst = expr == R_PLT_PC ? s.getPltVA() : s.getVA(a);
2980b57cec5SDimitry Andric   return !inBranchRange(type, branchAddr, dst);
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric uint32_t AArch64::getThunkSectionSpacing() const {
3020b57cec5SDimitry Andric   // See comment in Arch/ARM.cpp for a more detailed explanation of
3030b57cec5SDimitry Andric   // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to
3040b57cec5SDimitry Andric   // Thunk have a range of +/- 128 MiB
3050b57cec5SDimitry Andric   return (128 * 1024 * 1024) - 0x30000;
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric bool AArch64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
3095ffd83dbSDimitry Andric   if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
3105ffd83dbSDimitry Andric       type != R_AARCH64_PLT32)
3110b57cec5SDimitry Andric     return true;
3120b57cec5SDimitry Andric   // The AArch64 call and unconditional branch instructions have a range of
3135ffd83dbSDimitry Andric   // +/- 128 MiB. The PLT32 relocation supports a range up to +/- 2 GiB.
3145ffd83dbSDimitry Andric   uint64_t range =
3155ffd83dbSDimitry Andric       type == R_AARCH64_PLT32 ? (UINT64_C(1) << 31) : (128 * 1024 * 1024);
3160b57cec5SDimitry Andric   if (dst > src) {
3170b57cec5SDimitry Andric     // Immediate of branch is signed.
3180b57cec5SDimitry Andric     range -= 4;
3190b57cec5SDimitry Andric     return dst - src <= range;
3200b57cec5SDimitry Andric   }
3210b57cec5SDimitry Andric   return src - dst <= range;
3220b57cec5SDimitry Andric }
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric static void write32AArch64Addr(uint8_t *l, uint64_t imm) {
3250b57cec5SDimitry Andric   uint32_t immLo = (imm & 0x3) << 29;
3260b57cec5SDimitry Andric   uint32_t immHi = (imm & 0x1FFFFC) << 3;
3270b57cec5SDimitry Andric   uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3);
3280b57cec5SDimitry Andric   write32le(l, (read32le(l) & ~mask) | immLo | immHi);
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric // Return the bits [Start, End] from Val shifted Start bits.
3320b57cec5SDimitry Andric // For instance, getBits(0xF0, 4, 8) returns 0xF.
3330b57cec5SDimitry Andric static uint64_t getBits(uint64_t val, int start, int end) {
3340b57cec5SDimitry Andric   uint64_t mask = ((uint64_t)1 << (end + 1 - start)) - 1;
3350b57cec5SDimitry Andric   return (val >> start) & mask;
3360b57cec5SDimitry Andric }
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric // Update the immediate field in a AARCH64 ldr, str, and add instruction.
3410b57cec5SDimitry Andric static void or32AArch64Imm(uint8_t *l, uint64_t imm) {
3420b57cec5SDimitry Andric   or32le(l, (imm & 0xFFF) << 10);
3430b57cec5SDimitry Andric }
3440b57cec5SDimitry Andric 
34585868e8aSDimitry Andric // Update the immediate field in an AArch64 movk, movn or movz instruction
34685868e8aSDimitry Andric // for a signed relocation, and update the opcode of a movn or movz instruction
34785868e8aSDimitry Andric // to match the sign of the operand.
34885868e8aSDimitry Andric static void writeSMovWImm(uint8_t *loc, uint32_t imm) {
34985868e8aSDimitry Andric   uint32_t inst = read32le(loc);
35085868e8aSDimitry Andric   // Opcode field is bits 30, 29, with 10 = movz, 00 = movn and 11 = movk.
35185868e8aSDimitry Andric   if (!(inst & (1 << 29))) {
35285868e8aSDimitry Andric     // movn or movz.
35385868e8aSDimitry Andric     if (imm & 0x10000) {
35485868e8aSDimitry Andric       // Change opcode to movn, which takes an inverted operand.
35585868e8aSDimitry Andric       imm ^= 0xFFFF;
35685868e8aSDimitry Andric       inst &= ~(1 << 30);
35785868e8aSDimitry Andric     } else {
35885868e8aSDimitry Andric       // Change opcode to movz.
35985868e8aSDimitry Andric       inst |= 1 << 30;
36085868e8aSDimitry Andric     }
36185868e8aSDimitry Andric   }
36285868e8aSDimitry Andric   write32le(loc, inst | ((imm & 0xFFFF) << 5));
36385868e8aSDimitry Andric }
36485868e8aSDimitry Andric 
3655ffd83dbSDimitry Andric void AArch64::relocate(uint8_t *loc, const Relocation &rel,
3665ffd83dbSDimitry Andric                        uint64_t val) const {
3675ffd83dbSDimitry Andric   switch (rel.type) {
3680b57cec5SDimitry Andric   case R_AARCH64_ABS16:
3690b57cec5SDimitry Andric   case R_AARCH64_PREL16:
3705ffd83dbSDimitry Andric     checkIntUInt(loc, val, 16, rel);
371fe6060f1SDimitry Andric     write16(loc, val);
3720b57cec5SDimitry Andric     break;
3730b57cec5SDimitry Andric   case R_AARCH64_ABS32:
3740b57cec5SDimitry Andric   case R_AARCH64_PREL32:
3755ffd83dbSDimitry Andric     checkIntUInt(loc, val, 32, rel);
376fe6060f1SDimitry Andric     write32(loc, val);
3775ffd83dbSDimitry Andric     break;
3785ffd83dbSDimitry Andric   case R_AARCH64_PLT32:
379*297eecfbSDimitry Andric   case R_AARCH64_GOTPCREL32:
3805ffd83dbSDimitry Andric     checkInt(loc, val, 32, rel);
381fe6060f1SDimitry Andric     write32(loc, val);
3820b57cec5SDimitry Andric     break;
3830b57cec5SDimitry Andric   case R_AARCH64_ABS64:
3845f757f3fSDimitry Andric     // AArch64 relocations to tagged symbols have extended semantics, as
3855f757f3fSDimitry Andric     // described here:
3865f757f3fSDimitry Andric     // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#841extended-semantics-of-r_aarch64_relative.
3875f757f3fSDimitry Andric     // tl;dr: encode the symbol's special addend in the place, which is an
3885f757f3fSDimitry Andric     // offset to the point where the logical tag is derived from. Quick hack, if
3895f757f3fSDimitry Andric     // the addend is within the symbol's bounds, no need to encode the tag
3905f757f3fSDimitry Andric     // derivation offset.
3915f757f3fSDimitry Andric     if (rel.sym && rel.sym->isTagged() &&
3925f757f3fSDimitry Andric         (rel.addend < 0 ||
3935f757f3fSDimitry Andric          rel.addend >= static_cast<int64_t>(rel.sym->getSize())))
3945f757f3fSDimitry Andric       write64(loc, -rel.addend);
3955f757f3fSDimitry Andric     else
3965f757f3fSDimitry Andric       write64(loc, val);
3975f757f3fSDimitry Andric     break;
3980b57cec5SDimitry Andric   case R_AARCH64_PREL64:
399fe6060f1SDimitry Andric     write64(loc, val);
4000b57cec5SDimitry Andric     break;
4010b57cec5SDimitry Andric   case R_AARCH64_ADD_ABS_LO12_NC:
4020b57cec5SDimitry Andric     or32AArch64Imm(loc, val);
4030b57cec5SDimitry Andric     break;
4040b57cec5SDimitry Andric   case R_AARCH64_ADR_GOT_PAGE:
4050b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21:
4060b57cec5SDimitry Andric   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
4070b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
4085ffd83dbSDimitry Andric     checkInt(loc, val, 33, rel);
409bdd1243dSDimitry Andric     [[fallthrough]];
4100b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21_NC:
4110b57cec5SDimitry Andric     write32AArch64Addr(loc, val >> 12);
4120b57cec5SDimitry Andric     break;
4130b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_LO21:
4145ffd83dbSDimitry Andric     checkInt(loc, val, 21, rel);
4150b57cec5SDimitry Andric     write32AArch64Addr(loc, val);
4160b57cec5SDimitry Andric     break;
4170b57cec5SDimitry Andric   case R_AARCH64_JUMP26:
4180b57cec5SDimitry Andric     // Normally we would just write the bits of the immediate field, however
4190b57cec5SDimitry Andric     // when patching instructions for the cpu errata fix -fix-cortex-a53-843419
4200b57cec5SDimitry Andric     // we want to replace a non-branch instruction with a branch immediate
4210b57cec5SDimitry Andric     // instruction. By writing all the bits of the instruction including the
4220b57cec5SDimitry Andric     // opcode and the immediate (0 001 | 01 imm26) we can do this
4230b57cec5SDimitry Andric     // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of
4240b57cec5SDimitry Andric     // the instruction we want to patch.
4250b57cec5SDimitry Andric     write32le(loc, 0x14000000);
426bdd1243dSDimitry Andric     [[fallthrough]];
4270b57cec5SDimitry Andric   case R_AARCH64_CALL26:
4285ffd83dbSDimitry Andric     checkInt(loc, val, 28, rel);
4290b57cec5SDimitry Andric     or32le(loc, (val & 0x0FFFFFFC) >> 2);
4300b57cec5SDimitry Andric     break;
4310b57cec5SDimitry Andric   case R_AARCH64_CONDBR19:
4320b57cec5SDimitry Andric   case R_AARCH64_LD_PREL_LO19:
4335ffd83dbSDimitry Andric     checkAlignment(loc, val, 4, rel);
4345ffd83dbSDimitry Andric     checkInt(loc, val, 21, rel);
4350b57cec5SDimitry Andric     or32le(loc, (val & 0x1FFFFC) << 3);
4360b57cec5SDimitry Andric     break;
4370b57cec5SDimitry Andric   case R_AARCH64_LDST8_ABS_LO12_NC:
4380b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
4390b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 0, 11));
4400b57cec5SDimitry Andric     break;
4410b57cec5SDimitry Andric   case R_AARCH64_LDST16_ABS_LO12_NC:
4420b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
4435ffd83dbSDimitry Andric     checkAlignment(loc, val, 2, rel);
4440b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 1, 11));
4450b57cec5SDimitry Andric     break;
4460b57cec5SDimitry Andric   case R_AARCH64_LDST32_ABS_LO12_NC:
4470b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
4485ffd83dbSDimitry Andric     checkAlignment(loc, val, 4, rel);
4490b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 2, 11));
4500b57cec5SDimitry Andric     break;
4510b57cec5SDimitry Andric   case R_AARCH64_LDST64_ABS_LO12_NC:
4520b57cec5SDimitry Andric   case R_AARCH64_LD64_GOT_LO12_NC:
4530b57cec5SDimitry Andric   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
4540b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
4550b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
4565ffd83dbSDimitry Andric     checkAlignment(loc, val, 8, rel);
4570b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 3, 11));
4580b57cec5SDimitry Andric     break;
4590b57cec5SDimitry Andric   case R_AARCH64_LDST128_ABS_LO12_NC:
4600b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
4615ffd83dbSDimitry Andric     checkAlignment(loc, val, 16, rel);
4620b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 4, 11));
4630b57cec5SDimitry Andric     break;
464e8d8bef9SDimitry Andric   case R_AARCH64_LD64_GOTPAGE_LO15:
465e8d8bef9SDimitry Andric     checkAlignment(loc, val, 8, rel);
466e8d8bef9SDimitry Andric     or32AArch64Imm(loc, getBits(val, 3, 14));
467e8d8bef9SDimitry Andric     break;
46885868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G0:
4695ffd83dbSDimitry Andric     checkUInt(loc, val, 16, rel);
470bdd1243dSDimitry Andric     [[fallthrough]];
4710b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G0_NC:
4720b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF) << 5);
4730b57cec5SDimitry Andric     break;
47485868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G1:
4755ffd83dbSDimitry Andric     checkUInt(loc, val, 32, rel);
476bdd1243dSDimitry Andric     [[fallthrough]];
4770b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G1_NC:
4780b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF0000) >> 11);
4790b57cec5SDimitry Andric     break;
48085868e8aSDimitry Andric   case R_AARCH64_MOVW_UABS_G2:
4815ffd83dbSDimitry Andric     checkUInt(loc, val, 48, rel);
482bdd1243dSDimitry Andric     [[fallthrough]];
4830b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G2_NC:
4840b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF00000000) >> 27);
4850b57cec5SDimitry Andric     break;
4860b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G3:
4870b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF000000000000) >> 43);
4880b57cec5SDimitry Andric     break;
48985868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G0:
49085868e8aSDimitry Andric   case R_AARCH64_MOVW_SABS_G0:
49185868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G0:
4925ffd83dbSDimitry Andric     checkInt(loc, val, 17, rel);
493bdd1243dSDimitry Andric     [[fallthrough]];
49485868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G0_NC:
49585868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
49685868e8aSDimitry Andric     writeSMovWImm(loc, val);
49785868e8aSDimitry Andric     break;
49885868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G1:
49985868e8aSDimitry Andric   case R_AARCH64_MOVW_SABS_G1:
50085868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G1:
5015ffd83dbSDimitry Andric     checkInt(loc, val, 33, rel);
502bdd1243dSDimitry Andric     [[fallthrough]];
50385868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G1_NC:
50485868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
50585868e8aSDimitry Andric     writeSMovWImm(loc, val >> 16);
50685868e8aSDimitry Andric     break;
50785868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G2:
50885868e8aSDimitry Andric   case R_AARCH64_MOVW_SABS_G2:
50985868e8aSDimitry Andric   case R_AARCH64_TLSLE_MOVW_TPREL_G2:
5105ffd83dbSDimitry Andric     checkInt(loc, val, 49, rel);
511bdd1243dSDimitry Andric     [[fallthrough]];
51285868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G2_NC:
51385868e8aSDimitry Andric     writeSMovWImm(loc, val >> 32);
51485868e8aSDimitry Andric     break;
51585868e8aSDimitry Andric   case R_AARCH64_MOVW_PREL_G3:
51685868e8aSDimitry Andric     writeSMovWImm(loc, val >> 48);
51785868e8aSDimitry Andric     break;
5180b57cec5SDimitry Andric   case R_AARCH64_TSTBR14:
5195ffd83dbSDimitry Andric     checkInt(loc, val, 16, rel);
5200b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFC) << 3);
5210b57cec5SDimitry Andric     break;
5220b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_HI12:
5235ffd83dbSDimitry Andric     checkUInt(loc, val, 24, rel);
5240b57cec5SDimitry Andric     or32AArch64Imm(loc, val >> 12);
5250b57cec5SDimitry Andric     break;
5260b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
5270b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
5280b57cec5SDimitry Andric     or32AArch64Imm(loc, val);
5290b57cec5SDimitry Andric     break;
530fe6060f1SDimitry Andric   case R_AARCH64_TLSDESC:
531fe6060f1SDimitry Andric     // For R_AARCH64_TLSDESC the addend is stored in the second 64-bit word.
532fe6060f1SDimitry Andric     write64(loc + 8, val);
533fe6060f1SDimitry Andric     break;
5340b57cec5SDimitry Andric   default:
53585868e8aSDimitry Andric     llvm_unreachable("unknown relocation");
5360b57cec5SDimitry Andric   }
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric 
5395ffd83dbSDimitry Andric void AArch64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
5405ffd83dbSDimitry Andric                              uint64_t val) const {
5410b57cec5SDimitry Andric   // TLSDESC Global-Dynamic relocation are in the form:
5420b57cec5SDimitry Andric   //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
5430b57cec5SDimitry Andric   //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
5440b57cec5SDimitry Andric   //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
5450b57cec5SDimitry Andric   //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
5460b57cec5SDimitry Andric   //   blr     x1
5470b57cec5SDimitry Andric   // And it can optimized to:
5480b57cec5SDimitry Andric   //   movz    x0, #0x0, lsl #16
5490b57cec5SDimitry Andric   //   movk    x0, #0x10
5500b57cec5SDimitry Andric   //   nop
5510b57cec5SDimitry Andric   //   nop
5525ffd83dbSDimitry Andric   checkUInt(loc, val, 32, rel);
5530b57cec5SDimitry Andric 
5545ffd83dbSDimitry Andric   switch (rel.type) {
5550b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
5560b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_CALL:
5570b57cec5SDimitry Andric     write32le(loc, 0xd503201f); // nop
5580b57cec5SDimitry Andric     return;
5590b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
5600b57cec5SDimitry Andric     write32le(loc, 0xd2a00000 | (((val >> 16) & 0xffff) << 5)); // movz
5610b57cec5SDimitry Andric     return;
5620b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
5630b57cec5SDimitry Andric     write32le(loc, 0xf2800000 | ((val & 0xffff) << 5)); // movk
5640b57cec5SDimitry Andric     return;
5650b57cec5SDimitry Andric   default:
5660b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
5670b57cec5SDimitry Andric   }
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric 
5705ffd83dbSDimitry Andric void AArch64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
5715ffd83dbSDimitry Andric                              uint64_t val) const {
5720b57cec5SDimitry Andric   // TLSDESC Global-Dynamic relocation are in the form:
5730b57cec5SDimitry Andric   //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
5740b57cec5SDimitry Andric   //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
5750b57cec5SDimitry Andric   //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
5760b57cec5SDimitry Andric   //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
5770b57cec5SDimitry Andric   //   blr     x1
5780b57cec5SDimitry Andric   // And it can optimized to:
5790b57cec5SDimitry Andric   //   adrp    x0, :gottprel:v
5800b57cec5SDimitry Andric   //   ldr     x0, [x0, :gottprel_lo12:v]
5810b57cec5SDimitry Andric   //   nop
5820b57cec5SDimitry Andric   //   nop
5830b57cec5SDimitry Andric 
5845ffd83dbSDimitry Andric   switch (rel.type) {
5850b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
5860b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_CALL:
5870b57cec5SDimitry Andric     write32le(loc, 0xd503201f); // nop
5880b57cec5SDimitry Andric     break;
5890b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
5900b57cec5SDimitry Andric     write32le(loc, 0x90000000); // adrp
5915ffd83dbSDimitry Andric     relocateNoSym(loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, val);
5920b57cec5SDimitry Andric     break;
5930b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
5940b57cec5SDimitry Andric     write32le(loc, 0xf9400000); // ldr
5955ffd83dbSDimitry Andric     relocateNoSym(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val);
5960b57cec5SDimitry Andric     break;
5970b57cec5SDimitry Andric   default:
5980b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
5990b57cec5SDimitry Andric   }
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric 
6025ffd83dbSDimitry Andric void AArch64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
6035ffd83dbSDimitry Andric                              uint64_t val) const {
6045ffd83dbSDimitry Andric   checkUInt(loc, val, 32, rel);
6050b57cec5SDimitry Andric 
6065ffd83dbSDimitry Andric   if (rel.type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
6070b57cec5SDimitry Andric     // Generate MOVZ.
6080b57cec5SDimitry Andric     uint32_t regNo = read32le(loc) & 0x1f;
6090b57cec5SDimitry Andric     write32le(loc, (0xd2a00000 | regNo) | (((val >> 16) & 0xffff) << 5));
6100b57cec5SDimitry Andric     return;
6110b57cec5SDimitry Andric   }
6125ffd83dbSDimitry Andric   if (rel.type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
6130b57cec5SDimitry Andric     // Generate MOVK.
6140b57cec5SDimitry Andric     uint32_t regNo = read32le(loc) & 0x1f;
6150b57cec5SDimitry Andric     write32le(loc, (0xf2800000 | regNo) | ((val & 0xffff) << 5));
6160b57cec5SDimitry Andric     return;
6170b57cec5SDimitry Andric   }
6180b57cec5SDimitry Andric   llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
6190b57cec5SDimitry Andric }
6200b57cec5SDimitry Andric 
62104eeddc0SDimitry Andric AArch64Relaxer::AArch64Relaxer(ArrayRef<Relocation> relocs) {
622bdd1243dSDimitry Andric   if (!config->relax)
62304eeddc0SDimitry Andric     return;
62404eeddc0SDimitry Andric   // Check if R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC
62504eeddc0SDimitry Andric   // always appear in pairs.
62604eeddc0SDimitry Andric   size_t i = 0;
62704eeddc0SDimitry Andric   const size_t size = relocs.size();
62804eeddc0SDimitry Andric   for (; i != size; ++i) {
62904eeddc0SDimitry Andric     if (relocs[i].type == R_AARCH64_ADR_GOT_PAGE) {
63004eeddc0SDimitry Andric       if (i + 1 < size && relocs[i + 1].type == R_AARCH64_LD64_GOT_LO12_NC) {
63104eeddc0SDimitry Andric         ++i;
63204eeddc0SDimitry Andric         continue;
63304eeddc0SDimitry Andric       }
63404eeddc0SDimitry Andric       break;
63504eeddc0SDimitry Andric     } else if (relocs[i].type == R_AARCH64_LD64_GOT_LO12_NC) {
63604eeddc0SDimitry Andric       break;
63704eeddc0SDimitry Andric     }
63804eeddc0SDimitry Andric   }
63904eeddc0SDimitry Andric   safeToRelaxAdrpLdr = i == size;
64004eeddc0SDimitry Andric }
64104eeddc0SDimitry Andric 
6421fd87a68SDimitry Andric bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel,
6431fd87a68SDimitry Andric                                      const Relocation &addRel, uint64_t secAddr,
6441fd87a68SDimitry Andric                                      uint8_t *buf) const {
6451fd87a68SDimitry Andric   // When the address of sym is within the range of ADR then
6461fd87a68SDimitry Andric   // we may relax
6471fd87a68SDimitry Andric   // ADRP xn, sym
6481fd87a68SDimitry Andric   // ADD  xn, xn, :lo12: sym
6491fd87a68SDimitry Andric   // to
6501fd87a68SDimitry Andric   // NOP
6511fd87a68SDimitry Andric   // ADR xn, sym
6521fd87a68SDimitry Andric   if (!config->relax || adrpRel.type != R_AARCH64_ADR_PREL_PG_HI21 ||
6531fd87a68SDimitry Andric       addRel.type != R_AARCH64_ADD_ABS_LO12_NC)
6541fd87a68SDimitry Andric     return false;
6551fd87a68SDimitry Andric   // Check if the relocations apply to consecutive instructions.
6561fd87a68SDimitry Andric   if (adrpRel.offset + 4 != addRel.offset)
6571fd87a68SDimitry Andric     return false;
6581fd87a68SDimitry Andric   if (adrpRel.sym != addRel.sym)
6591fd87a68SDimitry Andric     return false;
6601fd87a68SDimitry Andric   if (adrpRel.addend != 0 || addRel.addend != 0)
6611fd87a68SDimitry Andric     return false;
6621fd87a68SDimitry Andric 
6631fd87a68SDimitry Andric   uint32_t adrpInstr = read32le(buf + adrpRel.offset);
6641fd87a68SDimitry Andric   uint32_t addInstr = read32le(buf + addRel.offset);
6651fd87a68SDimitry Andric   // Check if the first instruction is ADRP and the second instruction is ADD.
6661fd87a68SDimitry Andric   if ((adrpInstr & 0x9f000000) != 0x90000000 ||
6671fd87a68SDimitry Andric       (addInstr & 0xffc00000) != 0x91000000)
6681fd87a68SDimitry Andric     return false;
6691fd87a68SDimitry Andric   uint32_t adrpDestReg = adrpInstr & 0x1f;
6701fd87a68SDimitry Andric   uint32_t addDestReg = addInstr & 0x1f;
6711fd87a68SDimitry Andric   uint32_t addSrcReg = (addInstr >> 5) & 0x1f;
6721fd87a68SDimitry Andric   if (adrpDestReg != addDestReg || adrpDestReg != addSrcReg)
6731fd87a68SDimitry Andric     return false;
6741fd87a68SDimitry Andric 
6751fd87a68SDimitry Andric   Symbol &sym = *adrpRel.sym;
6761fd87a68SDimitry Andric   // Check if the address difference is within 1MiB range.
6771fd87a68SDimitry Andric   int64_t val = sym.getVA() - (secAddr + addRel.offset);
6781fd87a68SDimitry Andric   if (val < -1024 * 1024 || val >= 1024 * 1024)
6791fd87a68SDimitry Andric     return false;
6801fd87a68SDimitry Andric 
6811fd87a68SDimitry Andric   Relocation adrRel = {R_ABS, R_AARCH64_ADR_PREL_LO21, addRel.offset,
6821fd87a68SDimitry Andric                        /*addend=*/0, &sym};
6831fd87a68SDimitry Andric   // nop
6841fd87a68SDimitry Andric   write32le(buf + adrpRel.offset, 0xd503201f);
6851fd87a68SDimitry Andric   // adr x_<dest_reg>
6861fd87a68SDimitry Andric   write32le(buf + adrRel.offset, 0x10000000 | adrpDestReg);
6871fd87a68SDimitry Andric   target->relocate(buf + adrRel.offset, adrRel, val);
6881fd87a68SDimitry Andric   return true;
6891fd87a68SDimitry Andric }
6901fd87a68SDimitry Andric 
69104eeddc0SDimitry Andric bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
69204eeddc0SDimitry Andric                                      const Relocation &ldrRel, uint64_t secAddr,
69304eeddc0SDimitry Andric                                      uint8_t *buf) const {
69404eeddc0SDimitry Andric   if (!safeToRelaxAdrpLdr)
69504eeddc0SDimitry Andric     return false;
69604eeddc0SDimitry Andric 
69704eeddc0SDimitry Andric   // When the definition of sym is not preemptible then we may
69804eeddc0SDimitry Andric   // be able to relax
69904eeddc0SDimitry Andric   // ADRP xn, :got: sym
70004eeddc0SDimitry Andric   // LDR xn, [ xn :got_lo12: sym]
70104eeddc0SDimitry Andric   // to
70204eeddc0SDimitry Andric   // ADRP xn, sym
70304eeddc0SDimitry Andric   // ADD xn, xn, :lo_12: sym
70404eeddc0SDimitry Andric 
70504eeddc0SDimitry Andric   if (adrpRel.type != R_AARCH64_ADR_GOT_PAGE ||
70604eeddc0SDimitry Andric       ldrRel.type != R_AARCH64_LD64_GOT_LO12_NC)
70704eeddc0SDimitry Andric     return false;
70804eeddc0SDimitry Andric   // Check if the relocations apply to consecutive instructions.
70904eeddc0SDimitry Andric   if (adrpRel.offset + 4 != ldrRel.offset)
71004eeddc0SDimitry Andric     return false;
71104eeddc0SDimitry Andric   // Check if the relocations reference the same symbol and
71204eeddc0SDimitry Andric   // skip undefined, preemptible and STT_GNU_IFUNC symbols.
71304eeddc0SDimitry Andric   if (!adrpRel.sym || adrpRel.sym != ldrRel.sym || !adrpRel.sym->isDefined() ||
71404eeddc0SDimitry Andric       adrpRel.sym->isPreemptible || adrpRel.sym->isGnuIFunc())
71504eeddc0SDimitry Andric     return false;
71604eeddc0SDimitry Andric   // Check if the addends of the both relocations are zero.
71704eeddc0SDimitry Andric   if (adrpRel.addend != 0 || ldrRel.addend != 0)
71804eeddc0SDimitry Andric     return false;
71904eeddc0SDimitry Andric   uint32_t adrpInstr = read32le(buf + adrpRel.offset);
72004eeddc0SDimitry Andric   uint32_t ldrInstr = read32le(buf + ldrRel.offset);
72104eeddc0SDimitry Andric   // Check if the first instruction is ADRP and the second instruction is LDR.
72204eeddc0SDimitry Andric   if ((adrpInstr & 0x9f000000) != 0x90000000 ||
72304eeddc0SDimitry Andric       (ldrInstr & 0x3b000000) != 0x39000000)
72404eeddc0SDimitry Andric     return false;
72504eeddc0SDimitry Andric   // Check the value of the sf bit.
72604eeddc0SDimitry Andric   if (!(ldrInstr >> 31))
72704eeddc0SDimitry Andric     return false;
72804eeddc0SDimitry Andric   uint32_t adrpDestReg = adrpInstr & 0x1f;
72904eeddc0SDimitry Andric   uint32_t ldrDestReg = ldrInstr & 0x1f;
73004eeddc0SDimitry Andric   uint32_t ldrSrcReg = (ldrInstr >> 5) & 0x1f;
73104eeddc0SDimitry Andric   // Check if ADPR and LDR use the same register.
73204eeddc0SDimitry Andric   if (adrpDestReg != ldrDestReg || adrpDestReg != ldrSrcReg)
73304eeddc0SDimitry Andric     return false;
73404eeddc0SDimitry Andric 
73504eeddc0SDimitry Andric   Symbol &sym = *adrpRel.sym;
73681ad6265SDimitry Andric   // GOT references to absolute symbols can't be relaxed to use ADRP/ADD in
73781ad6265SDimitry Andric   // position-independent code because these instructions produce a relative
73881ad6265SDimitry Andric   // address.
73981ad6265SDimitry Andric   if (config->isPic && !cast<Defined>(sym).section)
74081ad6265SDimitry Andric     return false;
74104eeddc0SDimitry Andric   // Check if the address difference is within 4GB range.
74204eeddc0SDimitry Andric   int64_t val =
74304eeddc0SDimitry Andric       getAArch64Page(sym.getVA()) - getAArch64Page(secAddr + adrpRel.offset);
74404eeddc0SDimitry Andric   if (val != llvm::SignExtend64(val, 33))
74504eeddc0SDimitry Andric     return false;
74604eeddc0SDimitry Andric 
74704eeddc0SDimitry Andric   Relocation adrpSymRel = {R_AARCH64_PAGE_PC, R_AARCH64_ADR_PREL_PG_HI21,
74804eeddc0SDimitry Andric                            adrpRel.offset, /*addend=*/0, &sym};
74904eeddc0SDimitry Andric   Relocation addRel = {R_ABS, R_AARCH64_ADD_ABS_LO12_NC, ldrRel.offset,
75004eeddc0SDimitry Andric                        /*addend=*/0, &sym};
75104eeddc0SDimitry Andric 
75204eeddc0SDimitry Andric   // adrp x_<dest_reg>
75304eeddc0SDimitry Andric   write32le(buf + adrpSymRel.offset, 0x90000000 | adrpDestReg);
75404eeddc0SDimitry Andric   // add x_<dest reg>, x_<dest reg>
75504eeddc0SDimitry Andric   write32le(buf + addRel.offset, 0x91000000 | adrpDestReg | (adrpDestReg << 5));
75604eeddc0SDimitry Andric 
75704eeddc0SDimitry Andric   target->relocate(buf + adrpSymRel.offset, adrpSymRel,
75804eeddc0SDimitry Andric                    SignExtend64(getAArch64Page(sym.getVA()) -
75904eeddc0SDimitry Andric                                     getAArch64Page(secAddr + adrpSymRel.offset),
76004eeddc0SDimitry Andric                                 64));
76104eeddc0SDimitry Andric   target->relocate(buf + addRel.offset, addRel, SignExtend64(sym.getVA(), 64));
7621fd87a68SDimitry Andric   tryRelaxAdrpAdd(adrpSymRel, addRel, secAddr, buf);
76304eeddc0SDimitry Andric   return true;
76404eeddc0SDimitry Andric }
76504eeddc0SDimitry Andric 
7665f757f3fSDimitry Andric // Tagged symbols have upper address bits that are added by the dynamic loader,
7675f757f3fSDimitry Andric // and thus need the full 64-bit GOT entry. Do not relax such symbols.
7685f757f3fSDimitry Andric static bool needsGotForMemtag(const Relocation &rel) {
7695f757f3fSDimitry Andric   return rel.sym->isTagged() && needsGot(rel.expr);
7705f757f3fSDimitry Andric }
7715f757f3fSDimitry Andric 
772bdd1243dSDimitry Andric void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
773bdd1243dSDimitry Andric   uint64_t secAddr = sec.getOutputSection()->addr;
774bdd1243dSDimitry Andric   if (auto *s = dyn_cast<InputSection>(&sec))
775bdd1243dSDimitry Andric     secAddr += s->outSecOff;
7765f757f3fSDimitry Andric   else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
7775f757f3fSDimitry Andric     secAddr += ehIn->getParent()->outSecOff;
778bdd1243dSDimitry Andric   AArch64Relaxer relaxer(sec.relocs());
779bdd1243dSDimitry Andric   for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
780bdd1243dSDimitry Andric     const Relocation &rel = sec.relocs()[i];
781bdd1243dSDimitry Andric     uint8_t *loc = buf + rel.offset;
782bdd1243dSDimitry Andric     const uint64_t val =
783bdd1243dSDimitry Andric         sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
784bdd1243dSDimitry Andric                              secAddr + rel.offset, *rel.sym, rel.expr);
7855f757f3fSDimitry Andric 
7865f757f3fSDimitry Andric     if (needsGotForMemtag(rel)) {
7875f757f3fSDimitry Andric       relocate(loc, rel, val);
7885f757f3fSDimitry Andric       continue;
7895f757f3fSDimitry Andric     }
7905f757f3fSDimitry Andric 
791bdd1243dSDimitry Andric     switch (rel.expr) {
792bdd1243dSDimitry Andric     case R_AARCH64_GOT_PAGE_PC:
793bdd1243dSDimitry Andric       if (i + 1 < size &&
794bdd1243dSDimitry Andric           relaxer.tryRelaxAdrpLdr(rel, sec.relocs()[i + 1], secAddr, buf)) {
795bdd1243dSDimitry Andric         ++i;
796bdd1243dSDimitry Andric         continue;
797bdd1243dSDimitry Andric       }
798bdd1243dSDimitry Andric       break;
799bdd1243dSDimitry Andric     case R_AARCH64_PAGE_PC:
800bdd1243dSDimitry Andric       if (i + 1 < size &&
801bdd1243dSDimitry Andric           relaxer.tryRelaxAdrpAdd(rel, sec.relocs()[i + 1], secAddr, buf)) {
802bdd1243dSDimitry Andric         ++i;
803bdd1243dSDimitry Andric         continue;
804bdd1243dSDimitry Andric       }
805bdd1243dSDimitry Andric       break;
806bdd1243dSDimitry Andric     case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
807bdd1243dSDimitry Andric     case R_RELAX_TLS_GD_TO_IE_ABS:
808bdd1243dSDimitry Andric       relaxTlsGdToIe(loc, rel, val);
809bdd1243dSDimitry Andric       continue;
810bdd1243dSDimitry Andric     case R_RELAX_TLS_GD_TO_LE:
811bdd1243dSDimitry Andric       relaxTlsGdToLe(loc, rel, val);
812bdd1243dSDimitry Andric       continue;
813bdd1243dSDimitry Andric     case R_RELAX_TLS_IE_TO_LE:
814bdd1243dSDimitry Andric       relaxTlsIeToLe(loc, rel, val);
815bdd1243dSDimitry Andric       continue;
816bdd1243dSDimitry Andric     default:
817bdd1243dSDimitry Andric       break;
818bdd1243dSDimitry Andric     }
819bdd1243dSDimitry Andric     relocate(loc, rel, val);
820bdd1243dSDimitry Andric   }
821bdd1243dSDimitry Andric }
822bdd1243dSDimitry Andric 
8230b57cec5SDimitry Andric // AArch64 may use security features in variant PLT sequences. These are:
8240b57cec5SDimitry Andric // Pointer Authentication (PAC), introduced in armv8.3-a and Branch Target
8250b57cec5SDimitry Andric // Indicator (BTI) introduced in armv8.5-a. The additional instructions used
8260b57cec5SDimitry Andric // in the variant Plt sequences are encoded in the Hint space so they can be
8270b57cec5SDimitry Andric // deployed on older architectures, which treat the instructions as a nop.
8280b57cec5SDimitry Andric // PAC and BTI can be combined leading to the following combinations:
8290b57cec5SDimitry Andric // writePltHeader
8300b57cec5SDimitry Andric // writePltHeaderBti (no PAC Header needed)
8310b57cec5SDimitry Andric // writePlt
8320b57cec5SDimitry Andric // writePltBti (BTI only)
8330b57cec5SDimitry Andric // writePltPac (PAC only)
8340b57cec5SDimitry Andric // writePltBtiPac (BTI and PAC)
8350b57cec5SDimitry Andric //
8360b57cec5SDimitry Andric // When PAC is enabled the dynamic loader encrypts the address that it places
8370b57cec5SDimitry Andric // in the .got.plt using the pacia1716 instruction which encrypts the value in
8380b57cec5SDimitry Andric // x17 using the modifier in x16. The static linker places autia1716 before the
8390b57cec5SDimitry Andric // indirect branch to x17 to authenticate the address in x17 with the modifier
8400b57cec5SDimitry Andric // in x16. This makes it more difficult for an attacker to modify the value in
8410b57cec5SDimitry Andric // the .got.plt.
8420b57cec5SDimitry Andric //
8430b57cec5SDimitry Andric // When BTI is enabled all indirect branches must land on a bti instruction.
8440b57cec5SDimitry Andric // The static linker must place a bti instruction at the start of any PLT entry
8450b57cec5SDimitry Andric // that may be the target of an indirect branch. As the PLT entries call the
8460b57cec5SDimitry Andric // lazy resolver indirectly this must have a bti instruction at start. In
8470b57cec5SDimitry Andric // general a bti instruction is not needed for a PLT entry as indirect calls
8480b57cec5SDimitry Andric // are resolved to the function address and not the PLT entry for the function.
8490b57cec5SDimitry Andric // There are a small number of cases where the PLT address can escape, such as
8500b57cec5SDimitry Andric // taking the address of a function or ifunc via a non got-generating
8510b57cec5SDimitry Andric // relocation, and a shared library refers to that symbol.
8520b57cec5SDimitry Andric //
8530b57cec5SDimitry Andric // We use the bti c variant of the instruction which permits indirect branches
8540b57cec5SDimitry Andric // (br) via x16/x17 and indirect function calls (blr) via any register. The ABI
8550b57cec5SDimitry Andric // guarantees that all indirect branches from code requiring BTI protection
8560b57cec5SDimitry Andric // will go via x16/x17
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric namespace {
8590b57cec5SDimitry Andric class AArch64BtiPac final : public AArch64 {
8600b57cec5SDimitry Andric public:
8610b57cec5SDimitry Andric   AArch64BtiPac();
8620b57cec5SDimitry Andric   void writePltHeader(uint8_t *buf) const override;
863480093f4SDimitry Andric   void writePlt(uint8_t *buf, const Symbol &sym,
864480093f4SDimitry Andric                 uint64_t pltEntryAddr) const override;
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric private:
867349cc55cSDimitry Andric   bool btiHeader; // bti instruction needed in PLT Header and Entry
8680b57cec5SDimitry Andric   bool pacEntry;  // autia1716 instruction needed in PLT Entry
8690b57cec5SDimitry Andric };
8700b57cec5SDimitry Andric } // namespace
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric AArch64BtiPac::AArch64BtiPac() {
8730b57cec5SDimitry Andric   btiHeader = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
8740b57cec5SDimitry Andric   // A BTI (Branch Target Indicator) Plt Entry is only required if the
8750b57cec5SDimitry Andric   // address of the PLT entry can be taken by the program, which permits an
8760b57cec5SDimitry Andric   // indirect jump to the PLT entry. This can happen when the address
8770b57cec5SDimitry Andric   // of the PLT entry for a function is canonicalised due to the address of
878349cc55cSDimitry Andric   // the function in an executable being taken by a shared library, or
879349cc55cSDimitry Andric   // non-preemptible ifunc referenced by non-GOT-generating, non-PLT-generating
880349cc55cSDimitry Andric   // relocations.
8815ffd83dbSDimitry Andric   // The PAC PLT entries require dynamic loader support and this isn't known
8825ffd83dbSDimitry Andric   // from properties in the objects, so we use the command line flag.
8835ffd83dbSDimitry Andric   pacEntry = config->zPacPlt;
8840b57cec5SDimitry Andric 
885349cc55cSDimitry Andric   if (btiHeader || pacEntry) {
8860b57cec5SDimitry Andric     pltEntrySize = 24;
887480093f4SDimitry Andric     ipltEntrySize = 24;
888480093f4SDimitry Andric   }
8890b57cec5SDimitry Andric }
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric void AArch64BtiPac::writePltHeader(uint8_t *buf) const {
8920b57cec5SDimitry Andric   const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
8930b57cec5SDimitry Andric   const uint8_t pltData[] = {
8940b57cec5SDimitry Andric       0xf0, 0x7b, 0xbf, 0xa9, // stp    x16, x30, [sp,#-16]!
895bdd1243dSDimitry Andric       0x10, 0x00, 0x00, 0x90, // adrp   x16, Page(&(.got.plt[2]))
896bdd1243dSDimitry Andric       0x11, 0x02, 0x40, 0xf9, // ldr    x17, [x16, Offset(&(.got.plt[2]))]
897bdd1243dSDimitry Andric       0x10, 0x02, 0x00, 0x91, // add    x16, x16, Offset(&(.got.plt[2]))
8980b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6, // br     x17
8990b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5, // nop
9000b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5  // nop
9010b57cec5SDimitry Andric   };
9020b57cec5SDimitry Andric   const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric   uint64_t got = in.gotPlt->getVA();
9050b57cec5SDimitry Andric   uint64_t plt = in.plt->getVA();
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric   if (btiHeader) {
9080b57cec5SDimitry Andric     // PltHeader is called indirectly by plt[N]. Prefix pltData with a BTI C
9090b57cec5SDimitry Andric     // instruction.
9100b57cec5SDimitry Andric     memcpy(buf, btiData, sizeof(btiData));
9110b57cec5SDimitry Andric     buf += sizeof(btiData);
9120b57cec5SDimitry Andric     plt += sizeof(btiData);
9130b57cec5SDimitry Andric   }
9140b57cec5SDimitry Andric   memcpy(buf, pltData, sizeof(pltData));
9150b57cec5SDimitry Andric 
9165ffd83dbSDimitry Andric   relocateNoSym(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
9170b57cec5SDimitry Andric                 getAArch64Page(got + 16) - getAArch64Page(plt + 8));
9185ffd83dbSDimitry Andric   relocateNoSym(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
9195ffd83dbSDimitry Andric   relocateNoSym(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
9200b57cec5SDimitry Andric   if (!btiHeader)
9210b57cec5SDimitry Andric     // We didn't add the BTI c instruction so round out size with NOP.
9220b57cec5SDimitry Andric     memcpy(buf + sizeof(pltData), nopData, sizeof(nopData));
9230b57cec5SDimitry Andric }
9240b57cec5SDimitry Andric 
925480093f4SDimitry Andric void AArch64BtiPac::writePlt(uint8_t *buf, const Symbol &sym,
926480093f4SDimitry Andric                              uint64_t pltEntryAddr) const {
9270b57cec5SDimitry Andric   // The PLT entry is of the form:
9280b57cec5SDimitry Andric   // [btiData] addrInst (pacBr | stdBr) [nopData]
9290b57cec5SDimitry Andric   const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
9300b57cec5SDimitry Andric   const uint8_t addrInst[] = {
931bdd1243dSDimitry Andric       0x10, 0x00, 0x00, 0x90,  // adrp x16, Page(&(.got.plt[n]))
932bdd1243dSDimitry Andric       0x11, 0x02, 0x40, 0xf9,  // ldr  x17, [x16, Offset(&(.got.plt[n]))]
933bdd1243dSDimitry Andric       0x10, 0x02, 0x00, 0x91   // add  x16, x16, Offset(&(.got.plt[n]))
9340b57cec5SDimitry Andric   };
9350b57cec5SDimitry Andric   const uint8_t pacBr[] = {
9360b57cec5SDimitry Andric       0x9f, 0x21, 0x03, 0xd5,  // autia1716
9370b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6   // br   x17
9380b57cec5SDimitry Andric   };
9390b57cec5SDimitry Andric   const uint8_t stdBr[] = {
9400b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6,  // br   x17
9410b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5   // nop
9420b57cec5SDimitry Andric   };
9430b57cec5SDimitry Andric   const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
9440b57cec5SDimitry Andric 
945bdd1243dSDimitry Andric   // NEEDS_COPY indicates a non-ifunc canonical PLT entry whose address may
946349cc55cSDimitry Andric   // escape to shared objects. isInIplt indicates a non-preemptible ifunc. Its
94706c3fb27SDimitry Andric   // address may escape if referenced by a direct relocation. If relative
94806c3fb27SDimitry Andric   // vtables are used then if the vtable is in a shared object the offsets will
94906c3fb27SDimitry Andric   // be to the PLT entry. The condition is conservative.
95006c3fb27SDimitry Andric   bool hasBti = btiHeader &&
95106c3fb27SDimitry Andric                 (sym.hasFlag(NEEDS_COPY) || sym.isInIplt || sym.thunkAccessed);
952349cc55cSDimitry Andric   if (hasBti) {
9530b57cec5SDimitry Andric     memcpy(buf, btiData, sizeof(btiData));
9540b57cec5SDimitry Andric     buf += sizeof(btiData);
9550b57cec5SDimitry Andric     pltEntryAddr += sizeof(btiData);
9560b57cec5SDimitry Andric   }
9570b57cec5SDimitry Andric 
958480093f4SDimitry Andric   uint64_t gotPltEntryAddr = sym.getGotPltVA();
9590b57cec5SDimitry Andric   memcpy(buf, addrInst, sizeof(addrInst));
9605ffd83dbSDimitry Andric   relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
9615ffd83dbSDimitry Andric                 getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
9625ffd83dbSDimitry Andric   relocateNoSym(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
9635ffd83dbSDimitry Andric   relocateNoSym(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
9640b57cec5SDimitry Andric 
9650b57cec5SDimitry Andric   if (pacEntry)
9660b57cec5SDimitry Andric     memcpy(buf + sizeof(addrInst), pacBr, sizeof(pacBr));
9670b57cec5SDimitry Andric   else
9680b57cec5SDimitry Andric     memcpy(buf + sizeof(addrInst), stdBr, sizeof(stdBr));
969349cc55cSDimitry Andric   if (!hasBti)
9700b57cec5SDimitry Andric     // We didn't add the BTI c instruction so round out size with NOP.
9710b57cec5SDimitry Andric     memcpy(buf + sizeof(addrInst) + sizeof(stdBr), nopData, sizeof(nopData));
9720b57cec5SDimitry Andric }
9730b57cec5SDimitry Andric 
9740b57cec5SDimitry Andric static TargetInfo *getTargetInfo() {
97561cfbce3SDimitry Andric   if ((config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ||
97661cfbce3SDimitry Andric       config->zPacPlt) {
9770b57cec5SDimitry Andric     static AArch64BtiPac t;
9780b57cec5SDimitry Andric     return &t;
9790b57cec5SDimitry Andric   }
9800b57cec5SDimitry Andric   static AArch64 t;
9810b57cec5SDimitry Andric   return &t;
9820b57cec5SDimitry Andric }
9830b57cec5SDimitry Andric 
9845ffd83dbSDimitry Andric TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); }
9855f757f3fSDimitry Andric 
9865f757f3fSDimitry Andric template <class ELFT>
9875f757f3fSDimitry Andric static void
9885f757f3fSDimitry Andric addTaggedSymbolReferences(InputSectionBase &sec,
9895f757f3fSDimitry Andric                           DenseMap<Symbol *, unsigned> &referenceCount) {
9905f757f3fSDimitry Andric   assert(sec.type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC);
9915f757f3fSDimitry Andric 
9925f757f3fSDimitry Andric   const RelsOrRelas<ELFT> rels = sec.relsOrRelas<ELFT>();
9935f757f3fSDimitry Andric   if (rels.areRelocsRel())
9945f757f3fSDimitry Andric     error("non-RELA relocations are not allowed with memtag globals");
9955f757f3fSDimitry Andric 
9965f757f3fSDimitry Andric   for (const typename ELFT::Rela &rel : rels.relas) {
9975f757f3fSDimitry Andric     Symbol &sym = sec.getFile<ELFT>()->getRelocTargetSym(rel);
9985f757f3fSDimitry Andric     // Linker-synthesized symbols such as __executable_start may be referenced
9995f757f3fSDimitry Andric     // as tagged in input objfiles, and we don't want them to be tagged. A
10005f757f3fSDimitry Andric     // cheap way to exclude them is the type check, but their type is
10015f757f3fSDimitry Andric     // STT_NOTYPE. In addition, this save us from checking untaggable symbols,
10025f757f3fSDimitry Andric     // like functions or TLS symbols.
10035f757f3fSDimitry Andric     if (sym.type != STT_OBJECT)
10045f757f3fSDimitry Andric       continue;
10055f757f3fSDimitry Andric     // STB_LOCAL symbols can't be referenced from outside the object file, and
10065f757f3fSDimitry Andric     // thus don't need to be checked for references from other object files.
10075f757f3fSDimitry Andric     if (sym.binding == STB_LOCAL) {
10085f757f3fSDimitry Andric       sym.setIsTagged(true);
10095f757f3fSDimitry Andric       continue;
10105f757f3fSDimitry Andric     }
10115f757f3fSDimitry Andric     ++referenceCount[&sym];
10125f757f3fSDimitry Andric   }
10135f757f3fSDimitry Andric   sec.markDead();
10145f757f3fSDimitry Andric }
10155f757f3fSDimitry Andric 
10165f757f3fSDimitry Andric // A tagged symbol must be denoted as being tagged by all references and the
10175f757f3fSDimitry Andric // chosen definition. For simplicity, here, it must also be denoted as tagged
10185f757f3fSDimitry Andric // for all definitions. Otherwise:
10195f757f3fSDimitry Andric //
10205f757f3fSDimitry Andric //  1. A tagged definition can be used by an untagged declaration, in which case
10215f757f3fSDimitry Andric //     the untagged access may be PC-relative, causing a tag mismatch at
10225f757f3fSDimitry Andric //     runtime.
10235f757f3fSDimitry Andric //  2. An untagged definition can be used by a tagged declaration, where the
10245f757f3fSDimitry Andric //     compiler has taken advantage of the increased alignment of the tagged
10255f757f3fSDimitry Andric //     declaration, but the alignment at runtime is wrong, causing a fault.
10265f757f3fSDimitry Andric //
10275f757f3fSDimitry Andric // Ideally, this isn't a problem, as any TU that imports or exports tagged
10285f757f3fSDimitry Andric // symbols should also be built with tagging. But, to handle these cases, we
10295f757f3fSDimitry Andric // demote the symbol to be untagged.
10305f757f3fSDimitry Andric void lld::elf::createTaggedSymbols(const SmallVector<ELFFileBase *, 0> &files) {
10311db9f3b2SDimitry Andric   assert(hasMemtag());
10325f757f3fSDimitry Andric 
10335f757f3fSDimitry Andric   // First, collect all symbols that are marked as tagged, and count how many
10345f757f3fSDimitry Andric   // times they're marked as tagged.
10355f757f3fSDimitry Andric   DenseMap<Symbol *, unsigned> taggedSymbolReferenceCount;
10365f757f3fSDimitry Andric   for (InputFile* file : files) {
10375f757f3fSDimitry Andric     if (file->kind() != InputFile::ObjKind)
10385f757f3fSDimitry Andric       continue;
10395f757f3fSDimitry Andric     for (InputSectionBase *section : file->getSections()) {
10405f757f3fSDimitry Andric       if (!section || section->type != SHT_AARCH64_MEMTAG_GLOBALS_STATIC ||
10415f757f3fSDimitry Andric           section == &InputSection::discarded)
10425f757f3fSDimitry Andric         continue;
10435f757f3fSDimitry Andric       invokeELFT(addTaggedSymbolReferences, *section,
10445f757f3fSDimitry Andric                  taggedSymbolReferenceCount);
10455f757f3fSDimitry Andric     }
10465f757f3fSDimitry Andric   }
10475f757f3fSDimitry Andric 
10485f757f3fSDimitry Andric   // Now, go through all the symbols. If the number of declarations +
10495f757f3fSDimitry Andric   // definitions to a symbol exceeds the amount of times they're marked as
10505f757f3fSDimitry Andric   // tagged, it means we have an objfile that uses the untagged variant of the
10515f757f3fSDimitry Andric   // symbol.
10525f757f3fSDimitry Andric   for (InputFile *file : files) {
10535f757f3fSDimitry Andric     if (file->kind() != InputFile::BinaryKind &&
10545f757f3fSDimitry Andric         file->kind() != InputFile::ObjKind)
10555f757f3fSDimitry Andric       continue;
10565f757f3fSDimitry Andric 
10575f757f3fSDimitry Andric     for (Symbol *symbol : file->getSymbols()) {
10585f757f3fSDimitry Andric       // See `addTaggedSymbolReferences` for more details.
10595f757f3fSDimitry Andric       if (symbol->type != STT_OBJECT ||
10605f757f3fSDimitry Andric           symbol->binding == STB_LOCAL)
10615f757f3fSDimitry Andric         continue;
10625f757f3fSDimitry Andric       auto it = taggedSymbolReferenceCount.find(symbol);
10635f757f3fSDimitry Andric       if (it == taggedSymbolReferenceCount.end()) continue;
10645f757f3fSDimitry Andric       unsigned &remainingAllowedTaggedRefs = it->second;
10655f757f3fSDimitry Andric       if (remainingAllowedTaggedRefs == 0) {
10665f757f3fSDimitry Andric         taggedSymbolReferenceCount.erase(it);
10675f757f3fSDimitry Andric         continue;
10685f757f3fSDimitry Andric       }
10695f757f3fSDimitry Andric       --remainingAllowedTaggedRefs;
10705f757f3fSDimitry Andric     }
10715f757f3fSDimitry Andric   }
10725f757f3fSDimitry Andric 
10735f757f3fSDimitry Andric   // `addTaggedSymbolReferences` has already checked that we have RELA
10745f757f3fSDimitry Andric   // relocations, the only other way to get written addends is with
10755f757f3fSDimitry Andric   // --apply-dynamic-relocs.
10765f757f3fSDimitry Andric   if (!taggedSymbolReferenceCount.empty() && config->writeAddends)
10775f757f3fSDimitry Andric     error("--apply-dynamic-relocs cannot be used with MTE globals");
10785f757f3fSDimitry Andric 
10795f757f3fSDimitry Andric   // Now, `taggedSymbolReferenceCount` should only contain symbols that are
10805f757f3fSDimitry Andric   // defined as tagged exactly the same amount as it's referenced, meaning all
10815f757f3fSDimitry Andric   // uses are tagged.
10825f757f3fSDimitry Andric   for (auto &[symbol, remainingTaggedRefs] : taggedSymbolReferenceCount) {
10835f757f3fSDimitry Andric     assert(remainingTaggedRefs == 0 &&
10845f757f3fSDimitry Andric             "Symbol is defined as tagged more times than it's used");
10855f757f3fSDimitry Andric     symbol->setIsTagged(true);
10865f757f3fSDimitry Andric   }
10875f757f3fSDimitry Andric }
1088