xref: /freebsd/contrib/llvm-project/lld/ELF/Arch/AArch64.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- AArch64.cpp --------------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "Symbols.h"
10*0b57cec5SDimitry Andric #include "SyntheticSections.h"
11*0b57cec5SDimitry Andric #include "Target.h"
12*0b57cec5SDimitry Andric #include "Thunks.h"
13*0b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
14*0b57cec5SDimitry Andric #include "llvm/Object/ELF.h"
15*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric using namespace llvm;
18*0b57cec5SDimitry Andric using namespace llvm::support::endian;
19*0b57cec5SDimitry Andric using namespace llvm::ELF;
20*0b57cec5SDimitry Andric using namespace lld;
21*0b57cec5SDimitry Andric using namespace lld::elf;
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric // Page(Expr) is the page address of the expression Expr, defined
24*0b57cec5SDimitry Andric // as (Expr & ~0xFFF). (This applies even if the machine page size
25*0b57cec5SDimitry Andric // supported by the platform has a different value.)
26*0b57cec5SDimitry Andric uint64_t elf::getAArch64Page(uint64_t expr) {
27*0b57cec5SDimitry Andric   return expr & ~static_cast<uint64_t>(0xFFF);
28*0b57cec5SDimitry Andric }
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric namespace {
31*0b57cec5SDimitry Andric class AArch64 : public TargetInfo {
32*0b57cec5SDimitry Andric public:
33*0b57cec5SDimitry Andric   AArch64();
34*0b57cec5SDimitry Andric   RelExpr getRelExpr(RelType type, const Symbol &s,
35*0b57cec5SDimitry Andric                      const uint8_t *loc) const override;
36*0b57cec5SDimitry Andric   RelType getDynRel(RelType type) const override;
37*0b57cec5SDimitry Andric   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
38*0b57cec5SDimitry Andric   void writePltHeader(uint8_t *buf) const override;
39*0b57cec5SDimitry Andric   void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
40*0b57cec5SDimitry Andric                 int32_t index, unsigned relOff) const override;
41*0b57cec5SDimitry Andric   bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
42*0b57cec5SDimitry Andric                   uint64_t branchAddr, const Symbol &s) const override;
43*0b57cec5SDimitry Andric   uint32_t getThunkSectionSpacing() const override;
44*0b57cec5SDimitry Andric   bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
45*0b57cec5SDimitry Andric   bool usesOnlyLowPageBits(RelType type) const override;
46*0b57cec5SDimitry Andric   void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
47*0b57cec5SDimitry Andric   RelExpr adjustRelaxExpr(RelType type, const uint8_t *data,
48*0b57cec5SDimitry Andric                           RelExpr expr) const override;
49*0b57cec5SDimitry Andric   void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override;
50*0b57cec5SDimitry Andric   void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override;
51*0b57cec5SDimitry Andric   void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override;
52*0b57cec5SDimitry Andric };
53*0b57cec5SDimitry Andric } // namespace
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric AArch64::AArch64() {
56*0b57cec5SDimitry Andric   copyRel = R_AARCH64_COPY;
57*0b57cec5SDimitry Andric   relativeRel = R_AARCH64_RELATIVE;
58*0b57cec5SDimitry Andric   iRelativeRel = R_AARCH64_IRELATIVE;
59*0b57cec5SDimitry Andric   gotRel = R_AARCH64_GLOB_DAT;
60*0b57cec5SDimitry Andric   noneRel = R_AARCH64_NONE;
61*0b57cec5SDimitry Andric   pltRel = R_AARCH64_JUMP_SLOT;
62*0b57cec5SDimitry Andric   symbolicRel = R_AARCH64_ABS64;
63*0b57cec5SDimitry Andric   tlsDescRel = R_AARCH64_TLSDESC;
64*0b57cec5SDimitry Andric   tlsGotRel = R_AARCH64_TLS_TPREL64;
65*0b57cec5SDimitry Andric   pltEntrySize = 16;
66*0b57cec5SDimitry Andric   pltHeaderSize = 32;
67*0b57cec5SDimitry Andric   defaultMaxPageSize = 65536;
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric   // Align to the 2 MiB page size (known as a superpage or huge page).
70*0b57cec5SDimitry Andric   // FreeBSD automatically promotes 2 MiB-aligned allocations.
71*0b57cec5SDimitry Andric   defaultImageBase = 0x200000;
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric   needsThunks = true;
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
77*0b57cec5SDimitry Andric                             const uint8_t *loc) const {
78*0b57cec5SDimitry Andric   switch (type) {
79*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
80*0b57cec5SDimitry Andric     return R_AARCH64_TLSDESC_PAGE;
81*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
82*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
83*0b57cec5SDimitry Andric     return R_TLSDESC;
84*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_CALL:
85*0b57cec5SDimitry Andric     return R_TLSDESC_CALL;
86*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_HI12:
87*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
88*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
89*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
90*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
91*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
92*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
93*0b57cec5SDimitry Andric     return R_TLS;
94*0b57cec5SDimitry Andric   case R_AARCH64_CALL26:
95*0b57cec5SDimitry Andric   case R_AARCH64_CONDBR19:
96*0b57cec5SDimitry Andric   case R_AARCH64_JUMP26:
97*0b57cec5SDimitry Andric   case R_AARCH64_TSTBR14:
98*0b57cec5SDimitry Andric     return R_PLT_PC;
99*0b57cec5SDimitry Andric   case R_AARCH64_PREL16:
100*0b57cec5SDimitry Andric   case R_AARCH64_PREL32:
101*0b57cec5SDimitry Andric   case R_AARCH64_PREL64:
102*0b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_LO21:
103*0b57cec5SDimitry Andric   case R_AARCH64_LD_PREL_LO19:
104*0b57cec5SDimitry Andric     return R_PC;
105*0b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21:
106*0b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21_NC:
107*0b57cec5SDimitry Andric     return R_AARCH64_PAGE_PC;
108*0b57cec5SDimitry Andric   case R_AARCH64_LD64_GOT_LO12_NC:
109*0b57cec5SDimitry Andric   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
110*0b57cec5SDimitry Andric     return R_GOT;
111*0b57cec5SDimitry Andric   case R_AARCH64_ADR_GOT_PAGE:
112*0b57cec5SDimitry Andric   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
113*0b57cec5SDimitry Andric     return R_AARCH64_GOT_PAGE_PC;
114*0b57cec5SDimitry Andric   case R_AARCH64_NONE:
115*0b57cec5SDimitry Andric     return R_NONE;
116*0b57cec5SDimitry Andric   default:
117*0b57cec5SDimitry Andric     return R_ABS;
118*0b57cec5SDimitry Andric   }
119*0b57cec5SDimitry Andric }
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric RelExpr AArch64::adjustRelaxExpr(RelType type, const uint8_t *data,
122*0b57cec5SDimitry Andric                                  RelExpr expr) const {
123*0b57cec5SDimitry Andric   if (expr == R_RELAX_TLS_GD_TO_IE) {
124*0b57cec5SDimitry Andric     if (type == R_AARCH64_TLSDESC_ADR_PAGE21)
125*0b57cec5SDimitry Andric       return R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC;
126*0b57cec5SDimitry Andric     return R_RELAX_TLS_GD_TO_IE_ABS;
127*0b57cec5SDimitry Andric   }
128*0b57cec5SDimitry Andric   return expr;
129*0b57cec5SDimitry Andric }
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric bool AArch64::usesOnlyLowPageBits(RelType type) const {
132*0b57cec5SDimitry Andric   switch (type) {
133*0b57cec5SDimitry Andric   default:
134*0b57cec5SDimitry Andric     return false;
135*0b57cec5SDimitry Andric   case R_AARCH64_ADD_ABS_LO12_NC:
136*0b57cec5SDimitry Andric   case R_AARCH64_LD64_GOT_LO12_NC:
137*0b57cec5SDimitry Andric   case R_AARCH64_LDST128_ABS_LO12_NC:
138*0b57cec5SDimitry Andric   case R_AARCH64_LDST16_ABS_LO12_NC:
139*0b57cec5SDimitry Andric   case R_AARCH64_LDST32_ABS_LO12_NC:
140*0b57cec5SDimitry Andric   case R_AARCH64_LDST64_ABS_LO12_NC:
141*0b57cec5SDimitry Andric   case R_AARCH64_LDST8_ABS_LO12_NC:
142*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
143*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
144*0b57cec5SDimitry Andric   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
145*0b57cec5SDimitry Andric     return true;
146*0b57cec5SDimitry Andric   }
147*0b57cec5SDimitry Andric }
148*0b57cec5SDimitry Andric 
149*0b57cec5SDimitry Andric RelType AArch64::getDynRel(RelType type) const {
150*0b57cec5SDimitry Andric   if (type == R_AARCH64_ABS64)
151*0b57cec5SDimitry Andric     return type;
152*0b57cec5SDimitry Andric   return R_AARCH64_NONE;
153*0b57cec5SDimitry Andric }
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric void AArch64::writeGotPlt(uint8_t *buf, const Symbol &) const {
156*0b57cec5SDimitry Andric   write64le(buf, in.plt->getVA());
157*0b57cec5SDimitry Andric }
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric void AArch64::writePltHeader(uint8_t *buf) const {
160*0b57cec5SDimitry Andric   const uint8_t pltData[] = {
161*0b57cec5SDimitry Andric       0xf0, 0x7b, 0xbf, 0xa9, // stp    x16, x30, [sp,#-16]!
162*0b57cec5SDimitry Andric       0x10, 0x00, 0x00, 0x90, // adrp   x16, Page(&(.plt.got[2]))
163*0b57cec5SDimitry Andric       0x11, 0x02, 0x40, 0xf9, // ldr    x17, [x16, Offset(&(.plt.got[2]))]
164*0b57cec5SDimitry Andric       0x10, 0x02, 0x00, 0x91, // add    x16, x16, Offset(&(.plt.got[2]))
165*0b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6, // br     x17
166*0b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5, // nop
167*0b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5, // nop
168*0b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5  // nop
169*0b57cec5SDimitry Andric   };
170*0b57cec5SDimitry Andric   memcpy(buf, pltData, sizeof(pltData));
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric   uint64_t got = in.gotPlt->getVA();
173*0b57cec5SDimitry Andric   uint64_t plt = in.plt->getVA();
174*0b57cec5SDimitry Andric   relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
175*0b57cec5SDimitry Andric               getAArch64Page(got + 16) - getAArch64Page(plt + 4));
176*0b57cec5SDimitry Andric   relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
177*0b57cec5SDimitry Andric   relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
178*0b57cec5SDimitry Andric }
179*0b57cec5SDimitry Andric 
180*0b57cec5SDimitry Andric void AArch64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
181*0b57cec5SDimitry Andric                        uint64_t pltEntryAddr, int32_t index,
182*0b57cec5SDimitry Andric                        unsigned relOff) const {
183*0b57cec5SDimitry Andric   const uint8_t inst[] = {
184*0b57cec5SDimitry Andric       0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
185*0b57cec5SDimitry Andric       0x11, 0x02, 0x40, 0xf9, // ldr  x17, [x16, Offset(&(.plt.got[n]))]
186*0b57cec5SDimitry Andric       0x10, 0x02, 0x00, 0x91, // add  x16, x16, Offset(&(.plt.got[n]))
187*0b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6  // br   x17
188*0b57cec5SDimitry Andric   };
189*0b57cec5SDimitry Andric   memcpy(buf, inst, sizeof(inst));
190*0b57cec5SDimitry Andric 
191*0b57cec5SDimitry Andric   relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21,
192*0b57cec5SDimitry Andric               getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
193*0b57cec5SDimitry Andric   relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
194*0b57cec5SDimitry Andric   relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
195*0b57cec5SDimitry Andric }
196*0b57cec5SDimitry Andric 
197*0b57cec5SDimitry Andric bool AArch64::needsThunk(RelExpr expr, RelType type, const InputFile *file,
198*0b57cec5SDimitry Andric                          uint64_t branchAddr, const Symbol &s) const {
199*0b57cec5SDimitry Andric   // ELF for the ARM 64-bit architecture, section Call and Jump relocations
200*0b57cec5SDimitry Andric   // only permits range extension thunks for R_AARCH64_CALL26 and
201*0b57cec5SDimitry Andric   // R_AARCH64_JUMP26 relocation types.
202*0b57cec5SDimitry Andric   if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26)
203*0b57cec5SDimitry Andric     return false;
204*0b57cec5SDimitry Andric   uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA();
205*0b57cec5SDimitry Andric   return !inBranchRange(type, branchAddr, dst);
206*0b57cec5SDimitry Andric }
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric uint32_t AArch64::getThunkSectionSpacing() const {
209*0b57cec5SDimitry Andric   // See comment in Arch/ARM.cpp for a more detailed explanation of
210*0b57cec5SDimitry Andric   // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to
211*0b57cec5SDimitry Andric   // Thunk have a range of +/- 128 MiB
212*0b57cec5SDimitry Andric   return (128 * 1024 * 1024) - 0x30000;
213*0b57cec5SDimitry Andric }
214*0b57cec5SDimitry Andric 
215*0b57cec5SDimitry Andric bool AArch64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
216*0b57cec5SDimitry Andric   if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26)
217*0b57cec5SDimitry Andric     return true;
218*0b57cec5SDimitry Andric   // The AArch64 call and unconditional branch instructions have a range of
219*0b57cec5SDimitry Andric   // +/- 128 MiB.
220*0b57cec5SDimitry Andric   uint64_t range = 128 * 1024 * 1024;
221*0b57cec5SDimitry Andric   if (dst > src) {
222*0b57cec5SDimitry Andric     // Immediate of branch is signed.
223*0b57cec5SDimitry Andric     range -= 4;
224*0b57cec5SDimitry Andric     return dst - src <= range;
225*0b57cec5SDimitry Andric   }
226*0b57cec5SDimitry Andric   return src - dst <= range;
227*0b57cec5SDimitry Andric }
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric static void write32AArch64Addr(uint8_t *l, uint64_t imm) {
230*0b57cec5SDimitry Andric   uint32_t immLo = (imm & 0x3) << 29;
231*0b57cec5SDimitry Andric   uint32_t immHi = (imm & 0x1FFFFC) << 3;
232*0b57cec5SDimitry Andric   uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3);
233*0b57cec5SDimitry Andric   write32le(l, (read32le(l) & ~mask) | immLo | immHi);
234*0b57cec5SDimitry Andric }
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric // Return the bits [Start, End] from Val shifted Start bits.
237*0b57cec5SDimitry Andric // For instance, getBits(0xF0, 4, 8) returns 0xF.
238*0b57cec5SDimitry Andric static uint64_t getBits(uint64_t val, int start, int end) {
239*0b57cec5SDimitry Andric   uint64_t mask = ((uint64_t)1 << (end + 1 - start)) - 1;
240*0b57cec5SDimitry Andric   return (val >> start) & mask;
241*0b57cec5SDimitry Andric }
242*0b57cec5SDimitry Andric 
243*0b57cec5SDimitry Andric static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); }
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric // Update the immediate field in a AARCH64 ldr, str, and add instruction.
246*0b57cec5SDimitry Andric static void or32AArch64Imm(uint8_t *l, uint64_t imm) {
247*0b57cec5SDimitry Andric   or32le(l, (imm & 0xFFF) << 10);
248*0b57cec5SDimitry Andric }
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
251*0b57cec5SDimitry Andric   switch (type) {
252*0b57cec5SDimitry Andric   case R_AARCH64_ABS16:
253*0b57cec5SDimitry Andric   case R_AARCH64_PREL16:
254*0b57cec5SDimitry Andric     checkIntUInt(loc, val, 16, type);
255*0b57cec5SDimitry Andric     write16le(loc, val);
256*0b57cec5SDimitry Andric     break;
257*0b57cec5SDimitry Andric   case R_AARCH64_ABS32:
258*0b57cec5SDimitry Andric   case R_AARCH64_PREL32:
259*0b57cec5SDimitry Andric     checkIntUInt(loc, val, 32, type);
260*0b57cec5SDimitry Andric     write32le(loc, val);
261*0b57cec5SDimitry Andric     break;
262*0b57cec5SDimitry Andric   case R_AARCH64_ABS64:
263*0b57cec5SDimitry Andric   case R_AARCH64_PREL64:
264*0b57cec5SDimitry Andric     write64le(loc, val);
265*0b57cec5SDimitry Andric     break;
266*0b57cec5SDimitry Andric   case R_AARCH64_ADD_ABS_LO12_NC:
267*0b57cec5SDimitry Andric     or32AArch64Imm(loc, val);
268*0b57cec5SDimitry Andric     break;
269*0b57cec5SDimitry Andric   case R_AARCH64_ADR_GOT_PAGE:
270*0b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21:
271*0b57cec5SDimitry Andric   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
272*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
273*0b57cec5SDimitry Andric     checkInt(loc, val, 33, type);
274*0b57cec5SDimitry Andric     LLVM_FALLTHROUGH;
275*0b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_PG_HI21_NC:
276*0b57cec5SDimitry Andric     write32AArch64Addr(loc, val >> 12);
277*0b57cec5SDimitry Andric     break;
278*0b57cec5SDimitry Andric   case R_AARCH64_ADR_PREL_LO21:
279*0b57cec5SDimitry Andric     checkInt(loc, val, 21, type);
280*0b57cec5SDimitry Andric     write32AArch64Addr(loc, val);
281*0b57cec5SDimitry Andric     break;
282*0b57cec5SDimitry Andric   case R_AARCH64_JUMP26:
283*0b57cec5SDimitry Andric     // Normally we would just write the bits of the immediate field, however
284*0b57cec5SDimitry Andric     // when patching instructions for the cpu errata fix -fix-cortex-a53-843419
285*0b57cec5SDimitry Andric     // we want to replace a non-branch instruction with a branch immediate
286*0b57cec5SDimitry Andric     // instruction. By writing all the bits of the instruction including the
287*0b57cec5SDimitry Andric     // opcode and the immediate (0 001 | 01 imm26) we can do this
288*0b57cec5SDimitry Andric     // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of
289*0b57cec5SDimitry Andric     // the instruction we want to patch.
290*0b57cec5SDimitry Andric     write32le(loc, 0x14000000);
291*0b57cec5SDimitry Andric     LLVM_FALLTHROUGH;
292*0b57cec5SDimitry Andric   case R_AARCH64_CALL26:
293*0b57cec5SDimitry Andric     checkInt(loc, val, 28, type);
294*0b57cec5SDimitry Andric     or32le(loc, (val & 0x0FFFFFFC) >> 2);
295*0b57cec5SDimitry Andric     break;
296*0b57cec5SDimitry Andric   case R_AARCH64_CONDBR19:
297*0b57cec5SDimitry Andric   case R_AARCH64_LD_PREL_LO19:
298*0b57cec5SDimitry Andric     checkAlignment(loc, val, 4, type);
299*0b57cec5SDimitry Andric     checkInt(loc, val, 21, type);
300*0b57cec5SDimitry Andric     or32le(loc, (val & 0x1FFFFC) << 3);
301*0b57cec5SDimitry Andric     break;
302*0b57cec5SDimitry Andric   case R_AARCH64_LDST8_ABS_LO12_NC:
303*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
304*0b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 0, 11));
305*0b57cec5SDimitry Andric     break;
306*0b57cec5SDimitry Andric   case R_AARCH64_LDST16_ABS_LO12_NC:
307*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
308*0b57cec5SDimitry Andric     checkAlignment(loc, val, 2, type);
309*0b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 1, 11));
310*0b57cec5SDimitry Andric     break;
311*0b57cec5SDimitry Andric   case R_AARCH64_LDST32_ABS_LO12_NC:
312*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
313*0b57cec5SDimitry Andric     checkAlignment(loc, val, 4, type);
314*0b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 2, 11));
315*0b57cec5SDimitry Andric     break;
316*0b57cec5SDimitry Andric   case R_AARCH64_LDST64_ABS_LO12_NC:
317*0b57cec5SDimitry Andric   case R_AARCH64_LD64_GOT_LO12_NC:
318*0b57cec5SDimitry Andric   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
319*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
320*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
321*0b57cec5SDimitry Andric     checkAlignment(loc, val, 8, type);
322*0b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 3, 11));
323*0b57cec5SDimitry Andric     break;
324*0b57cec5SDimitry Andric   case R_AARCH64_LDST128_ABS_LO12_NC:
325*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
326*0b57cec5SDimitry Andric     checkAlignment(loc, val, 16, type);
327*0b57cec5SDimitry Andric     or32AArch64Imm(loc, getBits(val, 4, 11));
328*0b57cec5SDimitry Andric     break;
329*0b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G0_NC:
330*0b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF) << 5);
331*0b57cec5SDimitry Andric     break;
332*0b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G1_NC:
333*0b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF0000) >> 11);
334*0b57cec5SDimitry Andric     break;
335*0b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G2_NC:
336*0b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF00000000) >> 27);
337*0b57cec5SDimitry Andric     break;
338*0b57cec5SDimitry Andric   case R_AARCH64_MOVW_UABS_G3:
339*0b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFF000000000000) >> 43);
340*0b57cec5SDimitry Andric     break;
341*0b57cec5SDimitry Andric   case R_AARCH64_TSTBR14:
342*0b57cec5SDimitry Andric     checkInt(loc, val, 16, type);
343*0b57cec5SDimitry Andric     or32le(loc, (val & 0xFFFC) << 3);
344*0b57cec5SDimitry Andric     break;
345*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_HI12:
346*0b57cec5SDimitry Andric     checkUInt(loc, val, 24, type);
347*0b57cec5SDimitry Andric     or32AArch64Imm(loc, val >> 12);
348*0b57cec5SDimitry Andric     break;
349*0b57cec5SDimitry Andric   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
350*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
351*0b57cec5SDimitry Andric     or32AArch64Imm(loc, val);
352*0b57cec5SDimitry Andric     break;
353*0b57cec5SDimitry Andric   default:
354*0b57cec5SDimitry Andric     error(getErrorLocation(loc) + "unrecognized relocation " + toString(type));
355*0b57cec5SDimitry Andric   }
356*0b57cec5SDimitry Andric }
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric void AArch64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const {
359*0b57cec5SDimitry Andric   // TLSDESC Global-Dynamic relocation are in the form:
360*0b57cec5SDimitry Andric   //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
361*0b57cec5SDimitry Andric   //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
362*0b57cec5SDimitry Andric   //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
363*0b57cec5SDimitry Andric   //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
364*0b57cec5SDimitry Andric   //   blr     x1
365*0b57cec5SDimitry Andric   // And it can optimized to:
366*0b57cec5SDimitry Andric   //   movz    x0, #0x0, lsl #16
367*0b57cec5SDimitry Andric   //   movk    x0, #0x10
368*0b57cec5SDimitry Andric   //   nop
369*0b57cec5SDimitry Andric   //   nop
370*0b57cec5SDimitry Andric   checkUInt(loc, val, 32, type);
371*0b57cec5SDimitry Andric 
372*0b57cec5SDimitry Andric   switch (type) {
373*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
374*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_CALL:
375*0b57cec5SDimitry Andric     write32le(loc, 0xd503201f); // nop
376*0b57cec5SDimitry Andric     return;
377*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
378*0b57cec5SDimitry Andric     write32le(loc, 0xd2a00000 | (((val >> 16) & 0xffff) << 5)); // movz
379*0b57cec5SDimitry Andric     return;
380*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
381*0b57cec5SDimitry Andric     write32le(loc, 0xf2800000 | ((val & 0xffff) << 5)); // movk
382*0b57cec5SDimitry Andric     return;
383*0b57cec5SDimitry Andric   default:
384*0b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
385*0b57cec5SDimitry Andric   }
386*0b57cec5SDimitry Andric }
387*0b57cec5SDimitry Andric 
388*0b57cec5SDimitry Andric void AArch64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const {
389*0b57cec5SDimitry Andric   // TLSDESC Global-Dynamic relocation are in the form:
390*0b57cec5SDimitry Andric   //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
391*0b57cec5SDimitry Andric   //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
392*0b57cec5SDimitry Andric   //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
393*0b57cec5SDimitry Andric   //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
394*0b57cec5SDimitry Andric   //   blr     x1
395*0b57cec5SDimitry Andric   // And it can optimized to:
396*0b57cec5SDimitry Andric   //   adrp    x0, :gottprel:v
397*0b57cec5SDimitry Andric   //   ldr     x0, [x0, :gottprel_lo12:v]
398*0b57cec5SDimitry Andric   //   nop
399*0b57cec5SDimitry Andric   //   nop
400*0b57cec5SDimitry Andric 
401*0b57cec5SDimitry Andric   switch (type) {
402*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADD_LO12:
403*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_CALL:
404*0b57cec5SDimitry Andric     write32le(loc, 0xd503201f); // nop
405*0b57cec5SDimitry Andric     break;
406*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_ADR_PAGE21:
407*0b57cec5SDimitry Andric     write32le(loc, 0x90000000); // adrp
408*0b57cec5SDimitry Andric     relocateOne(loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, val);
409*0b57cec5SDimitry Andric     break;
410*0b57cec5SDimitry Andric   case R_AARCH64_TLSDESC_LD64_LO12:
411*0b57cec5SDimitry Andric     write32le(loc, 0xf9400000); // ldr
412*0b57cec5SDimitry Andric     relocateOne(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val);
413*0b57cec5SDimitry Andric     break;
414*0b57cec5SDimitry Andric   default:
415*0b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
416*0b57cec5SDimitry Andric   }
417*0b57cec5SDimitry Andric }
418*0b57cec5SDimitry Andric 
419*0b57cec5SDimitry Andric void AArch64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const {
420*0b57cec5SDimitry Andric   checkUInt(loc, val, 32, type);
421*0b57cec5SDimitry Andric 
422*0b57cec5SDimitry Andric   if (type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
423*0b57cec5SDimitry Andric     // Generate MOVZ.
424*0b57cec5SDimitry Andric     uint32_t regNo = read32le(loc) & 0x1f;
425*0b57cec5SDimitry Andric     write32le(loc, (0xd2a00000 | regNo) | (((val >> 16) & 0xffff) << 5));
426*0b57cec5SDimitry Andric     return;
427*0b57cec5SDimitry Andric   }
428*0b57cec5SDimitry Andric   if (type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
429*0b57cec5SDimitry Andric     // Generate MOVK.
430*0b57cec5SDimitry Andric     uint32_t regNo = read32le(loc) & 0x1f;
431*0b57cec5SDimitry Andric     write32le(loc, (0xf2800000 | regNo) | ((val & 0xffff) << 5));
432*0b57cec5SDimitry Andric     return;
433*0b57cec5SDimitry Andric   }
434*0b57cec5SDimitry Andric   llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
435*0b57cec5SDimitry Andric }
436*0b57cec5SDimitry Andric 
437*0b57cec5SDimitry Andric // AArch64 may use security features in variant PLT sequences. These are:
438*0b57cec5SDimitry Andric // Pointer Authentication (PAC), introduced in armv8.3-a and Branch Target
439*0b57cec5SDimitry Andric // Indicator (BTI) introduced in armv8.5-a. The additional instructions used
440*0b57cec5SDimitry Andric // in the variant Plt sequences are encoded in the Hint space so they can be
441*0b57cec5SDimitry Andric // deployed on older architectures, which treat the instructions as a nop.
442*0b57cec5SDimitry Andric // PAC and BTI can be combined leading to the following combinations:
443*0b57cec5SDimitry Andric // writePltHeader
444*0b57cec5SDimitry Andric // writePltHeaderBti (no PAC Header needed)
445*0b57cec5SDimitry Andric // writePlt
446*0b57cec5SDimitry Andric // writePltBti (BTI only)
447*0b57cec5SDimitry Andric // writePltPac (PAC only)
448*0b57cec5SDimitry Andric // writePltBtiPac (BTI and PAC)
449*0b57cec5SDimitry Andric //
450*0b57cec5SDimitry Andric // When PAC is enabled the dynamic loader encrypts the address that it places
451*0b57cec5SDimitry Andric // in the .got.plt using the pacia1716 instruction which encrypts the value in
452*0b57cec5SDimitry Andric // x17 using the modifier in x16. The static linker places autia1716 before the
453*0b57cec5SDimitry Andric // indirect branch to x17 to authenticate the address in x17 with the modifier
454*0b57cec5SDimitry Andric // in x16. This makes it more difficult for an attacker to modify the value in
455*0b57cec5SDimitry Andric // the .got.plt.
456*0b57cec5SDimitry Andric //
457*0b57cec5SDimitry Andric // When BTI is enabled all indirect branches must land on a bti instruction.
458*0b57cec5SDimitry Andric // The static linker must place a bti instruction at the start of any PLT entry
459*0b57cec5SDimitry Andric // that may be the target of an indirect branch. As the PLT entries call the
460*0b57cec5SDimitry Andric // lazy resolver indirectly this must have a bti instruction at start. In
461*0b57cec5SDimitry Andric // general a bti instruction is not needed for a PLT entry as indirect calls
462*0b57cec5SDimitry Andric // are resolved to the function address and not the PLT entry for the function.
463*0b57cec5SDimitry Andric // There are a small number of cases where the PLT address can escape, such as
464*0b57cec5SDimitry Andric // taking the address of a function or ifunc via a non got-generating
465*0b57cec5SDimitry Andric // relocation, and a shared library refers to that symbol.
466*0b57cec5SDimitry Andric //
467*0b57cec5SDimitry Andric // We use the bti c variant of the instruction which permits indirect branches
468*0b57cec5SDimitry Andric // (br) via x16/x17 and indirect function calls (blr) via any register. The ABI
469*0b57cec5SDimitry Andric // guarantees that all indirect branches from code requiring BTI protection
470*0b57cec5SDimitry Andric // will go via x16/x17
471*0b57cec5SDimitry Andric 
472*0b57cec5SDimitry Andric namespace {
473*0b57cec5SDimitry Andric class AArch64BtiPac final : public AArch64 {
474*0b57cec5SDimitry Andric public:
475*0b57cec5SDimitry Andric   AArch64BtiPac();
476*0b57cec5SDimitry Andric   void writePltHeader(uint8_t *buf) const override;
477*0b57cec5SDimitry Andric   void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
478*0b57cec5SDimitry Andric                 int32_t index, unsigned relOff) const override;
479*0b57cec5SDimitry Andric 
480*0b57cec5SDimitry Andric private:
481*0b57cec5SDimitry Andric   bool btiHeader; // bti instruction needed in PLT Header
482*0b57cec5SDimitry Andric   bool btiEntry;  // bti instruction needed in PLT Entry
483*0b57cec5SDimitry Andric   bool pacEntry;  // autia1716 instruction needed in PLT Entry
484*0b57cec5SDimitry Andric };
485*0b57cec5SDimitry Andric } // namespace
486*0b57cec5SDimitry Andric 
487*0b57cec5SDimitry Andric AArch64BtiPac::AArch64BtiPac() {
488*0b57cec5SDimitry Andric   btiHeader = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
489*0b57cec5SDimitry Andric   // A BTI (Branch Target Indicator) Plt Entry is only required if the
490*0b57cec5SDimitry Andric   // address of the PLT entry can be taken by the program, which permits an
491*0b57cec5SDimitry Andric   // indirect jump to the PLT entry. This can happen when the address
492*0b57cec5SDimitry Andric   // of the PLT entry for a function is canonicalised due to the address of
493*0b57cec5SDimitry Andric   // the function in an executable being taken by a shared library.
494*0b57cec5SDimitry Andric   // FIXME: There is a potential optimization to omit the BTI if we detect
495*0b57cec5SDimitry Andric   // that the address of the PLT entry isn't taken.
496*0b57cec5SDimitry Andric   btiEntry = btiHeader && !config->shared;
497*0b57cec5SDimitry Andric   pacEntry = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC);
498*0b57cec5SDimitry Andric 
499*0b57cec5SDimitry Andric   if (btiEntry || pacEntry)
500*0b57cec5SDimitry Andric     pltEntrySize = 24;
501*0b57cec5SDimitry Andric }
502*0b57cec5SDimitry Andric 
503*0b57cec5SDimitry Andric void AArch64BtiPac::writePltHeader(uint8_t *buf) const {
504*0b57cec5SDimitry Andric   const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
505*0b57cec5SDimitry Andric   const uint8_t pltData[] = {
506*0b57cec5SDimitry Andric       0xf0, 0x7b, 0xbf, 0xa9, // stp    x16, x30, [sp,#-16]!
507*0b57cec5SDimitry Andric       0x10, 0x00, 0x00, 0x90, // adrp   x16, Page(&(.plt.got[2]))
508*0b57cec5SDimitry Andric       0x11, 0x02, 0x40, 0xf9, // ldr    x17, [x16, Offset(&(.plt.got[2]))]
509*0b57cec5SDimitry Andric       0x10, 0x02, 0x00, 0x91, // add    x16, x16, Offset(&(.plt.got[2]))
510*0b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6, // br     x17
511*0b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5, // nop
512*0b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5  // nop
513*0b57cec5SDimitry Andric   };
514*0b57cec5SDimitry Andric   const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
515*0b57cec5SDimitry Andric 
516*0b57cec5SDimitry Andric   uint64_t got = in.gotPlt->getVA();
517*0b57cec5SDimitry Andric   uint64_t plt = in.plt->getVA();
518*0b57cec5SDimitry Andric 
519*0b57cec5SDimitry Andric   if (btiHeader) {
520*0b57cec5SDimitry Andric     // PltHeader is called indirectly by plt[N]. Prefix pltData with a BTI C
521*0b57cec5SDimitry Andric     // instruction.
522*0b57cec5SDimitry Andric     memcpy(buf, btiData, sizeof(btiData));
523*0b57cec5SDimitry Andric     buf += sizeof(btiData);
524*0b57cec5SDimitry Andric     plt += sizeof(btiData);
525*0b57cec5SDimitry Andric   }
526*0b57cec5SDimitry Andric   memcpy(buf, pltData, sizeof(pltData));
527*0b57cec5SDimitry Andric 
528*0b57cec5SDimitry Andric   relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
529*0b57cec5SDimitry Andric               getAArch64Page(got + 16) - getAArch64Page(plt + 8));
530*0b57cec5SDimitry Andric   relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
531*0b57cec5SDimitry Andric   relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
532*0b57cec5SDimitry Andric   if (!btiHeader)
533*0b57cec5SDimitry Andric     // We didn't add the BTI c instruction so round out size with NOP.
534*0b57cec5SDimitry Andric     memcpy(buf + sizeof(pltData), nopData, sizeof(nopData));
535*0b57cec5SDimitry Andric }
536*0b57cec5SDimitry Andric 
537*0b57cec5SDimitry Andric void AArch64BtiPac::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
538*0b57cec5SDimitry Andric                              uint64_t pltEntryAddr, int32_t index,
539*0b57cec5SDimitry Andric                              unsigned relOff) const {
540*0b57cec5SDimitry Andric   // The PLT entry is of the form:
541*0b57cec5SDimitry Andric   // [btiData] addrInst (pacBr | stdBr) [nopData]
542*0b57cec5SDimitry Andric   const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
543*0b57cec5SDimitry Andric   const uint8_t addrInst[] = {
544*0b57cec5SDimitry Andric       0x10, 0x00, 0x00, 0x90,  // adrp x16, Page(&(.plt.got[n]))
545*0b57cec5SDimitry Andric       0x11, 0x02, 0x40, 0xf9,  // ldr  x17, [x16, Offset(&(.plt.got[n]))]
546*0b57cec5SDimitry Andric       0x10, 0x02, 0x00, 0x91   // add  x16, x16, Offset(&(.plt.got[n]))
547*0b57cec5SDimitry Andric   };
548*0b57cec5SDimitry Andric   const uint8_t pacBr[] = {
549*0b57cec5SDimitry Andric       0x9f, 0x21, 0x03, 0xd5,  // autia1716
550*0b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6   // br   x17
551*0b57cec5SDimitry Andric   };
552*0b57cec5SDimitry Andric   const uint8_t stdBr[] = {
553*0b57cec5SDimitry Andric       0x20, 0x02, 0x1f, 0xd6,  // br   x17
554*0b57cec5SDimitry Andric       0x1f, 0x20, 0x03, 0xd5   // nop
555*0b57cec5SDimitry Andric   };
556*0b57cec5SDimitry Andric   const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
557*0b57cec5SDimitry Andric 
558*0b57cec5SDimitry Andric   if (btiEntry) {
559*0b57cec5SDimitry Andric     memcpy(buf, btiData, sizeof(btiData));
560*0b57cec5SDimitry Andric     buf += sizeof(btiData);
561*0b57cec5SDimitry Andric     pltEntryAddr += sizeof(btiData);
562*0b57cec5SDimitry Andric   }
563*0b57cec5SDimitry Andric 
564*0b57cec5SDimitry Andric   memcpy(buf, addrInst, sizeof(addrInst));
565*0b57cec5SDimitry Andric   relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21,
566*0b57cec5SDimitry Andric               getAArch64Page(gotPltEntryAddr) -
567*0b57cec5SDimitry Andric                   getAArch64Page(pltEntryAddr));
568*0b57cec5SDimitry Andric   relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
569*0b57cec5SDimitry Andric   relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
570*0b57cec5SDimitry Andric 
571*0b57cec5SDimitry Andric   if (pacEntry)
572*0b57cec5SDimitry Andric     memcpy(buf + sizeof(addrInst), pacBr, sizeof(pacBr));
573*0b57cec5SDimitry Andric   else
574*0b57cec5SDimitry Andric     memcpy(buf + sizeof(addrInst), stdBr, sizeof(stdBr));
575*0b57cec5SDimitry Andric   if (!btiEntry)
576*0b57cec5SDimitry Andric     // We didn't add the BTI c instruction so round out size with NOP.
577*0b57cec5SDimitry Andric     memcpy(buf + sizeof(addrInst) + sizeof(stdBr), nopData, sizeof(nopData));
578*0b57cec5SDimitry Andric }
579*0b57cec5SDimitry Andric 
580*0b57cec5SDimitry Andric static TargetInfo *getTargetInfo() {
581*0b57cec5SDimitry Andric   if (config->andFeatures & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
582*0b57cec5SDimitry Andric                              GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) {
583*0b57cec5SDimitry Andric     static AArch64BtiPac t;
584*0b57cec5SDimitry Andric     return &t;
585*0b57cec5SDimitry Andric   }
586*0b57cec5SDimitry Andric   static AArch64 t;
587*0b57cec5SDimitry Andric   return &t;
588*0b57cec5SDimitry Andric }
589*0b57cec5SDimitry Andric 
590*0b57cec5SDimitry Andric TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); }
591