xref: /llvm-project/lld/ELF/Arch/AArch64.cpp (revision 9178708c3bf926fe0d7767e26344f3f98b1e92ec)
121c0a9ceSRui Ueyama //===- AArch64.cpp --------------------------------------------------------===//
221c0a9ceSRui Ueyama //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
621c0a9ceSRui Ueyama //
721c0a9ceSRui Ueyama //===----------------------------------------------------------------------===//
821c0a9ceSRui Ueyama 
9ca35a19aSMitch Phillips #include "InputFiles.h"
10685b2125SFangrui Song #include "OutputSections.h"
1121c0a9ceSRui Ueyama #include "Symbols.h"
1221c0a9ceSRui Ueyama #include "SyntheticSections.h"
1321c0a9ceSRui Ueyama #include "Target.h"
14b8a59c8aSBob Haarman #include "lld/Common/ErrorHandler.h"
1527bb7990SFangrui Song #include "llvm/BinaryFormat/ELF.h"
1621c0a9ceSRui Ueyama #include "llvm/Support/Endian.h"
1721c0a9ceSRui Ueyama 
1821c0a9ceSRui Ueyama using namespace llvm;
1921c0a9ceSRui Ueyama using namespace llvm::support::endian;
2021c0a9ceSRui Ueyama using namespace llvm::ELF;
2107837b8fSFangrui Song using namespace lld;
2207837b8fSFangrui Song using namespace lld::elf;
2321c0a9ceSRui Ueyama 
2421c0a9ceSRui Ueyama // Page(Expr) is the page address of the expression Expr, defined
2521c0a9ceSRui Ueyama // as (Expr & ~0xFFF). (This applies even if the machine page size
2621c0a9ceSRui Ueyama // supported by the platform has a different value.)
2707837b8fSFangrui Song uint64_t elf::getAArch64Page(uint64_t expr) {
283837f427SRui Ueyama   return expr & ~static_cast<uint64_t>(0xFFF);
2921c0a9ceSRui Ueyama }
3021c0a9ceSRui Ueyama 
31c4d9cd8bSPeter Smith // A BTI landing pad is a valid target for an indirect branch when the Branch
32c4d9cd8bSPeter Smith // Target Identification has been enabled.  As linker generated branches are
33c4d9cd8bSPeter Smith // via x16 the BTI landing pads are defined as: BTI C, BTI J, BTI JC, PACIASP,
34c4d9cd8bSPeter Smith // PACIBSP.
354fadf41cSFangrui Song bool elf::isAArch64BTILandingPad(Ctx &ctx, Symbol &s, int64_t a) {
36c4d9cd8bSPeter Smith   // PLT entries accessed indirectly have a BTI c.
37acb2b1e7SFangrui Song   if (s.isInPlt(ctx))
38c4d9cd8bSPeter Smith     return true;
39c4d9cd8bSPeter Smith   Defined *d = dyn_cast<Defined>(&s);
40c4d9cd8bSPeter Smith   if (!isa_and_nonnull<InputSection>(d->section))
41c4d9cd8bSPeter Smith     // All places that we cannot disassemble are responsible for making
42c4d9cd8bSPeter Smith     // the target a BTI landing pad.
43c4d9cd8bSPeter Smith     return true;
44c4d9cd8bSPeter Smith   InputSection *isec = cast<InputSection>(d->section);
45c4d9cd8bSPeter Smith   uint64_t off = d->value + a;
46c4d9cd8bSPeter Smith   // Likely user error, but protect ourselves against out of bounds
47c4d9cd8bSPeter Smith   // access.
48c4d9cd8bSPeter Smith   if (off >= isec->getSize())
49c4d9cd8bSPeter Smith     return true;
50c4d9cd8bSPeter Smith   const uint8_t *buf = isec->content().begin();
51c4d9cd8bSPeter Smith   const uint32_t instr = read32le(buf + off);
52c4d9cd8bSPeter Smith   // All BTI instructions are HINT instructions which all have same encoding
53c4d9cd8bSPeter Smith   // apart from bits [11:5]
54c4d9cd8bSPeter Smith   if ((instr & 0xd503201f) == 0xd503201f &&
55c4d9cd8bSPeter Smith       is_contained({/*PACIASP*/ 0xd503233f, /*PACIBSP*/ 0xd503237f,
56c4d9cd8bSPeter Smith                     /*BTI C*/ 0xd503245f, /*BTI J*/ 0xd503249f,
57c4d9cd8bSPeter Smith                     /*BTI JC*/ 0xd50324df},
58c4d9cd8bSPeter Smith                    instr))
59c4d9cd8bSPeter Smith     return true;
60c4d9cd8bSPeter Smith   return false;
61c4d9cd8bSPeter Smith }
62c4d9cd8bSPeter Smith 
6321c0a9ceSRui Ueyama namespace {
64e208208aSPeter Smith class AArch64 : public TargetInfo {
6521c0a9ceSRui Ueyama public:
66c3e4998cSFangrui Song   AArch64(Ctx &);
673837f427SRui Ueyama   RelExpr getRelExpr(RelType type, const Symbol &s,
683837f427SRui Ueyama                      const uint8_t *loc) const override;
693837f427SRui Ueyama   RelType getDynRel(RelType type) const override;
70cc7cb952SAlex Richardson   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
713837f427SRui Ueyama   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
72c4c68b67SFangrui Song   void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
733837f427SRui Ueyama   void writePltHeader(uint8_t *buf) const override;
7437b28080SFangrui Song   void writePlt(uint8_t *buf, const Symbol &sym,
7537b28080SFangrui Song                 uint64_t pltEntryAddr) const override;
763837f427SRui Ueyama   bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
77bf535ac4SFangrui Song                   uint64_t branchAddr, const Symbol &s,
78bf535ac4SFangrui Song                   int64_t a) const override;
79a8656c62SPeter Smith   uint32_t getThunkSectionSpacing() const override;
803837f427SRui Ueyama   bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
813837f427SRui Ueyama   bool usesOnlyLowPageBits(RelType type) const override;
82deb5819dSFangrui Song   void relocate(uint8_t *loc, const Relocation &rel,
83deb5819dSFangrui Song                 uint64_t val) const override;
8450564ca0SFangrui Song   RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
85685b2125SFangrui Song   void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
86685b2125SFangrui Song 
87685b2125SFangrui Song private:
88685b2125SFangrui Song   void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
89685b2125SFangrui Song   void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
90685b2125SFangrui Song   void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
91821e04deSFangrui Song };
92821e04deSFangrui Song 
93821e04deSFangrui Song struct AArch64Relaxer {
946d03a690SFangrui Song   Ctx &ctx;
95821e04deSFangrui Song   bool safeToRelaxAdrpLdr = false;
96821e04deSFangrui Song 
976d03a690SFangrui Song   AArch64Relaxer(Ctx &ctx, ArrayRef<Relocation> relocs);
98685b2125SFangrui Song   bool tryRelaxAdrpAdd(const Relocation &adrpRel, const Relocation &addRel,
99685b2125SFangrui Song                        uint64_t secAddr, uint8_t *buf) const;
100685b2125SFangrui Song   bool tryRelaxAdrpLdr(const Relocation &adrpRel, const Relocation &ldrRel,
101685b2125SFangrui Song                        uint64_t secAddr, uint8_t *buf) const;
10221c0a9ceSRui Ueyama };
10321c0a9ceSRui Ueyama } // namespace
10421c0a9ceSRui Ueyama 
105cd14e713SRamkumar Ramachandra // Return the bits [Start, End] from Val shifted Start bits.
106cd14e713SRamkumar Ramachandra // For instance, getBits(0xF0, 4, 8) returns 0xF.
107cd14e713SRamkumar Ramachandra static uint64_t getBits(uint64_t val, int start, int end) {
108cd14e713SRamkumar Ramachandra   uint64_t mask = ((uint64_t)1 << (end + 1 - start)) - 1;
109cd14e713SRamkumar Ramachandra   return (val >> start) & mask;
110cd14e713SRamkumar Ramachandra }
111cd14e713SRamkumar Ramachandra 
112c3e4998cSFangrui Song AArch64::AArch64(Ctx &ctx) : TargetInfo(ctx) {
1133837f427SRui Ueyama   copyRel = R_AARCH64_COPY;
1143837f427SRui Ueyama   relativeRel = R_AARCH64_RELATIVE;
1153837f427SRui Ueyama   iRelativeRel = R_AARCH64_IRELATIVE;
1163837f427SRui Ueyama   gotRel = R_AARCH64_GLOB_DAT;
1173837f427SRui Ueyama   pltRel = R_AARCH64_JUMP_SLOT;
1183837f427SRui Ueyama   symbolicRel = R_AARCH64_ABS64;
1193837f427SRui Ueyama   tlsDescRel = R_AARCH64_TLSDESC;
1203837f427SRui Ueyama   tlsGotRel = R_AARCH64_TLS_TPREL64;
1213837f427SRui Ueyama   pltHeaderSize = 32;
122891a8655SFangrui Song   pltEntrySize = 16;
123891a8655SFangrui Song   ipltEntrySize = 16;
1243837f427SRui Ueyama   defaultMaxPageSize = 65536;
12521c0a9ceSRui Ueyama 
126c9de3b4dSDimitry Andric   // Align to the 2 MiB page size (known as a superpage or huge page).
127c9de3b4dSDimitry Andric   // FreeBSD automatically promotes 2 MiB-aligned allocations.
1283837f427SRui Ueyama   defaultImageBase = 0x200000;
129c9de3b4dSDimitry Andric 
1303837f427SRui Ueyama   needsThunks = true;
13121c0a9ceSRui Ueyama }
13221c0a9ceSRui Ueyama 
1333837f427SRui Ueyama RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
1343837f427SRui Ueyama                             const uint8_t *loc) const {
1353837f427SRui Ueyama   switch (type) {
136e54ed478SFangrui Song   case R_AARCH64_ABS16:
137e54ed478SFangrui Song   case R_AARCH64_ABS32:
138e54ed478SFangrui Song   case R_AARCH64_ABS64:
139e54ed478SFangrui Song   case R_AARCH64_ADD_ABS_LO12_NC:
140e54ed478SFangrui Song   case R_AARCH64_LDST128_ABS_LO12_NC:
141e54ed478SFangrui Song   case R_AARCH64_LDST16_ABS_LO12_NC:
142e54ed478SFangrui Song   case R_AARCH64_LDST32_ABS_LO12_NC:
143e54ed478SFangrui Song   case R_AARCH64_LDST64_ABS_LO12_NC:
144e54ed478SFangrui Song   case R_AARCH64_LDST8_ABS_LO12_NC:
145e54ed478SFangrui Song   case R_AARCH64_MOVW_SABS_G0:
146e54ed478SFangrui Song   case R_AARCH64_MOVW_SABS_G1:
147e54ed478SFangrui Song   case R_AARCH64_MOVW_SABS_G2:
148e54ed478SFangrui Song   case R_AARCH64_MOVW_UABS_G0:
149e54ed478SFangrui Song   case R_AARCH64_MOVW_UABS_G0_NC:
150e54ed478SFangrui Song   case R_AARCH64_MOVW_UABS_G1:
151e54ed478SFangrui Song   case R_AARCH64_MOVW_UABS_G1_NC:
152e54ed478SFangrui Song   case R_AARCH64_MOVW_UABS_G2:
153e54ed478SFangrui Song   case R_AARCH64_MOVW_UABS_G2_NC:
154e54ed478SFangrui Song   case R_AARCH64_MOVW_UABS_G3:
155e54ed478SFangrui Song     return R_ABS;
156cca9115bSDaniil Kovalev   case R_AARCH64_AUTH_ABS64:
15704996a28SFangrui Song     return RE_AARCH64_AUTH;
15821c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADR_PAGE21:
15904996a28SFangrui Song     return RE_AARCH64_TLSDESC_PAGE;
160*9178708cSDaniil Kovalev   case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
161*9178708cSDaniil Kovalev     return RE_AARCH64_AUTH_TLSDESC_PAGE;
16221c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_LD64_LO12:
16321c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADD_LO12:
16421c0a9ceSRui Ueyama     return R_TLSDESC;
165*9178708cSDaniil Kovalev   case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
166*9178708cSDaniil Kovalev   case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
167*9178708cSDaniil Kovalev     return RE_AARCH64_AUTH_TLSDESC;
16821c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_CALL:
16921c0a9ceSRui Ueyama     return R_TLSDESC_CALL;
17021c0a9ceSRui Ueyama   case R_AARCH64_TLSLE_ADD_TPREL_HI12:
17121c0a9ceSRui Ueyama   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
172e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
173e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
174e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
175e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
176e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
177d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G0:
178d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
179d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G1:
180d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
181d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G2:
18222c1bd57SFangrui Song     return R_TPREL;
18321c0a9ceSRui Ueyama   case R_AARCH64_CALL26:
18421c0a9ceSRui Ueyama   case R_AARCH64_CONDBR19:
18521c0a9ceSRui Ueyama   case R_AARCH64_JUMP26:
18621c0a9ceSRui Ueyama   case R_AARCH64_TSTBR14:
18792fbb602SDaniel Kiss     return R_PLT_PC;
188723b5a17SLeonard Chan   case R_AARCH64_PLT32:
18992fbb602SDaniel Kiss     const_cast<Symbol &>(s).thunkAccessed = true;
19021c0a9ceSRui Ueyama     return R_PLT_PC;
19121c0a9ceSRui Ueyama   case R_AARCH64_PREL16:
19221c0a9ceSRui Ueyama   case R_AARCH64_PREL32:
19321c0a9ceSRui Ueyama   case R_AARCH64_PREL64:
19421c0a9ceSRui Ueyama   case R_AARCH64_ADR_PREL_LO21:
195f681a8faSDavide Italiano   case R_AARCH64_LD_PREL_LO19:
196c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G0:
197c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G0_NC:
198c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G1:
199c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G1_NC:
200c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G2:
201c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G2_NC:
202c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G3:
20321c0a9ceSRui Ueyama     return R_PC;
20421c0a9ceSRui Ueyama   case R_AARCH64_ADR_PREL_PG_HI21:
205d37edd0cSPeter Collingbourne   case R_AARCH64_ADR_PREL_PG_HI21_NC:
20604996a28SFangrui Song     return RE_AARCH64_PAGE_PC;
20721c0a9ceSRui Ueyama   case R_AARCH64_LD64_GOT_LO12_NC:
20821c0a9ceSRui Ueyama   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
20921c0a9ceSRui Ueyama     return R_GOT;
210417d2d7cSDaniil Kovalev   case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
211417d2d7cSDaniil Kovalev   case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
212417d2d7cSDaniil Kovalev     return RE_AARCH64_AUTH_GOT;
2131ef5b987SDaniil Kovalev   case R_AARCH64_AUTH_GOT_LD_PREL19:
2141ef5b987SDaniil Kovalev   case R_AARCH64_AUTH_GOT_ADR_PREL_LO21:
2151ef5b987SDaniil Kovalev     return RE_AARCH64_AUTH_GOT_PC;
216988cc0a0SAdhemerval Zanella   case R_AARCH64_LD64_GOTPAGE_LO15:
21704996a28SFangrui Song     return RE_AARCH64_GOT_PAGE;
21821c0a9ceSRui Ueyama   case R_AARCH64_ADR_GOT_PAGE:
21921c0a9ceSRui Ueyama   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
22004996a28SFangrui Song     return RE_AARCH64_GOT_PAGE_PC;
221417d2d7cSDaniil Kovalev   case R_AARCH64_AUTH_ADR_GOT_PAGE:
222417d2d7cSDaniil Kovalev     return RE_AARCH64_AUTH_GOT_PAGE_PC;
22304a906ecSPiJoules   case R_AARCH64_GOTPCREL32:
2247acd2c06SDaniil Kovalev   case R_AARCH64_GOT_LD_PREL19:
22504a906ecSPiJoules     return R_GOT_PC;
22621c0a9ceSRui Ueyama   case R_AARCH64_NONE:
22721c0a9ceSRui Ueyama     return R_NONE;
228be85529dSRui Ueyama   default:
229c1a6defdSFangrui Song     Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
23009c2c5e1SFangrui Song              << ") against symbol " << &s;
231e54ed478SFangrui Song     return R_NONE;
23221c0a9ceSRui Ueyama   }
23321c0a9ceSRui Ueyama }
23421c0a9ceSRui Ueyama 
23550564ca0SFangrui Song RelExpr AArch64::adjustTlsExpr(RelType type, RelExpr expr) const {
2363837f427SRui Ueyama   if (expr == R_RELAX_TLS_GD_TO_IE) {
2373837f427SRui Ueyama     if (type == R_AARCH64_TLSDESC_ADR_PAGE21)
23804996a28SFangrui Song       return RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC;
23921c0a9ceSRui Ueyama     return R_RELAX_TLS_GD_TO_IE_ABS;
24021c0a9ceSRui Ueyama   }
2413837f427SRui Ueyama   return expr;
24221c0a9ceSRui Ueyama }
24321c0a9ceSRui Ueyama 
2443837f427SRui Ueyama bool AArch64::usesOnlyLowPageBits(RelType type) const {
2453837f427SRui Ueyama   switch (type) {
24621c0a9ceSRui Ueyama   default:
24721c0a9ceSRui Ueyama     return false;
24821c0a9ceSRui Ueyama   case R_AARCH64_ADD_ABS_LO12_NC:
24921c0a9ceSRui Ueyama   case R_AARCH64_LD64_GOT_LO12_NC:
25021c0a9ceSRui Ueyama   case R_AARCH64_LDST128_ABS_LO12_NC:
25121c0a9ceSRui Ueyama   case R_AARCH64_LDST16_ABS_LO12_NC:
25221c0a9ceSRui Ueyama   case R_AARCH64_LDST32_ABS_LO12_NC:
25321c0a9ceSRui Ueyama   case R_AARCH64_LDST64_ABS_LO12_NC:
25421c0a9ceSRui Ueyama   case R_AARCH64_LDST8_ABS_LO12_NC:
25521c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADD_LO12:
25621c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_LD64_LO12:
25721c0a9ceSRui Ueyama   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
25821c0a9ceSRui Ueyama     return true;
25921c0a9ceSRui Ueyama   }
26021c0a9ceSRui Ueyama }
26121c0a9ceSRui Ueyama 
2623837f427SRui Ueyama RelType AArch64::getDynRel(RelType type) const {
263cca9115bSDaniil Kovalev   if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64)
2643837f427SRui Ueyama     return type;
265f9936e1fSGeorge Rimar   return R_AARCH64_NONE;
26621c0a9ceSRui Ueyama }
26721c0a9ceSRui Ueyama 
268cc7cb952SAlex Richardson int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
269cc7cb952SAlex Richardson   switch (type) {
270cc7cb952SAlex Richardson   case R_AARCH64_TLSDESC:
271002ca63bSFangrui Song     return read64(ctx, buf + 8);
272f457863aSFangrui Song   case R_AARCH64_NONE:
273efb7a71aSFangrui Song   case R_AARCH64_GLOB_DAT:
274417d2d7cSDaniil Kovalev   case R_AARCH64_AUTH_GLOB_DAT:
275efb7a71aSFangrui Song   case R_AARCH64_JUMP_SLOT:
276f457863aSFangrui Song     return 0;
277cd14e713SRamkumar Ramachandra   case R_AARCH64_ABS16:
278cd14e713SRamkumar Ramachandra   case R_AARCH64_PREL16:
279002ca63bSFangrui Song     return SignExtend64<16>(read16(ctx, buf));
280cd14e713SRamkumar Ramachandra   case R_AARCH64_ABS32:
281767e64fcSFangrui Song   case R_AARCH64_PREL32:
28238dfcd9aSFangrui Song     return SignExtend64<32>(read32(ctx, buf));
283767e64fcSFangrui Song   case R_AARCH64_ABS64:
284767e64fcSFangrui Song   case R_AARCH64_PREL64:
285efb7a71aSFangrui Song   case R_AARCH64_RELATIVE:
286efb7a71aSFangrui Song   case R_AARCH64_IRELATIVE:
287efb7a71aSFangrui Song   case R_AARCH64_TLS_TPREL64:
288002ca63bSFangrui Song     return read64(ctx, buf);
289a6b204b8SSimon Tatham 
290a6b204b8SSimon Tatham     // The following relocation types all point at instructions, and
291a6b204b8SSimon Tatham     // relocate an immediate field in the instruction.
292a6b204b8SSimon Tatham     //
293a6b204b8SSimon Tatham     // The general rule, from AAELF64 §5.7.2 "Addends and PC-bias",
294a6b204b8SSimon Tatham     // says: "If the relocation relocates an instruction the immediate
295a6b204b8SSimon Tatham     // field of the instruction is extracted, scaled as required by
296a6b204b8SSimon Tatham     // the instruction field encoding, and sign-extended to 64 bits".
297a6b204b8SSimon Tatham 
298a6b204b8SSimon Tatham     // The R_AARCH64_MOVW family operates on wide MOV/MOVK/MOVZ
299a6b204b8SSimon Tatham     // instructions, which have a 16-bit immediate field with its low
300a6b204b8SSimon Tatham     // bit in bit 5 of the instruction encoding. When the immediate
301a6b204b8SSimon Tatham     // field is used as an implicit addend for REL-type relocations,
302a6b204b8SSimon Tatham     // it is treated as added to the low bits of the output value, not
303a6b204b8SSimon Tatham     // shifted depending on the relocation type.
304a6b204b8SSimon Tatham     //
305a6b204b8SSimon Tatham     // This allows REL relocations to express the requirement 'please
306a6b204b8SSimon Tatham     // add 12345 to this symbol value and give me the four 16-bit
307a6b204b8SSimon Tatham     // chunks of the result', by putting the same addend 12345 in all
308a6b204b8SSimon Tatham     // four instructions. Carries between the 16-bit chunks are
309a6b204b8SSimon Tatham     // handled correctly, because the whole 64-bit addition is done
310a6b204b8SSimon Tatham     // once per relocation.
311cd14e713SRamkumar Ramachandra   case R_AARCH64_MOVW_UABS_G0:
312cd14e713SRamkumar Ramachandra   case R_AARCH64_MOVW_UABS_G0_NC:
313cd14e713SRamkumar Ramachandra   case R_AARCH64_MOVW_UABS_G1:
314cd14e713SRamkumar Ramachandra   case R_AARCH64_MOVW_UABS_G1_NC:
315cd14e713SRamkumar Ramachandra   case R_AARCH64_MOVW_UABS_G2:
316cd14e713SRamkumar Ramachandra   case R_AARCH64_MOVW_UABS_G2_NC:
317cd14e713SRamkumar Ramachandra   case R_AARCH64_MOVW_UABS_G3:
318daf20859SSimon Tatham     return SignExtend64<16>(getBits(read32le(buf), 5, 20));
319a6b204b8SSimon Tatham 
320a6b204b8SSimon Tatham     // R_AARCH64_TSTBR14 points at a TBZ or TBNZ instruction, which
321a6b204b8SSimon Tatham     // has a 14-bit offset measured in instructions, i.e. shifted left
322a6b204b8SSimon Tatham     // by 2.
323cd14e713SRamkumar Ramachandra   case R_AARCH64_TSTBR14:
324daf20859SSimon Tatham     return SignExtend64<16>(getBits(read32le(buf), 5, 18) << 2);
325a6b204b8SSimon Tatham 
326a6b204b8SSimon Tatham     // R_AARCH64_CONDBR19 operates on the ordinary B.cond instruction,
327a6b204b8SSimon Tatham     // which has a 19-bit offset measured in instructions.
328a6b204b8SSimon Tatham     //
329a6b204b8SSimon Tatham     // R_AARCH64_LD_PREL_LO19 operates on the LDR (literal)
330a6b204b8SSimon Tatham     // instruction, which also has a 19-bit offset, measured in 4-byte
331a6b204b8SSimon Tatham     // chunks. So the calculation is the same as for
332a6b204b8SSimon Tatham     // R_AARCH64_CONDBR19.
333cd14e713SRamkumar Ramachandra   case R_AARCH64_CONDBR19:
334cd14e713SRamkumar Ramachandra   case R_AARCH64_LD_PREL_LO19:
335daf20859SSimon Tatham     return SignExtend64<21>(getBits(read32le(buf), 5, 23) << 2);
336a6b204b8SSimon Tatham 
337a6b204b8SSimon Tatham     // R_AARCH64_ADD_ABS_LO12_NC operates on ADD (immediate). The
338a6b204b8SSimon Tatham     // immediate can optionally be shifted left by 12 bits, but this
339a6b204b8SSimon Tatham     // relocation is intended for the case where it is not.
340cd14e713SRamkumar Ramachandra   case R_AARCH64_ADD_ABS_LO12_NC:
341daf20859SSimon Tatham     return SignExtend64<12>(getBits(read32le(buf), 10, 21));
342a6b204b8SSimon Tatham 
343a6b204b8SSimon Tatham     // R_AARCH64_ADR_PREL_LO21 operates on an ADR instruction, whose
344a6b204b8SSimon Tatham     // 21-bit immediate is split between two bits high up in the word
345a6b204b8SSimon Tatham     // (in fact the two _lowest_ order bits of the value) and 19 bits
346a6b204b8SSimon Tatham     // lower down.
347a6b204b8SSimon Tatham     //
348a6b204b8SSimon Tatham     // R_AARCH64_ADR_PREL_PG_HI21[_NC] operate on an ADRP instruction,
349a6b204b8SSimon Tatham     // which encodes the immediate in the same way, but will shift it
350a6b204b8SSimon Tatham     // left by 12 bits when the instruction executes. For the same
351a6b204b8SSimon Tatham     // reason as the MOVW family, we don't apply that left shift here.
352a6b204b8SSimon Tatham   case R_AARCH64_ADR_PREL_LO21:
353cd14e713SRamkumar Ramachandra   case R_AARCH64_ADR_PREL_PG_HI21:
354cd14e713SRamkumar Ramachandra   case R_AARCH64_ADR_PREL_PG_HI21_NC:
355daf20859SSimon Tatham     return SignExtend64<21>((getBits(read32le(buf), 5, 23) << 2) |
356daf20859SSimon Tatham                             getBits(read32le(buf), 29, 30));
357a6b204b8SSimon Tatham 
358a6b204b8SSimon Tatham     // R_AARCH64_{JUMP,CALL}26 operate on B and BL, which have a
359a6b204b8SSimon Tatham     // 26-bit offset measured in instructions.
360cd14e713SRamkumar Ramachandra   case R_AARCH64_JUMP26:
361cd14e713SRamkumar Ramachandra   case R_AARCH64_CALL26:
362daf20859SSimon Tatham     return SignExtend64<28>(getBits(read32le(buf), 0, 25) << 2);
363a6b204b8SSimon Tatham 
364cc7cb952SAlex Richardson   default:
365be5dad01SFangrui Song     InternalErr(ctx, buf) << "cannot read addend for relocation " << type;
366cc7cb952SAlex Richardson     return 0;
367cc7cb952SAlex Richardson   }
368cc7cb952SAlex Richardson }
369cc7cb952SAlex Richardson 
3703837f427SRui Ueyama void AArch64::writeGotPlt(uint8_t *buf, const Symbol &) const {
371002ca63bSFangrui Song   write64(ctx, buf, ctx.in.plt->getVA());
37221c0a9ceSRui Ueyama }
37321c0a9ceSRui Ueyama 
374c4c68b67SFangrui Song void AArch64::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
3751dd9a565SFangrui Song   if (ctx.arg.writeAddends)
376861bd36bSFangrui Song     write64(ctx, buf, s.getVA(ctx));
377c4c68b67SFangrui Song }
378c4c68b67SFangrui Song 
3793837f427SRui Ueyama void AArch64::writePltHeader(uint8_t *buf) const {
3803837f427SRui Ueyama   const uint8_t pltData[] = {
38121c0a9ceSRui Ueyama       0xf0, 0x7b, 0xbf, 0xa9, // stp    x16, x30, [sp,#-16]!
3824c244b28SFangrui Song       0x10, 0x00, 0x00, 0x90, // adrp   x16, Page(&(.got.plt[2]))
3834c244b28SFangrui Song       0x11, 0x02, 0x40, 0xf9, // ldr    x17, [x16, Offset(&(.got.plt[2]))]
3844c244b28SFangrui Song       0x10, 0x02, 0x00, 0x91, // add    x16, x16, Offset(&(.got.plt[2]))
38521c0a9ceSRui Ueyama       0x20, 0x02, 0x1f, 0xd6, // br     x17
38621c0a9ceSRui Ueyama       0x1f, 0x20, 0x03, 0xd5, // nop
38721c0a9ceSRui Ueyama       0x1f, 0x20, 0x03, 0xd5, // nop
38821c0a9ceSRui Ueyama       0x1f, 0x20, 0x03, 0xd5  // nop
38921c0a9ceSRui Ueyama   };
3903837f427SRui Ueyama   memcpy(buf, pltData, sizeof(pltData));
39121c0a9ceSRui Ueyama 
392e88b7ff0SFangrui Song   uint64_t got = ctx.in.gotPlt->getVA();
393e88b7ff0SFangrui Song   uint64_t plt = ctx.in.plt->getVA();
394deb5819dSFangrui Song   relocateNoSym(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
3953837f427SRui Ueyama                 getAArch64Page(got + 16) - getAArch64Page(plt + 4));
396deb5819dSFangrui Song   relocateNoSym(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
397deb5819dSFangrui Song   relocateNoSym(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
39821c0a9ceSRui Ueyama }
39921c0a9ceSRui Ueyama 
40037b28080SFangrui Song void AArch64::writePlt(uint8_t *buf, const Symbol &sym,
40137b28080SFangrui Song                        uint64_t pltEntryAddr) const {
4023837f427SRui Ueyama   const uint8_t inst[] = {
4034c244b28SFangrui Song       0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.got.plt[n]))
4044c244b28SFangrui Song       0x11, 0x02, 0x40, 0xf9, // ldr  x17, [x16, Offset(&(.got.plt[n]))]
4054c244b28SFangrui Song       0x10, 0x02, 0x00, 0x91, // add  x16, x16, Offset(&(.got.plt[n]))
40621c0a9ceSRui Ueyama       0x20, 0x02, 0x1f, 0xd6  // br   x17
40721c0a9ceSRui Ueyama   };
4083837f427SRui Ueyama   memcpy(buf, inst, sizeof(inst));
40921c0a9ceSRui Ueyama 
410acb2b1e7SFangrui Song   uint64_t gotPltEntryAddr = sym.getGotPltVA(ctx);
411deb5819dSFangrui Song   relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
4123837f427SRui Ueyama                 getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
413deb5819dSFangrui Song   relocateNoSym(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
414deb5819dSFangrui Song   relocateNoSym(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
41521c0a9ceSRui Ueyama }
41621c0a9ceSRui Ueyama 
4173837f427SRui Ueyama bool AArch64::needsThunk(RelExpr expr, RelType type, const InputFile *file,
418bf535ac4SFangrui Song                          uint64_t branchAddr, const Symbol &s,
419bf535ac4SFangrui Song                          int64_t a) const {
42002eab528SFangrui Song   // If s is an undefined weak symbol and does not have a PLT entry then it will
42102eab528SFangrui Song   // be resolved as a branch to the next instruction. If it is hidden, its
42202eab528SFangrui Song   // binding has been converted to local, so we just check isUndefined() here. A
42302eab528SFangrui Song   // undefined non-weak symbol will have been errored.
424acb2b1e7SFangrui Song   if (s.isUndefined() && !s.isInPlt(ctx))
425051c4d5bSPeter Smith     return false;
42631dddc97SPeter Smith   // ELF for the ARM 64-bit architecture, section Call and Jump relocations
42731dddc97SPeter Smith   // only permits range extension thunks for R_AARCH64_CALL26 and
42831dddc97SPeter Smith   // R_AARCH64_JUMP26 relocation types.
429723b5a17SLeonard Chan   if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
430723b5a17SLeonard Chan       type != R_AARCH64_PLT32)
43131dddc97SPeter Smith     return false;
432861bd36bSFangrui Song   uint64_t dst = expr == R_PLT_PC ? s.getPltVA(ctx) : s.getVA(ctx, a);
4333837f427SRui Ueyama   return !inBranchRange(type, branchAddr, dst);
43431dddc97SPeter Smith }
43531dddc97SPeter Smith 
436a8656c62SPeter Smith uint32_t AArch64::getThunkSectionSpacing() const {
437a8656c62SPeter Smith   // See comment in Arch/ARM.cpp for a more detailed explanation of
438a8656c62SPeter Smith   // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to
439a8656c62SPeter Smith   // Thunk have a range of +/- 128 MiB
440a8656c62SPeter Smith   return (128 * 1024 * 1024) - 0x30000;
441a8656c62SPeter Smith }
442a8656c62SPeter Smith 
4433837f427SRui Ueyama bool AArch64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
444723b5a17SLeonard Chan   if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
445723b5a17SLeonard Chan       type != R_AARCH64_PLT32)
44631dddc97SPeter Smith     return true;
44731dddc97SPeter Smith   // The AArch64 call and unconditional branch instructions have a range of
448723b5a17SLeonard Chan   // +/- 128 MiB. The PLT32 relocation supports a range up to +/- 2 GiB.
449723b5a17SLeonard Chan   uint64_t range =
450723b5a17SLeonard Chan       type == R_AARCH64_PLT32 ? (UINT64_C(1) << 31) : (128 * 1024 * 1024);
4513837f427SRui Ueyama   if (dst > src) {
45231dddc97SPeter Smith     // Immediate of branch is signed.
4533837f427SRui Ueyama     range -= 4;
4543837f427SRui Ueyama     return dst - src <= range;
45531dddc97SPeter Smith   }
4563837f427SRui Ueyama   return src - dst <= range;
45731dddc97SPeter Smith }
45831dddc97SPeter Smith 
4593837f427SRui Ueyama static void write32AArch64Addr(uint8_t *l, uint64_t imm) {
4603837f427SRui Ueyama   uint32_t immLo = (imm & 0x3) << 29;
4613837f427SRui Ueyama   uint32_t immHi = (imm & 0x1FFFFC) << 3;
4623837f427SRui Ueyama   uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3);
4633837f427SRui Ueyama   write32le(l, (read32le(l) & ~mask) | immLo | immHi);
46421c0a9ceSRui Ueyama }
46521c0a9ceSRui Ueyama 
466a6b204b8SSimon Tatham static void writeMaskedBits32le(uint8_t *p, int32_t v, uint32_t mask) {
467a6b204b8SSimon Tatham   write32le(p, (read32le(p) & ~mask) | v);
468a6b204b8SSimon Tatham }
46921c0a9ceSRui Ueyama 
47021c0a9ceSRui Ueyama // Update the immediate field in a AARCH64 ldr, str, and add instruction.
471a6b204b8SSimon Tatham static void write32Imm12(uint8_t *l, uint64_t imm) {
472a6b204b8SSimon Tatham   writeMaskedBits32le(l, (imm & 0xFFF) << 10, 0xFFF << 10);
47321c0a9ceSRui Ueyama }
47421c0a9ceSRui Ueyama 
475c2ccf4ccSPeter Collingbourne // Update the immediate field in an AArch64 movk, movn or movz instruction
476c2ccf4ccSPeter Collingbourne // for a signed relocation, and update the opcode of a movn or movz instruction
477c2ccf4ccSPeter Collingbourne // to match the sign of the operand.
478c2ccf4ccSPeter Collingbourne static void writeSMovWImm(uint8_t *loc, uint32_t imm) {
479c2ccf4ccSPeter Collingbourne   uint32_t inst = read32le(loc);
480c2ccf4ccSPeter Collingbourne   // Opcode field is bits 30, 29, with 10 = movz, 00 = movn and 11 = movk.
481c2ccf4ccSPeter Collingbourne   if (!(inst & (1 << 29))) {
482c2ccf4ccSPeter Collingbourne     // movn or movz.
483c2ccf4ccSPeter Collingbourne     if (imm & 0x10000) {
484c2ccf4ccSPeter Collingbourne       // Change opcode to movn, which takes an inverted operand.
485c2ccf4ccSPeter Collingbourne       imm ^= 0xFFFF;
486c2ccf4ccSPeter Collingbourne       inst &= ~(1 << 30);
487c2ccf4ccSPeter Collingbourne     } else {
488c2ccf4ccSPeter Collingbourne       // Change opcode to movz.
489c2ccf4ccSPeter Collingbourne       inst |= 1 << 30;
490c2ccf4ccSPeter Collingbourne     }
491c2ccf4ccSPeter Collingbourne   }
492c2ccf4ccSPeter Collingbourne   write32le(loc, inst | ((imm & 0xFFFF) << 5));
493c2ccf4ccSPeter Collingbourne }
494c2ccf4ccSPeter Collingbourne 
495deb5819dSFangrui Song void AArch64::relocate(uint8_t *loc, const Relocation &rel,
496deb5819dSFangrui Song                        uint64_t val) const {
497deb5819dSFangrui Song   switch (rel.type) {
49821c0a9ceSRui Ueyama   case R_AARCH64_ABS16:
49921c0a9ceSRui Ueyama   case R_AARCH64_PREL16:
5002c5dd03fSFangrui Song     checkIntUInt(ctx, loc, val, 16, rel);
501002ca63bSFangrui Song     write16(ctx, loc, val);
50221c0a9ceSRui Ueyama     break;
50321c0a9ceSRui Ueyama   case R_AARCH64_ABS32:
50421c0a9ceSRui Ueyama   case R_AARCH64_PREL32:
5052c5dd03fSFangrui Song     checkIntUInt(ctx, loc, val, 32, rel);
50638dfcd9aSFangrui Song     write32(ctx, loc, val);
50721c0a9ceSRui Ueyama     break;
508723b5a17SLeonard Chan   case R_AARCH64_PLT32:
50904a906ecSPiJoules   case R_AARCH64_GOTPCREL32:
5102c5dd03fSFangrui Song     checkInt(ctx, loc, val, 32, rel);
51138dfcd9aSFangrui Song     write32(ctx, loc, val);
512723b5a17SLeonard Chan     break;
51321c0a9ceSRui Ueyama   case R_AARCH64_ABS64:
514ca35a19aSMitch Phillips     // AArch64 relocations to tagged symbols have extended semantics, as
515ca35a19aSMitch Phillips     // described here:
516ca35a19aSMitch Phillips     // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#841extended-semantics-of-r_aarch64_relative.
517ca35a19aSMitch Phillips     // tl;dr: encode the symbol's special addend in the place, which is an
518ca35a19aSMitch Phillips     // offset to the point where the logical tag is derived from. Quick hack, if
519ca35a19aSMitch Phillips     // the addend is within the symbol's bounds, no need to encode the tag
520ca35a19aSMitch Phillips     // derivation offset.
521ca35a19aSMitch Phillips     if (rel.sym && rel.sym->isTagged() &&
522ca35a19aSMitch Phillips         (rel.addend < 0 ||
523ca35a19aSMitch Phillips          rel.addend >= static_cast<int64_t>(rel.sym->getSize())))
524002ca63bSFangrui Song       write64(ctx, loc, -rel.addend);
525ca35a19aSMitch Phillips     else
526002ca63bSFangrui Song       write64(ctx, loc, val);
527ca35a19aSMitch Phillips     break;
52821c0a9ceSRui Ueyama   case R_AARCH64_PREL64:
529002ca63bSFangrui Song     write64(ctx, loc, val);
53021c0a9ceSRui Ueyama     break;
531a9c43b9aSDaniil Kovalev   case R_AARCH64_AUTH_ABS64:
532a9c43b9aSDaniil Kovalev     // If val is wider than 32 bits, the relocation must have been moved from
533a9c43b9aSDaniil Kovalev     // .relr.auth.dyn to .rela.dyn, and the addend write is not needed.
534a9c43b9aSDaniil Kovalev     //
535a9c43b9aSDaniil Kovalev     // If val fits in 32 bits, we have two potential scenarios:
536a9c43b9aSDaniil Kovalev     // * True RELR: Write the 32-bit `val`.
537a9c43b9aSDaniil Kovalev     // * RELA: Even if the value now fits in 32 bits, it might have been
538a9c43b9aSDaniil Kovalev     //   converted from RELR during an iteration in
539a9c43b9aSDaniil Kovalev     //   finalizeAddressDependentContent(). Writing the value is harmless
540a9c43b9aSDaniil Kovalev     //   because dynamic linking ignores it.
541a9c43b9aSDaniil Kovalev     if (isInt<32>(val))
54238dfcd9aSFangrui Song       write32(ctx, loc, val);
543a9c43b9aSDaniil Kovalev     break;
54421c0a9ceSRui Ueyama   case R_AARCH64_ADD_ABS_LO12_NC:
545417d2d7cSDaniil Kovalev   case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
546a6b204b8SSimon Tatham     write32Imm12(loc, val);
54721c0a9ceSRui Ueyama     break;
54821c0a9ceSRui Ueyama   case R_AARCH64_ADR_GOT_PAGE:
549417d2d7cSDaniil Kovalev   case R_AARCH64_AUTH_ADR_GOT_PAGE:
55021c0a9ceSRui Ueyama   case R_AARCH64_ADR_PREL_PG_HI21:
55121c0a9ceSRui Ueyama   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
55221c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADR_PAGE21:
553*9178708cSDaniil Kovalev   case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
5542c5dd03fSFangrui Song     checkInt(ctx, loc, val, 33, rel);
555ec04e45cSFangrui Song     [[fallthrough]];
556d37edd0cSPeter Collingbourne   case R_AARCH64_ADR_PREL_PG_HI21_NC:
5573837f427SRui Ueyama     write32AArch64Addr(loc, val >> 12);
55821c0a9ceSRui Ueyama     break;
55921c0a9ceSRui Ueyama   case R_AARCH64_ADR_PREL_LO21:
5601ef5b987SDaniil Kovalev   case R_AARCH64_AUTH_GOT_ADR_PREL_LO21:
5612c5dd03fSFangrui Song     checkInt(ctx, loc, val, 21, rel);
5623837f427SRui Ueyama     write32AArch64Addr(loc, val);
56321c0a9ceSRui Ueyama     break;
56421c0a9ceSRui Ueyama   case R_AARCH64_JUMP26:
56520489ec5SPeter Smith     // Normally we would just write the bits of the immediate field, however
56620489ec5SPeter Smith     // when patching instructions for the cpu errata fix -fix-cortex-a53-843419
56720489ec5SPeter Smith     // we want to replace a non-branch instruction with a branch immediate
56820489ec5SPeter Smith     // instruction. By writing all the bits of the instruction including the
56920489ec5SPeter Smith     // opcode and the immediate (0 001 | 01 imm26) we can do this
57020489ec5SPeter Smith     // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of
57120489ec5SPeter Smith     // the instruction we want to patch.
5723837f427SRui Ueyama     write32le(loc, 0x14000000);
573ec04e45cSFangrui Song     [[fallthrough]];
57420489ec5SPeter Smith   case R_AARCH64_CALL26:
5752c5dd03fSFangrui Song     checkInt(ctx, loc, val, 28, rel);
576a6b204b8SSimon Tatham     writeMaskedBits32le(loc, (val & 0x0FFFFFFC) >> 2, 0x0FFFFFFC >> 2);
57721c0a9ceSRui Ueyama     break;
57821c0a9ceSRui Ueyama   case R_AARCH64_CONDBR19:
579f681a8faSDavide Italiano   case R_AARCH64_LD_PREL_LO19:
5807acd2c06SDaniil Kovalev   case R_AARCH64_GOT_LD_PREL19:
5811ef5b987SDaniil Kovalev   case R_AARCH64_AUTH_GOT_LD_PREL19:
5822c5dd03fSFangrui Song     checkAlignment(ctx, loc, val, 4, rel);
5832c5dd03fSFangrui Song     checkInt(ctx, loc, val, 21, rel);
584a6b204b8SSimon Tatham     writeMaskedBits32le(loc, (val & 0x1FFFFC) << 3, 0x1FFFFC << 3);
58521c0a9ceSRui Ueyama     break;
58621c0a9ceSRui Ueyama   case R_AARCH64_LDST8_ABS_LO12_NC:
587e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
588a6b204b8SSimon Tatham     write32Imm12(loc, getBits(val, 0, 11));
58921c0a9ceSRui Ueyama     break;
59021c0a9ceSRui Ueyama   case R_AARCH64_LDST16_ABS_LO12_NC:
591e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
5922c5dd03fSFangrui Song     checkAlignment(ctx, loc, val, 2, rel);
593a6b204b8SSimon Tatham     write32Imm12(loc, getBits(val, 1, 11));
59421c0a9ceSRui Ueyama     break;
59521c0a9ceSRui Ueyama   case R_AARCH64_LDST32_ABS_LO12_NC:
596e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
5972c5dd03fSFangrui Song     checkAlignment(ctx, loc, val, 4, rel);
598a6b204b8SSimon Tatham     write32Imm12(loc, getBits(val, 2, 11));
59921c0a9ceSRui Ueyama     break;
60021c0a9ceSRui Ueyama   case R_AARCH64_LDST64_ABS_LO12_NC:
6012e54353bSPeter Smith   case R_AARCH64_LD64_GOT_LO12_NC:
602417d2d7cSDaniil Kovalev   case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
6032e54353bSPeter Smith   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
604e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
6052e54353bSPeter Smith   case R_AARCH64_TLSDESC_LD64_LO12:
606*9178708cSDaniil Kovalev   case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
6072c5dd03fSFangrui Song     checkAlignment(ctx, loc, val, 8, rel);
608a6b204b8SSimon Tatham     write32Imm12(loc, getBits(val, 3, 11));
60921c0a9ceSRui Ueyama     break;
61021c0a9ceSRui Ueyama   case R_AARCH64_LDST128_ABS_LO12_NC:
611e72d3d32SPeter Smith   case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
6122c5dd03fSFangrui Song     checkAlignment(ctx, loc, val, 16, rel);
613a6b204b8SSimon Tatham     write32Imm12(loc, getBits(val, 4, 11));
61421c0a9ceSRui Ueyama     break;
615988cc0a0SAdhemerval Zanella   case R_AARCH64_LD64_GOTPAGE_LO15:
6162c5dd03fSFangrui Song     checkAlignment(ctx, loc, val, 8, rel);
617a6b204b8SSimon Tatham     write32Imm12(loc, getBits(val, 3, 14));
618988cc0a0SAdhemerval Zanella     break;
619c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_UABS_G0:
6202c5dd03fSFangrui Song     checkUInt(ctx, loc, val, 16, rel);
621ec04e45cSFangrui Song     [[fallthrough]];
62221c0a9ceSRui Ueyama   case R_AARCH64_MOVW_UABS_G0_NC:
623a6b204b8SSimon Tatham     writeMaskedBits32le(loc, (val & 0xFFFF) << 5, 0xFFFF << 5);
62421c0a9ceSRui Ueyama     break;
625c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_UABS_G1:
6262c5dd03fSFangrui Song     checkUInt(ctx, loc, val, 32, rel);
627ec04e45cSFangrui Song     [[fallthrough]];
62821c0a9ceSRui Ueyama   case R_AARCH64_MOVW_UABS_G1_NC:
629a6b204b8SSimon Tatham     writeMaskedBits32le(loc, (val & 0xFFFF0000) >> 11, 0xFFFF0000 >> 11);
63021c0a9ceSRui Ueyama     break;
631c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_UABS_G2:
6322c5dd03fSFangrui Song     checkUInt(ctx, loc, val, 48, rel);
633ec04e45cSFangrui Song     [[fallthrough]];
63421c0a9ceSRui Ueyama   case R_AARCH64_MOVW_UABS_G2_NC:
635a6b204b8SSimon Tatham     writeMaskedBits32le(loc, (val & 0xFFFF00000000) >> 27,
636a6b204b8SSimon Tatham                         0xFFFF00000000 >> 27);
63721c0a9ceSRui Ueyama     break;
63821c0a9ceSRui Ueyama   case R_AARCH64_MOVW_UABS_G3:
639a6b204b8SSimon Tatham     writeMaskedBits32le(loc, (val & 0xFFFF000000000000) >> 43,
640a6b204b8SSimon Tatham                         0xFFFF000000000000 >> 43);
64121c0a9ceSRui Ueyama     break;
642c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G0:
643c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_SABS_G0:
644d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G0:
6452c5dd03fSFangrui Song     checkInt(ctx, loc, val, 17, rel);
646ec04e45cSFangrui Song     [[fallthrough]];
647c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G0_NC:
648d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
649c2ccf4ccSPeter Collingbourne     writeSMovWImm(loc, val);
650c2ccf4ccSPeter Collingbourne     break;
651c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G1:
652c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_SABS_G1:
653d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G1:
6542c5dd03fSFangrui Song     checkInt(ctx, loc, val, 33, rel);
655ec04e45cSFangrui Song     [[fallthrough]];
656c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G1_NC:
657d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
658c2ccf4ccSPeter Collingbourne     writeSMovWImm(loc, val >> 16);
659c2ccf4ccSPeter Collingbourne     break;
660c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G2:
661c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_SABS_G2:
662d4695e1dSPeter Smith   case R_AARCH64_TLSLE_MOVW_TPREL_G2:
6632c5dd03fSFangrui Song     checkInt(ctx, loc, val, 49, rel);
664ec04e45cSFangrui Song     [[fallthrough]];
665c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G2_NC:
666c2ccf4ccSPeter Collingbourne     writeSMovWImm(loc, val >> 32);
667c2ccf4ccSPeter Collingbourne     break;
668c2ccf4ccSPeter Collingbourne   case R_AARCH64_MOVW_PREL_G3:
669c2ccf4ccSPeter Collingbourne     writeSMovWImm(loc, val >> 48);
670c2ccf4ccSPeter Collingbourne     break;
67121c0a9ceSRui Ueyama   case R_AARCH64_TSTBR14:
6722c5dd03fSFangrui Song     checkInt(ctx, loc, val, 16, rel);
673a6b204b8SSimon Tatham     writeMaskedBits32le(loc, (val & 0xFFFC) << 3, 0xFFFC << 3);
67421c0a9ceSRui Ueyama     break;
67521c0a9ceSRui Ueyama   case R_AARCH64_TLSLE_ADD_TPREL_HI12:
6762c5dd03fSFangrui Song     checkUInt(ctx, loc, val, 24, rel);
677a6b204b8SSimon Tatham     write32Imm12(loc, val >> 12);
67821c0a9ceSRui Ueyama     break;
67921c0a9ceSRui Ueyama   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
68021c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADD_LO12:
681*9178708cSDaniil Kovalev   case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
682a6b204b8SSimon Tatham     write32Imm12(loc, val);
68321c0a9ceSRui Ueyama     break;
684cc7cb952SAlex Richardson   case R_AARCH64_TLSDESC:
685cc7cb952SAlex Richardson     // For R_AARCH64_TLSDESC the addend is stored in the second 64-bit word.
686002ca63bSFangrui Song     write64(ctx, loc + 8, val);
687cc7cb952SAlex Richardson     break;
68821c0a9ceSRui Ueyama   default:
689e54ed478SFangrui Song     llvm_unreachable("unknown relocation");
69021c0a9ceSRui Ueyama   }
69121c0a9ceSRui Ueyama }
69221c0a9ceSRui Ueyama 
6931e57038bSFangrui Song void AArch64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
6941e57038bSFangrui Song                              uint64_t val) const {
69521c0a9ceSRui Ueyama   // TLSDESC Global-Dynamic relocation are in the form:
69621c0a9ceSRui Ueyama   //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
69721c0a9ceSRui Ueyama   //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
69821c0a9ceSRui Ueyama   //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
69921c0a9ceSRui Ueyama   //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
70021c0a9ceSRui Ueyama   //   blr     x1
70121c0a9ceSRui Ueyama   // And it can optimized to:
70221c0a9ceSRui Ueyama   //   movz    x0, #0x0, lsl #16
70321c0a9ceSRui Ueyama   //   movk    x0, #0x10
70421c0a9ceSRui Ueyama   //   nop
70521c0a9ceSRui Ueyama   //   nop
7062c5dd03fSFangrui Song   checkUInt(ctx, loc, val, 32, rel);
70721c0a9ceSRui Ueyama 
7081e57038bSFangrui Song   switch (rel.type) {
70921c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADD_LO12:
71021c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_CALL:
7113837f427SRui Ueyama     write32le(loc, 0xd503201f); // nop
71221c0a9ceSRui Ueyama     return;
71321c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADR_PAGE21:
7143837f427SRui Ueyama     write32le(loc, 0xd2a00000 | (((val >> 16) & 0xffff) << 5)); // movz
71521c0a9ceSRui Ueyama     return;
71621c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_LD64_LO12:
7173837f427SRui Ueyama     write32le(loc, 0xf2800000 | ((val & 0xffff) << 5)); // movk
71821c0a9ceSRui Ueyama     return;
71921c0a9ceSRui Ueyama   default:
72021c0a9ceSRui Ueyama     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
72121c0a9ceSRui Ueyama   }
72221c0a9ceSRui Ueyama }
72321c0a9ceSRui Ueyama 
7241e57038bSFangrui Song void AArch64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
7251e57038bSFangrui Song                              uint64_t val) const {
72621c0a9ceSRui Ueyama   // TLSDESC Global-Dynamic relocation are in the form:
72721c0a9ceSRui Ueyama   //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
72821c0a9ceSRui Ueyama   //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
72921c0a9ceSRui Ueyama   //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
73021c0a9ceSRui Ueyama   //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
73121c0a9ceSRui Ueyama   //   blr     x1
73221c0a9ceSRui Ueyama   // And it can optimized to:
73321c0a9ceSRui Ueyama   //   adrp    x0, :gottprel:v
73421c0a9ceSRui Ueyama   //   ldr     x0, [x0, :gottprel_lo12:v]
73521c0a9ceSRui Ueyama   //   nop
73621c0a9ceSRui Ueyama   //   nop
73721c0a9ceSRui Ueyama 
7381e57038bSFangrui Song   switch (rel.type) {
73921c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADD_LO12:
74021c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_CALL:
7413837f427SRui Ueyama     write32le(loc, 0xd503201f); // nop
74221c0a9ceSRui Ueyama     break;
74321c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_ADR_PAGE21:
7443837f427SRui Ueyama     write32le(loc, 0x90000000); // adrp
745deb5819dSFangrui Song     relocateNoSym(loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, val);
74621c0a9ceSRui Ueyama     break;
74721c0a9ceSRui Ueyama   case R_AARCH64_TLSDESC_LD64_LO12:
7483837f427SRui Ueyama     write32le(loc, 0xf9400000); // ldr
749deb5819dSFangrui Song     relocateNoSym(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val);
75021c0a9ceSRui Ueyama     break;
75121c0a9ceSRui Ueyama   default:
75221c0a9ceSRui Ueyama     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
75321c0a9ceSRui Ueyama   }
75421c0a9ceSRui Ueyama }
75521c0a9ceSRui Ueyama 
7561e57038bSFangrui Song void AArch64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
7571e57038bSFangrui Song                              uint64_t val) const {
7582c5dd03fSFangrui Song   checkUInt(ctx, loc, val, 32, rel);
75921c0a9ceSRui Ueyama 
7601e57038bSFangrui Song   if (rel.type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
76121c0a9ceSRui Ueyama     // Generate MOVZ.
7623837f427SRui Ueyama     uint32_t regNo = read32le(loc) & 0x1f;
7633837f427SRui Ueyama     write32le(loc, (0xd2a00000 | regNo) | (((val >> 16) & 0xffff) << 5));
76421c0a9ceSRui Ueyama     return;
76521c0a9ceSRui Ueyama   }
7661e57038bSFangrui Song   if (rel.type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
76721c0a9ceSRui Ueyama     // Generate MOVK.
7683837f427SRui Ueyama     uint32_t regNo = read32le(loc) & 0x1f;
7693837f427SRui Ueyama     write32le(loc, (0xf2800000 | regNo) | ((val & 0xffff) << 5));
77021c0a9ceSRui Ueyama     return;
77121c0a9ceSRui Ueyama   }
77221c0a9ceSRui Ueyama   llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
77321c0a9ceSRui Ueyama }
77421c0a9ceSRui Ueyama 
7756d03a690SFangrui Song AArch64Relaxer::AArch64Relaxer(Ctx &ctx, ArrayRef<Relocation> relocs)
7766d03a690SFangrui Song     : ctx(ctx) {
7771dd9a565SFangrui Song   if (!ctx.arg.relax)
7788acc3b4aSAlexander Shaposhnikov     return;
7798acc3b4aSAlexander Shaposhnikov   // Check if R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC
7808acc3b4aSAlexander Shaposhnikov   // always appear in pairs.
7818acc3b4aSAlexander Shaposhnikov   size_t i = 0;
7828acc3b4aSAlexander Shaposhnikov   const size_t size = relocs.size();
7838acc3b4aSAlexander Shaposhnikov   for (; i != size; ++i) {
7848acc3b4aSAlexander Shaposhnikov     if (relocs[i].type == R_AARCH64_ADR_GOT_PAGE) {
7858acc3b4aSAlexander Shaposhnikov       if (i + 1 < size && relocs[i + 1].type == R_AARCH64_LD64_GOT_LO12_NC) {
7868acc3b4aSAlexander Shaposhnikov         ++i;
7878acc3b4aSAlexander Shaposhnikov         continue;
7888acc3b4aSAlexander Shaposhnikov       }
7898acc3b4aSAlexander Shaposhnikov       break;
7908acc3b4aSAlexander Shaposhnikov     } else if (relocs[i].type == R_AARCH64_LD64_GOT_LO12_NC) {
7918acc3b4aSAlexander Shaposhnikov       break;
7928acc3b4aSAlexander Shaposhnikov     }
7938acc3b4aSAlexander Shaposhnikov   }
7948acc3b4aSAlexander Shaposhnikov   safeToRelaxAdrpLdr = i == size;
7958acc3b4aSAlexander Shaposhnikov }
7968acc3b4aSAlexander Shaposhnikov 
797821e04deSFangrui Song bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel,
7984450a2a2SAlexander Shaposhnikov                                      const Relocation &addRel, uint64_t secAddr,
7994450a2a2SAlexander Shaposhnikov                                      uint8_t *buf) const {
8004450a2a2SAlexander Shaposhnikov   // When the address of sym is within the range of ADR then
8014450a2a2SAlexander Shaposhnikov   // we may relax
8024450a2a2SAlexander Shaposhnikov   // ADRP xn, sym
8034450a2a2SAlexander Shaposhnikov   // ADD  xn, xn, :lo12: sym
8044450a2a2SAlexander Shaposhnikov   // to
8054450a2a2SAlexander Shaposhnikov   // NOP
8064450a2a2SAlexander Shaposhnikov   // ADR xn, sym
8071dd9a565SFangrui Song   if (!ctx.arg.relax || adrpRel.type != R_AARCH64_ADR_PREL_PG_HI21 ||
8084450a2a2SAlexander Shaposhnikov       addRel.type != R_AARCH64_ADD_ABS_LO12_NC)
8094450a2a2SAlexander Shaposhnikov     return false;
8104450a2a2SAlexander Shaposhnikov   // Check if the relocations apply to consecutive instructions.
8114450a2a2SAlexander Shaposhnikov   if (adrpRel.offset + 4 != addRel.offset)
8124450a2a2SAlexander Shaposhnikov     return false;
8134450a2a2SAlexander Shaposhnikov   if (adrpRel.sym != addRel.sym)
8144450a2a2SAlexander Shaposhnikov     return false;
8154450a2a2SAlexander Shaposhnikov   if (adrpRel.addend != 0 || addRel.addend != 0)
8164450a2a2SAlexander Shaposhnikov     return false;
8174450a2a2SAlexander Shaposhnikov 
8184450a2a2SAlexander Shaposhnikov   uint32_t adrpInstr = read32le(buf + adrpRel.offset);
8194450a2a2SAlexander Shaposhnikov   uint32_t addInstr = read32le(buf + addRel.offset);
8204450a2a2SAlexander Shaposhnikov   // Check if the first instruction is ADRP and the second instruction is ADD.
8214450a2a2SAlexander Shaposhnikov   if ((adrpInstr & 0x9f000000) != 0x90000000 ||
8224450a2a2SAlexander Shaposhnikov       (addInstr & 0xffc00000) != 0x91000000)
8234450a2a2SAlexander Shaposhnikov     return false;
8244450a2a2SAlexander Shaposhnikov   uint32_t adrpDestReg = adrpInstr & 0x1f;
8254450a2a2SAlexander Shaposhnikov   uint32_t addDestReg = addInstr & 0x1f;
8264450a2a2SAlexander Shaposhnikov   uint32_t addSrcReg = (addInstr >> 5) & 0x1f;
8274450a2a2SAlexander Shaposhnikov   if (adrpDestReg != addDestReg || adrpDestReg != addSrcReg)
8284450a2a2SAlexander Shaposhnikov     return false;
8294450a2a2SAlexander Shaposhnikov 
8304450a2a2SAlexander Shaposhnikov   Symbol &sym = *adrpRel.sym;
8314450a2a2SAlexander Shaposhnikov   // Check if the address difference is within 1MiB range.
832861bd36bSFangrui Song   int64_t val = sym.getVA(ctx) - (secAddr + addRel.offset);
8334450a2a2SAlexander Shaposhnikov   if (val < -1024 * 1024 || val >= 1024 * 1024)
8344450a2a2SAlexander Shaposhnikov     return false;
8354450a2a2SAlexander Shaposhnikov 
8364450a2a2SAlexander Shaposhnikov   Relocation adrRel = {R_ABS, R_AARCH64_ADR_PREL_LO21, addRel.offset,
8374450a2a2SAlexander Shaposhnikov                        /*addend=*/0, &sym};
8384450a2a2SAlexander Shaposhnikov   // nop
8394450a2a2SAlexander Shaposhnikov   write32le(buf + adrpRel.offset, 0xd503201f);
8404450a2a2SAlexander Shaposhnikov   // adr x_<dest_reg>
8414450a2a2SAlexander Shaposhnikov   write32le(buf + adrRel.offset, 0x10000000 | adrpDestReg);
842b4feb266SFangrui Song   ctx.target->relocate(buf + adrRel.offset, adrRel, val);
8434450a2a2SAlexander Shaposhnikov   return true;
8444450a2a2SAlexander Shaposhnikov }
8454450a2a2SAlexander Shaposhnikov 
846821e04deSFangrui Song bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
8478acc3b4aSAlexander Shaposhnikov                                      const Relocation &ldrRel, uint64_t secAddr,
8488acc3b4aSAlexander Shaposhnikov                                      uint8_t *buf) const {
8498acc3b4aSAlexander Shaposhnikov   if (!safeToRelaxAdrpLdr)
8508acc3b4aSAlexander Shaposhnikov     return false;
8518acc3b4aSAlexander Shaposhnikov 
8528acc3b4aSAlexander Shaposhnikov   // When the definition of sym is not preemptible then we may
8538acc3b4aSAlexander Shaposhnikov   // be able to relax
8548acc3b4aSAlexander Shaposhnikov   // ADRP xn, :got: sym
8558acc3b4aSAlexander Shaposhnikov   // LDR xn, [ xn :got_lo12: sym]
8568acc3b4aSAlexander Shaposhnikov   // to
8578acc3b4aSAlexander Shaposhnikov   // ADRP xn, sym
8588acc3b4aSAlexander Shaposhnikov   // ADD xn, xn, :lo_12: sym
8598acc3b4aSAlexander Shaposhnikov 
8608acc3b4aSAlexander Shaposhnikov   if (adrpRel.type != R_AARCH64_ADR_GOT_PAGE ||
8618acc3b4aSAlexander Shaposhnikov       ldrRel.type != R_AARCH64_LD64_GOT_LO12_NC)
8628acc3b4aSAlexander Shaposhnikov     return false;
8638acc3b4aSAlexander Shaposhnikov   // Check if the relocations apply to consecutive instructions.
8648acc3b4aSAlexander Shaposhnikov   if (adrpRel.offset + 4 != ldrRel.offset)
8658acc3b4aSAlexander Shaposhnikov     return false;
8668acc3b4aSAlexander Shaposhnikov   // Check if the relocations reference the same symbol and
8678acc3b4aSAlexander Shaposhnikov   // skip undefined, preemptible and STT_GNU_IFUNC symbols.
8688acc3b4aSAlexander Shaposhnikov   if (!adrpRel.sym || adrpRel.sym != ldrRel.sym || !adrpRel.sym->isDefined() ||
8698acc3b4aSAlexander Shaposhnikov       adrpRel.sym->isPreemptible || adrpRel.sym->isGnuIFunc())
8708acc3b4aSAlexander Shaposhnikov     return false;
8712bb7f226SAlexander Shaposhnikov   // Check if the addends of the both relocations are zero.
8728acc3b4aSAlexander Shaposhnikov   if (adrpRel.addend != 0 || ldrRel.addend != 0)
8738acc3b4aSAlexander Shaposhnikov     return false;
8748acc3b4aSAlexander Shaposhnikov   uint32_t adrpInstr = read32le(buf + adrpRel.offset);
8758acc3b4aSAlexander Shaposhnikov   uint32_t ldrInstr = read32le(buf + ldrRel.offset);
8768acc3b4aSAlexander Shaposhnikov   // Check if the first instruction is ADRP and the second instruction is LDR.
8778acc3b4aSAlexander Shaposhnikov   if ((adrpInstr & 0x9f000000) != 0x90000000 ||
8788acc3b4aSAlexander Shaposhnikov       (ldrInstr & 0x3b000000) != 0x39000000)
8798acc3b4aSAlexander Shaposhnikov     return false;
8808acc3b4aSAlexander Shaposhnikov   // Check the value of the sf bit.
8818acc3b4aSAlexander Shaposhnikov   if (!(ldrInstr >> 31))
8828acc3b4aSAlexander Shaposhnikov     return false;
8838acc3b4aSAlexander Shaposhnikov   uint32_t adrpDestReg = adrpInstr & 0x1f;
8848acc3b4aSAlexander Shaposhnikov   uint32_t ldrDestReg = ldrInstr & 0x1f;
8858acc3b4aSAlexander Shaposhnikov   uint32_t ldrSrcReg = (ldrInstr >> 5) & 0x1f;
8868acc3b4aSAlexander Shaposhnikov   // Check if ADPR and LDR use the same register.
8878acc3b4aSAlexander Shaposhnikov   if (adrpDestReg != ldrDestReg || adrpDestReg != ldrSrcReg)
8888acc3b4aSAlexander Shaposhnikov     return false;
8898acc3b4aSAlexander Shaposhnikov 
8908acc3b4aSAlexander Shaposhnikov   Symbol &sym = *adrpRel.sym;
891b064bc18SPeter Collingbourne   // GOT references to absolute symbols can't be relaxed to use ADRP/ADD in
892b064bc18SPeter Collingbourne   // position-independent code because these instructions produce a relative
893b064bc18SPeter Collingbourne   // address.
8941dd9a565SFangrui Song   if (ctx.arg.isPic && !cast<Defined>(sym).section)
895b064bc18SPeter Collingbourne     return false;
8968acc3b4aSAlexander Shaposhnikov   // Check if the address difference is within 4GB range.
8978acc3b4aSAlexander Shaposhnikov   int64_t val =
898861bd36bSFangrui Song       getAArch64Page(sym.getVA(ctx)) - getAArch64Page(secAddr + adrpRel.offset);
8998acc3b4aSAlexander Shaposhnikov   if (val != llvm::SignExtend64(val, 33))
9008acc3b4aSAlexander Shaposhnikov     return false;
9018acc3b4aSAlexander Shaposhnikov 
90204996a28SFangrui Song   Relocation adrpSymRel = {RE_AARCH64_PAGE_PC, R_AARCH64_ADR_PREL_PG_HI21,
9038acc3b4aSAlexander Shaposhnikov                            adrpRel.offset, /*addend=*/0, &sym};
9048acc3b4aSAlexander Shaposhnikov   Relocation addRel = {R_ABS, R_AARCH64_ADD_ABS_LO12_NC, ldrRel.offset,
9058acc3b4aSAlexander Shaposhnikov                        /*addend=*/0, &sym};
9068acc3b4aSAlexander Shaposhnikov 
9078acc3b4aSAlexander Shaposhnikov   // adrp x_<dest_reg>
9088acc3b4aSAlexander Shaposhnikov   write32le(buf + adrpSymRel.offset, 0x90000000 | adrpDestReg);
9098acc3b4aSAlexander Shaposhnikov   // add x_<dest reg>, x_<dest reg>
9108acc3b4aSAlexander Shaposhnikov   write32le(buf + addRel.offset, 0x91000000 | adrpDestReg | (adrpDestReg << 5));
9118acc3b4aSAlexander Shaposhnikov 
912b4feb266SFangrui Song   ctx.target->relocate(
913b4feb266SFangrui Song       buf + adrpSymRel.offset, adrpSymRel,
914861bd36bSFangrui Song       SignExtend64(getAArch64Page(sym.getVA(ctx)) -
9158acc3b4aSAlexander Shaposhnikov                        getAArch64Page(secAddr + adrpSymRel.offset),
9168acc3b4aSAlexander Shaposhnikov                    64));
917b4feb266SFangrui Song   ctx.target->relocate(buf + addRel.offset, addRel,
918861bd36bSFangrui Song                        SignExtend64(sym.getVA(ctx), 64));
9194450a2a2SAlexander Shaposhnikov   tryRelaxAdrpAdd(adrpSymRel, addRel, secAddr, buf);
9208acc3b4aSAlexander Shaposhnikov   return true;
9218acc3b4aSAlexander Shaposhnikov }
9228acc3b4aSAlexander Shaposhnikov 
923ca35a19aSMitch Phillips // Tagged symbols have upper address bits that are added by the dynamic loader,
924ca35a19aSMitch Phillips // and thus need the full 64-bit GOT entry. Do not relax such symbols.
925ca35a19aSMitch Phillips static bool needsGotForMemtag(const Relocation &rel) {
926ca35a19aSMitch Phillips   return rel.sym->isTagged() && needsGot(rel.expr);
927ca35a19aSMitch Phillips }
928ca35a19aSMitch Phillips 
929685b2125SFangrui Song void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
930685b2125SFangrui Song   uint64_t secAddr = sec.getOutputSection()->addr;
931685b2125SFangrui Song   if (auto *s = dyn_cast<InputSection>(&sec))
932685b2125SFangrui Song     secAddr += s->outSecOff;
9333cde1d80Ssimpal01   else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
9343cde1d80Ssimpal01     secAddr += ehIn->getParent()->outSecOff;
9356d03a690SFangrui Song   AArch64Relaxer relaxer(ctx, sec.relocs());
936c3c9e453SFangrui Song   for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
937c3c9e453SFangrui Song     const Relocation &rel = sec.relocs()[i];
938685b2125SFangrui Song     uint8_t *loc = buf + rel.offset;
9392b5cb1bfSFangrui Song     const uint64_t val = sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset);
940ca35a19aSMitch Phillips 
941ca35a19aSMitch Phillips     if (needsGotForMemtag(rel)) {
942ca35a19aSMitch Phillips       relocate(loc, rel, val);
943ca35a19aSMitch Phillips       continue;
944ca35a19aSMitch Phillips     }
945ca35a19aSMitch Phillips 
946685b2125SFangrui Song     switch (rel.expr) {
94704996a28SFangrui Song     case RE_AARCH64_GOT_PAGE_PC:
948685b2125SFangrui Song       if (i + 1 < size &&
949c3c9e453SFangrui Song           relaxer.tryRelaxAdrpLdr(rel, sec.relocs()[i + 1], secAddr, buf)) {
950685b2125SFangrui Song         ++i;
951685b2125SFangrui Song         continue;
952685b2125SFangrui Song       }
953685b2125SFangrui Song       break;
95404996a28SFangrui Song     case RE_AARCH64_PAGE_PC:
955685b2125SFangrui Song       if (i + 1 < size &&
956c3c9e453SFangrui Song           relaxer.tryRelaxAdrpAdd(rel, sec.relocs()[i + 1], secAddr, buf)) {
957685b2125SFangrui Song         ++i;
958685b2125SFangrui Song         continue;
959685b2125SFangrui Song       }
960685b2125SFangrui Song       break;
96104996a28SFangrui Song     case RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
962685b2125SFangrui Song     case R_RELAX_TLS_GD_TO_IE_ABS:
963685b2125SFangrui Song       relaxTlsGdToIe(loc, rel, val);
964685b2125SFangrui Song       continue;
965685b2125SFangrui Song     case R_RELAX_TLS_GD_TO_LE:
966685b2125SFangrui Song       relaxTlsGdToLe(loc, rel, val);
967685b2125SFangrui Song       continue;
968685b2125SFangrui Song     case R_RELAX_TLS_IE_TO_LE:
969685b2125SFangrui Song       relaxTlsIeToLe(loc, rel, val);
970685b2125SFangrui Song       continue;
971685b2125SFangrui Song     default:
972685b2125SFangrui Song       break;
973685b2125SFangrui Song     }
974685b2125SFangrui Song     relocate(loc, rel, val);
975685b2125SFangrui Song   }
976685b2125SFangrui Song }
977685b2125SFangrui Song 
978e208208aSPeter Smith // AArch64 may use security features in variant PLT sequences. These are:
979e208208aSPeter Smith // Pointer Authentication (PAC), introduced in armv8.3-a and Branch Target
980e208208aSPeter Smith // Indicator (BTI) introduced in armv8.5-a. The additional instructions used
981e208208aSPeter Smith // in the variant Plt sequences are encoded in the Hint space so they can be
982e208208aSPeter Smith // deployed on older architectures, which treat the instructions as a nop.
983e208208aSPeter Smith // PAC and BTI can be combined leading to the following combinations:
984e208208aSPeter Smith // writePltHeader
985e208208aSPeter Smith // writePltHeaderBti (no PAC Header needed)
986e208208aSPeter Smith // writePlt
987e208208aSPeter Smith // writePltBti (BTI only)
988e208208aSPeter Smith // writePltPac (PAC only)
989e208208aSPeter Smith // writePltBtiPac (BTI and PAC)
990e208208aSPeter Smith //
991e208208aSPeter Smith // When PAC is enabled the dynamic loader encrypts the address that it places
992e208208aSPeter Smith // in the .got.plt using the pacia1716 instruction which encrypts the value in
993e208208aSPeter Smith // x17 using the modifier in x16. The static linker places autia1716 before the
994e208208aSPeter Smith // indirect branch to x17 to authenticate the address in x17 with the modifier
995e208208aSPeter Smith // in x16. This makes it more difficult for an attacker to modify the value in
996e208208aSPeter Smith // the .got.plt.
997e208208aSPeter Smith //
998e208208aSPeter Smith // When BTI is enabled all indirect branches must land on a bti instruction.
999e208208aSPeter Smith // The static linker must place a bti instruction at the start of any PLT entry
1000e208208aSPeter Smith // that may be the target of an indirect branch. As the PLT entries call the
1001e208208aSPeter Smith // lazy resolver indirectly this must have a bti instruction at start. In
1002e208208aSPeter Smith // general a bti instruction is not needed for a PLT entry as indirect calls
1003e208208aSPeter Smith // are resolved to the function address and not the PLT entry for the function.
1004e208208aSPeter Smith // There are a small number of cases where the PLT address can escape, such as
1005e208208aSPeter Smith // taking the address of a function or ifunc via a non got-generating
1006e208208aSPeter Smith // relocation, and a shared library refers to that symbol.
1007e208208aSPeter Smith //
1008e208208aSPeter Smith // We use the bti c variant of the instruction which permits indirect branches
1009e208208aSPeter Smith // (br) via x16/x17 and indirect function calls (blr) via any register. The ABI
1010e208208aSPeter Smith // guarantees that all indirect branches from code requiring BTI protection
1011e208208aSPeter Smith // will go via x16/x17
1012e208208aSPeter Smith 
1013e208208aSPeter Smith namespace {
1014e208208aSPeter Smith class AArch64BtiPac final : public AArch64 {
1015e208208aSPeter Smith public:
1016c3e4998cSFangrui Song   AArch64BtiPac(Ctx &);
10173837f427SRui Ueyama   void writePltHeader(uint8_t *buf) const override;
101837b28080SFangrui Song   void writePlt(uint8_t *buf, const Symbol &sym,
101937b28080SFangrui Song                 uint64_t pltEntryAddr) const override;
1020e208208aSPeter Smith 
1021e208208aSPeter Smith private:
102219d53d45SFangrui Song   bool btiHeader; // bti instruction needed in PLT Header and Entry
10231c4f335eSDaniil Kovalev   enum {
10241c4f335eSDaniil Kovalev     PEK_NoAuth,
10251c4f335eSDaniil Kovalev     PEK_AuthHint, // use autia1716 instr for authenticated branch in PLT entry
10261c4f335eSDaniil Kovalev     PEK_Auth,     // use braa instr for authenticated branch in PLT entry
10271c4f335eSDaniil Kovalev   } pacEntryKind;
1028e208208aSPeter Smith };
1029e208208aSPeter Smith } // namespace
1030e208208aSPeter Smith 
1031c3e4998cSFangrui Song AArch64BtiPac::AArch64BtiPac(Ctx &ctx) : AArch64(ctx) {
10321dd9a565SFangrui Song   btiHeader = (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
1033e208208aSPeter Smith   // A BTI (Branch Target Indicator) Plt Entry is only required if the
1034e208208aSPeter Smith   // address of the PLT entry can be taken by the program, which permits an
1035e208208aSPeter Smith   // indirect jump to the PLT entry. This can happen when the address
1036e208208aSPeter Smith   // of the PLT entry for a function is canonicalised due to the address of
103719d53d45SFangrui Song   // the function in an executable being taken by a shared library, or
103819d53d45SFangrui Song   // non-preemptible ifunc referenced by non-GOT-generating, non-PLT-generating
103919d53d45SFangrui Song   // relocations.
1040b6162622SDaniel Kiss   // The PAC PLT entries require dynamic loader support and this isn't known
1041b6162622SDaniel Kiss   // from properties in the objects, so we use the command line flag.
10421c4f335eSDaniil Kovalev   // By default we only use hint-space instructions, but if we detect the
10431c4f335eSDaniil Kovalev   // PAuthABI, which requires v8.3-A, we can use the non-hint space
10441c4f335eSDaniil Kovalev   // instructions.
1045e208208aSPeter Smith 
10461c4f335eSDaniil Kovalev   if (ctx.arg.zPacPlt) {
10471c4f335eSDaniil Kovalev     if (llvm::any_of(ctx.aarch64PauthAbiCoreInfo,
10481c4f335eSDaniil Kovalev                      [](uint8_t c) { return c != 0; }))
10491c4f335eSDaniil Kovalev       pacEntryKind = PEK_Auth;
10501c4f335eSDaniil Kovalev     else
10511c4f335eSDaniil Kovalev       pacEntryKind = PEK_AuthHint;
10521c4f335eSDaniil Kovalev   } else {
10531c4f335eSDaniil Kovalev     pacEntryKind = PEK_NoAuth;
10541c4f335eSDaniil Kovalev   }
10551c4f335eSDaniil Kovalev 
10561c4f335eSDaniil Kovalev   if (btiHeader || (pacEntryKind != PEK_NoAuth)) {
10573837f427SRui Ueyama     pltEntrySize = 24;
1058891a8655SFangrui Song     ipltEntrySize = 24;
1059891a8655SFangrui Song   }
1060e145bc22SRui Ueyama }
1061e208208aSPeter Smith 
10623837f427SRui Ueyama void AArch64BtiPac::writePltHeader(uint8_t *buf) const {
10633837f427SRui Ueyama   const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
10643837f427SRui Ueyama   const uint8_t pltData[] = {
1065e208208aSPeter Smith       0xf0, 0x7b, 0xbf, 0xa9, // stp    x16, x30, [sp,#-16]!
10664c244b28SFangrui Song       0x10, 0x00, 0x00, 0x90, // adrp   x16, Page(&(.got.plt[2]))
10674c244b28SFangrui Song       0x11, 0x02, 0x40, 0xf9, // ldr    x17, [x16, Offset(&(.got.plt[2]))]
10684c244b28SFangrui Song       0x10, 0x02, 0x00, 0x91, // add    x16, x16, Offset(&(.got.plt[2]))
1069e208208aSPeter Smith       0x20, 0x02, 0x1f, 0xd6, // br     x17
1070e208208aSPeter Smith       0x1f, 0x20, 0x03, 0xd5, // nop
1071e208208aSPeter Smith       0x1f, 0x20, 0x03, 0xd5  // nop
1072e208208aSPeter Smith   };
10733837f427SRui Ueyama   const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
1074e208208aSPeter Smith 
1075e88b7ff0SFangrui Song   uint64_t got = ctx.in.gotPlt->getVA();
1076e88b7ff0SFangrui Song   uint64_t plt = ctx.in.plt->getVA();
1077e208208aSPeter Smith 
10783837f427SRui Ueyama   if (btiHeader) {
107947cfe8f3SFangrui Song     // PltHeader is called indirectly by plt[N]. Prefix pltData with a BTI C
1080e208208aSPeter Smith     // instruction.
10813837f427SRui Ueyama     memcpy(buf, btiData, sizeof(btiData));
10823837f427SRui Ueyama     buf += sizeof(btiData);
10833837f427SRui Ueyama     plt += sizeof(btiData);
1084e208208aSPeter Smith   }
10853837f427SRui Ueyama   memcpy(buf, pltData, sizeof(pltData));
1086e208208aSPeter Smith 
1087deb5819dSFangrui Song   relocateNoSym(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
1088a4ace3deSDaniil Kovalev                 getAArch64Page(got + 16) - getAArch64Page(plt + 4));
1089deb5819dSFangrui Song   relocateNoSym(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
1090deb5819dSFangrui Song   relocateNoSym(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
10913837f427SRui Ueyama   if (!btiHeader)
1092e208208aSPeter Smith     // We didn't add the BTI c instruction so round out size with NOP.
10933837f427SRui Ueyama     memcpy(buf + sizeof(pltData), nopData, sizeof(nopData));
1094e208208aSPeter Smith }
1095e208208aSPeter Smith 
109637b28080SFangrui Song void AArch64BtiPac::writePlt(uint8_t *buf, const Symbol &sym,
109737b28080SFangrui Song                              uint64_t pltEntryAddr) const {
1098e208208aSPeter Smith   // The PLT entry is of the form:
109947cfe8f3SFangrui Song   // [btiData] addrInst (pacBr | stdBr) [nopData]
11003837f427SRui Ueyama   const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
11013837f427SRui Ueyama   const uint8_t addrInst[] = {
11024c244b28SFangrui Song       0x10, 0x00, 0x00, 0x90,  // adrp x16, Page(&(.got.plt[n]))
11034c244b28SFangrui Song       0x11, 0x02, 0x40, 0xf9,  // ldr  x17, [x16, Offset(&(.got.plt[n]))]
11044c244b28SFangrui Song       0x10, 0x02, 0x00, 0x91   // add  x16, x16, Offset(&(.got.plt[n]))
1105e208208aSPeter Smith   };
11061c4f335eSDaniil Kovalev   const uint8_t pacHintBr[] = {
1107e208208aSPeter Smith       0x9f, 0x21, 0x03, 0xd5, // autia1716
1108e208208aSPeter Smith       0x20, 0x02, 0x1f, 0xd6  // br   x17
1109e208208aSPeter Smith   };
11101c4f335eSDaniil Kovalev   const uint8_t pacBr[] = {
11111c4f335eSDaniil Kovalev       0x30, 0x0a, 0x1f, 0xd7, // braa x17, x16
11121c4f335eSDaniil Kovalev       0x1f, 0x20, 0x03, 0xd5  // nop
11131c4f335eSDaniil Kovalev   };
11143837f427SRui Ueyama   const uint8_t stdBr[] = {
1115e208208aSPeter Smith       0x20, 0x02, 0x1f, 0xd6,  // br   x17
1116e208208aSPeter Smith       0x1f, 0x20, 0x03, 0xd5   // nop
1117e208208aSPeter Smith   };
11183837f427SRui Ueyama   const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
1119e208208aSPeter Smith 
1120bd16ffb3SFangrui Song   // NEEDS_COPY indicates a non-ifunc canonical PLT entry whose address may
112119d53d45SFangrui Song   // escape to shared objects. isInIplt indicates a non-preemptible ifunc. Its
112292fbb602SDaniel Kiss   // address may escape if referenced by a direct relocation. If relative
112392fbb602SDaniel Kiss   // vtables are used then if the vtable is in a shared object the offsets will
112492fbb602SDaniel Kiss   // be to the PLT entry. The condition is conservative.
112560827df7SDaniel Kiss   bool hasBti = btiHeader &&
112660827df7SDaniel Kiss                 (sym.hasFlag(NEEDS_COPY) || sym.isInIplt || sym.thunkAccessed);
112719d53d45SFangrui Song   if (hasBti) {
11283837f427SRui Ueyama     memcpy(buf, btiData, sizeof(btiData));
11293837f427SRui Ueyama     buf += sizeof(btiData);
11303837f427SRui Ueyama     pltEntryAddr += sizeof(btiData);
1131e208208aSPeter Smith   }
1132e208208aSPeter Smith 
1133acb2b1e7SFangrui Song   uint64_t gotPltEntryAddr = sym.getGotPltVA(ctx);
11343837f427SRui Ueyama   memcpy(buf, addrInst, sizeof(addrInst));
1135deb5819dSFangrui Song   relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
1136deb5819dSFangrui Song                 getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
1137deb5819dSFangrui Song   relocateNoSym(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
1138deb5819dSFangrui Song   relocateNoSym(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
1139e208208aSPeter Smith 
11401c4f335eSDaniil Kovalev   if (pacEntryKind != PEK_NoAuth)
11411c4f335eSDaniil Kovalev     memcpy(buf + sizeof(addrInst),
11421c4f335eSDaniil Kovalev            pacEntryKind == PEK_AuthHint ? pacHintBr : pacBr,
11431c4f335eSDaniil Kovalev            sizeof(pacEntryKind == PEK_AuthHint ? pacHintBr : pacBr));
1144e208208aSPeter Smith   else
11453837f427SRui Ueyama     memcpy(buf + sizeof(addrInst), stdBr, sizeof(stdBr));
114619d53d45SFangrui Song   if (!hasBti)
1147e208208aSPeter Smith     // We didn't add the BTI c instruction so round out size with NOP.
11483837f427SRui Ueyama     memcpy(buf + sizeof(addrInst) + sizeof(stdBr), nopData, sizeof(nopData));
1149e208208aSPeter Smith }
1150e208208aSPeter Smith 
1151ca35a19aSMitch Phillips template <class ELFT>
1152ca35a19aSMitch Phillips static void
1153d69cc05bSFangrui Song addTaggedSymbolReferences(Ctx &ctx, InputSectionBase &sec,
1154ca35a19aSMitch Phillips                           DenseMap<Symbol *, unsigned> &referenceCount) {
1155ca35a19aSMitch Phillips   assert(sec.type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC);
1156ca35a19aSMitch Phillips 
1157ca35a19aSMitch Phillips   const RelsOrRelas<ELFT> rels = sec.relsOrRelas<ELFT>();
1158ca35a19aSMitch Phillips   if (rels.areRelocsRel())
115909c2c5e1SFangrui Song     ErrAlways(ctx)
116009c2c5e1SFangrui Song         << "non-RELA relocations are not allowed with memtag globals";
1161ca35a19aSMitch Phillips 
1162ca35a19aSMitch Phillips   for (const typename ELFT::Rela &rel : rels.relas) {
1163f6455606SFangrui Song     Symbol &sym = sec.file->getRelocTargetSym(rel);
1164ca35a19aSMitch Phillips     // Linker-synthesized symbols such as __executable_start may be referenced
1165ca35a19aSMitch Phillips     // as tagged in input objfiles, and we don't want them to be tagged. A
1166ca35a19aSMitch Phillips     // cheap way to exclude them is the type check, but their type is
1167ca35a19aSMitch Phillips     // STT_NOTYPE. In addition, this save us from checking untaggable symbols,
1168ca35a19aSMitch Phillips     // like functions or TLS symbols.
1169ca35a19aSMitch Phillips     if (sym.type != STT_OBJECT)
1170ca35a19aSMitch Phillips       continue;
1171ca35a19aSMitch Phillips     // STB_LOCAL symbols can't be referenced from outside the object file, and
1172ca35a19aSMitch Phillips     // thus don't need to be checked for references from other object files.
1173ca35a19aSMitch Phillips     if (sym.binding == STB_LOCAL) {
1174ca35a19aSMitch Phillips       sym.setIsTagged(true);
1175ca35a19aSMitch Phillips       continue;
1176ca35a19aSMitch Phillips     }
1177ca35a19aSMitch Phillips     ++referenceCount[&sym];
1178ca35a19aSMitch Phillips   }
1179ca35a19aSMitch Phillips   sec.markDead();
1180ca35a19aSMitch Phillips }
1181ca35a19aSMitch Phillips 
1182ca35a19aSMitch Phillips // A tagged symbol must be denoted as being tagged by all references and the
1183ca35a19aSMitch Phillips // chosen definition. For simplicity, here, it must also be denoted as tagged
1184ca35a19aSMitch Phillips // for all definitions. Otherwise:
1185ca35a19aSMitch Phillips //
1186ca35a19aSMitch Phillips //  1. A tagged definition can be used by an untagged declaration, in which case
1187ca35a19aSMitch Phillips //     the untagged access may be PC-relative, causing a tag mismatch at
1188ca35a19aSMitch Phillips //     runtime.
1189ca35a19aSMitch Phillips //  2. An untagged definition can be used by a tagged declaration, where the
1190ca35a19aSMitch Phillips //     compiler has taken advantage of the increased alignment of the tagged
1191ca35a19aSMitch Phillips //     declaration, but the alignment at runtime is wrong, causing a fault.
1192ca35a19aSMitch Phillips //
1193ca35a19aSMitch Phillips // Ideally, this isn't a problem, as any TU that imports or exports tagged
1194ca35a19aSMitch Phillips // symbols should also be built with tagging. But, to handle these cases, we
1195ca35a19aSMitch Phillips // demote the symbol to be untagged.
11966d03a690SFangrui Song void elf::createTaggedSymbols(Ctx &ctx) {
11971c28f311SFangrui Song   assert(hasMemtag(ctx));
1198ca35a19aSMitch Phillips 
1199ca35a19aSMitch Phillips   // First, collect all symbols that are marked as tagged, and count how many
1200ca35a19aSMitch Phillips   // times they're marked as tagged.
1201ca35a19aSMitch Phillips   DenseMap<Symbol *, unsigned> taggedSymbolReferenceCount;
12026d03a690SFangrui Song   for (InputFile *file : ctx.objectFiles) {
1203ca35a19aSMitch Phillips     if (file->kind() != InputFile::ObjKind)
1204ca35a19aSMitch Phillips       continue;
1205ca35a19aSMitch Phillips     for (InputSectionBase *section : file->getSections()) {
1206ca35a19aSMitch Phillips       if (!section || section->type != SHT_AARCH64_MEMTAG_GLOBALS_STATIC ||
1207ca35a19aSMitch Phillips           section == &InputSection::discarded)
1208ca35a19aSMitch Phillips         continue;
1209d69cc05bSFangrui Song       invokeELFT(addTaggedSymbolReferences, ctx, *section,
1210ca35a19aSMitch Phillips                  taggedSymbolReferenceCount);
1211ca35a19aSMitch Phillips     }
1212ca35a19aSMitch Phillips   }
1213ca35a19aSMitch Phillips 
1214ca35a19aSMitch Phillips   // Now, go through all the symbols. If the number of declarations +
1215ca35a19aSMitch Phillips   // definitions to a symbol exceeds the amount of times they're marked as
1216ca35a19aSMitch Phillips   // tagged, it means we have an objfile that uses the untagged variant of the
1217ca35a19aSMitch Phillips   // symbol.
12186d03a690SFangrui Song   for (InputFile *file : ctx.objectFiles) {
1219ca35a19aSMitch Phillips     if (file->kind() != InputFile::BinaryKind &&
1220ca35a19aSMitch Phillips         file->kind() != InputFile::ObjKind)
1221ca35a19aSMitch Phillips       continue;
1222ca35a19aSMitch Phillips 
1223ca35a19aSMitch Phillips     for (Symbol *symbol : file->getSymbols()) {
1224ca35a19aSMitch Phillips       // See `addTaggedSymbolReferences` for more details.
1225ca35a19aSMitch Phillips       if (symbol->type != STT_OBJECT ||
1226ca35a19aSMitch Phillips           symbol->binding == STB_LOCAL)
1227ca35a19aSMitch Phillips         continue;
1228ca35a19aSMitch Phillips       auto it = taggedSymbolReferenceCount.find(symbol);
1229ca35a19aSMitch Phillips       if (it == taggedSymbolReferenceCount.end()) continue;
1230ca35a19aSMitch Phillips       unsigned &remainingAllowedTaggedRefs = it->second;
1231ca35a19aSMitch Phillips       if (remainingAllowedTaggedRefs == 0) {
1232ca35a19aSMitch Phillips         taggedSymbolReferenceCount.erase(it);
1233ca35a19aSMitch Phillips         continue;
1234ca35a19aSMitch Phillips       }
1235ca35a19aSMitch Phillips       --remainingAllowedTaggedRefs;
1236ca35a19aSMitch Phillips     }
1237ca35a19aSMitch Phillips   }
1238ca35a19aSMitch Phillips 
1239ca35a19aSMitch Phillips   // `addTaggedSymbolReferences` has already checked that we have RELA
1240ca35a19aSMitch Phillips   // relocations, the only other way to get written addends is with
1241ca35a19aSMitch Phillips   // --apply-dynamic-relocs.
12421dd9a565SFangrui Song   if (!taggedSymbolReferenceCount.empty() && ctx.arg.writeAddends)
124309c2c5e1SFangrui Song     ErrAlways(ctx) << "--apply-dynamic-relocs cannot be used with MTE globals";
1244ca35a19aSMitch Phillips 
1245ca35a19aSMitch Phillips   // Now, `taggedSymbolReferenceCount` should only contain symbols that are
1246ca35a19aSMitch Phillips   // defined as tagged exactly the same amount as it's referenced, meaning all
1247ca35a19aSMitch Phillips   // uses are tagged.
1248ca35a19aSMitch Phillips   for (auto &[symbol, remainingTaggedRefs] : taggedSymbolReferenceCount) {
1249ca35a19aSMitch Phillips     assert(remainingTaggedRefs == 0 &&
1250ca35a19aSMitch Phillips             "Symbol is defined as tagged more times than it's used");
1251ca35a19aSMitch Phillips     symbol->setIsTagged(true);
1252ca35a19aSMitch Phillips   }
1253ca35a19aSMitch Phillips }
1254b0fc36dfSFangrui Song 
1255e1a073c9SFangrui Song void elf::setAArch64TargetInfo(Ctx &ctx) {
1256b0fc36dfSFangrui Song   if ((ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ||
1257e1a073c9SFangrui Song       ctx.arg.zPacPlt)
1258e1a073c9SFangrui Song     ctx.target.reset(new AArch64BtiPac(ctx));
1259e1a073c9SFangrui Song   else
1260e1a073c9SFangrui Song     ctx.target.reset(new AArch64(ctx));
1261b0fc36dfSFangrui Song }
1262