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